diff --git a/Assets/Editor/Translation/scriptcanvas_en_us.ts b/Assets/Editor/Translation/scriptcanvas_en_us.ts
index 7b8361c879..6d436b7caf 100644
--- a/Assets/Editor/Translation/scriptcanvas_en_us.ts
+++ b/Assets/Editor/Translation/scriptcanvas_en_us.ts
@@ -62164,7 +62164,7 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro
HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGADDED_OUTPUT0_NAME
Simple Type: EntityID C++ Type: const EntityId&
- Entity
+ EntityID
HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGADDED_OUTPUT0_TOOLTIP
@@ -62202,7 +62202,7 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro
HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGREMOVED_OUTPUT0_NAME
Simple Type: EntityID C++ Type: const EntityId&
- Entity
+ EntityId
HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGREMOVED_OUTPUT0_TOOLTIP
@@ -81852,7 +81852,7 @@ The element is removed from its current parent and added as a child of the new p
HANDLER_SPAWNERCOMPONENTNOTIFICATIONBUS_ONENTITYSPAWNED_OUTPUT1_NAME
Simple Type: EntityID C++ Type: const EntityId&
- Entity
+ EntityID
HANDLER_SPAWNERCOMPONENTNOTIFICATIONBUS_ONENTITYSPAWNED_OUTPUT1_TOOLTIP
@@ -89198,7 +89198,7 @@ The element is removed from its current parent and added as a child of the new p
HANDLER_ENTITYBUS_ONENTITYACTIVATED_OUTPUT0_NAME
Simple Type: EntityID C++ Type: const EntityId&
- Entity
+ EntityID
HANDLER_ENTITYBUS_ONENTITYACTIVATED_OUTPUT0_TOOLTIP
@@ -89236,7 +89236,7 @@ The element is removed from its current parent and added as a child of the new p
HANDLER_ENTITYBUS_ONENTITYDEACTIVATED_OUTPUT0_NAME
Simple Type: EntityID C++ Type: const EntityId&
- Entity
+ EntityID
HANDLER_ENTITYBUS_ONENTITYDEACTIVATED_OUTPUT0_TOOLTIP
diff --git a/Assets/Engine/EngineAssets/Slices/DefaultLevelSetup.slice b/Assets/Engine/EngineAssets/Slices/DefaultLevelSetup.slice
index 1b7dfdf40d..b82c482c4f 100644
--- a/Assets/Engine/EngineAssets/Slices/DefaultLevelSetup.slice
+++ b/Assets/Engine/EngineAssets/Slices/DefaultLevelSetup.slice
@@ -145,7 +145,7 @@
-
+
diff --git a/Assets/Engine/Entities/GeomCache.ent b/Assets/Engine/Entities/GeomCache.ent
deleted file mode 100644
index e7a63190c3..0000000000
--- a/Assets/Engine/Entities/GeomCache.ent
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:cf441215a769562f88aa20711aee68dadcbf02597d1e2270547055e8e6aec6a3
-size 77
diff --git a/Assets/Engine/Scripts/Entities/Render/GeomCache.lua b/Assets/Engine/Scripts/Entities/Render/GeomCache.lua
deleted file mode 100644
index b496aecd8d..0000000000
--- a/Assets/Engine/Scripts/Entities/Render/GeomCache.lua
+++ /dev/null
@@ -1,178 +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
---
---
---
-----------------------------------------------------------------------------------------------------
-Script.ReloadScript("scripts/Utils/EntityUtils.lua")
-
-GeomCache =
-{
- Properties = {
- geomcacheFile = "EngineAssets/GeomCaches/defaultGeomCache.cax",
- bPlaying = 0,
- fStartTime = 0,
- bLooping = 0,
- objectStandIn = "",
- materialStandInMaterial = "",
- objectFirstFrameStandIn = "",
- materialFirstFrameStandInMaterial = "",
- objectLastFrameStandIn = "",
- materialLastFrameStandInMaterial = "",
- fStandInDistance = 0,
- fStreamInDistance = 0,
- Physics = {
- bPhysicalize = 0,
- }
- },
-
- Editor={
- Icon = "animobject.bmp",
- IconOnTop = 1,
- },
-
- bPlaying = 0,
- currentTime = 0,
- precacheTime = 0,
- bPrecachedOutputTriggered = false,
-}
-
-function GeomCache:OnLoad(table)
- self.currentTime = table.currentTime;
-end
-
-function GeomCache:OnSave(table)
- table.currentTime = self.currentTime;
-end
-
-function GeomCache:OnSpawn()
- self.currentTime = self.Properties.fStartTime;
- self:SetFromProperties();
-end
-
-function GeomCache:OnReset()
- self.currentTime = self.Properties.fStartTime;
- self.bPrecachedOutputTriggered = true;
- self:SetFromProperties();
-end
-
-function GeomCache:SetFromProperties()
- local Properties = self.Properties;
-
- if (Properties.geomcacheFile == "") then
- do return end;
- end
-
- self:LoadGeomCache(0, Properties.geomcacheFile);
-
- self.bPlaying = Properties.bPlaying;
- if (self.bPlaying == 0) then
- self.currentTime = Properties.fStartTime;
- end
-
- self:SetGeomCachePlaybackTime(self.currentTime);
- self:SetGeomCacheParams(Properties.bLooping, Properties.objectStandIn, Properties.materialStandInMaterial, Properties.objectFirstFrameStandIn,
- Properties.materialFirstFrameStandInMaterial, Properties.objectLastFrameStandIn, Properties.materialLastFrameStandInMaterial,
- Properties.fStandInDistance, Properties.fStreamInDistance);
- self:SetGeomCacheStreaming(false, 0);
-
- if (Properties.Physics.bPhysicalize == 1) then
- local tempPhysParams = EntityCommon.TempPhysParams;
- self:Physicalize(0, PE_ARTICULATED, tempPhysParams);
- end
-
- self:Activate(1);
-end
-
-function GeomCache:PhysicalizeThis()
- local Physics = self.Properties.Physics;
- EntityCommon.PhysicalizeRigid(self, 0, Physics, false);
-end
-
-function GeomCache:OnUpdate(dt)
- if (self.bPlaying == 1) then
- self:SetGeomCachePlaybackTime(self.currentTime);
- end
-
- if (self:IsGeomCacheStreaming() and not self.bPrecachedOutputTriggered) then
- local precachedTime = self:GetGeomCachePrecachedTime();
- if (precachedTime >= self.precacheTime) then
- self:ActivateOutput("Precached", true);
- self.bPrecachedOutputTriggered = true;
- end
- end
-
- if (self.bPlaying == 1) then
- self.currentTime = self.currentTime + dt;
- end
-end
-
-function GeomCache:OnPropertyChange()
- self:SetFromProperties();
-end
-
-function GeomCache:Event_Start(sender, val)
- self.bPlaying = 1;
-end
-
-function GeomCache:Event_Stop(sender, value)
- self.bPlaying = 0;
-end
-
-function GeomCache:Event_SetTime(sender, value)
- self.currentTime = value;
-end
-
-function GeomCache:Event_StartStreaming(sender, value)
- self.bPrecachedOutputTriggered = false;
- self:SetGeomCacheStreaming(true, self.currentTime);
-end
-
-function GeomCache:Event_StopStreaming(sender, value)
- self:SetGeomCacheStreaming(false, 0);
-end
-
-function GeomCache:Event_PrecacheTime(sender, value)
- self.precacheTime = value;
-end
-
-function GeomCache:Event_Hide(sender, value)
- self:Hide(1);
-end
-
-function GeomCache:Event_Unhide(sender, value)
- self:Hide(0);
-end
-
-function GeomCache:Event_StopDrawing(sender, value)
- self:SetGeomCacheDrawing(false);
-end
-
-function GeomCache:Event_StartDrawing(sender, value)
- self:SetGeomCacheDrawing(true);
-end
-
-GeomCache.FlowEvents =
-{
- Inputs =
- {
- Start = { GeomCache.Event_Start, "any" },
- Stop = { GeomCache.Event_Stop, "any" },
- SetTime = { GeomCache.Event_SetTime, "float" },
- StartStreaming = { GeomCache.Event_StartStreaming, "any" },
- StopStreaming = { GeomCache.Event_StopStreaming, "any" },
- PrecacheTime = { GeomCache.Event_PrecacheTime, "float" },
- Hide = { GeomCache.Event_Hide, "any" },
- Unhide = { GeomCache.Event_Unhide, "any" },
- StopDrawing = { GeomCache.Event_StopDrawing, "any" },
- StartDrawing = { GeomCache.Event_StartDrawing, "any" },
- },
- Outputs =
- {
- Precached = "bool",
- },
-}
diff --git a/AutomatedTesting/Assets/Physics/Collider_PxMeshAutoAssigned/SphereBot/r0-b_body.fbx.assetinfo b/AutomatedTesting/Assets/Physics/Collider_PxMeshAutoAssigned/SphereBot/R0-B_Body.fbx.assetinfo
similarity index 100%
rename from AutomatedTesting/Assets/Physics/Collider_PxMeshAutoAssigned/SphereBot/r0-b_body.fbx.assetinfo
rename to AutomatedTesting/Assets/Physics/Collider_PxMeshAutoAssigned/SphereBot/R0-B_Body.fbx.assetinfo
diff --git a/AutomatedTesting/Assets/Physics/Collider_PxMeshConvexMeshCollides/SphereBot/r0-b_body.fbx.assetinfo b/AutomatedTesting/Assets/Physics/Collider_PxMeshConvexMeshCollides/SphereBot/R0-B_Body.fbx.assetinfo
similarity index 100%
rename from AutomatedTesting/Assets/Physics/Collider_PxMeshConvexMeshCollides/SphereBot/r0-b_body.fbx.assetinfo
rename to AutomatedTesting/Assets/Physics/Collider_PxMeshConvexMeshCollides/SphereBot/R0-B_Body.fbx.assetinfo
diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py
index 34b2217916..6f3113d771 100644
--- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py
+++ b/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py
@@ -14,6 +14,7 @@ from datetime import datetime
import ly_test_tools.log.log_monitor
from AWS.common import constants
+from AWS.common.resource_mappings import AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY
from .aws_metrics_custom_thread import AWSMetricsThread
# fixture imports
@@ -200,6 +201,59 @@ class TestAWSMetricsWindows(object):
for thread in operational_threads:
thread.join()
+ @pytest.mark.parametrize('level', ['AWS/Metrics'])
+ def test_realtime_and_batch_analytics_no_global_accountid(self,
+ level: str,
+ launcher: pytest.fixture,
+ asset_processor: pytest.fixture,
+ workspace: pytest.fixture,
+ aws_utils: pytest.fixture,
+ resource_mappings: pytest.fixture,
+ aws_metrics_utils: pytest.fixture):
+ """
+ Verify that the metrics events are sent to CloudWatch and S3 for analytics.
+ """
+ # Remove top-level account ID from resource mappings
+ resource_mappings.clear_select_keys([AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY])
+ # Start Kinesis analytics application on a separate thread to avoid blocking the test.
+ kinesis_analytics_application_thread = AWSMetricsThread(target=update_kinesis_analytics_application_status,
+ args=(aws_metrics_utils, resource_mappings, True))
+ kinesis_analytics_application_thread.start()
+
+ log_monitor = setup(launcher, asset_processor)
+
+ # Kinesis analytics application needs to be in the running state before we start the game launcher.
+ kinesis_analytics_application_thread.join()
+ launcher.args = ['+LoadLevel', level]
+ launcher.args.extend(['-rhi=null'])
+ start_time = datetime.utcnow()
+ with launcher.start(launch_ap=False):
+ monitor_metrics_submission(log_monitor)
+
+ # Verify that real-time analytics metrics are delivered to CloudWatch.
+ aws_metrics_utils.verify_cloud_watch_delivery(
+ AWS_METRICS_FEATURE_NAME,
+ 'TotalLogins',
+ [],
+ start_time)
+ logger.info('Real-time metrics are sent to CloudWatch.')
+
+ # Run time-consuming operations on separate threads to avoid blocking the test.
+ operational_threads = list()
+ operational_threads.append(
+ AWSMetricsThread(target=query_metrics_from_s3,
+ args=(aws_metrics_utils, resource_mappings)))
+ operational_threads.append(
+ AWSMetricsThread(target=verify_operational_metrics,
+ args=(aws_metrics_utils, resource_mappings, start_time)))
+ operational_threads.append(
+ AWSMetricsThread(target=update_kinesis_analytics_application_status,
+ args=(aws_metrics_utils, resource_mappings, False)))
+ for thread in operational_threads:
+ thread.start()
+ for thread in operational_threads:
+ thread.join()
+
@pytest.mark.parametrize('level', ['AWS/Metrics'])
def test_unauthorized_user_request_rejected(self,
level: str,
diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/core/test_aws_resource_interaction.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/core/test_aws_resource_interaction.py
index 949186ad50..59c517fd1c 100644
--- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/core/test_aws_resource_interaction.py
+++ b/AutomatedTesting/Gem/PythonTests/AWS/Windows/core/test_aws_resource_interaction.py
@@ -18,6 +18,7 @@ import ly_test_tools.environment.process_utils as process_utils
import ly_test_tools.o3de.asset_processor_utils as asset_processor_utils
from AWS.common import constants
+from AWS.common.resource_mappings import AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY
# fixture imports
from assetpipeline.ap_fixtures.asset_processor_fixture import asset_processor
@@ -141,3 +142,51 @@ class TestAWSCoreAWSResourceInteraction(object):
'The expected file wasn\'t successfully downloaded.'
# clean up the file directories.
shutil.rmtree(s3_download_dir)
+
+ @pytest.mark.parametrize('expected_lines', [
+ ['(Script) - [S3] Head object request is done',
+ '(Script) - [S3] Head object success: Object example.txt is found.',
+ '(Script) - [S3] Get object success: Object example.txt is downloaded.',
+ '(Script) - [Lambda] Completed Invoke',
+ '(Script) - [Lambda] Invoke success: {"statusCode": 200, "body": {}}',
+ '(Script) - [DynamoDB] Results finished']])
+ @pytest.mark.parametrize('unexpected_lines', [
+ ['(Script) - [S3] Head object error: No response body.',
+ '(Script) - [S3] Get object error: Request validation failed, output file directory doesn\'t exist.',
+ '(Script) - Request validation failed, output file miss full path.',
+ '(Script) - ']])
+ def test_scripting_behavior_no_global_accountid(self,
+ level: str,
+ launcher: pytest.fixture,
+ workspace: pytest.fixture,
+ asset_processor: pytest.fixture,
+ resource_mappings: pytest.fixture,
+ aws_utils: pytest.fixture,
+ expected_lines: typing.List[str],
+ unexpected_lines: typing.List[str]):
+ """
+ Setup: Updates resource mapping file using existing CloudFormation stacks.
+ Tests: Interact with AWS S3, DynamoDB and Lambda services.
+ Verification: Script canvas nodes can communicate with AWS services successfully.
+ """
+
+ resource_mappings.clear_select_keys([AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY])
+ log_monitor, s3_download_dir = setup(launcher, asset_processor)
+ write_test_data_to_dynamodb_table(resource_mappings, aws_utils)
+
+ launcher.args = ['+LoadLevel', level]
+ launcher.args.extend(['-rhi=null'])
+
+ with launcher.start(launch_ap=False):
+ result = log_monitor.monitor_log_for_lines(
+ expected_lines=expected_lines,
+ unexpected_lines=unexpected_lines,
+ halt_on_unexpected=True
+ )
+
+ assert result, "Expected lines weren't found."
+
+ assert os.path.exists(os.path.join(s3_download_dir, 'output.txt')), \
+ 'The expected file wasn\'t successfully downloaded.'
+ # clean up the file directories.
+ shutil.rmtree(s3_download_dir)
diff --git a/AutomatedTesting/Gem/PythonTests/AWS/common/resource_mappings.py b/AutomatedTesting/Gem/PythonTests/AWS/common/resource_mappings.py
index 5f01ecdbf8..988d5bf1fc 100644
--- a/AutomatedTesting/Gem/PythonTests/AWS/common/resource_mappings.py
+++ b/AutomatedTesting/Gem/PythonTests/AWS/common/resource_mappings.py
@@ -102,3 +102,17 @@ class ResourceMappings:
def get_resource_name_id(self, resource_key: str):
return self._resource_mappings[AWS_RESOURCE_MAPPINGS_KEY][resource_key]['Name/ID']
+
+ def clear_select_keys(self, resource_keys=None) -> None:
+ """
+ Clears values from select resource mapping keys.
+ :param resource_keys: list of keys to clear out
+ """
+ with open(self._resource_mapping_file_path) as file_content:
+ resource_mappings = json.load(file_content)
+
+ for key in resource_keys:
+ resource_mappings[key] = ''
+
+ with open(self._resource_mapping_file_path, 'w') as file_content:
+ json.dump(resource_mappings, file_content, indent=4)
\ No newline at end of file
diff --git a/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/mock_asset_builder.py b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/mock_asset_builder.py
index 443a420b61..a6e8b97b63 100644
--- a/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/mock_asset_builder.py
+++ b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/mock_asset_builder.py
@@ -23,7 +23,7 @@ def create_jobs(request):
jobDescriptorList = []
for platformInfo in request.enabledPlatforms:
jobDesc = azlmbr.asset.builder.JobDescriptor()
- jobDesc.jobKey = jobKeyName
+ jobDesc.jobKey = f'{jobKeyName}-{platformInfo.identifier}'
jobDesc.set_platform_identifier(platformInfo.identifier)
jobDescriptorList.append(jobDesc)
@@ -38,7 +38,7 @@ def on_create_jobs(args):
return create_jobs(request)
except:
log_exception_traceback()
- # returing back a default CreateJobsResponse() records an asset error
+ # returning back a default CreateJobsResponse() records an asset error
return azlmbr.asset.builder.CreateJobsResponse()
def process_file(request):
@@ -58,6 +58,7 @@ def process_file(request):
fileOutput = open(tempFilename, "w")
fileOutput.write('{}')
fileOutput.close()
+ print(f'Wrote mock asset file: {tempFilename}')
# generate a product asset file entry
subId = binascii.crc32(mockFilename.encode())
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/bundler_batch_setup_fixture.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/bundler_batch_setup_fixture.py
index ff362c732c..9281d5947e 100755
--- a/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/bundler_batch_setup_fixture.py
+++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/bundler_batch_setup_fixture.py
@@ -158,7 +158,7 @@ def bundler_batch_setup_fixture(request, workspace, asset_processor, timeout) ->
else:
cmd.append(f"--{key}")
if append_defaults:
- cmd.append(f"--project-path={workspace.project}")
+ cmd.append(f"--project-path={workspace.paths.project()}")
return cmd
# ******
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_bundler_batch_tests.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_bundler_batch_tests.py
index 7f85e5e317..f5e5642573 100755
--- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_bundler_batch_tests.py
+++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_bundler_batch_tests.py
@@ -88,214 +88,6 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
bundler_batch_helper.call_bundles(help="")
bundler_batch_helper.call_bundleSeed(help="")
- @pytest.mark.BAT
- @pytest.mark.assetpipeline
- @pytest.mark.test_case_id("C16877175")
- @pytest.mark.skip("'animations/animationeditorfiles/sample1.animgraph' missing, needs investigation")
- def test_WindowsAndMac_CreateAssetList_DependenciesCorrect(self, workspace, bundler_batch_helper):
- r"""
- Tests that an asset list created maps dependencies correctly.
- testdependencieslevel\level.pak and lists of known dependencies are used for validation
-
- Test Steps:
- 1. Create an asset list from the level.pak
- 2. Create Lists of expected assets in the level.pak
- 3. Add lists of expected assets to a single list
- 4. Compare list of expected assets to actual assets
- """
- helper = bundler_batch_helper
-
- # Create the asset list file
- helper.call_assetLists(
- addSeed=r"levels\testdependencieslevel\level.pak",
- assetListFile=helper['asset_info_file_request']
- )
-
- assert os.path.isfile(helper["asset_info_file_result"])
-
- # Lists of known relative locations of assets
- default_level_assets = [
- "engineassets/texturemsg/defaultnouvs.dds",
- "engineassets/texturemsg/defaultnouvs.dds.1",
- "engineassets/texturemsg/defaultnouvs.dds.2",
- "engineassets/texturemsg/defaultnouvs.dds.3",
- "engineassets/texturemsg/defaultnouvs.dds.4",
- "engineassets/texturemsg/defaultnouvs.dds.5",
- "engineassets/texturemsg/defaultnouvs.dds.6",
- "engineassets/texturemsg/defaultnouvs.dds.7",
- "engineassets/texturemsg/defaultnouvs_ddn.dds",
- "engineassets/texturemsg/defaultnouvs_ddn.dds.1",
- "engineassets/texturemsg/defaultnouvs_ddn.dds.2",
- "engineassets/texturemsg/defaultnouvs_ddn.dds.3",
- "engineassets/texturemsg/defaultnouvs_ddn.dds.4",
- "engineassets/texturemsg/defaultnouvs_ddn.dds.5",
- "engineassets/texturemsg/defaultnouvs_spec.dds",
- "engineassets/texturemsg/defaultnouvs_spec.dds.1",
- "engineassets/texturemsg/defaultnouvs_spec.dds.2",
- "engineassets/texturemsg/defaultnouvs_spec.dds.3",
- "engineassets/texturemsg/defaultnouvs_spec.dds.4",
- "engineassets/texturemsg/defaultnouvs_spec.dds.5",
- "engineassets/textures/defaults/16_grey.dds",
- "engineassets/textures/cubemap/default_level_cubemap.dds",
- "engineassets/textures/cubemap/default_level_cubemap.dds.1",
- "engineassets/textures/cubemap/default_level_cubemap.dds.2",
- "engineassets/textures/cubemap/default_level_cubemap.dds.3",
- "engineassets/textures/cubemap/default_level_cubemap.dds.4",
- "engineassets/textures/cubemap/default_level_cubemap_diff.dds",
- "engineassets/materials/water/ocean_default.mtl",
- "engineassets/textures/defaults/spot_default.dds",
- "engineassets/textures/defaults/spot_default.dds.1",
- "engineassets/textures/defaults/spot_default.dds.2",
- "engineassets/textures/defaults/spot_default.dds.3",
- "engineassets/textures/defaults/spot_default.dds.4",
- "engineassets/textures/defaults/spot_default.dds.5",
- "materials/material_terrain_default.mtl",
- "textures/skys/night/half_moon.dds",
- "textures/skys/night/half_moon.dds.1",
- "textures/skys/night/half_moon.dds.2",
- "textures/skys/night/half_moon.dds.3",
- "textures/skys/night/half_moon.dds.4",
- "textures/skys/night/half_moon.dds.5",
- "textures/skys/night/half_moon.dds.6",
- "engineassets/materials/sky/sky.mtl",
- "levels/testdependencieslevel/level.pak",
- "levels/testdependencieslevel/terrain/cover.ctc",
- "levels/testdependencieslevel/terraintexture.pak",
- ]
-
- sequence_material_cube_assets = [
- "textures/test_texture_sequence/test_texture_sequence000.dds",
- "textures/test_texture_sequence/test_texture_sequence001.dds",
- "textures/test_texture_sequence/test_texture_sequence002.dds",
- "textures/test_texture_sequence/test_texture_sequence003.dds",
- "textures/test_texture_sequence/test_texture_sequence004.dds",
- "textures/test_texture_sequence/test_texture_sequence005.dds",
- "objects/_primitives/_box_1x1.cgf",
- "materials/test_texture_sequence.mtl",
- "objects/_primitives/_box_1x1.mtl",
- "textures/_primitives/middle_gray_checker.dds",
- "textures/_primitives/middle_gray_checker.dds.1",
- "textures/_primitives/middle_gray_checker.dds.2",
- "textures/_primitives/middle_gray_checker.dds.3",
- "textures/_primitives/middle_gray_checker.dds.4",
- "textures/_primitives/middle_gray_checker.dds.5",
- "textures/_primitives/middle_gray_checker_ddn.dds",
- "textures/_primitives/middle_gray_checker_ddn.dds.1",
- "textures/_primitives/middle_gray_checker_ddn.dds.2",
- "textures/_primitives/middle_gray_checker_ddn.dds.3",
- "textures/_primitives/middle_gray_checker_ddn.dds.4",
- "textures/_primitives/middle_gray_checker_ddn.dds.5",
- "textures/_primitives/middle_gray_checker_spec.dds",
- "textures/_primitives/middle_gray_checker_spec.dds.1",
- "textures/_primitives/middle_gray_checker_spec.dds.2",
- "textures/_primitives/middle_gray_checker_spec.dds.3",
- "textures/_primitives/middle_gray_checker_spec.dds.4",
- "textures/_primitives/middle_gray_checker_spec.dds.5",
- ]
-
- character_with_simplified_material_assets = [
- "objects/characters/jack/jack.actor",
- "objects/characters/jack/jack.mtl",
- "objects/characters/jack/textures/jack_diff.dds",
- "objects/characters/jack/textures/jack_diff.dds.1",
- "objects/characters/jack/textures/jack_diff.dds.2",
- "objects/characters/jack/textures/jack_diff.dds.3",
- "objects/characters/jack/textures/jack_diff.dds.4",
- "objects/characters/jack/textures/jack_diff.dds.5",
- "objects/characters/jack/textures/jack_diff.dds.6",
- "objects/characters/jack/textures/jack_diff.dds.7",
- "objects/characters/jack/textures/jack_spec.dds",
- "objects/characters/jack/textures/jack_spec.dds.1",
- "objects/characters/jack/textures/jack_spec.dds.2",
- "objects/characters/jack/textures/jack_spec.dds.3",
- "objects/characters/jack/textures/jack_spec.dds.4",
- "objects/characters/jack/textures/jack_spec.dds.5",
- "objects/characters/jack/textures/jack_spec.dds.6",
- "objects/characters/jack/textures/jack_spec.dds.7",
- "objects/default/editorprimitive.mtl",
- "engineassets/textures/grey.dds",
- "animations/animationeditorfiles/sample0.animgraph",
- "animations/motions/jack_death_fall_back_zup.motion",
- "animations/animationeditorfiles/sample1.animgraph",
- "animations/animationeditorfiles/sample0.motionset",
- "animations/motions/rin_jump.motion",
- "animations/animationeditorfiles/sample1.motionset",
- "animations/motions/rin_idle.motion",
- "animations/motions/jack_idle_aim_zup.motion",
- ]
-
- spawner_assets = [
- "slices/sphere.dynamicslice",
- "objects/default/primitive_sphere.cgf",
- "test1.luac",
- "test2.luac",
- ]
-
- ui_canvas_assets = [
- "fonts/vera.ttf",
- "fonts/vera.font",
- "scriptcanvas/mainmenu.scriptcanvas_compiled",
- "fonts/vera.fontfamily",
- "ui/canvas/start.uicanvas",
- "fonts/vera-italic.font",
- "ui/textureatlas/sample.texatlasidx",
- "fonts/vera-bold-italic.ttf",
- "fonts/vera-bold.font",
- "ui/textures/prefab/button_normal.dds",
- "ui/textures/prefab/button_normal.sprite",
- "fonts/vera-italic.ttf",
- "ui/textureatlas/sample.dds",
- "fonts/vera-bold-italic.font",
- "fonts/vera-bold.ttf",
- "ui/textures/prefab/button_disabled.dds",
- "ui/textures/prefab/button_disabled.sprite",
- ]
-
- wwise_and_atl_assets = [
- "libs/gameaudio/wwise/levels/testdependencieslevel/test_dependencies_level.xml",
- "sounds/wwise/test_bank3.bnk",
- "sounds/wwise/test_bank4.bnk",
- "sounds/wwise/test_bank5.bnk",
- "sounds/wwise/test_bank1.bnk",
- "sounds/wwise/init.bnk",
- "sounds/wwise/499820003.wem",
- "sounds/wwise/196049145.wem",
- ]
-
- particle_library_assets = [
- "libs/particles/milestone2particles.xml",
- "textures/milestone2/particles/fx_launchermuzzlering_01.dds",
- "textures/milestone2/particles/fx_launchermuzzlering_01.dds.1",
- "textures/milestone2/particles/fx_launchermuzzlering_01.dds.2",
- "textures/milestone2/particles/fx_launchermuzzlering_01.dds.3",
- "textures/milestone2/particles/fx_launchermuzzlering_01.dds.4",
- "textures/milestone2/particles/fx_launchermuzzlering_01.dds.5",
- "textures/milestone2/particles/fx_sparkstreak_01.dds",
- "textures/milestone2/particles/fx_launchermuzzlefront_01.dds",
- "textures/milestone2/particles/fx_launchermuzzlefront_01.dds.1",
- "textures/milestone2/particles/fx_launchermuzzlefront_01.dds.2",
- "textures/milestone2/particles/fx_launchermuzzlefront_01.dds.3",
- "textures/milestone2/particles/fx_launchermuzzlefront_01.dds.4",
- "textures/milestone2/particles/fx_launchermuzzlefront_01.dds.5",
- ]
-
- lens_flares_library_assets = ["libs/flares/flares.xml", "textures/lights/flare01.dds"]
-
- expected_assets_list = default_level_assets
- expected_assets_list.extend(sequence_material_cube_assets)
- expected_assets_list.extend(character_with_simplified_material_assets)
- expected_assets_list.extend(spawner_assets)
- expected_assets_list.extend(ui_canvas_assets)
- expected_assets_list.extend(wwise_and_atl_assets)
- expected_assets_list.extend(particle_library_assets)
- expected_assets_list.extend(lens_flares_library_assets) # All expected assets
-
- # Get actual calculated dependencies from the asset list created
- actual_assets_list = []
- for rel_path in helper.get_asset_relative_paths(helper["asset_info_file_result"]):
- actual_assets_list.append(rel_path)
-
- assert sorted(actual_assets_list) == sorted(expected_assets_list)
@pytest.mark.BAT
@pytest.mark.assetpipeline
@@ -310,9 +102,9 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
3. Read and store contents of asset list into memory
4. Attempt to create a new asset list in without using --allowOverwrites
5. Verify that Asset Bundler returns false
- 6. Verify that file contents of the orignally created asset list did not change from what was stored in memory
+ 6. Verify that file contents of the originally created asset list did not change from what was stored in memory
7. Attempt to create a new asset list without debug while allowing overwrites
- 8. Verify that file contents of the orignally created asset list changed from what was stored in memory
+ 8. Verify that file contents of the originally created asset list changed from what was stored in memory
"""
helper = bundler_batch_helper
seed_list = os.path.join(workspace.paths.engine_root(), "Assets", "Engine", "SeedAssetList.seed") # Engine seed list
@@ -919,7 +711,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
# Extra arguments for pattern comparison
cmd.extend([f"--filePatternType={pattern_type}", f"--filePattern={pattern}"])
if workspace.project:
- cmd.append(f'--project-path={project_name}')
+ cmd.append(f'--project-path={workspace.paths.project()}')
return cmd
# End generate_compare_command()
@@ -960,7 +752,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
output_mac_asset_list = helper.platform_file_name(last_output_arg, platform)
# Build execution command
- cmd = generate_compare_command(platform_arg, workspace.project)
+ cmd = generate_compare_command(platform_arg, workspace.paths.project())
# Execute command
subprocess.check_call(cmd)
@@ -995,7 +787,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
f"--comparisonRulesFile={rule_file}",
f"--comparisonType={args[1]}",
r"--addComparison",
- f"--project-path={workspace.project}",
+ f"--project-path={workspace.paths.project()}",
]
if args[1] == "4":
# If pattern comparison, append a few extra arguments
@@ -1117,7 +909,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
"--addDefaultSeedListFiles",
"--platform=pc",
"--print",
- f"--project-path={workspace.project}"
+ f"--project-path={workspace.paths.project()}"
],
universal_newlines=True,
)
@@ -1189,7 +981,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
# Make sure file gets deleted on teardown
request.addfinalizer(lambda: fs.delete([bundle_result_path], True, False))
- bundles_folder = os.path.join(workspace.paths.engine_root(), workspace.project, "Bundles")
+ bundles_folder = os.path.join(workspace.paths.project(), "Bundles")
level_pak = r"levels\testdependencieslevel\level.pak"
bundle_request_path = os.path.join(bundles_folder, "bundle.pak")
bundle_result_path = os.path.join(bundles_folder,
@@ -1243,23 +1035,64 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
2. Verify file was created
3. Verify that only the expected assets are present in the created asset list
"""
- expected_assets = [
+ expected_assets = sorted([
"ui/canvases/lyshineexamples/animation/multiplesequences.uicanvas",
- "ui/textures/prefab/button_normal.sprite"
- ]
+ "ui/textures/prefab/button_disabled.tif.streamingimage",
+ "ui/textures/prefab/tooltip_sliced.tif.streamingimage",
+ "ui/textures/prefab/button_normal.tif.streamingimage"
+ ])
+ # Printing these lists out can save a step in debugging if this test fails on Jenkins.
+ logger.info(f"expected_assets: {expected_assets}")
+
+ skip_assets = sorted([
+ "ui/scripts/lyshineexamples/animation/multiplesequences.luac",
+ "ui/scripts/lyshineexamples/unloadthiscanvasbutton.luac",
+ "fonts/vera.fontfamily",
+ "fonts/vera-italic.font",
+ "fonts/vera.font",
+ "fonts/vera-bold.font",
+ "fonts/vera-bold-italic.font",
+ "fonts/vera-italic.ttf",
+ "fonts/vera.ttf",
+ "fonts/vera-bold.ttf",
+ "fonts/vera-bold-italic.ttf"
+ ])
+ logger.info(f"skip_assets: {skip_assets}")
+
+ expected_and_skip_assets = sorted(expected_assets + skip_assets)
+ # Printing both together to make it quick to compare the results in the logs for a test failure on Jenkins
+ logger.info(f"expected_and_skip_assets: {expected_and_skip_assets}")
+
+ # First, generate an asset info file without skipping, to get a list that can be used as a baseline to verify
+ # the files were actually skipped, and not just missing.
+ bundler_batch_helper.call_assetLists(
+ assetListFile=bundler_batch_helper['asset_info_file_request'],
+ addSeed="ui/canvases/lyshineexamples/animation/multiplesequences.uicanvas"
+ )
+ assert os.path.isfile(bundler_batch_helper["asset_info_file_result"])
+ assets_in_no_skip_list = []
+ for rel_path in bundler_batch_helper.get_asset_relative_paths(bundler_batch_helper["asset_info_file_result"]):
+ assets_in_no_skip_list.append(rel_path)
+ assets_in_no_skip_list = sorted(assets_in_no_skip_list)
+ logger.info(f"assets_in_no_skip_list: {assets_in_no_skip_list}")
+ assert assets_in_no_skip_list == expected_and_skip_assets
+
+ # Now generate an asset info file using the skip command, and verify the skip files are not in the list.
bundler_batch_helper.call_assetLists(
assetListFile=bundler_batch_helper['asset_info_file_request'],
addSeed="ui/canvases/lyshineexamples/animation/multiplesequences.uicanvas",
- skip="ui/textures/prefab/button_disabled.sprite,ui/scripts/lyshineexamples/animation/multiplesequences.luac,"
- "ui/textures/prefab/tooltip_sliced.sprite,ui/scripts/lyshineexamples/unloadthiscanvasbutton.luac,fonts/vera.fontfamily,fonts/vera-italic.font,"
- "fonts/vera.font,fonts/vera-bold.font,fonts/vera-bold-italic.font,fonts/vera-italic.ttf,fonts/vera.ttf,fonts/vera-bold.ttf,fonts/vera-bold-italic.ttf"
+ allowOverwrites="",
+ skip=','.join(skip_assets)
)
+
assert os.path.isfile(bundler_batch_helper["asset_info_file_result"])
assets_in_list = []
for rel_path in bundler_batch_helper.get_asset_relative_paths(bundler_batch_helper["asset_info_file_result"]):
assets_in_list.append(rel_path)
+ assets_in_list = sorted(assets_in_list)
+ logger.info(f"assets_in_list: {assets_in_list}")
+ assert assets_in_list == expected_assets
- assert sorted(assets_in_list) == sorted(expected_assets)
@pytest.mark.BAT
@pytest.mark.assetpipeline
diff --git a/AutomatedTesting/Levels/Physics/ForceRegion_ImpulsesPxMeshShapedRigidBody/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo b/AutomatedTesting/Levels/Physics/ForceRegion_ImpulsesPxMeshShapedRigidBody/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo
similarity index 100%
rename from AutomatedTesting/Levels/Physics/ForceRegion_ImpulsesPxMeshShapedRigidBody/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo
rename to AutomatedTesting/Levels/Physics/ForceRegion_ImpulsesPxMeshShapedRigidBody/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo
diff --git a/AutomatedTesting/Levels/Physics/ForceRegion_PxMeshShapedForce/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo b/AutomatedTesting/Levels/Physics/ForceRegion_PxMeshShapedForce/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo
similarity index 100%
rename from AutomatedTesting/Levels/Physics/ForceRegion_PxMeshShapedForce/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo
rename to AutomatedTesting/Levels/Physics/ForceRegion_PxMeshShapedForce/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo
diff --git a/AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/rin_skeleton_newgeo - copy.fbx.assetinfo b/AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/rin_skeleton_newgeo - Copy.fbx.assetinfo
similarity index 100%
rename from AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/rin_skeleton_newgeo - copy.fbx.assetinfo
rename to AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/rin_skeleton_newgeo - Copy.fbx.assetinfo
diff --git a/AutomatedTesting/Levels/Physics/Physics_WorldBodyBusWorksOnEditorComponents/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo b/AutomatedTesting/Levels/Physics/Physics_WorldBodyBusWorksOnEditorComponents/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo
similarity index 100%
rename from AutomatedTesting/Levels/Physics/Physics_WorldBodyBusWorksOnEditorComponents/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo
rename to AutomatedTesting/Levels/Physics/Physics_WorldBodyBusWorksOnEditorComponents/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo
diff --git a/AutomatedTesting/Levels/Physics/RigidBody_COM_ComputingWorks/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo b/AutomatedTesting/Levels/Physics/RigidBody_COM_ComputingWorks/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo
similarity index 100%
rename from AutomatedTesting/Levels/Physics/RigidBody_COM_ComputingWorks/PhysXSedan/_dev_sedan_r0-b.fbx.assetinfo
rename to AutomatedTesting/Levels/Physics/RigidBody_COM_ComputingWorks/PhysXSedan/_dev_Sedan_r0-b.fbx.assetinfo
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e659270f84..f61a9561e8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,6 +14,7 @@ include(cmake/Version.cmake)
include(cmake/OutputDirectory.cmake)
if(NOT PROJECT_NAME)
+ include(cmake/CompilerSettings.cmake)
project(O3DE
LANGUAGES C CXX
VERSION ${LY_VERSION_STRING}
diff --git a/Code/Editor/AboutDialog.ui b/Code/Editor/AboutDialog.ui
index a6c5bb5d52..a36d65e35b 100644
--- a/Code/Editor/AboutDialog.ui
+++ b/Code/Editor/AboutDialog.ui
@@ -125,7 +125,7 @@
- General Availability
+ Stable 21.11
Qt::AutoText
diff --git a/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp b/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp
index 1c2be16a3d..6fc10e379a 100644
--- a/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp
+++ b/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp
@@ -199,41 +199,6 @@ namespace AzAssetBrowserRequestHandlerPrivate
}
}
}
-
- // Helper utility - determines if the thing being dragged is a FBX from the scene import pipeline
- // This is important to differentiate.
- // when someone drags a MTL file directly into the viewport, even from a FBX, we want to spawn it as a decal
- // but when someone drags a FBX that contains MTL files, we want only to spawn the meshes.
- // so we have to specifically differentiate here between the mimeData type that contains the source as the root
- // (dragging the fbx file itself)
- // and one which contains the actual product at its root.
-
- bool IsDragOfFBX(const QMimeData* mimeData)
- {
- AZStd::vector entries;
- if (!AssetBrowserEntry::FromMimeData(mimeData, entries))
- {
- // if mimedata does not even contain entries, no point in proceeding.
- return false;
- }
-
- for (auto entry : entries)
- {
- if (entry->GetEntryType() != AssetBrowserEntry::AssetEntryType::Source)
- {
- continue;
- }
- // this is a source file. Is it the filetype we're looking for?
- if (SourceAssetBrowserEntry* source = azrtti_cast(entry))
- {
- if (AzFramework::StringFunc::Equal(source->GetExtension().c_str(), ".fbx", false))
- {
- return true;
- }
- }
- }
- return false;
- }
}
AzAssetBrowserRequestHandler::AzAssetBrowserRequestHandler()
diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp
index 0ea22e8ce3..b77c6c4b3a 100644
--- a/Code/Editor/CryEdit.cpp
+++ b/Code/Editor/CryEdit.cpp
@@ -371,10 +371,8 @@ void CCryEditApp::RegisterActionHandlers()
ON_COMMAND(ID_EDIT_FETCH, OnEditFetch)
ON_COMMAND(ID_FILE_EXPORTTOGAMENOSURFACETEXTURE, OnFileExportToGameNoSurfaceTexture)
ON_COMMAND(ID_VIEW_SWITCHTOGAME, OnViewSwitchToGame)
- MainWindow::instance()->GetActionManager()->RegisterActionHandler(ID_VIEW_SWITCHTOGAME_FULLSCREEN, [this]() {
- ed_previewGameInFullscreen_once = true;
- OnViewSwitchToGame();
- });
+ ON_COMMAND(ID_VIEW_SWITCHTOGAME_VIEWPORT, OnViewSwitchToGame)
+ ON_COMMAND(ID_VIEW_SWITCHTOGAME_FULLSCREEN, OnViewSwitchToGameFullScreen)
ON_COMMAND(ID_MOVE_OBJECT, OnMoveObject)
ON_COMMAND(ID_RENAME_OBJ, OnRenameObj)
ON_COMMAND(ID_UNDO, OnUndo)
@@ -1362,16 +1360,6 @@ void CCryEditApp::CompileCriticalAssets() const
assetsInQueueNotifcation.BusDisconnect();
CCryEditApp::OutputStartupMessage(QString("Asset Processor is now ready."));
- // VERY early on, as soon as we can, request that the asset system make sure the following assets take priority over others,
- // so that by the time we ask for them there is a greater likelihood that they're already good to go.
- // these can be loaded later but are still important:
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "/texturemsg/");
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "engineassets/materials");
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "engineassets/geomcaches");
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "engineassets/objects");
-
- // some are specifically extra important and will cause issues if missing completely:
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::CompileAssetSync, "engineassets/objects/default.cgf");
}
bool CCryEditApp::ConnectToAssetProcessor() const
@@ -2585,6 +2573,12 @@ void CCryEditApp::OnViewSwitchToGame()
GetIEditor()->SetInGameMode(inGame);
}
+void CCryEditApp::OnViewSwitchToGameFullScreen()
+{
+ ed_previewGameInFullscreen_once = true;
+ OnViewSwitchToGame();
+}
+
//////////////////////////////////////////////////////////////////////////
void CCryEditApp::OnExportSelectedObjects()
{
@@ -4187,6 +4181,8 @@ extern "C" int AZ_DLL_EXPORT CryEditMain(int argc, char* argv[])
"\nThis could be because of incorrectly configured components, or missing required gems."
"\nSee other errors for more details.");
+ AzToolsFramework::EditorEventsBus::Broadcast(&AzToolsFramework::EditorEvents::NotifyEditorInitialized);
+
if (didCryEditStart)
{
app->EnableOnIdle();
diff --git a/Code/Editor/CryEdit.h b/Code/Editor/CryEdit.h
index f68cfdc33d..dd597dcc55 100644
--- a/Code/Editor/CryEdit.h
+++ b/Code/Editor/CryEdit.h
@@ -212,6 +212,7 @@ public:
void OnEditFetch();
void OnFileExportToGameNoSurfaceTexture();
void OnViewSwitchToGame();
+ void OnViewSwitchToGameFullScreen();
void OnViewDeploy();
void DeleteSelectedEntities(bool includeDescendants);
void OnMoveObject();
diff --git a/Code/Editor/Include/IEditorMaterialManager.h b/Code/Editor/Include/IEditorMaterialManager.h
index d76ec32829..6f71c5ddd1 100644
--- a/Code/Editor/Include/IEditorMaterialManager.h
+++ b/Code/Editor/Include/IEditorMaterialManager.h
@@ -9,10 +9,6 @@
#define CRYINCLUDE_EDITOR_MATERIAL_IEDITORMATERIALMANAGER_H
#pragma once
-#define MATERIAL_FILE_EXT ".mtl"
-#define DCC_MATERIAL_FILE_EXT ".dccmtl"
-#define MATERIALS_PATH "materials/"
-
#include
#include
diff --git a/Code/Editor/Include/IFileUtil.h b/Code/Editor/Include/IFileUtil.h
index 4d5f6e23c4..036a0bc5ee 100644
--- a/Code/Editor/Include/IFileUtil.h
+++ b/Code/Editor/Include/IFileUtil.h
@@ -60,7 +60,6 @@ struct IFileUtil
EFILE_TYPE_GEOMETRY,
EFILE_TYPE_TEXTURE,
EFILE_TYPE_SOUND,
- EFILE_TYPE_GEOMCACHE,
EFILE_TYPE_LAST,
};
diff --git a/Code/Editor/MainWindow.cpp b/Code/Editor/MainWindow.cpp
index ed72cd9170..1c5b6c567a 100644
--- a/Code/Editor/MainWindow.cpp
+++ b/Code/Editor/MainWindow.cpp
@@ -939,27 +939,27 @@ void MainWindow::InitActions()
.Connect(&QAction::triggered, this, &MainWindow::OnRefreshAudioSystem);
// Game actions
- am->AddAction(ID_VIEW_SWITCHTOGAME, tr("Play &Game"))
+ am->AddAction(ID_VIEW_SWITCHTOGAME, tr("Play Game"))
.SetIcon(QIcon(":/stylesheet/img/UI20/toolbar/Play.svg"))
+ .SetToolTip(tr("Play Game"))
+ .SetStatusTip(tr("Activate the game input mode"))
+ .SetCheckable(true)
+ .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdatePlayGame);
+ am->AddAction(ID_VIEW_SWITCHTOGAME_VIEWPORT, tr("Play Game"))
.SetShortcut(tr("Ctrl+G"))
.SetToolTip(tr("Play Game (Ctrl+G)"))
.SetStatusTip(tr("Activate the game input mode"))
- .SetApplyHoverEffect()
- .SetCheckable(true)
.RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdatePlayGame);
- am->AddAction(ID_VIEW_SWITCHTOGAME_FULLSCREEN, tr("Play &Game (Maximized)"))
+ am->AddAction(ID_VIEW_SWITCHTOGAME_FULLSCREEN, tr("Play Game (Maximized)"))
.SetShortcut(tr("Ctrl+Shift+G"))
.SetStatusTip(tr("Activate the game input mode (maximized)"))
- .SetIcon(Style::icon("Play"))
- .SetApplyHoverEffect()
- .SetCheckable(true);
+ .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdatePlayGame);
am->AddAction(ID_TOOLBAR_WIDGET_PLAYCONSOLE_LABEL, tr("Play Controls"))
.SetText(tr("Play Controls"));
am->AddAction(ID_SWITCH_PHYSICS, tr("Simulate"))
.SetIcon(QIcon(":/stylesheet/img/UI20/toolbar/Simulate_Physics.svg"))
.SetShortcut(tr("Ctrl+P"))
.SetToolTip(tr("Simulate (Ctrl+P)"))
- .SetCheckable(true)
.SetStatusTip(tr("Enable processing of Physics and AI."))
.SetApplyHoverEffect()
.SetCheckable(true)
@@ -1266,7 +1266,9 @@ void MainWindow::OnGameModeChanged(bool inGameMode)
// block signals on the switch to game actions before setting the checked state, as
// setting the checked state triggers the action, which will re-enter this function
// and result in an infinite loop
- AZStd::vector actions = { m_actionManager->GetAction(ID_VIEW_SWITCHTOGAME), m_actionManager->GetAction(ID_VIEW_SWITCHTOGAME_FULLSCREEN) };
+ AZStd::vector actions = { m_actionManager->GetAction(ID_VIEW_SWITCHTOGAME_VIEWPORT),
+ m_actionManager->GetAction(ID_VIEW_SWITCHTOGAME_FULLSCREEN),
+ m_actionManager->GetAction(ID_VIEW_SWITCHTOGAME)};
for (auto action : actions)
{
action->blockSignals(true);
diff --git a/Code/Editor/Objects/EntityObject.cpp b/Code/Editor/Objects/EntityObject.cpp
index 6e2354998c..b2dfc04102 100644
--- a/Code/Editor/Objects/EntityObject.cpp
+++ b/Code/Editor/Objects/EntityObject.cpp
@@ -956,11 +956,7 @@ void CEntityObject::Serialize(CObjectArchive& ar)
QString attachmentType;
xmlNode->getAttr("AttachmentType", attachmentType);
- if (attachmentType == "GeomCacheNode")
- {
- m_attachmentType = eAT_GeomCacheNode;
- }
- else if (attachmentType == "CharacterBone")
+ if (attachmentType == "CharacterBone")
{
m_attachmentType = eAT_CharacterBone;
}
@@ -987,11 +983,7 @@ void CEntityObject::Serialize(CObjectArchive& ar)
{
if (m_attachmentType != eAT_Pivot)
{
- if (m_attachmentType == eAT_GeomCacheNode)
- {
- xmlNode->setAttr("AttachmentType", "GeomCacheNode");
- }
- else if (m_attachmentType == eAT_CharacterBone)
+ if (m_attachmentType == eAT_CharacterBone)
{
xmlNode->setAttr("AttachmentType", "CharacterBone");
}
@@ -1091,11 +1083,7 @@ XmlNodeRef CEntityObject::Export([[maybe_unused]] const QString& levelPath, XmlN
objNode->setAttr("ParentId", parentEntity->GetEntityId());
if (m_attachmentType != eAT_Pivot)
{
- if (m_attachmentType == eAT_GeomCacheNode)
- {
- objNode->setAttr("AttachmentType", "GeomCacheNode");
- }
- else if (m_attachmentType == eAT_CharacterBone)
+ if (m_attachmentType == eAT_CharacterBone)
{
objNode->setAttr("AttachmentType", "CharacterBone");
}
diff --git a/Code/Editor/Objects/EntityObject.h b/Code/Editor/Objects/EntityObject.h
index dcc6ff7b22..a4f4752b75 100644
--- a/Code/Editor/Objects/EntityObject.h
+++ b/Code/Editor/Objects/EntityObject.h
@@ -131,7 +131,6 @@ public:
enum EAttachmentType
{
eAT_Pivot,
- eAT_GeomCacheNode,
eAT_CharacterBone,
};
diff --git a/Code/Editor/Objects/ObjectManager.cpp b/Code/Editor/Objects/ObjectManager.cpp
index ee7e9a8e96..265d828481 100644
--- a/Code/Editor/Objects/ObjectManager.cpp
+++ b/Code/Editor/Objects/ObjectManager.cpp
@@ -608,7 +608,7 @@ bool CObjectManager::AddObject(CBaseObject* obj)
if (CEntityObject* entityObj = qobject_cast(obj))
{
CEntityObject::EAttachmentType attachType = entityObj->GetAttachType();
- if (attachType == CEntityObject::EAttachmentType::eAT_GeomCacheNode || attachType == CEntityObject::EAttachmentType::eAT_CharacterBone)
+ if (attachType == CEntityObject::EAttachmentType::eAT_CharacterBone)
{
m_animatedAttachedEntities.insert(entityObj);
}
diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp
index d0091f968e..2073d0dd5a 100644
--- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp
+++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp
@@ -18,7 +18,6 @@
#include
#include
-#include
#include
#include
@@ -136,14 +135,6 @@ AssetCatalogModel::AssetCatalogModel(QObject* parent)
}
}
- // Special cases for SimpleAssets. If these get full-fledged AssetData types, these cases can be removed.
- QString textureExtensions = LmbrCentral::TextureAsset::GetFileFilter();
- m_extensionToAssetType.insert(AZStd::make_pair(textureExtensions.replace("*", "").replace(" ", "").toStdString().c_str(), AZStd::vector { AZ::AzTypeInfo::Uuid() }));
- QString materialExtensions = LmbrCentral::MaterialAsset::GetFileFilter();
- m_extensionToAssetType.insert(AZStd::make_pair(materialExtensions.replace("*", "").replace(" ", "").toStdString().c_str(), AZStd::vector { AZ::AzTypeInfo::Uuid() }));
- QString dccMaterialExtensions = LmbrCentral::DccMaterialAsset::GetFileFilter();
- m_extensionToAssetType.insert(AZStd::make_pair(dccMaterialExtensions.replace("*", "").replace(" ", "").toStdString().c_str(), AZStd::vector { AZ::AzTypeInfo::Uuid() }));
-
AZ::SerializeContext* serializeContext = nullptr;
EBUS_EVENT_RESULT(serializeContext, AZ::ComponentApplicationBus, GetSerializeContext);
AZ_Assert(serializeContext, "Failed to acquire application serialize context.");
diff --git a/Code/Editor/Resource.h b/Code/Editor/Resource.h
index b3640fac70..ba3cd39fe7 100644
--- a/Code/Editor/Resource.h
+++ b/Code/Editor/Resource.h
@@ -104,6 +104,7 @@
#define ID_FILE_EXPORTTOGAMENOSURFACETEXTURE 33473
#define ID_VIEW_SWITCHTOGAME 33477
#define ID_VIEW_SWITCHTOGAME_FULLSCREEN 33478
+#define ID_VIEW_SWITCHTOGAME_VIEWPORT 33479
#define ID_MOVE_OBJECT 33481
#define ID_RENAME_OBJ 33483
#define ID_FETCH 33496
diff --git a/Code/Editor/StartupLogoDialog.ui b/Code/Editor/StartupLogoDialog.ui
index c0b8115cb0..c2cbfcfd69 100644
--- a/Code/Editor/StartupLogoDialog.ui
+++ b/Code/Editor/StartupLogoDialog.ui
@@ -103,7 +103,7 @@
-
- General Availability
+ Stable 21.11
diff --git a/Code/Editor/ToolbarManager.cpp b/Code/Editor/ToolbarManager.cpp
index 00b7992ef0..6b610d23ce 100644
--- a/Code/Editor/ToolbarManager.cpp
+++ b/Code/Editor/ToolbarManager.cpp
@@ -590,6 +590,16 @@ AmazonToolbar ToolbarManager::GetObjectToolbar() const
return t;
}
+QMenu* ToolbarManager::CreatePlayButtonMenu() const
+{
+ QMenu* playButtonMenu = new QMenu("Play Game");
+
+ playButtonMenu->addAction(m_actionManager->GetAction(ID_VIEW_SWITCHTOGAME_VIEWPORT));
+ playButtonMenu->addAction(m_actionManager->GetAction(ID_VIEW_SWITCHTOGAME_FULLSCREEN));
+
+ return playButtonMenu;
+}
+
AmazonToolbar ToolbarManager::GetPlayConsoleToolbar() const
{
AmazonToolbar t = AmazonToolbar("PlayConsole", QObject::tr("Play Controls"));
@@ -598,8 +608,17 @@ AmazonToolbar ToolbarManager::GetPlayConsoleToolbar() const
t.AddAction(ID_TOOLBAR_WIDGET_SPACER_RIGHT, ORIGINAL_TOOLBAR_VERSION);
t.AddAction(ID_TOOLBAR_SEPARATOR, ORIGINAL_TOOLBAR_VERSION);
t.AddAction(ID_TOOLBAR_WIDGET_PLAYCONSOLE_LABEL, ORIGINAL_TOOLBAR_VERSION);
- t.AddAction(ID_VIEW_SWITCHTOGAME, TOOLBARS_WITH_PLAY_GAME);
- t.AddAction(ID_VIEW_SWITCHTOGAME_FULLSCREEN, TOOLBARS_WITH_PLAY_GAME);
+
+ QAction* playAction = m_actionManager->GetAction(ID_VIEW_SWITCHTOGAME);
+ QToolButton* playButton = new QToolButton(t.Toolbar());
+
+ QMenu* menu = CreatePlayButtonMenu();
+ menu->setParent(t.Toolbar());
+ playAction->setMenu(menu);
+
+ playButton->setDefaultAction(playAction);
+ t.AddWidget(playButton, ID_VIEW_SWITCHTOGAME, ORIGINAL_TOOLBAR_VERSION);
+
t.AddAction(ID_TOOLBAR_SEPARATOR, ORIGINAL_TOOLBAR_VERSION);
t.AddAction(ID_SWITCH_PHYSICS, TOOLBARS_WITH_PLAY_GAME);
return t;
@@ -728,7 +747,14 @@ void AmazonToolbar::SetActionsOnInternalToolbar(ActionManager* actionManager)
{
if (actionManager->HasAction(actionId))
{
- m_toolbar->addAction(actionManager->GetAction(actionId));
+ if (actionData.widget != nullptr)
+ {
+ m_toolbar->addWidget(actionData.widget);
+ }
+ else
+ {
+ m_toolbar->addAction(actionManager->GetAction(actionId));
+ }
}
}
}
@@ -1367,7 +1393,12 @@ void AmazonToolbar::InstantiateToolbar(QMainWindow* mainWindow, ToolbarManager*
void AmazonToolbar::AddAction(int actionId, int toolbarVersionAdded)
{
- m_actions.push_back({ actionId, toolbarVersionAdded });
+ AddWidget(nullptr, actionId, toolbarVersionAdded);
+}
+
+void AmazonToolbar::AddWidget(QWidget* widget, int actionId, int toolbarVersionAdded)
+{
+ m_actions.push_back({ actionId, toolbarVersionAdded, widget });
}
void AmazonToolbar::Clear()
diff --git a/Code/Editor/ToolbarManager.h b/Code/Editor/ToolbarManager.h
index be537533b6..ae6b0c7296 100644
--- a/Code/Editor/ToolbarManager.h
+++ b/Code/Editor/ToolbarManager.h
@@ -87,6 +87,7 @@ public:
const QString& GetTranslatedName() const { return m_translatedName; }
void AddAction(int actionId, int toolbarVersionAdded = 0);
+ void AddWidget(QWidget* widget, int actionId, int toolbarVersionAdded = 0);
QToolBar* Toolbar() const { return m_toolbar; }
@@ -117,6 +118,7 @@ private:
{
int actionId;
int toolbarVersionAdded;
+ QWidget* widget;
bool operator ==(const AmazonToolbar::ActionData& other) const
{
@@ -133,7 +135,9 @@ private:
class AmazonToolBarExpanderWatcher;
class ToolbarManager
+ : public QObject
{
+ Q_OBJECT
public:
explicit ToolbarManager(ActionManager* actionManager, MainWindow* mainWindow);
~ToolbarManager();
@@ -178,6 +182,8 @@ private:
void UpdateAllowedAreas(QToolBar* toolbar);
bool IsDirty(const AmazonToolbar& toolbar) const;
+ QMenu* CreatePlayButtonMenu() const;
+
const AmazonToolbar* FindDefaultToolbar(const QString& toolbarName) const;
AmazonToolbar* FindToolbar(const QString& toolbarName);
diff --git a/Code/Editor/TrackView/AtomOutputFrameCapture.cpp b/Code/Editor/TrackView/AtomOutputFrameCapture.cpp
index 94451e6914..5943e3c2d7 100644
--- a/Code/Editor/TrackView/AtomOutputFrameCapture.cpp
+++ b/Code/Editor/TrackView/AtomOutputFrameCapture.cpp
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -47,18 +48,42 @@ namespace TrackView
AZ::Name viewName = AZ::Name("MainCamera");
m_view = AZ::RPI::View::CreateView(viewName, AZ::RPI::View::UsageCamera);
m_renderPipeline->SetDefaultView(m_view);
+ m_targetView = scene.GetDefaultRenderPipeline()->GetDefaultView();
+ if (AZ::Render::PostProcessFeatureProcessor* fp = scene.GetFeatureProcessor())
+ {
+ // This will be set again to mimic the active camera in UpdateView
+ fp->SetViewAlias(m_view, m_targetView);
+ }
}
void AtomOutputFrameCapture::DestroyPipeline(AZ::RPI::Scene& scene)
{
+ if (AZ::Render::PostProcessFeatureProcessor* fp = scene.GetFeatureProcessor())
+ {
+ // Remove view alias introduced in CreatePipeline and UpdateView
+ fp->RemoveViewAlias(m_view);
+ }
scene.RemoveRenderPipeline(m_renderPipeline->GetId());
m_passHierarchy.clear();
m_renderPipeline.reset();
m_view.reset();
+ m_targetView.reset();
}
- void AtomOutputFrameCapture::UpdateView(const AZ::Matrix3x4& cameraTransform, const AZ::Matrix4x4& cameraProjection)
+ void AtomOutputFrameCapture::UpdateView(const AZ::Matrix3x4& cameraTransform, const AZ::Matrix4x4& cameraProjection, const AZ::RPI::ViewPtr targetView)
{
+ if (targetView && targetView != m_targetView)
+ {
+ if (AZ::RPI::Scene* scene = SceneFromGameEntityContext())
+ {
+ if (AZ::Render::PostProcessFeatureProcessor* fp = scene->GetFeatureProcessor())
+ {
+ fp->SetViewAlias(m_view, targetView);
+ m_targetView = targetView;
+ }
+ }
+ }
+
m_view->SetCameraTransform(cameraTransform);
m_view->SetViewToClipMatrix(cameraProjection);
}
diff --git a/Code/Editor/TrackView/AtomOutputFrameCapture.h b/Code/Editor/TrackView/AtomOutputFrameCapture.h
index 2686a81c99..4719ab08e5 100644
--- a/Code/Editor/TrackView/AtomOutputFrameCapture.h
+++ b/Code/Editor/TrackView/AtomOutputFrameCapture.h
@@ -39,11 +39,12 @@ namespace TrackView
CaptureFinishedCallback captureFinishedCallback);
//! Update the internal view that is associated with the created pipeline.
- void UpdateView(const AZ::Matrix3x4& cameraTransform, const AZ::Matrix4x4& cameraProjection);
+ void UpdateView(const AZ::Matrix3x4& cameraTransform, const AZ::Matrix4x4& cameraProjection, const AZ::RPI::ViewPtr targetView = nullptr);
private:
AZ::RPI::RenderPipelinePtr m_renderPipeline; //!< The internal render pipeline.
AZ::RPI::ViewPtr m_view; //!< The view associated with the render pipeline.
+ AZ::RPI::ViewPtr m_targetView; //!< The view that this render pipeline will mimic.
AZStd::vector m_passHierarchy; //!< Pass hierarchy (includes pipelineName and CopyToSwapChain).
CaptureFinishedCallback m_captureFinishedCallback; //!< Stored callback called from OnCaptureFinished.
diff --git a/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp b/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp
index d7901e338a..a796a8ce37 100644
--- a/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp
+++ b/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp
@@ -16,6 +16,7 @@
#include
#include
+#include
// Qt
#include
@@ -91,9 +92,12 @@ namespace
static void UpdateAtomOutputFrameCaptureView(TrackView::AtomOutputFrameCapture& atomOutputFrameCapture, const int width, const int height)
{
const AZ::EntityId activeCameraEntityId = TrackView::ActiveCameraEntityId();
+ AZ::RPI::ViewPtr view = nullptr;
+ AZ::RPI::ViewProviderBus::EventResult(view, activeCameraEntityId, &AZ::RPI::ViewProvider::GetView);
atomOutputFrameCapture.UpdateView(
TrackView::TransformFromEntityId(activeCameraEntityId),
- TrackView::ProjectionFromCameraEntityId(activeCameraEntityId, static_cast(width), static_cast(height)));
+ TrackView::ProjectionFromCameraEntityId(activeCameraEntityId, aznumeric_cast(width), aznumeric_cast(height)),
+ view);
}
CSequenceBatchRenderDialog::CSequenceBatchRenderDialog(float fps, QWidget* pParent /* = nullptr */)
diff --git a/Code/Editor/Util/FileUtil.cpp b/Code/Editor/Util/FileUtil.cpp
index 36c1879407..9f96d45381 100644
--- a/Code/Editor/Util/FileUtil.cpp
+++ b/Code/Editor/Util/FileUtil.cpp
@@ -54,8 +54,8 @@
#include
#endif
-bool CFileUtil::s_singleFileDlgPref[IFileUtil::EFILE_TYPE_LAST] = { true, true, true, true, true };
-bool CFileUtil::s_multiFileDlgPref[IFileUtil::EFILE_TYPE_LAST] = { true, true, true, true, true };
+bool CFileUtil::s_singleFileDlgPref[IFileUtil::EFILE_TYPE_LAST] = { true, true, true, true };
+bool CFileUtil::s_multiFileDlgPref[IFileUtil::EFILE_TYPE_LAST] = { true, true, true, true };
CAutoRestorePrimaryCDRoot::~CAutoRestorePrimaryCDRoot()
{
diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp
index 06bb0b0cac..b03e1affdc 100644
--- a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp
+++ b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp
@@ -1677,9 +1677,13 @@ namespace AZ
// they will trigger a ReleaseAsset call sometime after the AssetManager has begun to shut down, which can lead to
// race conditions.
+ // Make sure the streamer request is removed first before the asset is released
+ // If the asset is released first it could lead to a race condition where another thread starts loading the asset
+ // again and attempts to add a new streamer request with the same ID before the old one has been removed, causing
+ // that load request to fail
+ RemoveActiveStreamerRequest(assetId);
weakAsset = {};
loadingAsset.Reset();
- RemoveActiveStreamerRequest(assetId);
};
auto&& [deadline, priority] = GetEffectiveDeadlineAndPriority(*handler, asset.GetType(), loadParams);
diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp b/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp
index 6f5ccc93e4..2307a9372c 100644
--- a/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp
+++ b/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp
@@ -56,11 +56,12 @@ namespace AZ
int numberOfWorkerThreads = m_numberOfWorkerThreads;
if (numberOfWorkerThreads <= 0) // spawn default number of threads
{
+ #if (AZ_TRAIT_THREAD_NUM_JOB_MANAGER_WORKER_THREADS)
+ numberOfWorkerThreads = AZ_TRAIT_THREAD_NUM_JOB_MANAGER_WORKER_THREADS;
+ #else
uint32_t scaledHardwareThreads = Threading::CalcNumWorkerThreads(cl_jobThreadsConcurrencyRatio, cl_jobThreadsMinNumber, cl_jobThreadsNumReserved);
numberOfWorkerThreads = AZ::GetMin(static_cast(desc.m_workerThreads.capacity()), scaledHardwareThreads);
- #if (AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS)
- numberOfWorkerThreads = AZ::GetMin(numberOfWorkerThreads, AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS);
- #endif // (AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS)
+ #endif // (AZ_TRAIT_THREAD_NUM_JOB_MANAGER_WORKER_THREADS)
}
threadDesc.m_cpuId = AFFINITY_MASK_USERTHREADS;
diff --git a/Code/Framework/AzCore/AzCore/Math/Vector3.h b/Code/Framework/AzCore/AzCore/Math/Vector3.h
index 821dc8292c..6b7c53266d 100644
--- a/Code/Framework/AzCore/AzCore/Math/Vector3.h
+++ b/Code/Framework/AzCore/AzCore/Math/Vector3.h
@@ -100,7 +100,7 @@ namespace AZ
void Set(float x, float y, float z);
//! Sets components from an array of 3 floats in xyz order.
- void Set(float values[]);
+ void Set(const float values[]);
//! Indexed access using operator(), just for convenience.
float operator()(int32_t index) const;
diff --git a/Code/Framework/AzCore/AzCore/Math/Vector3.inl b/Code/Framework/AzCore/AzCore/Math/Vector3.inl
index 879ade38cf..6371c688b8 100644
--- a/Code/Framework/AzCore/AzCore/Math/Vector3.inl
+++ b/Code/Framework/AzCore/AzCore/Math/Vector3.inl
@@ -186,7 +186,7 @@ namespace AZ
}
- AZ_MATH_INLINE void Vector3::Set(float values[])
+ AZ_MATH_INLINE void Vector3::Set(const float values[])
{
m_value = Simd::Vec3::LoadImmediate(values[0], values[1], values[2]);
}
diff --git a/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp b/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp
index 3047a2894e..1b39eb81bd 100644
--- a/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp
+++ b/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp
@@ -32,7 +32,12 @@ namespace AZ
if (!s_instance)
{
- s_instance = AZ::Environment::CreateVariable(NameDictionaryInstanceName);
+ // Because the NameDictionary allocates memory using the AZ::Allocator and it is created
+ // in the executable memory space, it's ownership cannot be transferred to other module memory spaces
+ // Otherwise this could cause the the NameDictionary to be destroyed in static de-init
+ // after the AZ::Allocators have been destroyed
+ // Therefore we supply the isTransferOwnership value of false using CreateVariableEx
+ s_instance = AZ::Environment::CreateVariableEx(NameDictionaryInstanceName, true, false);
}
}
@@ -50,7 +55,12 @@ namespace AZ
if (!s_instance)
{
- s_instance = Environment::FindVariable(NameDictionaryInstanceName);
+ // Because the NameDictionary allocates memory using the AZ::Allocator and it is created
+ // in the executable memory space, it's ownership cannot be transferred to other module memory spaces
+ // Otherwise this could cause the the NameDictionary to be destroyed in static de-init
+ // after the AZ::Allocators have been destroyed
+ // Therefore we supply the isTransferOwnership value of false using CreateVariableEx
+ s_instance = AZ::Environment::CreateVariableEx(NameDictionaryInstanceName, true, false);
}
return s_instance.IsConstructed();
diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.cpp
index da02e70181..0ba44e4e61 100644
--- a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.cpp
+++ b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.cpp
@@ -104,6 +104,8 @@ namespace AZ
->HandlesType();
jsonContext->Serializer()
->HandlesType();
+ jsonContext->Serializer()
+ ->HandlesType();
MathReflect(jsonContext);
}
diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.cpp
index 2392ff435f..ad1839f974 100644
--- a/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.cpp
+++ b/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.cpp
@@ -15,6 +15,7 @@ namespace AZ
AZ_CLASS_ALLOCATOR_IMPL(JsonAnySerializer, SystemAllocator, 0);
AZ_CLASS_ALLOCATOR_IMPL(JsonVariantSerializer, SystemAllocator, 0);
AZ_CLASS_ALLOCATOR_IMPL(JsonOptionalSerializer, SystemAllocator, 0);
+ AZ_CLASS_ALLOCATOR_IMPL(JsonBitsetSerializer, SystemAllocator, 0);
JsonSerializationResult::Result JsonUnsupportedTypesSerializer::Load(void*, const Uuid&, const rapidjson::Value&,
JsonDeserializerContext& context)
@@ -49,4 +50,10 @@ namespace AZ
return "The Json Serialization doesn't support AZStd::optional by design. No JSON format has yet been found that wasn't deemed too "
"complex or overly verbose.";
}
+
+ AZStd::string_view JsonBitsetSerializer::GetMessage() const
+ {
+ return "The Json Serialization doesn't support AZStd::bitset by design. No JSON format has yet been found that is content creator "
+ "friendly i.e., easy to comprehend the intent.";
+ }
} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.h b/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.h
index d913289d3d..fdcac4c761 100644
--- a/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.h
+++ b/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.h
@@ -65,4 +65,14 @@ namespace AZ
protected:
AZStd::string_view GetMessage() const override;
};
+
+ class JsonBitsetSerializer : public JsonUnsupportedTypesSerializer
+ {
+ public:
+ AZ_RTTI(JsonBitsetSerializer, "{10CE969D-D69E-4B3F-8593-069736F8F705}", JsonUnsupportedTypesSerializer);
+ AZ_CLASS_ALLOCATOR_DECL;
+
+ protected:
+ AZStd::string_view GetMessage() const override;
+ };
} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp
index 56b56e96a1..1cacef7ff3 100644
--- a/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp
+++ b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp
@@ -30,8 +30,13 @@ namespace AZ
if (Interface::Get() == nullptr)
{
+ #if (AZ_TRAIT_THREAD_NUM_TASK_GRAPH_WORKER_THREADS)
+ const uint32_t numberOfWorkerThreads = AZ_TRAIT_THREAD_NUM_TASK_GRAPH_WORKER_THREADS;
+ #else
+ const uint32_t numberOfWorkerThreads = Threading::CalcNumWorkerThreads(cl_taskGraphThreadsConcurrencyRatio, cl_taskGraphThreadsMinNumber, cl_taskGraphThreadsNumReserved);
+ #endif // (AZ_TRAIT_THREAD_NUM_TASK_GRAPH_WORKER_THREADS)
Interface::Register(this); // small window that another thread can try to use taskgraph between this line and the set instance.
- m_taskExecutor = aznew TaskExecutor(Threading::CalcNumWorkerThreads(cl_taskGraphThreadsConcurrencyRatio, cl_taskGraphThreadsMinNumber, cl_taskGraphThreadsNumReserved));
+ m_taskExecutor = aznew TaskExecutor(numberOfWorkerThreads);
TaskExecutor::SetInstance(m_taskExecutor);
}
}
diff --git a/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h b/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h
index 495c8d5f2c..e05e000a4e 100644
--- a/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h
+++ b/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h
@@ -75,7 +75,6 @@
#define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 0
#define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0
#define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 0
-#define AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS 0
#define AZ_TRAIT_PERF_MEMORYBENCHMARK_IS_AVAILABLE 0
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0
diff --git a/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h b/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h
index 6ba369e86d..2c0d554078 100644
--- a/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h
+++ b/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h
@@ -75,7 +75,6 @@
#define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1
#define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0
#define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 0
-#define AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS 0
#define AZ_TRAIT_PERF_MEMORYBENCHMARK_IS_AVAILABLE 0
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0
diff --git a/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h b/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h
index a41b5c6baa..816a28b728 100644
--- a/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h
+++ b/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h
@@ -75,7 +75,6 @@
#define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1
#define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0
#define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 0
-#define AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS 0
#define AZ_TRAIT_PERF_MEMORYBENCHMARK_IS_AVAILABLE 0
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0
diff --git a/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h b/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h
index 2f9fcefdbd..83cff9b54f 100644
--- a/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h
+++ b/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h
@@ -75,7 +75,6 @@
#define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1
#define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0
#define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 1
-#define AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS 0
#define AZ_TRAIT_PERF_MEMORYBENCHMARK_IS_AVAILABLE 1
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0
diff --git a/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h b/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h
index d53f4b057e..b0832c54f6 100644
--- a/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h
+++ b/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h
@@ -76,7 +76,6 @@
#define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1
#define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0
#define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 0
-#define AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS 0
#define AZ_TRAIT_PERF_MEMORYBENCHMARK_IS_AVAILABLE 0
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0
diff --git a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp
index e33dbce9c1..3f2d9491a7 100644
--- a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp
+++ b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp
@@ -652,7 +652,7 @@ namespace UnitTest
threads.emplace_back([this, &threadCount, &cv, assetUuid]() {
bool checkLoaded = true;
- for (int i = 0; i < 5000; i++)
+ for (int i = 0; i < 1000; i++)
{
Asset asset1 =
m_testAssetManager->GetAsset(assetUuid, azrtti_typeid(), AZ::Data::AssetLoadBehavior::PreLoad);
@@ -678,7 +678,7 @@ namespace UnitTest
while (threadCount > 0 && !timedOut)
{
AZStd::unique_lock lock(mutex);
- timedOut = (AZStd::cv_status::timeout == cv.wait_until(lock, AZStd::chrono::system_clock::now() + DefaultTimeoutSeconds * 20000));
+ timedOut = (AZStd::cv_status::timeout == cv.wait_until(lock, AZStd::chrono::system_clock::now() + DefaultTimeoutSeconds));
}
ASSERT_EQ(threadCount, 0) << "Thread count is non-zero, a thread has likely deadlocked. Test will not shut down cleanly.";
@@ -1190,7 +1190,7 @@ namespace UnitTest
#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
TEST_F(AssetJobsFloodTest, DISABLED_ContainerFilterTest_ContainersWithAndWithoutFiltering_Success)
#else
- TEST_F(AssetJobsFloodTest, DISABLED_ContainerFilterTest_ContainersWithAndWithoutFiltering_Success)
+ TEST_F(AssetJobsFloodTest, ContainerFilterTest_ContainersWithAndWithoutFiltering_Success)
#endif // !AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
{
m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusConnect();
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h
index fd4196a296..282898c37d 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h
@@ -927,6 +927,9 @@ namespace AzToolsFramework
/// Notify that the MainWindow has been fully initialized
virtual void NotifyMainWindowInitialized(QMainWindow* /*mainWindow*/) {}
+ /// Notify that the Editor has been fully initialized
+ virtual void NotifyEditorInitialized() {}
+
/// Signal that an asset should be highlighted / selected
virtual void SelectAsset(const QString& /* assetPath */) {}
};
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp
index 3c7495e836..056872edab 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp
@@ -214,12 +214,17 @@ namespace AzToolsFramework
, public AZ::BehaviorEBusHandler
{
AZ_EBUS_BEHAVIOR_BINDER(EditorEventsBusHandler, "{352F80BB-469A-40B6-B322-FE57AB51E4DA}", AZ::SystemAllocator,
- NotifyRegisterViews);
+ NotifyRegisterViews, NotifyEditorInitialized);
void NotifyRegisterViews() override
{
Call(FN_NotifyRegisterViews);
}
+
+ void NotifyEditorInitialized() override
+ {
+ Call(FN_NotifyEditorInitialized);
+ }
};
} // Internal
@@ -443,6 +448,7 @@ namespace AzToolsFramework
->Attribute(AZ::Script::Attributes::Module, "editor")
->Handler()
->Event("NotifyRegisterViews", &EditorEvents::NotifyRegisterViews)
+ ->Event("NotifyEditorInitialized", &EditorEvents::NotifyEditorInitialized)
;
behaviorContext->EBus("ViewPaneCallbackBus")
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp
index 7da6f794d6..172bd3a29c 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp
@@ -234,11 +234,6 @@ namespace AzToolsFramework
return SourceFileDetails("Icons/AssetBrowser/Lua_16.svg");
}
- if (AzFramework::StringFunc::Equal(extension.c_str(), ".mtl"))
- {
- return SourceFileDetails("Icons/AssetBrowser/Material_16.svg");
- }
-
if (AzFramework::StringFunc::Equal(extension.c_str(), AzToolsFramework::SliceUtilities::GetSliceFileExtension().c_str()))
{
return SourceFileDetails("Icons/AssetBrowser/Slice_16.svg");
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp
index 4ebeb03a71..eae8ec2a1e 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp
@@ -31,7 +31,10 @@ AZ_POP_DISABLE_WARNING
AZ_CVAR(
bool, ed_hideAssetPickerPathColumn, true, nullptr, AZ::ConsoleFunctorFlags::Null,
"Hide AssetPicker path column for a clearer view.");
-AZ_CVAR_EXTERNED(bool, ed_useNewAssetBrowserTableView);
+
+AZ_CVAR(
+ bool, ed_useNewAssetPickerView, false, nullptr, AZ::ConsoleFunctorFlags::Null,
+ "Uses the new Asset Picker View.");
namespace AzToolsFramework
{
@@ -106,7 +109,7 @@ namespace AzToolsFramework
m_persistentState = AZ::UserSettings::CreateFind(AZ::Crc32(("AssetBrowserTreeView_Dialog_" + name).toUtf8().data()), AZ::UserSettings::CT_GLOBAL);
m_ui->m_assetBrowserTableViewWidget->setVisible(false);
- if (ed_useNewAssetBrowserTableView)
+ if (ed_useNewAssetPickerView)
{
m_ui->m_assetBrowserTreeViewWidget->setVisible(false);
m_ui->m_assetBrowserTableViewWidget->setVisible(true);
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIComponent.cpp
index 2cca3804ea..20a15643c6 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIComponent.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIComponent.cpp
@@ -597,11 +597,13 @@ namespace AzToolsFramework
pte.SetVisibleEnforcement(true);
}
+ ScopedUndoBatch undo("Modify Entity Property");
PropertyOutcome result = pte.SetProperty(propertyPath, value);
if (result.IsSuccess())
{
PropertyEditorEntityChangeNotificationBus::Event(componentInstance.GetEntityId(), &PropertyEditorEntityChangeNotifications::OnEntityComponentPropertyChanged, componentInstance.GetComponentId());
}
+ undo.MarkEntityDirty(componentInstance.GetEntityId());
return result;
}
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp
index 8098727177..5b51944a75 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp
@@ -175,20 +175,14 @@ namespace AzToolsFramework::Prefab
m_focusedInstance = focusedInstance;
m_focusedTemplateId = focusedInstance->get().GetTemplateId();
- AZ::EntityId containerEntityId;
-
- if (focusedInstance->get().GetParentInstance() != AZStd::nullopt)
- {
- containerEntityId = focusedInstance->get().GetContainerEntityId();
- }
- else
- {
- containerEntityId = AZ::EntityId();
- }
-
// Focus on the descendants of the container entity in the Editor, if the interface is initialized.
if (m_focusModeInterface)
{
+ const AZ::EntityId containerEntityId =
+ (focusedInstance->get().GetParentInstance() != AZStd::nullopt)
+ ? focusedInstance->get().GetContainerEntityId()
+ : AZ::EntityId();
+
m_focusModeInterface->SetFocusRoot(containerEntityId);
}
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp
index 920e99665d..c1fc9138d1 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp
@@ -64,6 +64,9 @@ namespace AzToolsFramework::Prefab
);
m_backButton->setToolTip("Up one level (-)");
+
+ // Currently hide this button until we can correctly disable/enable it based on context.
+ m_backButton->hide();
}
void PrefabViewportFocusPathHandler::OnPrefabFocusChanged()
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp
index a449fa0055..9ecbdf5ffc 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp
@@ -45,6 +45,7 @@ AZ_POP_DISABLE_WARNING
#include
#include
#include
+#include
#include
#include
#include
@@ -894,25 +895,51 @@ namespace AzToolsFramework
{
if (!m_prefabsAreEnabled)
{
- return m_isLevelEntityEditor ? InspectorLayout::LEVEL : InspectorLayout::ENTITY;
+ return m_isLevelEntityEditor ? InspectorLayout::Level : InspectorLayout::Entity;
}
+ // Prefabs layout logic
+
+ // If this is the container entity for the root instance, treat it like a level entity.
AZ::EntityId levelContainerEntityId = m_prefabPublicInterface->GetLevelInstanceContainerEntityId();
if (AZStd::find(m_selectedEntityIds.begin(), m_selectedEntityIds.end(), levelContainerEntityId) != m_selectedEntityIds.end())
{
if (m_selectedEntityIds.size() > 1)
{
- return InspectorLayout::INVALID;
+ return InspectorLayout::Invalid;
}
else
{
- return InspectorLayout::LEVEL;
+ return InspectorLayout::Level;
}
}
else
{
- return InspectorLayout::ENTITY;
+ // If this is the container entity for the currently focused prefab, utilize a separate layout.
+ if (auto prefabFocusPublicInterface = AZ::Interface::Get())
+ {
+ AzFramework::EntityContextId editorEntityContextId = AzFramework::EntityContextId::CreateNull();
+ EditorEntityContextRequestBus::BroadcastResult(
+ editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
+
+ AZ::EntityId focusedPrefabContainerEntityId =
+ prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId);
+ if (AZStd::find(m_selectedEntityIds.begin(), m_selectedEntityIds.end(), focusedPrefabContainerEntityId) !=
+ m_selectedEntityIds.end())
+ {
+ if (m_selectedEntityIds.size() > 1)
+ {
+ return InspectorLayout::Invalid;
+ }
+ else
+ {
+ return InspectorLayout::ContainerEntityOfFocusedPrefab;
+ }
+ }
+ }
}
+
+ return InspectorLayout::Entity;
}
void EntityPropertyEditor::UpdateEntityDisplay()
@@ -921,7 +948,7 @@ namespace AzToolsFramework
InspectorLayout layout = GetCurrentInspectorLayout();
- if (layout == InspectorLayout::LEVEL)
+ if (!m_prefabsAreEnabled && layout == InspectorLayout::Level)
{
AZStd::string levelName;
AzToolsFramework::EditorRequestBus::BroadcastResult(levelName, &AzToolsFramework::EditorRequests::GetLevelName);
@@ -963,14 +990,19 @@ namespace AzToolsFramework
InspectorLayout layout = GetCurrentInspectorLayout();
- if (layout == InspectorLayout::LEVEL)
+ if (layout == InspectorLayout::Level)
{
// The Level Inspector should only have a list of selectable components after the
// level entity itself is valid (i.e. "selected").
return selection.empty() ? SelectionEntityTypeInfo::None : SelectionEntityTypeInfo::LevelEntity;
}
- if (layout == InspectorLayout::INVALID)
+ if (layout == InspectorLayout::ContainerEntityOfFocusedPrefab)
+ {
+ return selection.empty() ? SelectionEntityTypeInfo::None : SelectionEntityTypeInfo::ContainerEntityOfFocusedPrefab;
+ }
+
+ if (layout == InspectorLayout::Invalid)
{
return SelectionEntityTypeInfo::Mixed;
}
@@ -1140,7 +1172,8 @@ namespace AzToolsFramework
}
}
- bool isLevelLayout = GetCurrentInspectorLayout() == InspectorLayout::LEVEL;
+ bool isLevelLayout = GetCurrentInspectorLayout() == InspectorLayout::Level;
+ bool isContainerOfFocusedPrefabLayout = GetCurrentInspectorLayout() == InspectorLayout::ContainerEntityOfFocusedPrefab;
m_gui->m_entityDetailsLabel->setText(entityDetailsLabelText);
m_gui->m_entityDetailsLabel->setVisible(entityDetailsVisible);
@@ -1148,10 +1181,14 @@ namespace AzToolsFramework
m_gui->m_entityNameLabel->setVisible(hasEntitiesDisplayed);
m_gui->m_entityIcon->setVisible(hasEntitiesDisplayed);
m_gui->m_pinButton->setVisible(m_overrideSelectedEntityIds.empty() && hasEntitiesDisplayed && !m_isSystemEntityEditor);
- m_gui->m_statusLabel->setVisible(hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout);
- m_gui->m_statusComboBox->setVisible(hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout);
- m_gui->m_entityIdLabel->setVisible(hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout);
- m_gui->m_entityIdText->setVisible(hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout);
+ m_gui->m_statusLabel->setVisible(
+ hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout);
+ m_gui->m_statusComboBox->setVisible(
+ hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout);
+ m_gui->m_entityIdLabel->setVisible(
+ hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout);
+ m_gui->m_entityIdText->setVisible(
+ hasEntitiesDisplayed && !m_isSystemEntityEditor && !isLevelLayout);
bool displayComponentSearchBox = hasEntitiesDisplayed;
if (hasEntitiesDisplayed)
@@ -1159,7 +1196,9 @@ namespace AzToolsFramework
// Build up components to display
SharedComponentArray sharedComponentArray;
BuildSharedComponentArray(sharedComponentArray,
- !(selectionEntityTypeInfo == SelectionEntityTypeInfo::OnlyStandardEntities || selectionEntityTypeInfo == SelectionEntityTypeInfo::OnlyPrefabEntities));
+ !(selectionEntityTypeInfo == SelectionEntityTypeInfo::OnlyStandardEntities ||
+ selectionEntityTypeInfo == SelectionEntityTypeInfo::OnlyPrefabEntities) ||
+ selectionEntityTypeInfo == SelectionEntityTypeInfo::ContainerEntityOfFocusedPrefab);
if (sharedComponentArray.size() == 0)
{
@@ -1175,7 +1214,8 @@ namespace AzToolsFramework
UpdateEntityDisplay();
}
- m_gui->m_darkBox->setVisible(displayComponentSearchBox && !m_isSystemEntityEditor && !isLevelLayout);
+ m_gui->m_darkBox->setVisible(
+ displayComponentSearchBox && !m_isSystemEntityEditor && !isLevelLayout && !isContainerOfFocusedPrefabLayout);
m_gui->m_entitySearchBox->setVisible(displayComponentSearchBox);
bool displayAddComponentMenu = CanAddComponentsToSelection(selectionEntityTypeInfo);
@@ -4665,13 +4705,6 @@ namespace AzToolsFramework
{
if (mimeData->hasFormat(AssetBrowser::AssetBrowserEntry::GetMimeType()))
{
- // extra special case: MTLs from FBX drags are ignored. are we dragging a FBX file?
- bool isDraggingFBXFile = false;
- AssetBrowser::AssetBrowserEntry::ForEachEntryInMimeData(mimeData, [&](const AssetBrowser::SourceAssetBrowserEntry* source)
- {
- isDraggingFBXFile = isDraggingFBXFile || AzFramework::StringFunc::Equal(source->GetExtension().c_str(), ".fbx", false);
- });
-
// the usual case - we only allow asset browser drops of assets that have actually been associated with a kind of component.
AssetBrowser::AssetBrowserEntry::ForEachEntryInMimeData(mimeData, [&](const AssetBrowser::ProductAssetBrowserEntry* product)
{
@@ -4683,17 +4716,7 @@ namespace AzToolsFramework
if (canCreateComponent && !componentTypeId.IsNull())
{
- // we have a component type that handles this asset.
- // but we disallow it if its a MTL file from a FBX and the FBX itself is being dragged. Its still allowed
- // to drag the actual MTL.
- EBusFindAssetTypeByName materialAssetTypeResult("Material");
- AZ::AssetTypeInfoBus::BroadcastResult(materialAssetTypeResult, &AZ::AssetTypeInfo::GetAssetType);
- AZ::Data::AssetType materialAssetType = materialAssetTypeResult.GetAssetType();
-
- if ((!isDraggingFBXFile) || (product->GetAssetType() != materialAssetType))
- {
- callbackFunction(product);
- }
+ callbackFunction(product);
}
});
}
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx
index 5279cefa9f..8dd0ffc4ee 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx
@@ -354,7 +354,8 @@ namespace AzToolsFramework
OnlyLayerEntities,
OnlyPrefabEntities,
Mixed,
- LevelEntity
+ LevelEntity,
+ ContainerEntityOfFocusedPrefab
};
/**
* Returns what kinds of entities are in the current selection. This is used because mixed selection
@@ -364,7 +365,7 @@ namespace AzToolsFramework
SelectionEntityTypeInfo GetSelectionEntityTypeInfo(const EntityIdList& selection) const;
/**
- * Returns true if a selection matching the passed in selection informatation allows components to be added.
+ * Returns true if a selection matching the passed in selection information allows components to be added.
*/
bool CanAddComponentsToSelection(const SelectionEntityTypeInfo& selectionEntityTypeInfo) const;
@@ -581,9 +582,10 @@ namespace AzToolsFramework
enum class InspectorLayout
{
- ENTITY = 0, // All selected entities are regular entities
- LEVEL, // The selected entity is the level prefab container entity
- INVALID // Other entities are selected alongside the level prefab container entity
+ Entity = 0, // All selected entities are regular entities.
+ Level, // The selected entity is the prefab container entity for the level prefab, or the slice level entity.
+ ContainerEntityOfFocusedPrefab, // The selected entity is the prefab container entity for the focused prefab.
+ Invalid // Other entities are selected alongside the level prefab container entity.
};
InspectorLayout GetCurrentInspectorLayout() const;
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp
index 0df4cc5d5b..b35132e620 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp
@@ -29,6 +29,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -1188,8 +1189,10 @@ namespace AzToolsFramework
continue;
}
- const AZ::Aabb bound = CalculateEditorEntitySelectionBounds(entityId, viewportInfo);
- debugDisplay.DrawSolidBox(bound.GetMin(), bound.GetMax());
+ if (const AZ::Aabb bound = CalculateEditorEntitySelectionBounds(entityId, viewportInfo); bound.IsValid())
+ {
+ debugDisplay.DrawSolidBox(bound.GetMin(), bound.GetMax());
+ }
}
debugDisplay.DepthTestOn();
@@ -1345,39 +1348,6 @@ namespace AzToolsFramework
EndRecordManipulatorCommand();
});
- // surface
- translationManipulators->InstallSurfaceManipulatorMouseDownCallback(
- [this, manipulatorEntityIds]([[maybe_unused]] const SurfaceManipulator::Action& action)
- {
- BuildSortedEntityIdVectorFromEntityIdMap(m_entityIdManipulators.m_lookups, manipulatorEntityIds->m_entityIds);
-
- InitializeTranslationLookup(m_entityIdManipulators);
-
- m_axisPreview.m_translation = m_entityIdManipulators.m_manipulators->GetLocalTransform().GetTranslation();
- m_axisPreview.m_orientation = QuaternionFromTransformNoScaling(m_entityIdManipulators.m_manipulators->GetLocalTransform());
-
- // [ref 1.]
- BeginRecordManipulatorCommand();
- });
-
- translationManipulators->InstallSurfaceManipulatorMouseMoveCallback(
- [this, prevModifiers, manipulatorEntityIds](const SurfaceManipulator::Action& action) mutable
- {
- UpdateTranslationManipulator(
- action, manipulatorEntityIds->m_entityIds, m_entityIdManipulators, m_pivotOverrideFrame, prevModifiers,
- m_transformChangedInternally, m_spaceCluster.m_spaceLock);
- });
-
- translationManipulators->InstallSurfaceManipulatorMouseUpCallback(
- [this, manipulatorEntityIds]([[maybe_unused]] const SurfaceManipulator::Action& action)
- {
- AzToolsFramework::EditorTransformChangeNotificationBus::Broadcast(
- &AzToolsFramework::EditorTransformChangeNotificationBus::Events::OnEntityTransformChanged,
- manipulatorEntityIds->m_entityIds);
-
- EndRecordManipulatorCommand();
- });
-
// transfer ownership
m_entityIdManipulators.m_manipulators = AZStd::move(translationManipulators);
}
@@ -3615,6 +3585,16 @@ namespace AzToolsFramework
m_selectedEntityIds.clear();
m_selectedEntityIds.reserve(selectedEntityIds.size());
AZStd::copy(selectedEntityIds.begin(), selectedEntityIds.end(), AZStd::inserter(m_selectedEntityIds, m_selectedEntityIds.end()));
+
+ // Do not create manipulators for the container entity of the focused prefab.
+ if (auto prefabFocusPublicInterface = AZ::Interface::Get())
+ {
+ AzFramework::EntityContextId editorEntityContextId = GetEntityContextId();
+ if (AZ::EntityId focusRoot = prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId); focusRoot.IsValid())
+ {
+ m_selectedEntityIds.erase(focusRoot);
+ }
+ }
}
void EditorTransformComponentSelection::OnTransformChanged(
diff --git a/Code/LauncherUnified/Launcher.cpp b/Code/LauncherUnified/Launcher.cpp
index 0f832ff1a5..97859a604b 100644
--- a/Code/LauncherUnified/Launcher.cpp
+++ b/Code/LauncherUnified/Launcher.cpp
@@ -369,7 +369,6 @@ namespace O3DELauncher
}
}
- void CompileCriticalAssets();
void CreateRemoteFileIO();
bool ConnectToAssetProcessor()
@@ -397,29 +396,11 @@ namespace O3DELauncher
{
AZ_TracePrintf("Launcher", "Connected to Asset Processor\n");
CreateRemoteFileIO();
- CompileCriticalAssets();
}
return connectedToAssetProcessor;
}
- //! Compiles the critical assets that are within the Engine directory of Open 3D Engine
- //! This code should be in a centralized location, but doesn't belong in AzFramework
- //! since it is specific to how Open 3D Engine projects has assets setup
- void CompileCriticalAssets()
- {
- // VERY early on, as soon as we can, request that the asset system make sure the following assets take priority over others,
- // so that by the time we ask for them there is a greater likelihood that they're already good to go.
- // these can be loaded later but are still important:
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "/texturemsg/");
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "engineassets/materials");
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "engineassets/geomcaches");
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, "engineassets/objects");
-
- // some are specifically extra important and will cause issues if missing completely:
- AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::CompileAssetSync, "engineassets/objects/default.cgf");
- }
-
//! Remote FileIO to use as a Virtual File System
//! Communication of FileIOBase operations occur through an AssetProcessor connection
void CreateRemoteFileIO()
diff --git a/Code/Tools/AssetBundler/source/models/AssetBundlerAbstractFileTableModel.cpp b/Code/Tools/AssetBundler/source/models/AssetBundlerAbstractFileTableModel.cpp
index 45d01b9b5b..8def0a698c 100644
--- a/Code/Tools/AssetBundler/source/models/AssetBundlerAbstractFileTableModel.cpp
+++ b/Code/Tools/AssetBundler/source/models/AssetBundlerAbstractFileTableModel.cpp
@@ -61,8 +61,12 @@ namespace AssetBundler
{
AZStd::string absolutePath = filePath.toUtf8().data();
if (AZ::IO::FileIOBase::GetInstance()->Exists(absolutePath.c_str()))
- {
- AZStd::string projectName = pathToProjectNameMap.at(absolutePath);
+ {
+ AZStd::string projectName;
+ if (pathToProjectNameMap.contains(absolutePath))
+ {
+ projectName = pathToProjectNameMap.at(absolutePath);
+ }
// If a project name is already specified, then the associated file is a default file
LoadFile(absolutePath, projectName, !projectName.empty());
diff --git a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp
index 62b063c83b..f9b5d6aef7 100644
--- a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp
+++ b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp
@@ -690,7 +690,6 @@ namespace AssetBuilderSDK
static const char* textureExtensions = ".dds";
static const char* staticMeshExtensions = ".cgf";
static const char* skinnedMeshExtensions = ".skin";
- static const char* materialExtensions = ".mtl";
// MIPS
static const int c_MaxMipsCount = 11; // 11 is for 8k textures non-compressed. When not compressed it is using one file per mip.
@@ -699,7 +698,6 @@ namespace AssetBuilderSDK
// XML files may contain generic data (avoid this in new builders - use a custom extension!)
static const char* xmlExtensions = ".xml";
- static const char* geomCacheExtensions = ".cax";
static const char* skeletonExtensions = ".chr";
static AZ::Data::AssetType unknownAssetType = AZ::Data::AssetType::CreateNull();
@@ -710,7 +708,6 @@ namespace AssetBuilderSDK
static AZ::Data::AssetType textureMipsAssetType("{3918728C-D3CA-4D9E-813E-A5ED20C6821E}");
static AZ::Data::AssetType skinnedMeshLodsAssetType("{58E5824F-C27B-46FD-AD48-865BA41B7A51}");
static AZ::Data::AssetType staticMeshLodsAssetType("{9AAE4926-CB6A-4C60-9948-A1A22F51DB23}");
- static AZ::Data::AssetType geomCacheAssetType("{EBC96071-E960-41B6-B3E3-328F515AE5DA}");
static AZ::Data::AssetType skeletonAssetType("{60161B46-21F0-4396-A4F0-F2CCF0664CDE}");
static AZ::Data::AssetType entityIconAssetType("{3436C30E-E2C5-4C3B-A7B9-66C94A28701B}");
@@ -807,11 +804,6 @@ namespace AssetBuilderSDK
return textureAssetType;
}
- if (AzFramework::StringFunc::Find(materialExtensions, extension.c_str()) != AZStd::string::npos)
- {
- return materialAssetType;
- }
-
if (AzFramework::StringFunc::Find(staticMeshExtensions, extension.c_str()) != AZStd::string::npos)
{
return meshAssetType;
@@ -822,11 +814,6 @@ namespace AssetBuilderSDK
return skinnedMeshAssetType;
}
- if (AzFramework::StringFunc::Find(geomCacheExtensions, extension.c_str()) != AZStd::string::npos)
- {
- return geomCacheAssetType;
- }
-
if (AzFramework::StringFunc::Find(skeletonExtensions, extension.c_str()) != AZStd::string::npos)
{
return skeletonAssetType;
diff --git a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp
index f8d758e092..1a6063cff0 100644
--- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp
+++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp
@@ -243,7 +243,7 @@ void AssetProcessorManagerTest::SetUp()
m_mockApplicationManager->BusConnect();
m_assetProcessorManager.reset(new AssetProcessorManager_Test(m_config.get()));
- m_assertAbsorber.Clear();
+ m_errorAbsorber->Clear();
m_isIdling = false;
@@ -334,9 +334,9 @@ TEST_F(AssetProcessorManagerTest, UnitTestForGettingJobInfoBySourceUUIDSuccess)
EXPECT_STRCASEEQ(relFileName.toUtf8().data(), response.m_jobList[0].m_sourceFile.c_str());
EXPECT_STRCASEEQ(tempPath.filePath("subfolder1").toUtf8().data(), response.m_jobList[0].m_watchFolder.c_str());
- ASSERT_EQ(m_assertAbsorber.m_numWarningsAbsorbed, 0);
- ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 0);
- ASSERT_EQ(m_assertAbsorber.m_numAssertsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numWarningsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0);
}
TEST_F(AssetProcessorManagerTest, WarningsAndErrorsReported_SuccessfullySavedToDatabase)
@@ -388,9 +388,9 @@ TEST_F(AssetProcessorManagerTest, WarningsAndErrorsReported_SuccessfullySavedToD
ASSERT_EQ(response.m_jobList[0].m_warningCount, 11);
ASSERT_EQ(response.m_jobList[0].m_errorCount, 22);
- ASSERT_EQ(m_assertAbsorber.m_numWarningsAbsorbed, 0);
- ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 0);
- ASSERT_EQ(m_assertAbsorber.m_numAssertsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numWarningsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0);
}
@@ -1312,8 +1312,8 @@ void PathDependencyTest::SetUp()
void PathDependencyTest::TearDown()
{
- ASSERT_EQ(m_assertAbsorber.m_numAssertsAbsorbed, 0);
- ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0);
AssetProcessorManagerTest::TearDown();
}
@@ -1617,7 +1617,7 @@ TEST_F(PathDependencyTest, AssetProcessed_Impl_SelfReferrentialProductDependency
mainFile.m_products.push_back(productAssetId);
// tell the APM that the asset has been processed and allow it to bubble through its event queue:
- m_assertAbsorber.Clear();
+ m_errorAbsorber->Clear();
m_assetProcessorManager->AssetProcessed(jobDetails.m_jobEntry, processJobResponse);
ASSERT_TRUE(BlockUntilIdle(5000));
@@ -1627,8 +1627,8 @@ TEST_F(PathDependencyTest, AssetProcessed_Impl_SelfReferrentialProductDependency
ASSERT_TRUE(dependencyContainer.empty());
// We are testing 2 different dependencies, so we should get 2 warnings
- ASSERT_EQ(m_assertAbsorber.m_numWarningsAbsorbed, 2);
- m_assertAbsorber.Clear();
+ ASSERT_EQ(m_errorAbsorber->m_numWarningsAbsorbed, 2);
+ m_errorAbsorber->Clear();
}
// This test shows the process of deferring resolution of a path dependency works.
@@ -1945,8 +1945,8 @@ TEST_F(PathDependencyTest, WildcardDependencies_ExcludePathsExisting_ResolveCorr
);
// Test asset PrimaryFile1 has 4 conflict dependencies
- ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 4);
- m_assertAbsorber.Clear();
+ ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 4);
+ m_errorAbsorber->Clear();
}
TEST_F(PathDependencyTest, WildcardDependencies_Deferred_ResolveCorrectly)
@@ -2093,8 +2093,8 @@ TEST_F(PathDependencyTest, WildcardDependencies_ExcludedPathDeferred_ResolveCorr
// Test asset PrimaryFile1 has 4 conflict dependencies
// After test assets dep2 and dep3 are processed,
// another 2 errors will be raised because of the confliction
- ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 6);
- m_assertAbsorber.Clear();
+ ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 6);
+ m_errorAbsorber->Clear();
}
void PathDependencyTest::RunWildcardTest(bool useCorrectDatabaseSeparator, AssetBuilderSDK::ProductPathDependencyType pathDependencyType, bool buildDependenciesFirst)
diff --git a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h
index 3443a4c519..2f0121485e 100644
--- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h
+++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h
@@ -58,7 +58,6 @@ protected:
AZStd::unique_ptr m_assetProcessorManager;
AZStd::unique_ptr m_mockApplicationManager;
AZStd::unique_ptr m_config;
- UnitTestUtils::AssertAbsorber m_assertAbsorber; // absorb asserts/warnings/errors so that the unit test output is not cluttered
QString m_gameName;
QDir m_normalizedCacheRootDir;
AZStd::atomic_bool m_isIdling;
diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectBuilderWorker_linux.cpp b/Code/Tools/ProjectManager/Platform/Linux/ProjectBuilderWorker_linux.cpp
index 2987fc4dc2..fdeaef93bb 100644
--- a/Code/Tools/ProjectManager/Platform/Linux/ProjectBuilderWorker_linux.cpp
+++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectBuilderWorker_linux.cpp
@@ -23,25 +23,11 @@ namespace O3DE::ProjectManager
QString cmakeGenerator = (whichNinjaResult.IsSuccess()) ? "Ninja Multi-Config" : "Unix Makefiles";
bool compileProfileOnBuild = (whichNinjaResult.IsSuccess());
- // On Linux the default compiler is gcc. For O3DE, it is clang, so we need to specify the version of clang that is detected
- // in order to get the compiler option.
- auto compilerOptionResult = ProjectUtils::FindSupportedCompilerForPlatform();
- if (!compilerOptionResult.IsSuccess())
- {
- return AZ::Failure(compilerOptionResult.GetError());
- }
- auto clangCompilers = compilerOptionResult.GetValue().split('|');
- AZ_Assert(clangCompilers.length()==2, "Invalid clang compiler pair specification");
-
- QString clangCompilerOption = clangCompilers[0];
- QString clangPPCompilerOption = clangCompilers[1];
QString targetBuildPath = QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix);
QStringList generateProjectArgs = QStringList{ProjectCMakeCommand,
"-B", ProjectBuildPathPostfix,
"-S", ".",
QString("-G%1").arg(cmakeGenerator),
- QString("-DCMAKE_C_COMPILER=").append(clangCompilerOption),
- QString("-DCMAKE_CXX_COMPILER=").append(clangPPCompilerOption),
QString("-DLY_3RDPARTY_PATH=").append(thirdPartyPath)};
if (!compileProfileOnBuild)
{
diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Linux.h b/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Linux.h
index 7c0543361f..d7edcfcf12 100644
--- a/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Linux.h
+++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Linux.h
@@ -9,3 +9,4 @@
#pragma once
#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false
+#define AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT false
diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp b/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp
index e901d807b4..a7bd2dae08 100644
--- a/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp
+++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp
@@ -17,13 +17,11 @@ namespace O3DE::ProjectManager
namespace ProjectUtils
{
// The list of clang C/C++ compiler command lines to validate on the host Linux system
- const QStringList SupportedClangCommands = {"clang-12|clang++-12"};
+ const QStringList SupportedClangVersions = {"13", "12", "11", "10", "9", "8", "7", "6.0"};
AZ::Outcome GetCommandLineProcessEnvironment()
{
QProcessEnvironment currentEnvironment(QProcessEnvironment::systemEnvironment());
- currentEnvironment.insert("CC", "clang-12");
- currentEnvironment.insert("CXX", "clang++-12");
return AZ::Success(currentEnvironment);
}
@@ -39,16 +37,13 @@ namespace O3DE::ProjectManager
}
// Look for the first compatible version of clang. The list below will contain the known clang compilers that have been tested for O3DE.
- for (const QString& supportClangCommand : SupportedClangCommands)
+ for (const QString& supportClangVersion : SupportedClangVersions)
{
- auto clangCompilers = supportClangCommand.split('|');
- AZ_Assert(clangCompilers.length()==2, "Invalid clang compiler pair specification");
-
- auto whichClangResult = ProjectUtils::ExecuteCommandResult("which", QStringList{clangCompilers[0]}, QProcessEnvironment::systemEnvironment());
- auto whichClangPPResult = ProjectUtils::ExecuteCommandResult("which", QStringList{clangCompilers[1]}, QProcessEnvironment::systemEnvironment());
+ auto whichClangResult = ProjectUtils::ExecuteCommandResult("which", QStringList{QString("clang-%1").arg(supportClangVersion)}, QProcessEnvironment::systemEnvironment());
+ auto whichClangPPResult = ProjectUtils::ExecuteCommandResult("which", QStringList{QString("clang++-%1").arg(supportClangVersion)}, QProcessEnvironment::systemEnvironment());
if (whichClangResult.IsSuccess() && whichClangPPResult.IsSuccess())
{
- return AZ::Success(supportClangCommand);
+ return AZ::Success(QString("clang-%1").arg(supportClangVersion));
}
}
return AZ::Failure(QObject::tr("Clang not found.
"
@@ -101,5 +96,10 @@ namespace O3DE::ProjectManager
{
return AZ::Utils::GetExecutableDirectory();
}
+
+ AZ::Outcome CreateDesktopShortcut([[maybe_unused]] const QString& filename, [[maybe_unused]] const QString& targetPath, [[maybe_unused]] const QStringList& arguments)
+ {
+ return AZ::Failure(QObject::tr("Creating desktop shortcuts functionality not implemented for this platform yet."));
+ }
} // namespace ProjectUtils
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Mac.h b/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Mac.h
index 7c0543361f..d7edcfcf12 100644
--- a/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Mac.h
+++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Mac.h
@@ -9,3 +9,4 @@
#pragma once
#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false
+#define AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT false
diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp b/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp
index b768200398..62011bf04b 100644
--- a/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp
+++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp
@@ -137,5 +137,10 @@ namespace O3DE::ProjectManager
return editorPath;
}
+
+ AZ::Outcome CreateDesktopShortcut([[maybe_unused]] const QString& filename, [[maybe_unused]] const QString& targetPath, [[maybe_unused]] const QStringList& arguments)
+ {
+ return AZ::Failure(QObject::tr("Creating desktop shortcuts functionality not implemented for this platform yet."));
+ }
} // namespace ProjectUtils
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Windows.h b/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Windows.h
index e6422b5a77..9e4d29b58f 100644
--- a/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Windows.h
+++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Windows.h
@@ -9,3 +9,4 @@
#pragma once
#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR true
+#define AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT true
diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp b/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp
index 871f8e9567..d08da1d5e1 100644
--- a/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp
+++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
#include
@@ -146,5 +147,26 @@ namespace O3DE::ProjectManager
{
return AZ::Utils::GetExecutableDirectory();
}
+
+ AZ::Outcome CreateDesktopShortcut(const QString& filename, const QString& targetPath, const QStringList& arguments)
+ {
+ const QString cmd{"powershell.exe"};
+ const QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
+ const QString shortcutPath = QString("%1/%2.lnk").arg(desktopPath).arg(filename);
+ const QString arg = QString("$s=(New-Object -COM WScript.Shell).CreateShortcut('%1');$s.TargetPath='%2';$s.Arguments='%3';$s.Save();")
+ .arg(shortcutPath)
+ .arg(targetPath)
+ .arg(arguments.join(' '));
+ auto createShortcutResult = ExecuteCommandResult(cmd, QStringList{"-Command", arg}, QProcessEnvironment::systemEnvironment());
+ if (!createShortcutResult.IsSuccess())
+ {
+ return AZ::Failure(QObject::tr("Failed to create desktop shortcut %1
"
+ "Please verify you have permission to create files at the specified location.
%2")
+ .arg(shortcutPath)
+ .arg(createShortcutResult.GetError()));
+ }
+
+ return AZ::Success(QObject::tr("Desktop shortcut created at
%2").arg(desktopPath).arg(shortcutPath));
+ }
} // namespace ProjectUtils
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qrc b/Code/Tools/ProjectManager/Resources/ProjectManager.qrc
index 8dd7e4c9b5..2260ae62b9 100644
--- a/Code/Tools/ProjectManager/Resources/ProjectManager.qrc
+++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qrc
@@ -41,5 +41,6 @@
Download.svg
in_progress.gif
gem.svg
+ checkmark.svg
diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss
index d3ec066be7..426f409581 100644
--- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss
+++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss
@@ -563,6 +563,52 @@ QProgressBar::chunk {
margin-top:5px;
}
+#gemCatalogUpdateGemButton,
+#gemCatalogUninstallGemButton
+{
+ qproperty-flat: true;
+ min-height:24px;
+ max-height:24px;
+ border-radius: 3px;
+ text-align:center;
+ font-size:12px;
+ font-weight:600;
+}
+
+#gemCatalogUpdateGemButton {
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #888888, stop: 1.0 #555555);
+}
+#gemCatalogUpdateGemButton:hover {
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #999999, stop: 1.0 #666666);
+}
+#gemCatalogUpdateGemButton:pressed {
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #555555, stop: 1.0 #777777);
+}
+
+#footer > #gemCatalogUninstallGemButton,
+#gemCatalogUninstallGemButton {
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #E32C27, stop: 1.0 #951D21);
+}
+#footer > #gemCatalogUninstallGemButton:hover,
+#gemCatalogUninstallGemButton:hover {
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #FD3129, stop: 1.0 #AF2221);
+}
+#footer > #gemCatalogUninstallGemButton:pressed,
+#gemCatalogUninstallGemButton:pressed {
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #951D1F, stop: 1.0 #C92724);
+}
+
+#gemCatalogDialogSubTitle {
+ font-size:14px;
+ font-weight:600;
+}
+
/************** Filter Tag widget **************/
#FilterTagWidgetTextLabel {
diff --git a/Code/Tools/ProjectManager/Resources/checkmark.svg b/Code/Tools/ProjectManager/Resources/checkmark.svg
new file mode 100644
index 0000000000..d612b35370
--- /dev/null
+++ b/Code/Tools/ProjectManager/Resources/checkmark.svg
@@ -0,0 +1,12 @@
+
+
diff --git a/Code/Tools/ProjectManager/Source/DownloadController.cpp b/Code/Tools/ProjectManager/Source/DownloadController.cpp
index 6326b2fc11..06e51b5116 100644
--- a/Code/Tools/ProjectManager/Source/DownloadController.cpp
+++ b/Code/Tools/ProjectManager/Source/DownloadController.cpp
@@ -18,7 +18,6 @@ namespace O3DE::ProjectManager
{
DownloadController::DownloadController(QWidget* parent)
: QObject()
- , m_lastProgress(0)
, m_parent(parent)
{
m_worker = new DownloadWorker();
@@ -69,10 +68,9 @@ namespace O3DE::ProjectManager
}
}
- void DownloadController::UpdateUIProgress(int progress)
+ void DownloadController::UpdateUIProgress(int bytesDownloaded, int totalBytes)
{
- m_lastProgress = progress;
- emit GemDownloadProgress(m_gemNames.front(), progress);
+ emit GemDownloadProgress(m_gemNames.front(), bytesDownloaded, totalBytes);
}
void DownloadController::HandleResults(const QString& result)
@@ -88,6 +86,7 @@ namespace O3DE::ProjectManager
QString gemName = m_gemNames.front();
m_gemNames.erase(m_gemNames.begin());
emit Done(gemName, succeeded);
+ emit GemDownloadRemoved(gemName);
if (!m_gemNames.empty())
{
diff --git a/Code/Tools/ProjectManager/Source/DownloadController.h b/Code/Tools/ProjectManager/Source/DownloadController.h
index 0bf0ae473c..211d9b48bc 100644
--- a/Code/Tools/ProjectManager/Source/DownloadController.h
+++ b/Code/Tools/ProjectManager/Source/DownloadController.h
@@ -53,7 +53,7 @@ namespace O3DE::ProjectManager
}
}
public slots:
- void UpdateUIProgress(int progress);
+ void UpdateUIProgress(int bytesDownloaded, int totalBytes);
void HandleResults(const QString& result);
signals:
@@ -61,14 +61,12 @@ namespace O3DE::ProjectManager
void Done(const QString& gemName, bool success = true);
void GemDownloadAdded(const QString& gemName);
void GemDownloadRemoved(const QString& gemName);
- void GemDownloadProgress(const QString& gemName, int percentage);
+ void GemDownloadProgress(const QString& gemName, int bytesDownloaded, int totalBytes);
private:
DownloadWorker* m_worker;
QThread m_workerThread;
QWidget* m_parent;
AZStd::vector m_gemNames;
-
- int m_lastProgress;
};
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/DownloadWorker.cpp b/Code/Tools/ProjectManager/Source/DownloadWorker.cpp
index 9bda1b34cc..560bfe05de 100644
--- a/Code/Tools/ProjectManager/Source/DownloadWorker.cpp
+++ b/Code/Tools/ProjectManager/Source/DownloadWorker.cpp
@@ -20,12 +20,13 @@ namespace O3DE::ProjectManager
void DownloadWorker::StartDownload()
{
- auto gemDownloadProgress = [=](int downloadProgress)
+ auto gemDownloadProgress = [=](int bytesDownloaded, int totalBytes)
{
- m_downloadProgress = downloadProgress;
- emit UpdateProgress(downloadProgress);
+ emit UpdateProgress(bytesDownloaded, totalBytes);
};
- AZ::Outcome gemInfoResult = PythonBindingsInterface::Get()->DownloadGem(m_gemName, gemDownloadProgress);
+ AZ::Outcome gemInfoResult =
+ PythonBindingsInterface::Get()->DownloadGem(m_gemName, gemDownloadProgress, /*force*/true);
+
if (gemInfoResult.IsSuccess())
{
emit Done("");
diff --git a/Code/Tools/ProjectManager/Source/DownloadWorker.h b/Code/Tools/ProjectManager/Source/DownloadWorker.h
index 316a730a78..4084080ff7 100644
--- a/Code/Tools/ProjectManager/Source/DownloadWorker.h
+++ b/Code/Tools/ProjectManager/Source/DownloadWorker.h
@@ -31,12 +31,11 @@ namespace O3DE::ProjectManager
void SetGemToDownload(const QString& gemName, bool downloadNow = true);
signals:
- void UpdateProgress(int progress);
+ void UpdateProgress(int bytesDownloaded, int totalBytes);
void Done(QString result = "");
private:
QString m_gemName;
- int m_downloadProgress;
};
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp
index bd0a6e9bc3..e676ba73d3 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp
@@ -15,6 +15,8 @@
#include
#include
#include
+#include
+#include
namespace O3DE::ProjectManager
{
@@ -224,7 +226,6 @@ namespace O3DE::ProjectManager
connect(m_downloadController, &DownloadController::GemDownloadAdded, this, &CartOverlayWidget::GemDownloadAdded);
connect(m_downloadController, &DownloadController::GemDownloadRemoved, this, &CartOverlayWidget::GemDownloadRemoved);
connect(m_downloadController, &DownloadController::GemDownloadProgress, this, &CartOverlayWidget::GemDownloadProgress);
- connect(m_downloadController, &DownloadController::Done, this, &CartOverlayWidget::GemDownloadComplete);
}
void CartOverlayWidget::GemDownloadAdded(const QString& gemName)
@@ -288,29 +289,41 @@ namespace O3DE::ProjectManager
}
}
- void CartOverlayWidget::GemDownloadProgress(const QString& gemName, int percentage)
+ void CartOverlayWidget::GemDownloadProgress(const QString& gemName, int bytesDownloaded, int totalBytes)
{
QWidget* gemToUpdate = m_downloadingListWidget->findChild(gemName);
if (gemToUpdate)
{
QLabel* progressLabel = gemToUpdate->findChild("DownloadProgressLabel");
- if (progressLabel)
- {
- progressLabel->setText(QString("%1%").arg(percentage));
- }
QProgressBar* progressBar = gemToUpdate->findChild("DownloadProgressBar");
- if (progressBar)
+
+ // totalBytes can be 0 if the server does not return a content-length for the object
+ if (totalBytes != 0)
{
- progressBar->setValue(percentage);
+ int downloadPercentage = static_cast((bytesDownloaded / static_cast(totalBytes)) * 100);
+ if (progressLabel)
+ {
+ progressLabel->setText(QString("%1%").arg(downloadPercentage));
+ }
+ if (progressBar)
+ {
+ progressBar->setValue(downloadPercentage);
+ }
+ }
+ else
+ {
+ if (progressLabel)
+ {
+ progressLabel->setText(QLocale::system().formattedDataSize(bytesDownloaded));
+ }
+ if (progressBar)
+ {
+ progressBar->setRange(0, 0);
+ }
}
}
}
- void CartOverlayWidget::GemDownloadComplete(const QString& gemName, bool /*success*/)
- {
- GemDownloadRemoved(gemName); // update the list to remove the gem that has finished
- }
-
QVector CartOverlayWidget::GetTagsFromModelIndices(const QVector& gems) const
{
QVector tags;
@@ -389,7 +402,7 @@ namespace O3DE::ProjectManager
{
const QVector toBeAdded = m_gemModel->GatherGemsToBeAdded(/*includeDependencies=*/true);
const QVector toBeRemoved = m_gemModel->GatherGemsToBeRemoved(/*includeDependencies=*/true);
- if (toBeAdded.isEmpty() && toBeRemoved.isEmpty())
+ if (toBeAdded.isEmpty() && toBeRemoved.isEmpty() && m_downloadController->IsDownloadQueueEmpty())
{
return;
}
@@ -430,6 +443,7 @@ namespace O3DE::ProjectManager
GemCatalogHeaderWidget::GemCatalogHeaderWidget(GemModel* gemModel, GemSortFilterProxyModel* filterProxyModel, DownloadController* downloadController, QWidget* parent)
: QFrame(parent)
+ , m_downloadController(downloadController)
{
QHBoxLayout* hLayout = new QHBoxLayout();
hLayout->setAlignment(Qt::AlignLeft);
@@ -456,8 +470,25 @@ namespace O3DE::ProjectManager
hLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));
hLayout->addSpacerItem(new QSpacerItem(75, 0, QSizePolicy::Fixed));
- CartButton* cartButton = new CartButton(gemModel, downloadController);
- hLayout->addWidget(cartButton);
+ // spinner
+ m_downloadSpinnerMovie = new QMovie(":/in_progress.gif");
+ m_downloadSpinner = new QLabel(this);
+ m_downloadSpinner->setScaledContents(true);
+ m_downloadSpinner->setMaximumSize(16, 16);
+ m_downloadSpinner->setMovie(m_downloadSpinnerMovie);
+ hLayout->addWidget(m_downloadSpinner);
+ hLayout->addSpacing(8);
+
+ // downloading label
+ m_downloadLabel = new QLabel(tr("Downloading"));
+ hLayout->addWidget(m_downloadLabel);
+ m_downloadSpinner->hide();
+ m_downloadLabel->hide();
+
+ hLayout->addSpacing(16);
+
+ m_cartButton = new CartButton(gemModel, downloadController);
+ hLayout->addWidget(m_cartButton);
hLayout->addSpacing(16);
// Separating line
@@ -469,6 +500,7 @@ namespace O3DE::ProjectManager
hLayout->addSpacing(16);
QMenu* gemMenu = new QMenu(this);
+ gemMenu->addAction( tr("Refresh"), [this]() { emit RefreshGems(); });
gemMenu->addAction( tr("Show Gem Repos"), [this]() { emit OpenGemsRepo(); });
gemMenu->addSeparator();
gemMenu->addAction( tr("Add Existing Gem"), [this]() { emit AddGem(); });
@@ -479,6 +511,27 @@ namespace O3DE::ProjectManager
gemMenuButton->setIcon(QIcon(":/menu.svg"));
gemMenuButton->setIconSize(QSize(36, 24));
hLayout->addWidget(gemMenuButton);
+
+ connect(m_downloadController, &DownloadController::GemDownloadAdded, this, &GemCatalogHeaderWidget::GemDownloadAdded);
+ connect(m_downloadController, &DownloadController::GemDownloadRemoved, this, &GemCatalogHeaderWidget::GemDownloadRemoved);
+ }
+
+ void GemCatalogHeaderWidget::GemDownloadAdded(const QString& /*gemName*/)
+ {
+ m_downloadSpinner->show();
+ m_downloadLabel->show();
+ m_downloadSpinnerMovie->start();
+ m_cartButton->ShowOverlay();
+ }
+
+ void GemCatalogHeaderWidget::GemDownloadRemoved(const QString& /*gemName*/)
+ {
+ if (m_downloadController->IsDownloadQueueEmpty())
+ {
+ m_downloadSpinner->hide();
+ m_downloadLabel->hide();
+ m_downloadSpinnerMovie->stop();
+ }
}
void GemCatalogHeaderWidget::ReinitForProject()
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h
index f3242d6db7..5174fde57d 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h
@@ -24,6 +24,7 @@ QT_FORWARD_DECLARE_CLASS(QVBoxLayout)
QT_FORWARD_DECLARE_CLASS(QHBoxLayout)
QT_FORWARD_DECLARE_CLASS(QHideEvent)
QT_FORWARD_DECLARE_CLASS(QMoveEvent)
+QT_FORWARD_DECLARE_CLASS(QMovie)
namespace O3DE::ProjectManager
{
@@ -39,8 +40,7 @@ namespace O3DE::ProjectManager
public slots:
void GemDownloadAdded(const QString& gemName);
void GemDownloadRemoved(const QString& gemName);
- void GemDownloadProgress(const QString& gemName, int percentage);
- void GemDownloadComplete(const QString& gemName, bool success);
+ void GemDownloadProgress(const QString& gemName, int bytesDownloaded, int totalBytes);
private:
QVector GetTagsFromModelIndices(const QVector& gems) const;
@@ -96,12 +96,22 @@ namespace O3DE::ProjectManager
void ReinitForProject();
+ public slots:
+ void GemDownloadAdded(const QString& gemName);
+ void GemDownloadRemoved(const QString& gemName);
+
signals:
void AddGem();
void OpenGemsRepo();
+ void RefreshGems();
private:
AzQtComponents::SearchLineEdit* m_filterLineEdit = nullptr;
inline constexpr static int s_height = 60;
+ DownloadController* m_downloadController = nullptr;
+ QLabel* m_downloadSpinner = nullptr;
+ QLabel* m_downloadLabel = nullptr;
+ QMovie* m_downloadSpinnerMovie = nullptr;
+ CartButton* m_cartButton = nullptr;
};
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp
index 732f4813a2..0dacbbb906 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp
@@ -12,7 +12,11 @@
#include
#include
#include
+#include
+#include
#include
+#include
+
#include
#include
#include
@@ -47,6 +51,7 @@ namespace O3DE::ProjectManager
vLayout->addWidget(m_headerWidget);
connect(m_gemModel, &GemModel::gemStatusChanged, this, &GemCatalogScreen::OnGemStatusChanged);
+ connect(m_headerWidget, &GemCatalogHeaderWidget::RefreshGems, this, &GemCatalogScreen::Refresh);
connect(m_headerWidget, &GemCatalogHeaderWidget::OpenGemsRepo, this, &GemCatalogScreen::HandleOpenGemRepo);
connect(m_headerWidget, &GemCatalogHeaderWidget::AddGem, this, &GemCatalogScreen::OnAddGemClicked);
connect(m_downloadController, &DownloadController::Done, this, &GemCatalogScreen::OnGemDownloadResult);
@@ -60,6 +65,8 @@ namespace O3DE::ProjectManager
m_gemInspector->setFixedWidth(240);
connect(m_gemInspector, &GemInspector::TagClicked, [=](const Tag& tag) { SelectGem(tag.id); });
+ connect(m_gemInspector, &GemInspector::UpdateGem, this, &GemCatalogScreen::UpdateGem);
+ connect(m_gemInspector, &GemInspector::UninstallGem, this, &GemCatalogScreen::UninstallGem);
QWidget* filterWidget = new QWidget(this);
filterWidget->setFixedWidth(240);
@@ -99,7 +106,7 @@ namespace O3DE::ProjectManager
FillModel(projectPath);
- m_proxyModel->ResetFilters();
+ m_proxyModel->ResetFilters(false);
m_proxyModel->sort(/*column=*/0);
if (m_filterWidget)
@@ -118,9 +125,10 @@ namespace O3DE::ProjectManager
// Select the first entry after everything got correctly sized
QTimer::singleShot(200, [=]{
- QModelIndex firstModelIndex = m_gemListView->model()->index(0,0);
- m_gemListView->selectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect);
- });
+ QModelIndex firstModelIndex = m_gemModel->index(0, 0);
+ QModelIndex proxyIndex = m_proxyModel->mapFromSource(firstModelIndex);
+ m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect);
+ });
}
void GemCatalogScreen::OnAddGemClicked()
@@ -202,7 +210,7 @@ namespace O3DE::ProjectManager
const bool gemFound = gemInfoHash.contains(gemName);
if (!gemFound && !m_gemModel->IsAdded(index) && !m_gemModel->IsAddedDependency(index))
{
- m_gemModel->removeRow(i);
+ m_gemModel->RemoveGem(index);
}
else
{
@@ -228,8 +236,11 @@ namespace O3DE::ProjectManager
m_proxyModel->sort(/*column=*/0);
// temporary, until we can refresh filter counts
- m_proxyModel->ResetFilters();
+ m_proxyModel->ResetFilters(false);
m_filterWidget->ResetAllFilters();
+
+ // Reselect the same selection to proc UI updates
+ m_proxyModel->GetSelectionModel()->setCurrentIndex(m_proxyModel->GetSelectionModel()->currentIndex(), QItemSelectionModel::Select);
}
void GemCatalogScreen::OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies)
@@ -253,24 +264,24 @@ namespace O3DE::ProjectManager
notification = GemModel::GetDisplayName(modelIndex);
if (numChangedDependencies > 0)
{
- notification += " " + tr("and") + " ";
+ notification += tr(" and ");
}
if (added && GemModel::GetDownloadStatus(modelIndex) == GemInfo::DownloadStatus::NotDownloaded)
{
m_downloadController->AddGemDownload(GemModel::GetName(modelIndex));
- GemModel::SetDownloadStatus(*m_proxyModel, m_proxyModel->mapFromSource(modelIndex), GemInfo::DownloadStatus::Downloading);
+ GemModel::SetDownloadStatus(*m_gemModel, modelIndex, GemInfo::DownloadStatus::Downloading);
}
}
- if (numChangedDependencies == 1 )
+ if (numChangedDependencies == 1)
{
- notification += "1 Gem " + tr("dependency");
+ notification += tr("1 Gem dependency");
}
else if (numChangedDependencies > 1)
{
- notification += QString("%1 Gem ").arg(numChangedDependencies) + tr("dependencies");
+ notification += tr("%1 Gem %2").arg(QString(numChangedDependencies), tr("dependencies"));
}
- notification += " " + (added ? tr("activated") : tr("deactivated"));
+ notification += (added ? tr(" activated") : tr(" deactivated"));
AzQtComponents::ToastConfiguration toastConfiguration(AzQtComponents::ToastType::Custom, notification, "");
toastConfiguration.m_customIconImage = ":/gem.svg";
@@ -290,10 +301,102 @@ namespace O3DE::ProjectManager
}
QModelIndex proxyIndex = m_proxyModel->mapFromSource(modelIndex);
- m_proxyModel->GetSelectionModel()->select(proxyIndex, QItemSelectionModel::ClearAndSelect);
+ m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect);
m_gemListView->scrollTo(proxyIndex);
}
+ void GemCatalogScreen::UpdateGem(const QModelIndex& modelIndex)
+ {
+ const QString selectedGemName = m_gemModel->GetName(modelIndex);
+ const QString selectedGemLastUpdate = m_gemModel->GetLastUpdated(modelIndex);
+ const QString selectedDisplayGemName = m_gemModel->GetDisplayName(modelIndex);
+ const QString selectedGemRepoUri = m_gemModel->GetRepoUri(modelIndex);
+
+ // Refresh gem repo
+ if (!selectedGemRepoUri.isEmpty())
+ {
+ AZ::Outcome refreshResult = PythonBindingsInterface::Get()->RefreshGemRepo(selectedGemRepoUri);
+ if (refreshResult.IsSuccess())
+ {
+ Refresh();
+ }
+ else
+ {
+ QMessageBox::critical(
+ this, tr("Operation failed"),
+ tr("Failed to refresh gem repository %1
Error:
%2").arg(selectedGemRepoUri, refreshResult.GetError().c_str()));
+ }
+ }
+ // If repo uri isn't specified warn user that repo might not be refreshed
+ else
+ {
+ int result = QMessageBox::warning(
+ this, tr("Gem Repository Unspecified"),
+ tr("The repo for %1 is unspecfied. Repository cannot be automatically refreshed. "
+ "Please ensure this gem's repo is refreshed before attempting to update.")
+ .arg(selectedDisplayGemName),
+ QMessageBox::Cancel, QMessageBox::Ok);
+
+ // Allow user to cancel update to manually refresh repo
+ if (result != QMessageBox::Ok)
+ {
+ return;
+ }
+ }
+
+ // Check if there is an update avaliable now that repo is refreshed
+ bool updateAvaliable = PythonBindingsInterface::Get()->IsGemUpdateAvaliable(selectedGemName, selectedGemLastUpdate);
+
+ GemUpdateDialog* confirmUpdateDialog = new GemUpdateDialog(selectedGemName, updateAvaliable, this);
+ if (confirmUpdateDialog->exec() == QDialog::Accepted)
+ {
+ m_downloadController->AddGemDownload(selectedGemName);
+ }
+ }
+
+ void GemCatalogScreen::UninstallGem(const QModelIndex& modelIndex)
+ {
+ const QString selectedDisplayGemName = m_gemModel->GetDisplayName(modelIndex);
+
+ GemUninstallDialog* confirmUninstallDialog = new GemUninstallDialog(selectedDisplayGemName, this);
+ if (confirmUninstallDialog->exec() == QDialog::Accepted)
+ {
+ const QString selectedGemPath = m_gemModel->GetPath(modelIndex);
+
+ // Remove gem from gems to be added
+ GemModel::SetIsAdded(*m_gemModel, modelIndex, false);
+
+ // Unregister the gem
+ auto unregisterResult = PythonBindingsInterface::Get()->UnregisterGem(selectedGemPath);
+ if (!unregisterResult)
+ {
+ QMessageBox::critical(this, tr("Failed to unregister gem"), unregisterResult.GetError().c_str());
+ }
+ else
+ {
+ const QString selectedGemName = m_gemModel->GetName(modelIndex);
+
+ // Remove gem from model
+ m_gemModel->RemoveGem(modelIndex);
+
+ // Delete uninstalled gem directory
+ if (!ProjectUtils::DeleteProjectFiles(selectedGemPath, /*force*/true))
+ {
+ QMessageBox::critical(
+ this, tr("Failed to remove gem directory"), tr("Could not delete gem directory at:
%1").arg(selectedGemPath));
+ }
+
+ // Show undownloaded remote gem again
+ Refresh();
+
+ // Select remote gem
+ QModelIndex remoteGemIndex = m_gemModel->FindIndexByNameString(selectedGemName);
+ QModelIndex proxyIndex = m_proxyModel->mapFromSource(remoteGemIndex);
+ m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect);
+ }
+ }
+ }
+
void GemCatalogScreen::hideEvent(QHideEvent* event)
{
ScreenWidget::hideEvent(event);
@@ -472,7 +575,8 @@ namespace O3DE::ProjectManager
if (succeeded)
{
// refresh the information for downloaded gems
- const AZ::Outcome, AZStd::string>& allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(m_projectPath);
+ const AZ::Outcome, AZStd::string>& allGemInfosResult =
+ PythonBindingsInterface::Get()->GetAllGemInfos(m_projectPath);
if (allGemInfosResult.IsSuccess())
{
// we should find the gem name now in all gem infos
@@ -480,19 +584,45 @@ namespace O3DE::ProjectManager
{
if (gemInfo.m_name == gemName)
{
- QModelIndex index = m_gemModel->FindIndexByNameString(gemName);
- if (index.isValid())
+ QModelIndex oldIndex = m_gemModel->FindIndexByNameString(gemName);
+ if (oldIndex.isValid())
{
- m_gemModel->setData(index, GemInfo::Downloaded, GemModel::RoleDownloadStatus);
- m_gemModel->setData(index, gemInfo.m_path, GemModel::RolePath);
- m_gemModel->setData(index, gemInfo.m_path, GemModel::RoleDirectoryLink);
+ // Check if old gem is selected
+ bool oldGemSelected = false;
+ if (m_gemModel->GetSelectionModel()->currentIndex() == oldIndex)
+ {
+ oldGemSelected = true;
+ }
+
+ // Remove old remote gem
+ m_gemModel->RemoveGem(oldIndex);
+
+ // Add new downloaded version of gem
+ QModelIndex newIndex = m_gemModel->AddGem(gemInfo);
+ GemModel::SetDownloadStatus(*m_gemModel, newIndex, GemInfo::DownloadSuccessful);
+ GemModel::SetIsAdded(*m_gemModel, newIndex, true);
+
+ // Select new version of gem if it was previously selected
+ if (oldGemSelected)
+ {
+ QModelIndex proxyIndex = m_proxyModel->mapFromSource(newIndex);
+ m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect);
+ }
}
- return;
+ break;
}
}
}
}
+ else
+ {
+ QModelIndex index = m_gemModel->FindIndexByNameString(gemName);
+ if (index.isValid())
+ {
+ GemModel::SetDownloadStatus(*m_gemModel, index, GemInfo::DownloadFailed);
+ }
+ }
}
ProjectManagerScreen GemCatalogScreen::GetScreenEnum()
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h
index da6d2efa7b..c5fbb057ef 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h
@@ -51,6 +51,8 @@ namespace O3DE::ProjectManager
void SelectGem(const QString& gemName);
void OnGemDownloadResult(const QString& gemName, bool succeeded = true);
void Refresh();
+ void UpdateGem(const QModelIndex& modelIndex);
+ void UninstallGem(const QModelIndex& modelIndex);
protected:
void hideEvent(QHideEvent* event) override;
@@ -77,6 +79,6 @@ namespace O3DE::ProjectManager
DownloadController* m_downloadController = nullptr;
bool m_notificationsEnabled = true;
QSet m_gemsToRegisterWithProject;
- QString m_projectPath = nullptr;
+ QString m_projectPath;
};
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h
index 12cce5a4ea..5c1bc90c6e 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h
@@ -57,7 +57,9 @@ namespace O3DE::ProjectManager
UnknownDownloadStatus = -1,
NotDownloaded,
Downloading,
- Downloaded,
+ DownloadSuccessful,
+ DownloadFailed,
+ Downloaded
};
static QString GetDownloadStatusString(DownloadStatus status);
@@ -85,6 +87,7 @@ namespace O3DE::ProjectManager
QString m_licenseLink;
QString m_directoryLink;
QString m_documentationLink;
+ QString m_repoUri;
QString m_version = "Unknown Version";
QString m_lastUpdatedDate = "Unknown Date";
int m_binarySizeInKB = 0;
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp
index 1bcfc6ce9d..26844b43e6 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp
@@ -14,6 +14,7 @@
#include
#include
#include
+#include
namespace O3DE::ProjectManager
{
@@ -70,6 +71,8 @@ namespace O3DE::ProjectManager
void GemInspector::Update(const QModelIndex& modelIndex)
{
+ m_curModelIndex = modelIndex;
+
if (!modelIndex.isValid())
{
m_mainWidget->hide();
@@ -123,6 +126,20 @@ namespace O3DE::ProjectManager
const int binarySize = m_model->GetBinarySizeInKB(modelIndex);
m_binarySizeLabel->setText(tr("Binary Size: %1").arg(binarySize ? tr("%1 KB").arg(binarySize) : tr("Unknown")));
+ // Update and Uninstall buttons
+ if (m_model->GetGemOrigin(modelIndex) == GemInfo::Remote &&
+ (m_model->GetDownloadStatus(modelIndex) == GemInfo::Downloaded ||
+ m_model->GetDownloadStatus(modelIndex) == GemInfo::DownloadSuccessful))
+ {
+ m_updateGemButton->show();
+ m_uninstallGemButton->show();
+ }
+ else
+ {
+ m_updateGemButton->hide();
+ m_uninstallGemButton->hide();
+ }
+
m_mainWidget->adjustSize();
m_mainWidget->show();
}
@@ -223,7 +240,7 @@ namespace O3DE::ProjectManager
// Depending gems
m_dependingGems = new GemsSubWidget();
- connect(m_dependingGems, &GemsSubWidget::TagClicked, this, [=](const Tag& tag){ emit TagClicked(tag); });
+ connect(m_dependingGems, &GemsSubWidget::TagClicked, this, [this](const Tag& tag){ emit TagClicked(tag); });
m_mainLayout->addWidget(m_dependingGems);
m_mainLayout->addSpacing(20);
@@ -234,5 +251,20 @@ namespace O3DE::ProjectManager
m_versionLabel = CreateStyledLabel(m_mainLayout, s_baseFontSize, s_textColor);
m_lastUpdatedLabel = CreateStyledLabel(m_mainLayout, s_baseFontSize, s_textColor);
m_binarySizeLabel = CreateStyledLabel(m_mainLayout, s_baseFontSize, s_textColor);
+
+ m_mainLayout->addSpacing(20);
+
+ // Update and Uninstall buttons
+ m_updateGemButton = new QPushButton(tr("Update Gem"));
+ m_updateGemButton->setObjectName("gemCatalogUpdateGemButton");
+ m_mainLayout->addWidget(m_updateGemButton);
+ connect(m_updateGemButton, &QPushButton::clicked, this , [this]{ emit UpdateGem(m_curModelIndex); });
+
+ m_mainLayout->addSpacing(10);
+
+ m_uninstallGemButton = new QPushButton(tr("Uninstall Gem"));
+ m_uninstallGemButton->setObjectName("gemCatalogUninstallGemButton");
+ m_mainLayout->addWidget(m_uninstallGemButton);
+ connect(m_uninstallGemButton, &QPushButton::clicked, this , [this]{ emit UninstallGem(m_curModelIndex); });
}
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h
index 9a6ad84dea..6a5de17fcd 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.h
@@ -16,11 +16,12 @@
#include
#include
-#include
#endif
QT_FORWARD_DECLARE_CLASS(QVBoxLayout)
QT_FORWARD_DECLARE_CLASS(QLabel)
+QT_FORWARD_DECLARE_CLASS(QSpacerItem)
+QT_FORWARD_DECLARE_CLASS(QPushButton)
namespace O3DE::ProjectManager
{
@@ -45,6 +46,8 @@ namespace O3DE::ProjectManager
signals:
void TagClicked(const Tag& tag);
+ void UpdateGem(const QModelIndex& modelIndex);
+ void UninstallGem(const QModelIndex& modelIndex);
private slots:
void OnSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
@@ -55,6 +58,7 @@ namespace O3DE::ProjectManager
GemModel* m_model = nullptr;
QWidget* m_mainWidget = nullptr;
QVBoxLayout* m_mainLayout = nullptr;
+ QModelIndex m_curModelIndex;
// General info (top) section
QLabel* m_nameLabel = nullptr;
@@ -77,5 +81,8 @@ namespace O3DE::ProjectManager
QLabel* m_versionLabel = nullptr;
QLabel* m_lastUpdatedLabel = nullptr;
QLabel* m_binarySizeLabel = nullptr;
+
+ QPushButton* m_updateGemButton = nullptr;
+ QPushButton* m_uninstallGemButton = nullptr;
};
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp
index e15c4b3b39..dd94e42fc4 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp
@@ -37,6 +37,8 @@ namespace O3DE::ProjectManager
SetStatusIcon(m_notDownloadedPixmap, ":/Download.svg");
SetStatusIcon(m_unknownStatusPixmap, ":/X.svg");
+ SetStatusIcon(m_downloadSuccessfulPixmap, ":/checkmark.svg");
+ SetStatusIcon(m_downloadFailedPixmap, ":/Warning.svg");
m_downloadingMovie = new QMovie(":/in_progress.gif");
}
@@ -480,6 +482,14 @@ namespace O3DE::ProjectManager
currentFrame = currentFrame.scaled(s_statusIconSize, s_statusIconSize);
statusPixmap = ¤tFrame;
}
+ else if (downloadStatus == GemInfo::DownloadStatus::DownloadSuccessful)
+ {
+ statusPixmap = &m_downloadSuccessfulPixmap;
+ }
+ else if (downloadStatus == GemInfo::DownloadStatus::DownloadFailed)
+ {
+ statusPixmap = &m_downloadFailedPixmap;
+ }
else if (downloadStatus == GemInfo::DownloadStatus::NotDownloaded)
{
statusPixmap = &m_notDownloadedPixmap;
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h
index c013be0d9e..107de6de15 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h
@@ -97,6 +97,8 @@ namespace O3DE::ProjectManager
QPixmap m_unknownStatusPixmap;
QPixmap m_notDownloadedPixmap;
+ QPixmap m_downloadSuccessfulPixmap;
+ QPixmap m_downloadFailedPixmap;
QMovie* m_downloadingMovie = nullptr;
};
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp
index 88c54de0b3..95fdc8e1e2 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp
@@ -26,14 +26,14 @@ namespace O3DE::ProjectManager
return m_selectionModel;
}
- void GemModel::AddGem(const GemInfo& gemInfo)
+ QModelIndex GemModel::AddGem(const GemInfo& gemInfo)
{
if (FindIndexByNameString(gemInfo.m_name).isValid())
{
// do not add gems with duplicate names
// this can happen by mistake or when a gem repo has a gem with the same name as a local gem
AZ_TracePrintf("GemModel", "Ignoring duplicate gem: %s", gemInfo.m_name.toUtf8().constData());
- return;
+ return QModelIndex();
}
QStandardItem* item = new QStandardItem();
@@ -61,11 +61,28 @@ namespace O3DE::ProjectManager
item->setData(gemInfo.m_downloadStatus, RoleDownloadStatus);
item->setData(gemInfo.m_licenseText, RoleLicenseText);
item->setData(gemInfo.m_licenseLink, RoleLicenseLink);
+ item->setData(gemInfo.m_repoUri, RoleRepoUri);
appendRow(item);
const QModelIndex modelIndex = index(rowCount()-1, 0);
m_nameToIndexMap[gemInfo.m_name] = modelIndex;
+
+ return modelIndex;
+ }
+
+ void GemModel::RemoveGem(const QModelIndex& modelIndex)
+ {
+ removeRow(modelIndex.row());
+ }
+
+ void GemModel::RemoveGem(const QString& gemName)
+ {
+ auto nameFind = m_nameToIndexMap.find(gemName);
+ if (nameFind != m_nameToIndexMap.end())
+ {
+ removeRow(nameFind->row());
+ }
}
void GemModel::Clear()
@@ -255,6 +272,11 @@ namespace O3DE::ProjectManager
return modelIndex.data(RoleLicenseLink).toString();
}
+ QString GemModel::GetRepoUri(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RoleRepoUri).toString();
+ }
+
GemModel* GemModel::GetSourceModel(QAbstractItemModel* model)
{
GemSortFilterProxyModel* proxyModel = qobject_cast(model);
@@ -369,11 +391,30 @@ namespace O3DE::ProjectManager
void GemModel::OnRowsAboutToBeRemoved(const QModelIndex& parent, int first, int last)
{
+ bool selectedRowRemoved = false;
for (int i = first; i <= last; ++i)
{
QModelIndex modelIndex = index(i, 0, parent);
const QString& gemName = GetName(modelIndex);
m_nameToIndexMap.remove(gemName);
+
+ if (GetSelectionModel()->isRowSelected(i))
+ {
+ selectedRowRemoved = true;
+ }
+ }
+
+ // Select a valid row if currently selected row was removed
+ if (selectedRowRemoved)
+ {
+ for (const QModelIndex& index : m_nameToIndexMap)
+ {
+ if (index.isValid())
+ {
+ GetSelectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
+ break;
+ }
+ }
}
}
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h
index e25a1c7703..bb89d46861 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h
@@ -51,10 +51,13 @@ namespace O3DE::ProjectManager
RoleRequirement,
RoleDownloadStatus,
RoleLicenseText,
- RoleLicenseLink
+ RoleLicenseLink,
+ RoleRepoUri
};
- void AddGem(const GemInfo& gemInfo);
+ QModelIndex AddGem(const GemInfo& gemInfo);
+ void RemoveGem(const QModelIndex& modelIndex);
+ void RemoveGem(const QString& gemName);
void Clear();
void UpdateGemDependencies();
@@ -80,6 +83,7 @@ namespace O3DE::ProjectManager
static QString GetRequirement(const QModelIndex& modelIndex);
static QString GetLicenseText(const QModelIndex& modelIndex);
static QString GetLicenseLink(const QModelIndex& modelIndex);
+ static QString GetRepoUri(const QModelIndex& modelIndex);
static GemModel* GetSourceModel(QAbstractItemModel* model);
static const GemModel* GetSourceModel(const QAbstractItemModel* model);
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp
index 32d0e2fee9..a32492cf1e 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp
@@ -204,9 +204,12 @@ namespace O3DE::ProjectManager
emit OnInvalidated();
}
- void GemSortFilterProxyModel::ResetFilters()
+ void GemSortFilterProxyModel::ResetFilters(bool clearSearchString)
{
- m_searchString.clear();
+ if (clearSearchString)
+ {
+ m_searchString.clear();
+ }
m_gemSelectedFilter = GemSelected::NoFilter;
m_gemActiveFilter = GemActive::NoFilter;
m_gemOriginFilter = {};
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h
index ab739e62f9..0c58d66ccf 100644
--- a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h
@@ -70,7 +70,7 @@ namespace O3DE::ProjectManager
void SetFeatures(const QSet& features) { m_featureFilter = features; InvalidateFilter(); }
void InvalidateFilter();
- void ResetFilters();
+ void ResetFilters(bool clearSearchString = true);
signals:
void OnInvalidated();
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemUninstallDialog.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemUninstallDialog.cpp
new file mode 100644
index 0000000000..1408e29b6d
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemUninstallDialog.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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
+#include
+
+namespace O3DE::ProjectManager
+{
+ GemUninstallDialog::GemUninstallDialog(const QString& gemName, QWidget* parent)
+ : QDialog(parent)
+ {
+ setWindowTitle(tr("Uninstall Remote Gem"));
+ setObjectName("GemUninstallDialog");
+ setAttribute(Qt::WA_DeleteOnClose);
+ setModal(true);
+
+ QVBoxLayout* layout = new QVBoxLayout();
+ layout->setMargin(30);
+ layout->setAlignment(Qt::AlignTop);
+ setLayout(layout);
+
+ // Body
+ QLabel* subTitleLabel = new QLabel(tr("Are you sure you want to uninstall %1?").arg(gemName));
+ subTitleLabel->setObjectName("gemCatalogDialogSubTitle");
+ layout->addWidget(subTitleLabel);
+
+ layout->addSpacing(10);
+
+ QLabel* bodyLabel = new QLabel(tr("The Gem and its related files will be uninstalled. This does not affect the Gem's repository. "
+ "You can reinstall this Gem from the Catalog, but its contents may be subject to change."));
+ bodyLabel->setWordWrap(true);
+ bodyLabel->setFixedSize(QSize(440, 80));
+ layout->addWidget(bodyLabel);
+
+ layout->addSpacing(40);
+
+ // Buttons
+ QDialogButtonBox* dialogButtons = new QDialogButtonBox();
+ dialogButtons->setObjectName("footer");
+ layout->addWidget(dialogButtons);
+
+ QPushButton* cancelButton = dialogButtons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole);
+ cancelButton->setProperty("secondary", true);
+ QPushButton* uninstallButton = dialogButtons->addButton(tr("Uninstall Gem"), QDialogButtonBox::ApplyRole);
+ uninstallButton->setObjectName("gemCatalogUninstallGemButton");
+
+ connect(cancelButton, &QPushButton::clicked, this, &QDialog::reject);
+ connect(uninstallButton, &QPushButton::clicked, this, &QDialog::accept);
+ }
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemUninstallDialog.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemUninstallDialog.h
new file mode 100644
index 0000000000..9e3f4c3f3b
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemUninstallDialog.h
@@ -0,0 +1,25 @@
+/*
+ * 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
+
+#if !defined(Q_MOC_RUN)
+#include
+#endif
+
+namespace O3DE::ProjectManager
+{
+ class GemUninstallDialog
+ : public QDialog
+ {
+ Q_OBJECT // AUTOMOC
+ public:
+ explicit GemUninstallDialog(const QString& gemName, QWidget *parent = nullptr);
+ ~GemUninstallDialog() = default;
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemUpdateDialog.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemUpdateDialog.cpp
new file mode 100644
index 0000000000..82d205aab5
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemUpdateDialog.cpp
@@ -0,0 +1,64 @@
+/*
+ * 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
+#include
+
+namespace O3DE::ProjectManager
+{
+ GemUpdateDialog::GemUpdateDialog(const QString& gemName, bool updateAvaliable, QWidget* parent)
+ : QDialog(parent)
+ {
+ setWindowTitle(tr("Update Remote Gem"));
+ setObjectName("GemUpdateDialog");
+ setAttribute(Qt::WA_DeleteOnClose);
+ setModal(true);
+
+ QVBoxLayout* layout = new QVBoxLayout();
+ layout->setMargin(30);
+ layout->setAlignment(Qt::AlignTop);
+ setLayout(layout);
+
+ // Body
+ QLabel* subTitleLabel = new QLabel(tr("%1 to the latest version of %2?").arg(
+ updateAvaliable ? tr("Update") : tr("Force update"), gemName));
+ subTitleLabel->setObjectName("gemCatalogDialogSubTitle");
+ layout->addWidget(subTitleLabel);
+
+ layout->addSpacing(10);
+
+ QLabel* bodyLabel = new QLabel(tr("%1The latest version of this Gem may not be compatible with your engine. "
+ "Updating this Gem will remove any local changes made to this Gem, "
+ "and may remove old features that are in use.").arg(
+ updateAvaliable ? "" : tr("No update detected for Gem. "
+ "This will force a re-download of the gem. ")));
+ bodyLabel->setWordWrap(true);
+ bodyLabel->setFixedSize(QSize(440, 80));
+ layout->addWidget(bodyLabel);
+
+ layout->addSpacing(40);
+
+ // Buttons
+ QDialogButtonBox* dialogButtons = new QDialogButtonBox();
+ dialogButtons->setObjectName("footer");
+ layout->addWidget(dialogButtons);
+
+ QPushButton* cancelButton = dialogButtons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole);
+ cancelButton->setProperty("secondary", true);
+ QPushButton* updateButton =
+ dialogButtons->addButton(tr("%1Update Gem").arg(updateAvaliable ? "" : tr("Force ")), QDialogButtonBox::ApplyRole);
+
+ connect(cancelButton, &QPushButton::clicked, this, &QDialog::reject);
+ connect(updateButton, &QPushButton::clicked, this, &QDialog::accept);
+ }
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemUpdateDialog.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemUpdateDialog.h
new file mode 100644
index 0000000000..cf34abfb3d
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemUpdateDialog.h
@@ -0,0 +1,25 @@
+/*
+ * 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
+
+#if !defined(Q_MOC_RUN)
+#include
+#endif
+
+namespace O3DE::ProjectManager
+{
+ class GemUpdateDialog
+ : public QDialog
+ {
+ Q_OBJECT // AUTOMOC
+ public :
+ explicit GemUpdateDialog(const QString& gemName, bool updateAvaliable = true, QWidget* parent = nullptr);
+ ~GemUpdateDialog() = default;
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp
index 794635a3e3..91432c2346 100644
--- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp
@@ -75,7 +75,7 @@ namespace O3DE::ProjectManager
// Select the first entry after everything got correctly sized
QTimer::singleShot(200, [=]{
QModelIndex firstModelIndex = m_gemRepoListView->model()->index(0,0);
- m_gemRepoListView->selectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect);
+ m_gemRepoListView->selectionModel()->setCurrentIndex(firstModelIndex, QItemSelectionModel::ClearAndSelect);
});
}
diff --git a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp
index c425c344e1..98916cccf6 100644
--- a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp
+++ b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp
@@ -8,7 +8,11 @@
#include
#include
+#include
+#include
#include
+#include
+#include
#include
#include
@@ -23,6 +27,7 @@
#include
#include
#include
+#include
namespace O3DE::ProjectManager
{
@@ -205,6 +210,29 @@ namespace O3DE::ProjectManager
{
AzQtComponents::ShowFileOnDesktop(m_projectInfo.m_path);
});
+
+#if AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT
+ menu->addAction(tr("Create Editor desktop shortcut..."), this, [this]()
+ {
+ AZ::IO::FixedMaxPath executableDirectory = ProjectUtils::GetEditorDirectory();
+ AZStd::string executableFilename = "Editor";
+ AZ::IO::FixedMaxPath editorExecutablePath = executableDirectory / (executableFilename + AZ_TRAIT_OS_EXECUTABLE_EXTENSION);
+
+ const QString shortcutName = QString("%1 Editor").arg(m_projectInfo.m_displayName);
+ const QString arg = QString("--regset=\"/Amazon/AzCore/Bootstrap/project_path=%1\"").arg(m_projectInfo.m_path);
+
+ auto result = ProjectUtils::CreateDesktopShortcut(shortcutName, editorExecutablePath.c_str(), { arg });
+ if(result.IsSuccess())
+ {
+ QMessageBox::information(this, tr("Desktop Shortcut Created"), result.GetValue());
+ }
+ else
+ {
+ QMessageBox::critical(this, tr("Failed to create shortcut"), result.GetError());
+ }
+ });
+#endif // AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT
+
menu->addSeparator();
menu->addAction(tr("Duplicate"), this, [this]() { emit CopyProject(m_projectInfo); });
menu->addSeparator();
diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp
index bb2bcd070e..4a0e1c153c 100644
--- a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp
+++ b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp
@@ -628,11 +628,11 @@ namespace O3DE::ProjectManager
return AZ::Failure(QObject::tr("Process for command '%1' timed out at %2 seconds").arg(cmd).arg(commandTimeoutSeconds));
}
int resultCode = execProcess.exitCode();
+ QString resultOutput = execProcess.readAllStandardOutput();
if (resultCode != 0)
{
- return AZ::Failure(QObject::tr("Process for command '%1' failed (result code %2").arg(cmd).arg(resultCode));
+ return AZ::Failure(QObject::tr("Process for command '%1' failed (result code %2) %3").arg(cmd).arg(resultCode).arg(resultOutput));
}
- QString resultOutput = execProcess.readAllStandardOutput();
return AZ::Success(resultOutput);
}
diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.h b/Code/Tools/ProjectManager/Source/ProjectUtils.h
index 890d50d2de..ee605b5117 100644
--- a/Code/Tools/ProjectManager/Source/ProjectUtils.h
+++ b/Code/Tools/ProjectManager/Source/ProjectUtils.h
@@ -68,6 +68,15 @@ namespace O3DE::ProjectManager
AZ::Outcome GetProjectBuildPath(const QString& projectPath);
AZ::Outcome OpenCMakeGUI(const QString& projectPath);
AZ::Outcome RunGetPythonScript(const QString& enginePath);
+
+ /**
+ * Create a desktop shortcut.
+ * @param filename the name of the desktop shorcut file
+ * @param target the path to the target to run
+ * @param arguments the argument list to provide to the target
+ * @return AZ::Outcome with the command result on success
+ */
+ AZ::Outcome CreateDesktopShortcut(const QString& filename, const QString& targetPath, const QStringList& arguments);
AZ::IO::FixedMaxPath GetEditorDirectory();
diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp
index 021066e1c7..d1dedaaec4 100644
--- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp
+++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp
@@ -515,7 +515,11 @@ namespace O3DE::ProjectManager
auto pyProjectPath = QString_To_Py_Path(projectPath);
for (auto path : m_manifest.attr("get_all_gems")(pyProjectPath))
{
- gems.push_back(GemInfoFromPath(path, pyProjectPath));
+ GemInfo gemInfo = GemInfoFromPath(path, pyProjectPath);
+ // Mark as downloaded because this gem was registered with an existing directory
+ gemInfo.m_downloadStatus = GemInfo::DownloadStatus::Downloaded;
+
+ gems.push_back(AZStd::move(gemInfo));
}
});
if (!result.IsSuccess())
@@ -560,7 +564,7 @@ namespace O3DE::ProjectManager
return AZ::Success(AZStd::move(gemNames));
}
- AZ::Outcome PythonBindings::RegisterGem(const QString& gemPath, const QString& projectPath)
+ AZ::Outcome PythonBindings::GemRegistration(const QString& gemPath, const QString& projectPath, bool remove)
{
bool registrationResult = false;
auto result = ExecuteWithLockErrorHandling(
@@ -582,7 +586,8 @@ namespace O3DE::ProjectManager
pybind11::none(), // default_restricted_folder
pybind11::none(), // default_third_party_folder
pybind11::none(), // external_subdir_engine_path
- externalProjectPath // external_subdir_project_path
+ externalProjectPath, // external_subdir_project_path
+ remove // remove
);
// Returns an exit code so boolify it then invert result
@@ -595,12 +600,23 @@ namespace O3DE::ProjectManager
}
else if (!registrationResult)
{
- return AZ::Failure(AZStd::string::format("Failed to register gem path %s", gemPath.toUtf8().constData()));
+ return AZ::Failure(AZStd::string::format(
+ "Failed to %s gem path %s", remove ? "unregister" : "register", gemPath.toUtf8().constData()));
}
return AZ::Success();
}
+ AZ::Outcome PythonBindings::RegisterGem(const QString& gemPath, const QString& projectPath)
+ {
+ return GemRegistration(gemPath, projectPath);
+ }
+
+ AZ::Outcome PythonBindings::UnregisterGem(const QString& gemPath, const QString& projectPath)
+ {
+ return GemRegistration(gemPath, projectPath, /*remove*/true);
+ }
+
bool PythonBindings::AddProject(const QString& path)
{
bool registrationResult = false;
@@ -715,6 +731,7 @@ namespace O3DE::ProjectManager
gemInfo.m_documentationLink = Py_To_String_Optional(data, "documentation_url", "");
gemInfo.m_licenseText = Py_To_String_Optional(data, "license", "Unspecified License");
gemInfo.m_licenseLink = Py_To_String_Optional(data, "license_url", "");
+ gemInfo.m_repoUri = Py_To_String_Optional(data, "repo_uri", "");
if (gemInfo.m_creator.contains("Open 3D Engine"))
{
@@ -728,6 +745,11 @@ namespace O3DE::ProjectManager
{
gemInfo.m_gemOrigin = GemInfo::GemOrigin::Remote;
}
+ // If no origin was provided this cannot be remote and would be specified if O3DE so it should be local
+ else
+ {
+ gemInfo.m_gemOrigin = GemInfo::GemOrigin::Local;
+ }
// As long Base Open3DEngine gems are installed before first startup non-remote gems will be downloaded
if (gemInfo.m_gemOrigin != GemInfo::GemOrigin::Remote)
@@ -1166,49 +1188,6 @@ namespace O3DE::ProjectManager
return AZ::Success(AZStd::move(gemRepos));
}
- AZ::Outcome PythonBindings::DownloadGem(const QString& gemName, std::function gemProgressCallback)
- {
- // This process is currently limited to download a single gem at a time.
- bool downloadSucceeded = false;
-
- m_requestCancelDownload = false;
- auto result = ExecuteWithLockErrorHandling(
- [&]
- {
- auto downloadResult = m_download.attr("download_gem")(
- QString_To_Py_String(gemName), // gem name
- pybind11::none(), // destination path
- false, // skip auto register
- false, // force
- pybind11::cpp_function(
- [this, gemProgressCallback](int progress)
- {
- gemProgressCallback(progress);
-
- return m_requestCancelDownload;
- }) // Callback for download progress and cancelling
- );
- downloadSucceeded = (downloadResult.cast() == 0);
- });
-
-
- if (!result.IsSuccess())
- {
- return result;
- }
- else if (!downloadSucceeded)
- {
- return AZ::Failure("Failed to download gem.");
- }
-
- return AZ::Success();
- }
-
- void PythonBindings::CancelDownload()
- {
- m_requestCancelDownload = true;
- }
-
AZ::Outcome, AZStd::string> PythonBindings::GetAllGemRepoGemsInfos()
{
QVector gemInfos;
@@ -1235,4 +1214,64 @@ namespace O3DE::ProjectManager
return AZ::Success(AZStd::move(gemInfos));
}
+
+ AZ::Outcome PythonBindings::DownloadGem(
+ const QString& gemName, std::function gemProgressCallback, bool force)
+ {
+ // This process is currently limited to download a single gem at a time.
+ bool downloadSucceeded = false;
+
+ m_requestCancelDownload = false;
+ auto result = ExecuteWithLockErrorHandling(
+ [&]
+ {
+ auto downloadResult = m_download.attr("download_gem")(
+ QString_To_Py_String(gemName), // gem name
+ pybind11::none(), // destination path
+ false, // skip auto register
+ force, // force overwrite
+ pybind11::cpp_function(
+ [this, gemProgressCallback](int bytesDownloaded, int totalBytes)
+ {
+ gemProgressCallback(bytesDownloaded, totalBytes);
+
+ return m_requestCancelDownload;
+ }) // Callback for download progress and cancelling
+ );
+ downloadSucceeded = (downloadResult.cast() == 0);
+ });
+
+
+ if (!result.IsSuccess())
+ {
+ return result;
+ }
+ else if (!downloadSucceeded)
+ {
+ return AZ::Failure("Failed to download gem.");
+ }
+
+ return AZ::Success();
+ }
+
+ void PythonBindings::CancelDownload()
+ {
+ m_requestCancelDownload = true;
+ }
+
+ bool PythonBindings::IsGemUpdateAvaliable(const QString& gemName, const QString& lastUpdated)
+ {
+ bool updateAvaliableResult = false;
+ bool result = ExecuteWithLock(
+ [&]
+ {
+ auto pyGemName = QString_To_Py_String(gemName);
+ auto pyLastUpdated = QString_To_Py_String(lastUpdated);
+ auto pythonUpdateAvaliableResult = m_download.attr("is_o3de_gem_update_available")(pyGemName, pyLastUpdated);
+
+ updateAvaliableResult = pythonUpdateAvaliableResult.cast();
+ });
+
+ return result && updateAvaliableResult;
+ }
}
diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h
index 4375d56d02..ecc6f65dc3 100644
--- a/Code/Tools/ProjectManager/Source/PythonBindings.h
+++ b/Code/Tools/ProjectManager/Source/PythonBindings.h
@@ -43,6 +43,7 @@ namespace O3DE::ProjectManager
AZ::Outcome, AZStd::string> GetAllGemInfos(const QString& projectPath) override;
AZ::Outcome, AZStd::string> GetEnabledGemNames(const QString& projectPath) override;
AZ::Outcome RegisterGem(const QString& gemPath, const QString& projectPath = {}) override;
+ AZ::Outcome UnregisterGem(const QString& gemPath, const QString& projectPath = {}) override;
// Project
AZ::Outcome CreateProject(const QString& projectTemplatePath, const ProjectInfo& projectInfo) override;
@@ -64,9 +65,10 @@ namespace O3DE::ProjectManager
bool AddGemRepo(const QString& repoUri) override;
bool RemoveGemRepo(const QString& repoUri) override;
AZ::Outcome, AZStd::string> GetAllGemRepoInfos() override;
- AZ::Outcome DownloadGem(const QString& gemName, std::function gemProgressCallback) override;
- void CancelDownload() override;
AZ::Outcome, AZStd::string> GetAllGemRepoGemsInfos() override;
+ AZ::Outcome DownloadGem(const QString& gemName, std::function gemProgressCallback, bool force = false) override;
+ void CancelDownload() override;
+ bool IsGemUpdateAvaliable(const QString& gemName, const QString& lastUpdated) override;
private:
AZ_DISABLE_COPY_MOVE(PythonBindings);
@@ -77,6 +79,7 @@ namespace O3DE::ProjectManager
GemRepoInfo GetGemRepoInfo(pybind11::handle repoUri);
ProjectInfo ProjectInfoFromPath(pybind11::handle path);
ProjectTemplateInfo ProjectTemplateInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath);
+ AZ::Outcome GemRegistration(const QString& gemPath, const QString& projectPath, bool remove = false);
bool RegisterThisEngine();
bool StopPython();
diff --git a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h
index 1134804f1f..65337869fd 100644
--- a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h
+++ b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h
@@ -94,11 +94,19 @@ namespace O3DE::ProjectManager
/**
* Registers the gem to the specified project, or to the o3de_manifest.json if no project path is given
* @param gemPath the path to the gem
- * @param projectPath the path to the project. If empty, will register the external path in o3de_manifest.json
+ * @param projectPath the path to the project. If empty, will register the external path in o3de_manifest.json
* @return An outcome with the success flag as well as an error message in case of a failure.
*/
virtual AZ::Outcome RegisterGem(const QString& gemPath, const QString& projectPath = {}) = 0;
+ /**
+ * Unregisters the gem from the specified project, or from the o3de_manifest.json if no project path is given
+ * @param gemPath the path to the gem
+ * @param projectPath the path to the project. If empty, will unregister the external path in o3de_manifest.json
+ * @return An outcome with the success flag as well as an error message in case of a failure.
+ */
+ virtual AZ::Outcome UnregisterGem(const QString& gemPath, const QString& projectPath = {}) = 0;
+
// Projects
@@ -209,24 +217,34 @@ namespace O3DE::ProjectManager
*/
virtual AZ::Outcome, AZStd::string> GetAllGemRepoInfos() = 0;
- /**
- * Downloads and registers a Gem.
- * @param gemName the name of the Gem to download
- * @param gemProgressCallback a callback function that is called with an int percentage download value
- * @return an outcome with a string error message on failure.
- */
- virtual AZ::Outcome DownloadGem(const QString& gemName, std::function gemProgressCallback) = 0;
-
- /**
- * Cancels the current download.
- */
- virtual void CancelDownload() = 0;
-
/**
* Gathers all gem infos for all gems registered from repos.
* @return A list of gem infos.
*/
virtual AZ::Outcome, AZStd::string> GetAllGemRepoGemsInfos() = 0;
+
+ /**
+ * Downloads and registers a Gem.
+ * @param gemName the name of the Gem to download.
+ * @param gemProgressCallback a callback function that is called with an int percentage download value.
+ * @param force should we forcibly overwrite the old version of the gem.
+ * @return an outcome with a string error message on failure.
+ */
+ virtual AZ::Outcome DownloadGem(
+ const QString& gemName, std::function gemProgressCallback, bool force = false) = 0;
+
+ /**
+ * Cancels the current download.
+ */
+ virtual void CancelDownload() = 0;
+
+ /**
+ * Checks if there is an update avaliable for a gem on a repo.
+ * @param gemName the name of the gem to check.
+ * @param lastUpdated last time the gem was update.
+ * @return true if update is avaliable, false if not.
+ */
+ virtual bool IsGemUpdateAvaliable(const QString& gemName, const QString& lastUpdated) = 0;
};
using PythonBindingsInterface = AZ::Interface;
diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake
index e2e35717f6..fcfae2f336 100644
--- a/Code/Tools/ProjectManager/project_manager_files.cmake
+++ b/Code/Tools/ProjectManager/project_manager_files.cmake
@@ -96,6 +96,10 @@ set(FILES
Source/GemCatalog/GemListHeaderWidget.cpp
Source/GemCatalog/GemModel.h
Source/GemCatalog/GemModel.cpp
+ Source/GemCatalog/GemUninstallDialog.h
+ Source/GemCatalog/GemUninstallDialog.cpp
+ Source/GemCatalog/GemUpdateDialog.h
+ Source/GemCatalog/GemUpdateDialog.cpp
Source/GemCatalog/GemDependenciesDialog.h
Source/GemCatalog/GemDependenciesDialog.cpp
Source/GemCatalog/GemRequirementDialog.h
diff --git a/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingConstants.h b/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingConstants.h
index 97eb5b6492..a3d18c1ea1 100644
--- a/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingConstants.h
+++ b/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingConstants.h
@@ -68,7 +68,7 @@ namespace AWSCore
},
"AccountIdString": {
"type": "string",
- "pattern": "^[0-9]{12}$|EMPTY"
+ "pattern": "^[0-9]{12}$|EMPTY|^$"
},
"NonEmptyString": {
"type": "string",
diff --git a/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingManagerTest.cpp b/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingManagerTest.cpp
index fb03dea4c0..a90518006f 100644
--- a/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingManagerTest.cpp
+++ b/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingManagerTest.cpp
@@ -59,6 +59,34 @@ R"({
"Version": "1.0.0"
})";
+static constexpr const char TEST_VALID_EMPTY_ACCOUNTID_RESOURCE_MAPPING_CONFIG_FILE[] =
+ R"({
+ "AWSResourceMappings": {
+ "TestLambda": {
+ "Type": "AWS::Lambda::Function",
+ "Name/ID": "MyTestLambda",
+ "Region": "us-east-1",
+ "AccountId": "012345678912"
+ },
+ "TestS3Bucket": {
+ "Type": "AWS::S3::Bucket",
+ "Name/ID": "MyTestS3Bucket"
+ },
+ "TestService.RESTApiId": {
+ "Type": "AWS::ApiGateway::RestApi",
+ "Name/ID": "1234567890"
+ },
+ "TestService.RESTApiStage": {
+ "Type": "AWS::ApiGateway::Stage",
+ "Name/ID": "prod",
+ "Region": "us-east-1"
+ }
+ },
+ "AccountId": "",
+ "Region": "us-west-2",
+ "Version": "1.0.0"
+})";
+
static constexpr const char TEST_INVALID_RESOURCE_MAPPING_CONFIG_FILE[] =
R"({
"AWSResourceMappings": {},
@@ -237,6 +265,21 @@ TEST_F(AWSResourceMappingManagerTest, ActivateManager_ParseValidConfigFile_Confi
EXPECT_TRUE(actualEbusCalls == testThreadNumber);
}
+TEST_F(AWSResourceMappingManagerTest, ActivateManager_ParseValidConfigFile_GlobalAccountIdEmpty)
+{
+ CreateTestConfigFile(TEST_VALID_EMPTY_ACCOUNTID_RESOURCE_MAPPING_CONFIG_FILE);
+ m_resourceMappingManager->ActivateManager();
+
+ AZStd::string actualAccountId;
+ AZStd::string actualRegion;
+ AWSResourceMappingRequestBus::BroadcastResult(actualAccountId, &AWSResourceMappingRequests::GetDefaultAccountId);
+ AWSResourceMappingRequestBus::BroadcastResult(actualRegion, &AWSResourceMappingRequests::GetDefaultRegion);
+ EXPECT_EQ(m_reloadConfigurationCounter, 0);
+ EXPECT_TRUE(actualAccountId.empty());
+ EXPECT_FALSE(actualRegion.empty());
+ EXPECT_TRUE(m_resourceMappingManager->GetStatus() == AWSResourceMappingManager::Status::Ready);
+}
+
TEST_F(AWSResourceMappingManagerTest, DeactivateManager_AfterActivatingWithValidConfigFile_ConfigDataGetCleanedUp)
{
CreateTestConfigFile(TEST_VALID_RESOURCE_MAPPING_CONFIG_FILE);
diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/controller/view_edit_controller.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/controller/view_edit_controller.py
index bdfe7fa11e..39f7b5ccf1 100755
--- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/controller/view_edit_controller.py
+++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/controller/view_edit_controller.py
@@ -69,17 +69,13 @@ class ViewEditController(QObject):
json_dict: Dict[str, any] = \
json_utils.convert_resources_to_json_dict(self._proxy_model.get_resources(), self._config_file_json_source)
- configuration: Configuration = self._configuration_manager.configuration
- if json_dict.get(json_utils.RESOURCE_MAPPING_ACCOUNTID_JSON_KEY_NAME) == \
- json_utils.RESOURCE_MAPPING_ACCOUNTID_TEMPLATE_VALUE:
- json_dict[json_utils.RESOURCE_MAPPING_ACCOUNTID_JSON_KEY_NAME] = configuration.account_id
-
if json_dict == self._config_file_json_source:
# skip because no difference found against existing json file
return True
# try to write in memory json content into json file
try:
+ configuration: Configuration = self._configuration_manager.configuration
config_file_full_path: str = file_utils.join_path(configuration.config_directory, config_file_name)
json_utils.write_into_json_file(config_file_full_path, json_dict)
self._config_file_json_source = json_dict
diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/controller/test_view_edit_controller.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/controller/test_view_edit_controller.py
index c73bddcd9c..41d4490c44 100755
--- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/controller/test_view_edit_controller.py
+++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/controller/test_view_edit_controller.py
@@ -420,8 +420,30 @@ class TestViewEditController(TestCase):
self._mocked_view_edit_page.config_file_combobox.currentText.return_value = \
TestViewEditController._expected_config_file_name
expected_json_dict: Dict[str, any] = {
- "dummyKey": "dummyValue",
- self._expected_account_id_attribute_name: self._expected_account_id_template_vale}
+ "dummyKey": "dummyValue"
+ }
+ mock_json_utils.validate_resources_according_to_json_schema.return_value = []
+ mock_json_utils.convert_resources_to_json_dict.return_value = expected_json_dict
+ mock_file_utils.join_path.return_value = TestViewEditController._expected_config_file_full_path
+ mocked_call_args: call = self._mocked_view_edit_page.save_changes_button.clicked.connect.call_args[0]
+
+ mocked_call_args[0]() # triggering save_changes_button connected function
+ mock_json_utils.convert_resources_to_json_dict.assert_called_once()
+ mock_json_utils.write_into_json_file.assert_called_once_with(
+ TestViewEditController._expected_config_file_full_path, expected_json_dict)
+ self._mocked_proxy_model.override_all_resources_status.assert_called_once_with(
+ ResourceMappingAttributesStatus(ResourceMappingAttributesStatus.SUCCESS_STATUS_VALUE,
+ [ResourceMappingAttributesStatus.SUCCESS_STATUS_VALUE]))
+
+ @patch("controller.view_edit_controller.file_utils")
+ @patch("controller.view_edit_controller.json_utils")
+ def test_page_save_changes_button_json_file_saved_and_template_account_id_unchanged(
+ self, mock_json_utils: MagicMock, mock_file_utils: MagicMock) -> None:
+ self._mocked_view_edit_page.config_file_combobox.currentText.return_value = \
+ TestViewEditController._expected_config_file_name
+ expected_json_dict: Dict[str, any] = {
+ self._expected_account_id_attribute_name: self._expected_account_id_template_vale
+ }
mock_json_utils.RESOURCE_MAPPING_ACCOUNTID_JSON_KEY_NAME = self._expected_account_id_attribute_name
mock_json_utils.RESOURCE_MAPPING_ACCOUNTID_TEMPLATE_VALUE = self._expected_account_id_template_vale
mock_json_utils.validate_resources_according_to_json_schema.return_value = []
@@ -430,7 +452,31 @@ class TestViewEditController(TestCase):
mocked_call_args: call = self._mocked_view_edit_page.save_changes_button.clicked.connect.call_args[0]
mocked_call_args[0]() # triggering save_changes_button connected function
- assert expected_json_dict["AccountId"] == self._mocked_configuration_manager.configuration.account_id
+ assert expected_json_dict[mock_json_utils.RESOURCE_MAPPING_ACCOUNTID_JSON_KEY_NAME] == self._expected_account_id_template_vale
+ mock_json_utils.convert_resources_to_json_dict.assert_called_once()
+ mock_json_utils.write_into_json_file.assert_called_once_with(
+ TestViewEditController._expected_config_file_full_path, expected_json_dict)
+ self._mocked_proxy_model.override_all_resources_status.assert_called_once_with(
+ ResourceMappingAttributesStatus(ResourceMappingAttributesStatus.SUCCESS_STATUS_VALUE,
+ [ResourceMappingAttributesStatus.SUCCESS_STATUS_VALUE]))
+
+ @patch("controller.view_edit_controller.file_utils")
+ @patch("controller.view_edit_controller.json_utils")
+ def test_page_save_changes_button_json_file_saved_and_empty_account_id_unchanged(
+ self, mock_json_utils: MagicMock, mock_file_utils: MagicMock) -> None:
+ self._mocked_view_edit_page.config_file_combobox.currentText.return_value = \
+ TestViewEditController._expected_config_file_name
+ expected_json_dict: Dict[str, any] = {
+ self._expected_account_id_attribute_name: ''
+ }
+ mock_json_utils.RESOURCE_MAPPING_ACCOUNTID_JSON_KEY_NAME = self._expected_account_id_attribute_name
+ mock_json_utils.validate_resources_according_to_json_schema.return_value = []
+ mock_json_utils.convert_resources_to_json_dict.return_value = expected_json_dict
+ mock_file_utils.join_path.return_value = TestViewEditController._expected_config_file_full_path
+ mocked_call_args: call = self._mocked_view_edit_page.save_changes_button.clicked.connect.call_args[0]
+
+ mocked_call_args[0]() # triggering save_changes_button connected function
+ assert expected_json_dict[mock_json_utils.RESOURCE_MAPPING_ACCOUNTID_JSON_KEY_NAME] == ''
mock_json_utils.convert_resources_to_json_dict.assert_called_once()
mock_json_utils.write_into_json_file.assert_called_once_with(
TestViewEditController._expected_config_file_full_path, expected_json_dict)
diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/utils/test_json_utils.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/utils/test_json_utils.py
index 7eb92ff222..9fe99461ba 100755
--- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/utils/test_json_utils.py
+++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/tests/unit/utils/test_json_utils.py
@@ -103,6 +103,11 @@ class TestJsonUtils(TestCase):
invalid_json_dict.pop(json_utils.RESOURCE_MAPPING_ACCOUNTID_JSON_KEY_NAME)
self.assertRaises(KeyError, json_utils.validate_json_dict_according_to_json_schema, invalid_json_dict)
+ def test_validate_json_dict_according_to_json_schema_raise_error_when_json_dict_has_empty_accountid(self) -> None:
+ valid_json_dict: Dict[str, any] = copy.deepcopy(TestJsonUtils._expected_json_dict)
+ valid_json_dict[json_utils.RESOURCE_MAPPING_ACCOUNTID_JSON_KEY_NAME] = ''
+ json_utils.validate_json_dict_according_to_json_schema(valid_json_dict)
+
def test_validate_json_dict_according_to_json_schema_pass_when_json_dict_has_template_accountid(self) -> None:
valid_json_dict: Dict[str, any] = copy.deepcopy(TestJsonUtils._expected_json_dict)
valid_json_dict[json_utils.RESOURCE_MAPPING_ACCOUNTID_JSON_KEY_NAME] = \
diff --git a/Gems/AWSCore/Code/Tools/ResourceMappingTool/utils/json_utils.py b/Gems/AWSCore/Code/Tools/ResourceMappingTool/utils/json_utils.py
index 5b9377ada3..7926cca970 100755
--- a/Gems/AWSCore/Code/Tools/ResourceMappingTool/utils/json_utils.py
+++ b/Gems/AWSCore/Code/Tools/ResourceMappingTool/utils/json_utils.py
@@ -28,7 +28,7 @@ _RESOURCE_MAPPING_JSON_FORMAT_VERSION: str = "1.0.0"
RESOURCE_MAPPING_ACCOUNTID_JSON_KEY_NAME: str = "AccountId"
RESOURCE_MAPPING_ACCOUNTID_TEMPLATE_VALUE: str = "EMPTY"
-_RESOURCE_MAPPING_ACCOUNTID_PATTERN: str = f"^[0-9]{{12}}|{RESOURCE_MAPPING_ACCOUNTID_TEMPLATE_VALUE}$"
+_RESOURCE_MAPPING_ACCOUNTID_PATTERN: str = f"^[0-9]{{12}}$|{RESOURCE_MAPPING_ACCOUNTID_TEMPLATE_VALUE}|^$"
_RESOURCE_MAPPING_REGION_PATTERN: str = "^[a-z]{2}-[a-z]{4,9}-[0-9]{1}$"
_RESOURCE_MAPPING_VERSION_PATTERN: str = "^[0-9]{1}.[0-9]{1}.[0-9]{1}$"
diff --git a/Gems/AWSMetrics/Code/Include/Private/MetricsAttribute.h b/Gems/AWSMetrics/Code/Include/Public/MetricsAttribute.h
similarity index 100%
rename from Gems/AWSMetrics/Code/Include/Private/MetricsAttribute.h
rename to Gems/AWSMetrics/Code/Include/Public/MetricsAttribute.h
diff --git a/Gems/AWSMetrics/Code/awsmetrics_files.cmake b/Gems/AWSMetrics/Code/awsmetrics_files.cmake
index b51235c957..b1a3a647df 100644
--- a/Gems/AWSMetrics/Code/awsmetrics_files.cmake
+++ b/Gems/AWSMetrics/Code/awsmetrics_files.cmake
@@ -8,6 +8,7 @@
set(FILES
Include/Public/AWSMetricsBus.h
+ Include/Public/MetricsAttribute.h
Include/Private/AWSMetricsConstant.h
Include/Private/AWSMetricsServiceApi.h
Include/Private/AWSMetricsSystemComponent.h
@@ -15,7 +16,6 @@ set(FILES
Include/Private/DefaultClientIdProvider.h
Include/Private/GlobalStatistics.h
Include/Private/IdentityProvider.h
- Include/Private/MetricsAttribute.h
Include/Private/MetricsEvent.h
Include/Private/MetricsEventBuilder.h
Include/Private/MetricsManager.h
diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp
index e41c04a0be..99b7c814d1 100644
--- a/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp
+++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp
@@ -82,7 +82,7 @@ namespace AZ
// Register Shader Asset Builder
AssetBuilderSDK::AssetBuilderDesc shaderAssetBuilderDescriptor;
shaderAssetBuilderDescriptor.m_name = "Shader Asset Builder";
- shaderAssetBuilderDescriptor.m_version = 107; // Required .azsl extension in .shader file references
+ shaderAssetBuilderDescriptor.m_version = 108; // The Build Time Stamp of ShaderAsset And ShaderVariantAsset Should Be Based On GetTimeUTCMilliSecond()
// .shader file changes trigger rebuilds
shaderAssetBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern( AZStd::string::format("*.%s", RPI::ShaderSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard));
shaderAssetBuilderDescriptor.m_busId = azrtti_typeid();
@@ -108,7 +108,7 @@ namespace AZ
shaderVariantAssetBuilderDescriptor.m_name = "Shader Variant Asset Builder";
// Both "Shader Variant Asset Builder" and "Shader Asset Builder" produce ShaderVariantAsset products. If you update
// ShaderVariantAsset you will need to update BOTH version numbers, not just "Shader Variant Asset Builder".
- shaderVariantAssetBuilderDescriptor.m_version = 26; // [AZSL] Changing inlineConstant to rootConstant keyword work.
+ shaderVariantAssetBuilderDescriptor.m_version = 27; // The Build Time Stamp of ShaderAsset And ShaderVariantAsset Should Be Based On GetTimeUTCMilliSecond().
shaderVariantAssetBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern(AZStd::string::format("*.%s", RPI::ShaderVariantListSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard));
shaderVariantAssetBuilderDescriptor.m_busId = azrtti_typeid();
shaderVariantAssetBuilderDescriptor.m_createJobFunction = AZStd::bind(&ShaderVariantAssetBuilder::CreateJobs, &m_shaderVariantAssetBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp
index 89e202a4bc..e431b74282 100644
--- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp
+++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp
@@ -162,7 +162,7 @@ namespace AZ
// has the same value, because later the ShaderVariantTreeAsset job will fetch this value from the local ShaderAsset
// which could cross platforms (i.e. building an android ShaderVariantTreeAsset on PC would fetch the tiemstamp from
// the PC's ShaderAsset).
- AZStd::sys_time_t shaderAssetBuildTimestamp = AZStd::GetTimeNowMicroSecond();
+ AZ::u64 shaderAssetBuildTimestamp = AZStd::GetTimeUTCMilliSecond();
// Need to get the name of the azsl file from the .shader source asset, to be able to declare a dependency to SRG Layout Job.
// and the macro options to preprocess.
@@ -229,8 +229,8 @@ namespace AZ
} // for all request.m_enabledPlatforms
AZ_TracePrintf(
- ShaderAssetBuilderName, "CreateJobs for %s took %llu microseconds", shaderAssetSourceFileFullPath.c_str(),
- AZStd::GetTimeNowMicroSecond() - shaderAssetBuildTimestamp);
+ ShaderAssetBuilderName, "CreateJobs for %s took %llu milliseconds", shaderAssetSourceFileFullPath.c_str(),
+ AZStd::GetTimeUTCMilliSecond() - shaderAssetBuildTimestamp);
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
}
@@ -355,8 +355,8 @@ namespace AZ
return;
}
- // Get the time stamp string as sys_time_t, and also convert back to string to make sure it was converted correctly.
- AZStd::sys_time_t shaderAssetBuildTimestamp = 0;
+ // Get the time stamp string as u64, and also convert back to string to make sure it was converted correctly.
+ AZ::u64 shaderAssetBuildTimestamp = 0;
auto shaderAssetBuildTimestampIterator = request.m_jobDescription.m_jobParameters.find(ShaderAssetBuildTimestampParam);
if (shaderAssetBuildTimestampIterator != request.m_jobDescription.m_jobParameters.end())
{
diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp
index bb40baca7d..5eaa0d9ddb 100644
--- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp
+++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp
@@ -765,7 +765,7 @@ namespace AZ
return;
}
- const AZStd::sys_time_t shaderVariantAssetBuildTimestamp = AZStd::GetTimeNowMicroSecond();
+ const AZ::u64 shaderVariantAssetBuildTimestamp = AZStd::GetTimeUTCMilliSecond();
auto supervariantList = ShaderBuilderUtility::GetSupervariantListFromShaderSourceData(shaderSourceDescriptor);
diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.h b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.h
index 2eaf1d9d8b..b0457656af 100644
--- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.h
+++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.h
@@ -38,7 +38,7 @@ namespace AZ
const AZStd::string& m_tempDirPath;
//! Used to synchronize versions of the ShaderAsset and ShaderVariantAsset,
//! especially during hot-reload. A (ShaderVariantAsset.timestamp) >= (ShaderAsset.timestamp).
- const AZStd::sys_time_t m_assetBuildTimestamp;
+ const AZ::u64 m_assetBuildTimestamp;
const RPI::ShaderSourceData& m_shaderSourceDataDescriptor;
const RPI::ShaderOptionGroupLayout& m_shaderOptionGroupLayout;
const MapOfStringToStageType& m_shaderEntryPoints;
diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli
index a7122aaf3a..59817af701 100644
--- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli
+++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli
@@ -166,7 +166,7 @@ float DirectionalLightShadow::GetThickness(uint lightIndex, float3 shadowCoords[
bool2 DirectionalLightShadow::IsShadowed(float3 shadowCoord, uint indexOfCascade)
{
static const float PixelMargin = 1.5; // avoiding artifact between cascade levels.
- static const float DepthMargin = 0.01; // avoiding artifact when near depth bounds.
+ static const float DepthMargin = 1e-8; // avoiding artifact when near depth bounds.
// size is the shadowap's width and height.
const uint size = ViewSrg::m_directionalLightShadows[m_lightIndex].m_shadowmapSize;
@@ -210,8 +210,8 @@ float DirectionalLightShadow::GetVisibilityFromLightNoFilter()
float DirectionalLightShadow::GetVisibilityFromLightPcf()
{
- static const float DepthMargin = 0.01; // avoiding artifact when near depth bounds.
static const float PixelMargin = 1.5; // avoiding artifact between cascade levels.
+ static const float DepthMargin = 1e-8; // avoiding artifact when near depth bounds.
const uint size = ViewSrg::m_directionalLightShadows[m_lightIndex].m_shadowmapSize;
const uint cascadeCount = ViewSrg::m_directionalLightShadows[m_lightIndex].m_cascadeCount;
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance.azshader
index 31fae5d98b..a9b5567f6b 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance.azshader and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance.azshader differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_dx12_0.azshadervariant
index 19e9fdfc8d..6d4b6d0fca 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_dx12_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_dx12_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_null_0.azshadervariant
index 43c4a615cf..5d8800a6fe 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_null_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_null_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_vulkan_0.azshadervariant
index 75f070a03e..930f7898c4 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_vulkan_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_vulkan_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance.azshader
index 0025388bc1..268020b431 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance.azshader and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance.azshader differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_dx12_0.azshadervariant
index 34a9b3659f..d95ec6c1b9 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_dx12_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_dx12_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_null_0.azshadervariant
index 4a2b0e9944..3253ddba37 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_null_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_null_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_vulkan_0.azshadervariant
index c053a7db19..c38b94c4f1 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_vulkan_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_vulkan_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn.azshader
index c507b12563..5c46d368ce 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn.azshader and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn.azshader differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_dx12_0.azshadervariant
index f60c713597..eb6938f8c9 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_dx12_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_dx12_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_null_0.azshadervariant
index 3e810bcfb5..8c83c1e3ff 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_null_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_null_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_vulkan_0.azshadervariant
index 5918f277b5..2fbb9ffffe 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_vulkan_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_vulkan_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow.azshader
index 120eb70e54..96053f4091 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow.azshader and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow.azshader differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_dx12_0.azshadervariant
index d38d779696..4bdbdddf33 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_dx12_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_dx12_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_null_0.azshadervariant
index 6d7a604701..77668a2450 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_null_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_null_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_vulkan_0.azshadervariant
index dee941cfae..fb3dd771ca 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_vulkan_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_vulkan_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification.azshader
index e2e0fa90f5..eda8d53376 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification.azshader and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification.azshader differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_dx12_0.azshadervariant
index 7a92fc2de5..2df610df77 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_dx12_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_dx12_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_null_0.azshadervariant
index 43408b26f3..f2458e692b 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_null_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_null_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_vulkan_0.azshadervariant
index 877085446d..0e08e84f74 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_vulkan_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_vulkan_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing.azshader
index 2c403c77f8..1cea4860a1 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing.azshader and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing.azshader differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_dx12_0.azshadervariant
index 4bcc47ee43..5605a47e9c 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_dx12_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_dx12_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_null_0.azshadervariant
index f173416210..15f3477cb5 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_null_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_null_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_vulkan_0.azshadervariant
index 0eb04a25b8..c2bcd4ab07 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_vulkan_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_vulkan_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit.azshader
index 2847d0035a..9958708a64 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit.azshader and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit.azshader differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_dx12_0.azshadervariant
index 93cfb47819..fbd1d90251 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_dx12_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_dx12_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_null_0.azshadervariant
index 4a16e24211..483be0eceb 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_null_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_null_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_vulkan_0.azshadervariant
index df52c9c8d2..530eef2f10 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_vulkan_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_vulkan_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss.azshader
index d95fd5b3b2..eddac4e2bd 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss.azshader and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss.azshader differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_dx12_0.azshadervariant
index c853de4d14..ad06bbd104 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_dx12_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_dx12_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_null_0.azshadervariant
index 40e18c215c..527b42569a 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_null_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_null_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_vulkan_0.azshadervariant
index 34761ccf98..426d955938 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_vulkan_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_vulkan_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation.azshader
index c19020dc84..08ed61ab03 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation.azshader and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation.azshader differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_dx12_0.azshadervariant
index a7d44b5541..d1012a896f 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_dx12_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_dx12_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_null_0.azshadervariant
index 82e0065216..cb730be1df 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_null_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_null_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_vulkan_0.azshadervariant
index 20b81aee6c..b58af4c473 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_vulkan_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_vulkan_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender.azshader
index aec2786540..56009d56ab 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender.azshader and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender.azshader differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_dx12_0.azshadervariant
index de851f187e..e9893c96da 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_dx12_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_dx12_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_null_0.azshadervariant
index 5d8207dfdb..d195b08c34 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_null_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_null_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_vulkan_0.azshadervariant
index c819e57c4c..47789d9b9b 100644
Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_vulkan_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_vulkan_0.azshadervariant differ
diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h
index 2ac184e2e0..23cd76ca20 100644
--- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h
+++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h
@@ -30,7 +30,7 @@ namespace AZ
class TransformServiceFeatureProcessor;
class RayTracingFeatureProcessor;
- class MeshDataInstance
+ class ModelDataInstance
{
friend class MeshFeatureProcessor;
friend class MeshLoader;
@@ -47,7 +47,7 @@ namespace AZ
public:
using ModelChangedEvent = MeshFeatureProcessorInterface::ModelChangedEvent;
- MeshLoader(const Data::Asset& modelAsset, MeshDataInstance* parent);
+ MeshLoader(const Data::Asset& modelAsset, ModelDataInstance* parent);
~MeshLoader();
ModelChangedEvent& GetModelChangedEvent();
@@ -68,7 +68,7 @@ namespace AZ
} };
MeshFeatureProcessorInterface::ModelChangedEvent m_modelChangedEvent;
Data::Asset m_modelAsset;
- MeshDataInstance* m_parent = nullptr;
+ ModelDataInstance* m_parent = nullptr;
};
void DeInit();
@@ -99,7 +99,8 @@ namespace AZ
//! A reference to the original model asset in case it got cloned before creating the model instance.
Data::Asset m_originalModelAsset;
- Data::Instance m_shaderResourceGroup;
+ //! List of object SRGs used by meshes in this model
+ AZStd::vector> m_objectSrgList;
AZStd::unique_ptr m_meshLoader;
RPI::Scene* m_scene = nullptr;
RHI::DrawItemSortKey m_sortKey;
@@ -152,7 +153,7 @@ namespace AZ
Data::Instance GetModel(const MeshHandle& meshHandle) const override;
Data::Asset GetModelAsset(const MeshHandle& meshHandle) const override;
- Data::Instance GetObjectSrg(const MeshHandle& meshHandle) const override;
+ const AZStd::vector>& GetObjectSrgs(const MeshHandle& meshHandle) const override;
void QueueObjectSrgForCompile(const MeshHandle& meshHandle) const override;
void SetMaterialAssignmentMap(const MeshHandle& meshHandle, const Data::Instance& material) override;
void SetMaterialAssignmentMap(const MeshHandle& meshHandle, const MaterialAssignmentMap& materials) override;
@@ -195,7 +196,7 @@ namespace AZ
void OnRenderPipelineRemoved(RPI::RenderPipeline* pipeline) override;
AZStd::concurrency_checker m_meshDataChecker;
- StableDynamicArray m_meshData;
+ StableDynamicArray m_modelData;
TransformServiceFeatureProcessor* m_transformService;
RayTracingFeatureProcessor* m_rayTracingFeatureProcessor = nullptr;
AZ::RPI::ShaderSystemInterface::GlobalShaderOptionUpdatedEvent::Handler m_handleGlobalShaderOptionUpdate;
diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h
index cffbe5c3c5..356b1936ca 100644
--- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h
+++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessorInterface.h
@@ -20,7 +20,7 @@ namespace AZ
{
namespace Render
{
- class MeshDataInstance;
+ class ModelDataInstance;
//! Settings to apply to a mesh handle when acquiring it for the first time
struct MeshHandleDescriptor
@@ -40,7 +40,7 @@ namespace AZ
public:
AZ_RTTI(AZ::Render::MeshFeatureProcessorInterface, "{975D7F0C-2E7E-4819-94D0-D3C4E2024721}", FeatureProcessor);
- using MeshHandle = StableDynamicArrayHandle;
+ using MeshHandle = StableDynamicArrayHandle;
using ModelChangedEvent = Event>;
//! Acquires a model with an optional collection of material assignments.
@@ -61,12 +61,15 @@ namespace AZ
virtual Data::Instance GetModel(const MeshHandle& meshHandle) const = 0;
//! Gets the underlying RPI::ModelAsset for a meshHandle.
virtual Data::Asset GetModelAsset(const MeshHandle& meshHandle) const = 0;
- //! Gets the ObjectSrg for a meshHandle.
- //! Updating the ObjectSrg should be followed by a call to QueueObjectSrgForCompile,
- //! instead of compiling the srg directly. This way, if the srg has already been queued for compile,
- //! it will not be queued twice in the same frame. The ObjectSrg should not be updated during
+
+ //! Gets the ObjectSrgs for a meshHandle.
+ //! Updating the ObjectSrgs should be followed by a call to QueueObjectSrgForCompile,
+ //! instead of compiling the srgs directly. This way, if the srgs have already been queued for compile,
+ //! they will not be queued twice in the same frame. The ObjectSrgs should not be updated during
//! Simulate, or it will create a race between updating the data and the call to Compile
- virtual Data::Instance GetObjectSrg(const MeshHandle& meshHandle) const = 0;
+ //! Cases where there may be multiple ObjectSrgs: if a model has multiple submeshes and those submeshes use different
+ //! materials with different object SRGs.
+ virtual const AZStd::vector>& GetObjectSrgs(const MeshHandle& meshHandle) const = 0;
//! Queues the object srg for compile.
virtual void QueueObjectSrgForCompile(const MeshHandle& meshHandle) const = 0;
//! Sets the MaterialAssignmentMap for a meshHandle, using just a single material for the DefaultMaterialAssignmentId.
diff --git a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h
index 35e399997f..2c818d3c9b 100644
--- a/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h
+++ b/Gems/Atom/Feature/Common/Code/Mocks/MockMeshFeatureProcessor.h
@@ -19,7 +19,7 @@ namespace UnitTest
MOCK_METHOD1(CloneMesh, MeshHandle(const MeshHandle&));
MOCK_CONST_METHOD1(GetModel, AZStd::intrusive_ptr(const MeshHandle&));
MOCK_CONST_METHOD1(GetModelAsset, AZ::Data::Asset(const MeshHandle&));
- MOCK_CONST_METHOD1(GetObjectSrg, AZStd::intrusive_ptr(const MeshHandle&));
+ MOCK_CONST_METHOD1(GetObjectSrgs, const AZStd::vector>&(const MeshHandle&));
MOCK_CONST_METHOD1(QueueObjectSrgForCompile, void(const MeshHandle&));
MOCK_CONST_METHOD1(GetMaterialAssignmentMap, const AZ::Render::MaterialAssignmentMap&(const MeshHandle&));
MOCK_METHOD2(ConnectModelChangeEventHandler, void(const MeshHandle&, ModelChangedEvent::Handler&));
diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp
index b6c6910fd3..ce5d3cc363 100644
--- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp
@@ -1056,7 +1056,7 @@ namespace AZ
// if the shadow is rendering in an EnvironmentCubeMapPass it also needs to be a ReflectiveCubeMap view,
// to filter out shadows from objects that are excluded from the cubemap
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass();
- passFilter.SetOwenrScene(GetParentScene()); // only handles passes for this scene
+ passFilter.SetOwnerScene(GetParentScene()); // only handles passes for this scene
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&usageFlags]([[maybe_unused]] RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
{
usageFlags |= RPI::View::UsageReflectiveCubeMap;
@@ -1248,6 +1248,32 @@ namespace AZ
property.m_shadowmapViewNeedsUpdate = true;
}
+ float DirectionalLightFeatureProcessor::GetShadowmapSizeFromCameraView(const LightHandle handle, const RPI::View* cameraView) const
+ {
+ const DirectionalLightShadowData& shadowData = m_shadowData.at(cameraView).GetData(handle.GetIndex());
+ return static_cast(shadowData.m_shadowmapSize);
+ }
+
+ void DirectionalLightFeatureProcessor::SnapAabbToPixelIncrements(const float invShadowmapSize, Vector3& orthoMin, Vector3& orthoMax)
+ {
+ // This function stops the cascaded shadowmap from shimmering as the camera moves.
+ // See CascadedShadowsManager.cpp in the Microsoft CascadedShadowMaps11 sample for details.
+
+ const Vector3 normalizeByBufferSize = Vector3(invShadowmapSize, invShadowmapSize, invShadowmapSize);
+
+ const Vector3 worldUnitsPerTexel = (orthoMax - orthoMin) * normalizeByBufferSize;
+
+ // We snap the camera to 1 pixel increments so that moving the camera does not cause the shadows to jitter.
+ // This is a matter of dividing by the world space size of a texel
+ orthoMin /= worldUnitsPerTexel;
+ orthoMin = orthoMin.GetFloor();
+ orthoMin *= worldUnitsPerTexel;
+
+ orthoMax /= worldUnitsPerTexel;
+ orthoMax = orthoMax.GetFloor();
+ orthoMax *= worldUnitsPerTexel;
+ }
+
void DirectionalLightFeatureProcessor::UpdateShadowmapViews(LightHandle handle)
{
ShadowProperty& property = m_shadowProperties.GetData(handle.GetIndex());
@@ -1259,18 +1285,26 @@ namespace AZ
for (auto& segmentIt : property.m_segments)
{
+ const float invShadowmapSize = 1.0f / GetShadowmapSizeFromCameraView(handle, segmentIt.first);
+
for (uint16_t cascadeIndex = 0; cascadeIndex < segmentIt.second.size(); ++cascadeIndex)
{
- const Aabb viewAabb = CalculateShadowViewAabb(
- handle, segmentIt.first, cascadeIndex, lightTransform);
+ const Aabb viewAabb = CalculateShadowViewAabb(handle, segmentIt.first, cascadeIndex, lightTransform);
if (viewAabb.IsValid() && viewAabb.IsFinite())
{
+ const float cascadeNear = viewAabb.GetMin().GetY();
+ const float cascadeFar = viewAabb.GetMax().GetY();
+
+ Vector3 snappedAabbMin = viewAabb.GetMin();
+ Vector3 snappedAabbMax = viewAabb.GetMax();
+
+ SnapAabbToPixelIncrements(invShadowmapSize, snappedAabbMin, snappedAabbMax);
+
Matrix4x4 viewToClipMatrix = Matrix4x4::CreateIdentity();
- MakeOrthographicMatrixRH(viewToClipMatrix,
- viewAabb.GetMin().GetElement(0), viewAabb.GetMax().GetElement(0),
- viewAabb.GetMin().GetElement(2), viewAabb.GetMax().GetElement(2),
- viewAabb.GetMin().GetElement(1), viewAabb.GetMax().GetElement(1));
+ MakeOrthographicMatrixRH(
+ viewToClipMatrix, snappedAabbMin.GetElement(0), snappedAabbMax.GetElement(0), snappedAabbMin.GetElement(2),
+ snappedAabbMax.GetElement(2), cascadeNear, cascadeFar);
CascadeSegment& segment = segmentIt.second[cascadeIndex];
segment.m_aabb = viewAabb;
diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h
index 8d7a9d76e4..77f2db38d6 100644
--- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h
+++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h
@@ -341,6 +341,9 @@ namespace AZ
//! This draws bounding boxes of cascades.
void DrawCascadeBoundingBoxes(LightHandle handle);
+ float GetShadowmapSizeFromCameraView(const LightHandle handle, const RPI::View* cameraView) const;
+ void SnapAabbToPixelIncrements(const float invShadowmapSize, Vector3& orthoMin, Vector3& orthoMax);
+
IndexedDataVector m_shadowProperties;
// [GFX TODO][ATOM-2012] shadow for multiple directional lights
LightHandle m_shadowingLightHandle;
diff --git a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp
index a9bb7271ab..09f0d3f917 100644
--- a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp
@@ -97,7 +97,12 @@ namespace AZ
Utils::PngFile image = Utils::PngFile::Create(readbackResult.m_imageDescriptor.m_size, format, *buffer);
Utils::PngFile::SaveSettings saveSettings;
- saveSettings.m_compressionLevel = r_pngCompressionLevel;
+
+ if (auto console = AZ::Interface::Get(); console != nullptr)
+ {
+ console->GetCvarValue("r_pngCompressionLevel", saveSettings.m_compressionLevel);
+ }
+
// We should probably strip alpha to save space, especially for automated test screenshots. Alpha is left in to maintain
// prior behavior, changing this is out of scope for the current task. Note, it would have bit of a cascade effect where
// AtomSampleViewer's ScriptReporter assumes an RGBA image.
diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp
index 99f01ea630..112eff64a8 100644
--- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp
@@ -67,7 +67,7 @@ namespace AZ
m_handleGlobalShaderOptionUpdate.Disconnect();
DisableSceneNotification();
- AZ_Warning("MeshFeatureProcessor", m_meshData.size() == 0,
+ AZ_Warning("MeshFeatureProcessor", m_modelData.size() == 0,
"Deactivaing the MeshFeatureProcessor, but there are still outstanding mesh handles.\n"
);
m_transformService = nullptr;
@@ -81,7 +81,7 @@ namespace AZ
AZStd::concurrency_check_scope scopeCheck(m_meshDataChecker);
- const auto iteratorRanges = m_meshData.GetParallelRanges();
+ const auto iteratorRanges = m_modelData.GetParallelRanges();
AZ::JobCompletion jobCompletion;
for (const auto& iteratorRange : iteratorRanges)
{
@@ -125,11 +125,11 @@ namespace AZ
m_forceRebuildDrawPackets = false;
// CullingSystem::RegisterOrUpdateCullable() is not threadsafe, so need to do those updates in a single thread
- for (MeshDataInstance& meshDataInstance : m_meshData)
+ for (ModelDataInstance& modelDataInstance : m_modelData)
{
- if (meshDataInstance.m_model && meshDataInstance.m_cullBoundsNeedsUpdate)
+ if (modelDataInstance.m_model && modelDataInstance.m_cullBoundsNeedsUpdate)
{
- meshDataInstance.UpdateCullBounds(m_transformService);
+ modelDataInstance.UpdateCullBounds(m_transformService);
}
}
}
@@ -151,14 +151,14 @@ namespace AZ
AZ_PROFILE_SCOPE(AzRender, "MeshFeatureProcessor: AcquireMesh");
// don't need to check the concurrency during emplace() because the StableDynamicArray won't move the other elements during insertion
- MeshHandle meshDataHandle = m_meshData.emplace();
+ MeshHandle meshDataHandle = m_modelData.emplace();
meshDataHandle->m_descriptor = descriptor;
meshDataHandle->m_scene = GetParentScene();
meshDataHandle->m_materialAssignments = materials;
meshDataHandle->m_objectId = m_transformService->ReserveObjectId();
meshDataHandle->m_originalModelAsset = descriptor.m_modelAsset;
- meshDataHandle->m_meshLoader = AZStd::make_unique(descriptor.m_modelAsset, &*meshDataHandle);
+ meshDataHandle->m_meshLoader = AZStd::make_unique(descriptor.m_modelAsset, &*meshDataHandle);
return meshDataHandle;
}
@@ -183,7 +183,7 @@ namespace AZ
m_transformService->ReleaseObjectId(meshHandle->m_objectId);
AZStd::concurrency_check_scope scopeCheck(m_meshDataChecker);
- m_meshData.erase(meshHandle);
+ m_modelData.erase(meshHandle);
return true;
}
@@ -215,9 +215,10 @@ namespace AZ
return {};
}
- Data::Instance MeshFeatureProcessor::GetObjectSrg(const MeshHandle& meshHandle) const
+ const AZStd::vector>& MeshFeatureProcessor::GetObjectSrgs(const MeshHandle& meshHandle) const
{
- return meshHandle.IsValid() ? meshHandle->m_shaderResourceGroup : nullptr;
+ static AZStd::vector> staticEmptyList;
+ return meshHandle.IsValid() ? meshHandle->m_objectSrgList : staticEmptyList;
}
void MeshFeatureProcessor::QueueObjectSrgForCompile(const MeshHandle& meshHandle) const
@@ -274,9 +275,9 @@ namespace AZ
{
if (meshHandle.IsValid())
{
- MeshDataInstance& meshData = *meshHandle;
- meshData.m_cullBoundsNeedsUpdate = true;
- meshData.m_objectSrgNeedsUpdate = true;
+ ModelDataInstance& modelData = *meshHandle;
+ modelData.m_cullBoundsNeedsUpdate = true;
+ modelData.m_objectSrgNeedsUpdate = true;
m_transformService->SetTransformForId(meshHandle->m_objectId, transform, nonUniformScale);
@@ -292,10 +293,10 @@ namespace AZ
{
if (meshHandle.IsValid())
{
- MeshDataInstance& meshData = *meshHandle;
- meshData.m_aabb = localAabb;
- meshData.m_cullBoundsNeedsUpdate = true;
- meshData.m_objectSrgNeedsUpdate = true;
+ ModelDataInstance& modelData = *meshHandle;
+ modelData.m_aabb = localAabb;
+ modelData.m_cullBoundsNeedsUpdate = true;
+ modelData.m_objectSrgNeedsUpdate = true;
}
};
@@ -465,7 +466,7 @@ namespace AZ
void MeshFeatureProcessor::UpdateMeshReflectionProbes()
{
// we need to rebuild the Srg for any meshes that are using the forward pass IBL specular option
- for (auto& meshInstance : m_meshData)
+ for (auto& meshInstance : m_modelData)
{
if (meshInstance.m_descriptor.m_useForwardPassIblSpecular)
{
@@ -474,14 +475,14 @@ namespace AZ
}
}
- // MeshDataInstance::MeshLoader...
- MeshDataInstance::MeshLoader::MeshLoader(const Data::Asset& modelAsset, MeshDataInstance* parent)
+ // ModelDataInstance::MeshLoader...
+ ModelDataInstance::MeshLoader::MeshLoader(const Data::Asset& modelAsset, ModelDataInstance* parent)
: m_modelAsset(modelAsset)
, m_parent(parent)
{
if (!m_modelAsset.GetId().IsValid())
{
- AZ_Error("MeshDataInstance::MeshLoader", false, "Invalid model asset Id.");
+ AZ_Error("ModelDataInstance::MeshLoader", false, "Invalid model asset Id.");
return;
}
@@ -494,19 +495,19 @@ namespace AZ
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
}
- MeshDataInstance::MeshLoader::~MeshLoader()
+ ModelDataInstance::MeshLoader::~MeshLoader()
{
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
Data::AssetBus::Handler::BusDisconnect();
}
- MeshFeatureProcessorInterface::ModelChangedEvent& MeshDataInstance::MeshLoader::GetModelChangedEvent()
+ MeshFeatureProcessorInterface::ModelChangedEvent& ModelDataInstance::MeshLoader::GetModelChangedEvent()
{
return m_modelChangedEvent;
}
//! AssetBus::Handler overrides...
- void MeshDataInstance::MeshLoader::OnAssetReady(Data::Asset asset)
+ void ModelDataInstance::MeshLoader::OnAssetReady(Data::Asset asset)
{
Data::Asset modelAsset = asset;
@@ -527,7 +528,7 @@ namespace AZ
}
else
{
- AZ_Error("MeshDataInstance", false, "Cannot clone model for '%s'. Cloth simulation results won't be individual per entity.", modelAsset->GetName().GetCStr());
+ AZ_Error("ModelDataInstance", false, "Cannot clone model for '%s'. Cloth simulation results won't be individual per entity.", modelAsset->GetName().GetCStr());
model = RPI::Model::FindOrCreate(modelAsset);
}
}
@@ -547,29 +548,29 @@ namespace AZ
{
//when running with null renderer, the RPI::Model::FindOrCreate(...) is expected to return nullptr, so suppress this error.
AZ_Error(
- "MeshDataInstance::OnAssetReady", RHI::IsNullRenderer(), "Failed to create model instance for '%s'",
+ "ModelDataInstance::OnAssetReady", RHI::IsNullRenderer(), "Failed to create model instance for '%s'",
asset.GetHint().c_str());
}
}
- void MeshDataInstance::MeshLoader::OnModelReloaded(Data::Asset asset)
+ void ModelDataInstance::MeshLoader::OnModelReloaded(Data::Asset asset)
{
OnAssetReady(asset);
}
- void MeshDataInstance::MeshLoader::OnAssetError(Data::Asset asset)
+ void ModelDataInstance::MeshLoader::OnAssetError(Data::Asset asset)
{
// Note: m_modelAsset and asset represents same asset, but only m_modelAsset contains the file path in its hint from serialization
AZ_Error(
- "MeshDataInstance::MeshLoader", false, "Failed to load asset %s. It may be missing, or not be finished processing",
+ "ModelDataInstance::MeshLoader", false, "Failed to load asset %s. It may be missing, or not be finished processing",
m_modelAsset.GetHint().c_str());
AzFramework::AssetSystemRequestBus::Broadcast(
&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetByUuid, m_modelAsset.GetId().m_guid);
}
- void MeshDataInstance::MeshLoader::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId)
+ void ModelDataInstance::MeshLoader::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId)
{
if (assetId == m_modelAsset.GetId())
{
@@ -584,7 +585,7 @@ namespace AZ
}
}
- void MeshDataInstance::MeshLoader::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId)
+ void ModelDataInstance::MeshLoader::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId)
{
if (assetId == m_modelAsset.GetId())
{
@@ -599,9 +600,9 @@ namespace AZ
}
}
- // MeshDataInstance...
+ // ModelDataInstance...
- void MeshDataInstance::DeInit()
+ void ModelDataInstance::DeInit()
{
m_scene->GetCullingScene()->UnregisterCullable(m_cullable);
@@ -609,11 +610,11 @@ namespace AZ
m_drawPacketListsByLod.clear();
m_materialAssignments.clear();
- m_shaderResourceGroup = {};
+ m_objectSrgList = {};
m_model = {};
}
- void MeshDataInstance::Init(Data::Instance model)
+ void ModelDataInstance::Init(Data::Instance model)
{
m_model = model;
const size_t modelLodCount = m_model->GetLodCount();
@@ -623,11 +624,11 @@ namespace AZ
BuildDrawPacketList(modelLodIndex);
}
- if (m_shaderResourceGroup)
+ for(auto& objectSrg : m_objectSrgList)
{
// Set object Id once since it never changes
RHI::ShaderInputNameIndex objectIdIndex = "m_objectId";
- m_shaderResourceGroup->SetConstant(objectIdIndex, m_objectId.GetIndex());
+ objectSrg->SetConstant(objectIdIndex, m_objectId.GetIndex());
objectIdIndex.AssertValid();
}
@@ -643,12 +644,12 @@ namespace AZ
m_objectSrgNeedsUpdate = true;
}
- void MeshDataInstance::BuildDrawPacketList(size_t modelLodIndex)
+ void ModelDataInstance::BuildDrawPacketList(size_t modelLodIndex)
{
RPI::ModelLod& modelLod = *m_model->GetLods()[modelLodIndex];
const size_t meshCount = modelLod.GetMeshes().size();
- MeshDataInstance::DrawPacketList& drawPacketListOut = m_drawPacketListsByLod[modelLodIndex];
+ ModelDataInstance::DrawPacketList& drawPacketListOut = m_drawPacketListsByLod[modelLodIndex];
drawPacketListOut.clear();
drawPacketListOut.reserve(meshCount);
@@ -682,27 +683,32 @@ namespace AZ
continue;
}
- if (m_shaderResourceGroup && m_shaderResourceGroup->GetLayout()->GetHash() != objectSrgLayout->GetHash())
+ Data::Instance meshObjectSrg;
+
+ // See if the object SRG for this mesh is already in our list of object SRGs
+ for (auto& objectSrgIter : m_objectSrgList)
{
- AZ_Warning("MeshFeatureProcessor", false, "All materials on a model must use the same per-object ShaderResourceGroup. Skipping.");
- continue;
+ if (objectSrgIter->GetLayout()->GetHash() == objectSrgLayout->GetHash())
+ {
+ meshObjectSrg = objectSrgIter;
+ }
}
- // The first time we find the per-surface SRG asset we create an instance and store it
- // in shaderResourceGroupInOut. All of the Model's draw packets will use this same instance.
- if (!m_shaderResourceGroup)
+ // If the object SRG for this mesh was not already in the list, create it and add it to the list
+ if (!meshObjectSrg)
{
auto& shaderAsset = material->GetAsset()->GetMaterialTypeAsset()->GetShaderAssetForObjectSrg();
- m_shaderResourceGroup = RPI::ShaderResourceGroup::Create(shaderAsset, objectSrgLayout->GetName());
- if (!m_shaderResourceGroup)
+ meshObjectSrg = RPI::ShaderResourceGroup::Create(shaderAsset, objectSrgLayout->GetName());
+ if (!meshObjectSrg)
{
AZ_Warning("MeshFeatureProcessor", false, "Failed to create a new shader resource group, skipping.");
continue;
}
+ m_objectSrgList.push_back(meshObjectSrg);
}
// setup the mesh draw packet
- RPI::MeshDrawPacket drawPacket(modelLod, meshIndex, material, m_shaderResourceGroup, materialAssignment.m_matModUvOverrides);
+ RPI::MeshDrawPacket drawPacket(modelLod, meshIndex, material, meshObjectSrg, materialAssignment.m_matModUvOverrides);
// set the shader option to select forward pass IBL specular if necessary
if (!drawPacket.SetShaderOption(AZ::Name("o_meshUseForwardPassIBLSpecular"), AZ::RPI::ShaderOptionValue{ m_descriptor.m_useForwardPassIblSpecular }))
@@ -726,7 +732,7 @@ namespace AZ
}
}
- void MeshDataInstance::SetRayTracingData()
+ void ModelDataInstance::SetRayTracingData()
{
if (!m_model)
{
@@ -993,7 +999,7 @@ namespace AZ
rayTracingFeatureProcessor->SetMesh(m_objectId, m_model->GetModelAsset()->GetId(), subMeshes);
}
- void MeshDataInstance::RemoveRayTracingData()
+ void ModelDataInstance::RemoveRayTracingData()
{
// remove from ray tracing
RayTracingFeatureProcessor* rayTracingFeatureProcessor = m_scene->GetFeatureProcessor();
@@ -1003,7 +1009,7 @@ namespace AZ
}
}
- void MeshDataInstance::SetSortKey(RHI::DrawItemSortKey sortKey)
+ void ModelDataInstance::SetSortKey(RHI::DrawItemSortKey sortKey)
{
m_sortKey = sortKey;
for (auto& drawPacketList : m_drawPacketListsByLod)
@@ -1015,24 +1021,24 @@ namespace AZ
}
}
- RHI::DrawItemSortKey MeshDataInstance::GetSortKey() const
+ RHI::DrawItemSortKey ModelDataInstance::GetSortKey() const
{
return m_sortKey;
}
- void MeshDataInstance::SetMeshLodConfiguration(RPI::Cullable::LodConfiguration meshLodConfig)
+ void ModelDataInstance::SetMeshLodConfiguration(RPI::Cullable::LodConfiguration meshLodConfig)
{
m_cullable.m_lodData.m_lodConfiguration = meshLodConfig;
}
- RPI::Cullable::LodConfiguration MeshDataInstance::GetMeshLodConfiguration() const
+ RPI::Cullable::LodConfiguration ModelDataInstance::GetMeshLodConfiguration() const
{
return m_cullable.m_lodData.m_lodConfiguration;
}
- void MeshDataInstance::UpdateDrawPackets(bool forceUpdate /*= false*/)
+ void ModelDataInstance::UpdateDrawPackets(bool forceUpdate /*= false*/)
{
- AZ_PROFILE_SCOPE(AzRender, "MeshDataInstance:: UpdateDrawPackets");
+ AZ_PROFILE_SCOPE(AzRender, "ModelDataInstance:: UpdateDrawPackets");
for (auto& drawPacketList : m_drawPacketListsByLod)
{
for (auto& drawPacket : drawPacketList)
@@ -1045,9 +1051,9 @@ namespace AZ
}
}
- void MeshDataInstance::BuildCullable()
+ void ModelDataInstance::BuildCullable()
{
- AZ_PROFILE_SCOPE(AzRender, "MeshDataInstance: BuildCullable");
+ AZ_PROFILE_SCOPE(AzRender, "ModelDataInstance: BuildCullable");
AZ_Assert(m_cullableNeedsRebuild, "This function only needs to be called if the cullable to be rebuilt");
AZ_Assert(m_model, "The model has not finished loading yet");
@@ -1122,9 +1128,9 @@ namespace AZ
m_cullBoundsNeedsUpdate = true;
}
- void MeshDataInstance::UpdateCullBounds(const TransformServiceFeatureProcessor* transformService)
+ void ModelDataInstance::UpdateCullBounds(const TransformServiceFeatureProcessor* transformService)
{
- AZ_PROFILE_SCOPE(AzRender, "MeshDataInstance: UpdateCullBounds");
+ AZ_PROFILE_SCOPE(AzRender, "ModelDataInstance: UpdateCullBounds");
AZ_Assert(m_cullBoundsNeedsUpdate, "This function only needs to be called if the culling bounds need to be rebuilt");
AZ_Assert(m_model, "The model has not finished loading yet");
@@ -1148,74 +1154,74 @@ namespace AZ
m_cullBoundsNeedsUpdate = false;
}
- void MeshDataInstance::UpdateObjectSrg()
+ void ModelDataInstance::UpdateObjectSrg()
{
- if (!m_shaderResourceGroup)
+ for (auto& objectSrg : m_objectSrgList)
{
- return;
+ ReflectionProbeFeatureProcessor* reflectionProbeFeatureProcessor = m_scene->GetFeatureProcessor