Merge remote-tracking branch 'upstream/stabilization/2110' into Atom/santorac/MaterialEditorHandlesMissingTextures

monroegm-disable-blank-issue-2
santorac 4 years ago
commit db3d41ad9d

@ -14,6 +14,7 @@ from datetime import datetime
import ly_test_tools.log.log_monitor import ly_test_tools.log.log_monitor
from AWS.common import constants from AWS.common import constants
from AWS.common.resource_mappings import AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY
from .aws_metrics_custom_thread import AWSMetricsThread from .aws_metrics_custom_thread import AWSMetricsThread
# fixture imports # fixture imports
@ -200,6 +201,59 @@ class TestAWSMetricsWindows(object):
for thread in operational_threads: for thread in operational_threads:
thread.join() 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']) @pytest.mark.parametrize('level', ['AWS/Metrics'])
def test_unauthorized_user_request_rejected(self, def test_unauthorized_user_request_rejected(self,
level: str, level: str,

@ -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 import ly_test_tools.o3de.asset_processor_utils as asset_processor_utils
from AWS.common import constants from AWS.common import constants
from AWS.common.resource_mappings import AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY
# fixture imports # fixture imports
from assetpipeline.ap_fixtures.asset_processor_fixture import asset_processor from assetpipeline.ap_fixtures.asset_processor_fixture import asset_processor
@ -141,3 +142,51 @@ class TestAWSCoreAWSResourceInteraction(object):
'The expected file wasn\'t successfully downloaded.' 'The expected file wasn\'t successfully downloaded.'
# clean up the file directories. # clean up the file directories.
shutil.rmtree(s3_download_dir) 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)

@ -102,3 +102,17 @@ class ResourceMappings:
def get_resource_name_id(self, resource_key: str): def get_resource_name_id(self, resource_key: str):
return self._resource_mappings[AWS_RESOURCE_MAPPINGS_KEY][resource_key]['Name/ID'] 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)

@ -158,7 +158,7 @@ def bundler_batch_setup_fixture(request, workspace, asset_processor, timeout) ->
else: else:
cmd.append(f"--{key}") cmd.append(f"--{key}")
if append_defaults: if append_defaults:
cmd.append(f"--project-path={workspace.project}") cmd.append(f"--project-path={workspace.paths.project()}")
return cmd return cmd
# ****** # ******

@ -88,214 +88,6 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
bundler_batch_helper.call_bundles(help="") bundler_batch_helper.call_bundles(help="")
bundler_batch_helper.call_bundleSeed(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.BAT
@pytest.mark.assetpipeline @pytest.mark.assetpipeline
@ -310,9 +102,9 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
3. Read and store contents of asset list into memory 3. Read and store contents of asset list into memory
4. Attempt to create a new asset list in without using --allowOverwrites 4. Attempt to create a new asset list in without using --allowOverwrites
5. Verify that Asset Bundler returns false 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 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 helper = bundler_batch_helper
seed_list = os.path.join(workspace.paths.engine_root(), "Assets", "Engine", "SeedAssetList.seed") # Engine seed list 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 # Extra arguments for pattern comparison
cmd.extend([f"--filePatternType={pattern_type}", f"--filePattern={pattern}"]) cmd.extend([f"--filePatternType={pattern_type}", f"--filePattern={pattern}"])
if workspace.project: if workspace.project:
cmd.append(f'--project-path={project_name}') cmd.append(f'--project-path={workspace.paths.project()}')
return cmd return cmd
# End generate_compare_command() # End generate_compare_command()
@ -960,7 +752,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
output_mac_asset_list = helper.platform_file_name(last_output_arg, platform) output_mac_asset_list = helper.platform_file_name(last_output_arg, platform)
# Build execution command # Build execution command
cmd = generate_compare_command(platform_arg, workspace.project) cmd = generate_compare_command(platform_arg, workspace.paths.project())
# Execute command # Execute command
subprocess.check_call(cmd) subprocess.check_call(cmd)
@ -995,7 +787,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
f"--comparisonRulesFile={rule_file}", f"--comparisonRulesFile={rule_file}",
f"--comparisonType={args[1]}", f"--comparisonType={args[1]}",
r"--addComparison", r"--addComparison",
f"--project-path={workspace.project}", f"--project-path={workspace.paths.project()}",
] ]
if args[1] == "4": if args[1] == "4":
# If pattern comparison, append a few extra arguments # If pattern comparison, append a few extra arguments
@ -1117,7 +909,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
"--addDefaultSeedListFiles", "--addDefaultSeedListFiles",
"--platform=pc", "--platform=pc",
"--print", "--print",
f"--project-path={workspace.project}" f"--project-path={workspace.paths.project()}"
], ],
universal_newlines=True, universal_newlines=True,
) )
@ -1189,7 +981,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
# Make sure file gets deleted on teardown # Make sure file gets deleted on teardown
request.addfinalizer(lambda: fs.delete([bundle_result_path], True, False)) 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" level_pak = r"levels\testdependencieslevel\level.pak"
bundle_request_path = os.path.join(bundles_folder, "bundle.pak") bundle_request_path = os.path.join(bundles_folder, "bundle.pak")
bundle_result_path = os.path.join(bundles_folder, bundle_result_path = os.path.join(bundles_folder,
@ -1243,23 +1035,64 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
2. Verify file was created 2. Verify file was created
3. Verify that only the expected assets are present in the created asset list 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/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( bundler_batch_helper.call_assetLists(
assetListFile=bundler_batch_helper['asset_info_file_request'], assetListFile=bundler_batch_helper['asset_info_file_request'],
addSeed="ui/canvases/lyshineexamples/animation/multiplesequences.uicanvas", addSeed="ui/canvases/lyshineexamples/animation/multiplesequences.uicanvas",
skip="ui/textures/prefab/button_disabled.sprite,ui/scripts/lyshineexamples/animation/multiplesequences.luac," allowOverwrites="",
"ui/textures/prefab/tooltip_sliced.sprite,ui/scripts/lyshineexamples/unloadthiscanvasbutton.luac,fonts/vera.fontfamily,fonts/vera-italic.font," skip=','.join(skip_assets)
"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"
) )
assert os.path.isfile(bundler_batch_helper["asset_info_file_result"]) assert os.path.isfile(bundler_batch_helper["asset_info_file_result"])
assets_in_list = [] assets_in_list = []
for rel_path in bundler_batch_helper.get_asset_relative_paths(bundler_batch_helper["asset_info_file_result"]): 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.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.BAT
@pytest.mark.assetpipeline @pytest.mark.assetpipeline

@ -125,7 +125,7 @@
</size> </size>
</property> </property>
<property name="text"> <property name="text">
<string>General Availability</string> <string>Stable 21.11</string>
</property> </property>
<property name="textFormat"> <property name="textFormat">
<enum>Qt::AutoText</enum> <enum>Qt::AutoText</enum>

@ -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<AssetBrowserEntry*> 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<SourceAssetBrowserEntry*>(entry))
{
if (AzFramework::StringFunc::Equal(source->GetExtension().c_str(), ".fbx", false))
{
return true;
}
}
}
return false;
}
} }
AzAssetBrowserRequestHandler::AzAssetBrowserRequestHandler() AzAssetBrowserRequestHandler::AzAssetBrowserRequestHandler()

@ -4181,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." "\nThis could be because of incorrectly configured components, or missing required gems."
"\nSee other errors for more details."); "\nSee other errors for more details.");
AzToolsFramework::EditorEventsBus::Broadcast(&AzToolsFramework::EditorEvents::NotifyEditorInitialized);
if (didCryEditStart) if (didCryEditStart)
{ {
app->EnableOnIdle(); app->EnableOnIdle();

@ -9,10 +9,6 @@
#define CRYINCLUDE_EDITOR_MATERIAL_IEDITORMATERIALMANAGER_H #define CRYINCLUDE_EDITOR_MATERIAL_IEDITORMATERIALMANAGER_H
#pragma once #pragma once
#define MATERIAL_FILE_EXT ".mtl"
#define DCC_MATERIAL_FILE_EXT ".dccmtl"
#define MATERIALS_PATH "materials/"
#include <Include/IBaseLibraryManager.h> #include <Include/IBaseLibraryManager.h>
#include <IMaterial.h> #include <IMaterial.h>

@ -18,7 +18,6 @@
#include <LmbrCentral/Rendering/LensFlareAsset.h> #include <LmbrCentral/Rendering/LensFlareAsset.h>
#include <LmbrCentral/Rendering/MeshAsset.h> #include <LmbrCentral/Rendering/MeshAsset.h>
#include <LmbrCentral/Rendering/MaterialAsset.h>
#include <AzCore/Memory/Memory.h> #include <AzCore/Memory/Memory.h>
#include <AzCore/RTTI/TypeInfo.h> #include <AzCore/RTTI/TypeInfo.h>
@ -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::Uuid> { AZ::AzTypeInfo<LmbrCentral::TextureAsset>::Uuid() }));
QString materialExtensions = LmbrCentral::MaterialAsset::GetFileFilter();
m_extensionToAssetType.insert(AZStd::make_pair(materialExtensions.replace("*", "").replace(" ", "").toStdString().c_str(), AZStd::vector<AZ::Uuid> { AZ::AzTypeInfo<LmbrCentral::MaterialAsset>::Uuid() }));
QString dccMaterialExtensions = LmbrCentral::DccMaterialAsset::GetFileFilter();
m_extensionToAssetType.insert(AZStd::make_pair(dccMaterialExtensions.replace("*", "").replace(" ", "").toStdString().c_str(), AZStd::vector<AZ::Uuid> { AZ::AzTypeInfo<LmbrCentral::DccMaterialAsset>::Uuid() }));
AZ::SerializeContext* serializeContext = nullptr; AZ::SerializeContext* serializeContext = nullptr;
EBUS_EVENT_RESULT(serializeContext, AZ::ComponentApplicationBus, GetSerializeContext); EBUS_EVENT_RESULT(serializeContext, AZ::ComponentApplicationBus, GetSerializeContext);
AZ_Assert(serializeContext, "Failed to acquire application serialize context."); AZ_Assert(serializeContext, "Failed to acquire application serialize context.");

@ -103,7 +103,7 @@
<item> <item>
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_2">
<property name="text"> <property name="text">
<string>General Availability</string> <string>Stable 21.11</string>
</property> </property>
</widget> </widget>
</item> </item>

@ -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 // they will trigger a ReleaseAsset call sometime after the AssetManager has begun to shut down, which can lead to
// race conditions. // 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 = {}; weakAsset = {};
loadingAsset.Reset(); loadingAsset.Reset();
RemoveActiveStreamerRequest(assetId);
}; };
auto&& [deadline, priority] = GetEffectiveDeadlineAndPriority(*handler, asset.GetType(), loadParams); auto&& [deadline, priority] = GetEffectiveDeadlineAndPriority(*handler, asset.GetType(), loadParams);

@ -56,11 +56,12 @@ namespace AZ
int numberOfWorkerThreads = m_numberOfWorkerThreads; int numberOfWorkerThreads = m_numberOfWorkerThreads;
if (numberOfWorkerThreads <= 0) // spawn default number of threads 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); uint32_t scaledHardwareThreads = Threading::CalcNumWorkerThreads(cl_jobThreadsConcurrencyRatio, cl_jobThreadsMinNumber, cl_jobThreadsNumReserved);
numberOfWorkerThreads = AZ::GetMin(static_cast<unsigned int>(desc.m_workerThreads.capacity()), scaledHardwareThreads); numberOfWorkerThreads = AZ::GetMin(static_cast<unsigned int>(desc.m_workerThreads.capacity()), scaledHardwareThreads);
#if (AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS) #endif // (AZ_TRAIT_THREAD_NUM_JOB_MANAGER_WORKER_THREADS)
numberOfWorkerThreads = AZ::GetMin(numberOfWorkerThreads, AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS);
#endif // (AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS)
} }
threadDesc.m_cpuId = AFFINITY_MASK_USERTHREADS; threadDesc.m_cpuId = AFFINITY_MASK_USERTHREADS;

@ -104,6 +104,8 @@ namespace AZ
->HandlesType<AZStd::variant>(); ->HandlesType<AZStd::variant>();
jsonContext->Serializer<JsonOptionalSerializer>() jsonContext->Serializer<JsonOptionalSerializer>()
->HandlesType<AZStd::optional>(); ->HandlesType<AZStd::optional>();
jsonContext->Serializer<JsonBitsetSerializer>()
->HandlesType<AZStd::bitset>();
MathReflect(jsonContext); MathReflect(jsonContext);
} }

@ -15,6 +15,7 @@ namespace AZ
AZ_CLASS_ALLOCATOR_IMPL(JsonAnySerializer, SystemAllocator, 0); AZ_CLASS_ALLOCATOR_IMPL(JsonAnySerializer, SystemAllocator, 0);
AZ_CLASS_ALLOCATOR_IMPL(JsonVariantSerializer, SystemAllocator, 0); AZ_CLASS_ALLOCATOR_IMPL(JsonVariantSerializer, SystemAllocator, 0);
AZ_CLASS_ALLOCATOR_IMPL(JsonOptionalSerializer, 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&, JsonSerializationResult::Result JsonUnsupportedTypesSerializer::Load(void*, const Uuid&, const rapidjson::Value&,
JsonDeserializerContext& context) 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 " 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."; "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 } // namespace AZ

@ -65,4 +65,14 @@ namespace AZ
protected: protected:
AZStd::string_view GetMessage() const override; 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 } // namespace AZ

@ -30,8 +30,13 @@ namespace AZ
if (Interface<TaskGraphActiveInterface>::Get() == nullptr) if (Interface<TaskGraphActiveInterface>::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<TaskGraphActiveInterface>::Register(this); // small window that another thread can try to use taskgraph between this line and the set instance. Interface<TaskGraphActiveInterface>::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); TaskExecutor::SetInstance(m_taskExecutor);
} }
} }

@ -75,7 +75,6 @@
#define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 0 #define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 0
#define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0 #define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0
#define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 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_PERF_MEMORYBENCHMARK_IS_AVAILABLE 0
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0

@ -75,7 +75,6 @@
#define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1 #define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1
#define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0 #define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0
#define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 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_PERF_MEMORYBENCHMARK_IS_AVAILABLE 0
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0

@ -75,7 +75,6 @@
#define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1 #define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1
#define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0 #define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0
#define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 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_PERF_MEMORYBENCHMARK_IS_AVAILABLE 0
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0

@ -75,7 +75,6 @@
#define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1 #define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1
#define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0 #define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0
#define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 1 #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_PERF_MEMORYBENCHMARK_IS_AVAILABLE 1
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0

@ -76,7 +76,6 @@
#define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1 #define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1
#define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0 #define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0
#define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 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_PERF_MEMORYBENCHMARK_IS_AVAILABLE 0
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0
#define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0

@ -652,7 +652,7 @@ namespace UnitTest
threads.emplace_back([this, &threadCount, &cv, assetUuid]() { threads.emplace_back([this, &threadCount, &cv, assetUuid]() {
bool checkLoaded = true; bool checkLoaded = true;
for (int i = 0; i < 5000; i++) for (int i = 0; i < 1000; i++)
{ {
Asset<AssetWithAssetReference> asset1 = Asset<AssetWithAssetReference> asset1 =
m_testAssetManager->GetAsset(assetUuid, azrtti_typeid<AssetWithAssetReference>(), AZ::Data::AssetLoadBehavior::PreLoad); m_testAssetManager->GetAsset(assetUuid, azrtti_typeid<AssetWithAssetReference>(), AZ::Data::AssetLoadBehavior::PreLoad);
@ -678,7 +678,7 @@ namespace UnitTest
while (threadCount > 0 && !timedOut) while (threadCount > 0 && !timedOut)
{ {
AZStd::unique_lock<AZStd::mutex> lock(mutex); AZStd::unique_lock<AZStd::mutex> 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."; 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 #if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
TEST_F(AssetJobsFloodTest, DISABLED_ContainerFilterTest_ContainersWithAndWithoutFiltering_Success) TEST_F(AssetJobsFloodTest, DISABLED_ContainerFilterTest_ContainersWithAndWithoutFiltering_Success)
#else #else
TEST_F(AssetJobsFloodTest, DISABLED_ContainerFilterTest_ContainersWithAndWithoutFiltering_Success) TEST_F(AssetJobsFloodTest, ContainerFilterTest_ContainersWithAndWithoutFiltering_Success)
#endif // !AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS #endif // !AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
{ {
m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusConnect(); m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusConnect();

@ -1241,6 +1241,10 @@ namespace AZ::IO
m_arrZips.insert(revItZip.base(), desc); m_arrZips.insert(revItZip.base(), desc);
// This lock is for m_arrZips.
// Unlock it now because the modification is complete, and events responding to this signal
// will attempt to lock the same mutex, causing the application to lock up.
lock.unlock();
m_levelOpenEvent.Signal(levelDirs); m_levelOpenEvent.Signal(levelDirs);
} }

@ -927,6 +927,9 @@ namespace AzToolsFramework
/// Notify that the MainWindow has been fully initialized /// Notify that the MainWindow has been fully initialized
virtual void NotifyMainWindowInitialized(QMainWindow* /*mainWindow*/) {} virtual void NotifyMainWindowInitialized(QMainWindow* /*mainWindow*/) {}
/// Notify that the Editor has been fully initialized
virtual void NotifyEditorInitialized() {}
/// Signal that an asset should be highlighted / selected /// Signal that an asset should be highlighted / selected
virtual void SelectAsset(const QString& /* assetPath */) {} virtual void SelectAsset(const QString& /* assetPath */) {}
}; };

@ -214,12 +214,17 @@ namespace AzToolsFramework
, public AZ::BehaviorEBusHandler , public AZ::BehaviorEBusHandler
{ {
AZ_EBUS_BEHAVIOR_BINDER(EditorEventsBusHandler, "{352F80BB-469A-40B6-B322-FE57AB51E4DA}", AZ::SystemAllocator, AZ_EBUS_BEHAVIOR_BINDER(EditorEventsBusHandler, "{352F80BB-469A-40B6-B322-FE57AB51E4DA}", AZ::SystemAllocator,
NotifyRegisterViews); NotifyRegisterViews, NotifyEditorInitialized);
void NotifyRegisterViews() override void NotifyRegisterViews() override
{ {
Call(FN_NotifyRegisterViews); Call(FN_NotifyRegisterViews);
} }
void NotifyEditorInitialized() override
{
Call(FN_NotifyEditorInitialized);
}
}; };
} // Internal } // Internal
@ -443,6 +448,7 @@ namespace AzToolsFramework
->Attribute(AZ::Script::Attributes::Module, "editor") ->Attribute(AZ::Script::Attributes::Module, "editor")
->Handler<Internal::EditorEventsBusHandler>() ->Handler<Internal::EditorEventsBusHandler>()
->Event("NotifyRegisterViews", &EditorEvents::NotifyRegisterViews) ->Event("NotifyRegisterViews", &EditorEvents::NotifyRegisterViews)
->Event("NotifyEditorInitialized", &EditorEvents::NotifyEditorInitialized)
; ;
behaviorContext->EBus<ViewPaneCallbackBus>("ViewPaneCallbackBus") behaviorContext->EBus<ViewPaneCallbackBus>("ViewPaneCallbackBus")

@ -234,11 +234,6 @@ namespace AzToolsFramework
return SourceFileDetails("Icons/AssetBrowser/Lua_16.svg"); 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())) if (AzFramework::StringFunc::Equal(extension.c_str(), AzToolsFramework::SliceUtilities::GetSliceFileExtension().c_str()))
{ {
return SourceFileDetails("Icons/AssetBrowser/Slice_16.svg"); return SourceFileDetails("Icons/AssetBrowser/Slice_16.svg");

@ -31,7 +31,10 @@ AZ_POP_DISABLE_WARNING
AZ_CVAR( AZ_CVAR(
bool, ed_hideAssetPickerPathColumn, true, nullptr, AZ::ConsoleFunctorFlags::Null, bool, ed_hideAssetPickerPathColumn, true, nullptr, AZ::ConsoleFunctorFlags::Null,
"Hide AssetPicker path column for a clearer view."); "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 namespace AzToolsFramework
{ {
@ -106,7 +109,7 @@ namespace AzToolsFramework
m_persistentState = AZ::UserSettings::CreateFind<AzToolsFramework::QWidgetSavedState>(AZ::Crc32(("AssetBrowserTreeView_Dialog_" + name).toUtf8().data()), AZ::UserSettings::CT_GLOBAL); m_persistentState = AZ::UserSettings::CreateFind<AzToolsFramework::QWidgetSavedState>(AZ::Crc32(("AssetBrowserTreeView_Dialog_" + name).toUtf8().data()), AZ::UserSettings::CT_GLOBAL);
m_ui->m_assetBrowserTableViewWidget->setVisible(false); m_ui->m_assetBrowserTableViewWidget->setVisible(false);
if (ed_useNewAssetBrowserTableView) if (ed_useNewAssetPickerView)
{ {
m_ui->m_assetBrowserTreeViewWidget->setVisible(false); m_ui->m_assetBrowserTreeViewWidget->setVisible(false);
m_ui->m_assetBrowserTableViewWidget->setVisible(true); m_ui->m_assetBrowserTableViewWidget->setVisible(true);

@ -597,11 +597,13 @@ namespace AzToolsFramework
pte.SetVisibleEnforcement(true); pte.SetVisibleEnforcement(true);
} }
ScopedUndoBatch undo("Modify Entity Property");
PropertyOutcome result = pte.SetProperty(propertyPath, value); PropertyOutcome result = pte.SetProperty(propertyPath, value);
if (result.IsSuccess()) if (result.IsSuccess())
{ {
PropertyEditorEntityChangeNotificationBus::Event(componentInstance.GetEntityId(), &PropertyEditorEntityChangeNotifications::OnEntityComponentPropertyChanged, componentInstance.GetComponentId()); PropertyEditorEntityChangeNotificationBus::Event(componentInstance.GetEntityId(), &PropertyEditorEntityChangeNotifications::OnEntityComponentPropertyChanged, componentInstance.GetComponentId());
} }
undo.MarkEntityDirty(componentInstance.GetEntityId());
return result; return result;
} }

@ -64,6 +64,9 @@ namespace AzToolsFramework::Prefab
); );
m_backButton->setToolTip("Up one level (-)"); 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() void PrefabViewportFocusPathHandler::OnPrefabFocusChanged()

@ -4705,13 +4705,6 @@ namespace AzToolsFramework
{ {
if (mimeData->hasFormat(AssetBrowser::AssetBrowserEntry::GetMimeType())) 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<AssetBrowser::SourceAssetBrowserEntry>(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. // the usual case - we only allow asset browser drops of assets that have actually been associated with a kind of component.
AssetBrowser::AssetBrowserEntry::ForEachEntryInMimeData<AssetBrowser::ProductAssetBrowserEntry>(mimeData, [&](const AssetBrowser::ProductAssetBrowserEntry* product) AssetBrowser::AssetBrowserEntry::ForEachEntryInMimeData<AssetBrowser::ProductAssetBrowserEntry>(mimeData, [&](const AssetBrowser::ProductAssetBrowserEntry* product)
{ {
@ -4723,17 +4716,7 @@ namespace AzToolsFramework
if (canCreateComponent && !componentTypeId.IsNull()) if (canCreateComponent && !componentTypeId.IsNull())
{ {
// we have a component type that handles this asset. callbackFunction(product);
// 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);
}
} }
}); });
} }

@ -690,7 +690,6 @@ namespace AssetBuilderSDK
static const char* textureExtensions = ".dds"; static const char* textureExtensions = ".dds";
static const char* staticMeshExtensions = ".cgf"; static const char* staticMeshExtensions = ".cgf";
static const char* skinnedMeshExtensions = ".skin"; static const char* skinnedMeshExtensions = ".skin";
static const char* materialExtensions = ".mtl";
// MIPS // MIPS
static const int c_MaxMipsCount = 11; // 11 is for 8k textures non-compressed. When not compressed it is using one file per mip. static const int c_MaxMipsCount = 11; // 11 is for 8k textures non-compressed. When not compressed it is using one file per mip.
@ -805,11 +804,6 @@ namespace AssetBuilderSDK
return textureAssetType; 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) if (AzFramework::StringFunc::Find(staticMeshExtensions, extension.c_str()) != AZStd::string::npos)
{ {
return meshAssetType; return meshAssetType;

@ -9,3 +9,4 @@
#pragma once #pragma once
#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false #define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false
#define AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT false

@ -96,5 +96,10 @@ namespace O3DE::ProjectManager
{ {
return AZ::Utils::GetExecutableDirectory(); return AZ::Utils::GetExecutableDirectory();
} }
AZ::Outcome<QString, QString> 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 ProjectUtils
} // namespace O3DE::ProjectManager } // namespace O3DE::ProjectManager

@ -9,3 +9,4 @@
#pragma once #pragma once
#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false #define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false
#define AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT false

@ -137,5 +137,10 @@ namespace O3DE::ProjectManager
return editorPath; return editorPath;
} }
AZ::Outcome<QString, QString> 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 ProjectUtils
} // namespace O3DE::ProjectManager } // namespace O3DE::ProjectManager

@ -9,3 +9,4 @@
#pragma once #pragma once
#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR true #define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR true
#define AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT true

@ -13,6 +13,7 @@
#include <QFileInfo> #include <QFileInfo>
#include <QProcess> #include <QProcess>
#include <QProcessEnvironment> #include <QProcessEnvironment>
#include <QStandardPaths>
#include <AzCore/Utils/Utils.h> #include <AzCore/Utils/Utils.h>
@ -146,5 +147,26 @@ namespace O3DE::ProjectManager
{ {
return AZ::Utils::GetExecutableDirectory(); return AZ::Utils::GetExecutableDirectory();
} }
AZ::Outcome<QString, QString> 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 <br><br>"
"Please verify you have permission to create files at the specified location.<br><br> %2")
.arg(shortcutPath)
.arg(createShortcutResult.GetError()));
}
return AZ::Success(QObject::tr("Desktop shortcut created at<br><a href=\"%1\">%2</a>").arg(desktopPath).arg(shortcutPath));
}
} // namespace ProjectUtils } // namespace ProjectUtils
} // namespace O3DE::ProjectManager } // namespace O3DE::ProjectManager

@ -126,7 +126,8 @@ namespace O3DE::ProjectManager
// Select the first entry after everything got correctly sized // Select the first entry after everything got correctly sized
QTimer::singleShot(200, [=]{ QTimer::singleShot(200, [=]{
QModelIndex firstModelIndex = m_gemModel->index(0, 0); QModelIndex firstModelIndex = m_gemModel->index(0, 0);
m_gemModel->GetSelectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect); QModelIndex proxyIndex = m_proxyModel->mapFromSource(firstModelIndex);
m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect);
}); });
} }
@ -209,7 +210,7 @@ namespace O3DE::ProjectManager
const bool gemFound = gemInfoHash.contains(gemName); const bool gemFound = gemInfoHash.contains(gemName);
if (!gemFound && !m_gemModel->IsAdded(index) && !m_gemModel->IsAddedDependency(index)) if (!gemFound && !m_gemModel->IsAdded(index) && !m_gemModel->IsAddedDependency(index))
{ {
m_gemModel->removeRow(i); m_gemModel->RemoveGem(index);
} }
else else
{ {
@ -239,7 +240,7 @@ namespace O3DE::ProjectManager
m_filterWidget->ResetAllFilters(); m_filterWidget->ResetAllFilters();
// Reselect the same selection to proc UI updates // Reselect the same selection to proc UI updates
m_proxyModel->GetSelectionModel()->select(m_proxyModel->GetSelectionModel()->selection(), QItemSelectionModel::Select); m_proxyModel->GetSelectionModel()->setCurrentIndex(m_proxyModel->GetSelectionModel()->currentIndex(), QItemSelectionModel::Select);
} }
void GemCatalogScreen::OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies) void GemCatalogScreen::OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies)
@ -268,7 +269,7 @@ namespace O3DE::ProjectManager
if (added && GemModel::GetDownloadStatus(modelIndex) == GemInfo::DownloadStatus::NotDownloaded) if (added && GemModel::GetDownloadStatus(modelIndex) == GemInfo::DownloadStatus::NotDownloaded)
{ {
m_downloadController->AddGemDownload(GemModel::GetName(modelIndex)); 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);
} }
} }
@ -300,7 +301,7 @@ namespace O3DE::ProjectManager
} }
QModelIndex proxyIndex = m_proxyModel->mapFromSource(modelIndex); QModelIndex proxyIndex = m_proxyModel->mapFromSource(modelIndex);
m_proxyModel->GetSelectionModel()->select(proxyIndex, QItemSelectionModel::ClearAndSelect); m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect);
m_gemListView->scrollTo(proxyIndex); m_gemListView->scrollTo(proxyIndex);
} }
@ -362,6 +363,9 @@ namespace O3DE::ProjectManager
{ {
const QString selectedGemPath = m_gemModel->GetPath(modelIndex); const QString selectedGemPath = m_gemModel->GetPath(modelIndex);
// Remove gem from gems to be added
GemModel::SetIsAdded(*m_gemModel, modelIndex, false);
// Unregister the gem // Unregister the gem
auto unregisterResult = PythonBindingsInterface::Get()->UnregisterGem(selectedGemPath); auto unregisterResult = PythonBindingsInterface::Get()->UnregisterGem(selectedGemPath);
if (!unregisterResult) if (!unregisterResult)
@ -370,8 +374,10 @@ namespace O3DE::ProjectManager
} }
else else
{ {
const QString selectedGemName = m_gemModel->GetName(modelIndex);
// Remove gem from model // Remove gem from model
m_gemModel->removeRow(modelIndex.row()); m_gemModel->RemoveGem(modelIndex);
// Delete uninstalled gem directory // Delete uninstalled gem directory
if (!ProjectUtils::DeleteProjectFiles(selectedGemPath, /*force*/true)) if (!ProjectUtils::DeleteProjectFiles(selectedGemPath, /*force*/true))
@ -382,6 +388,11 @@ namespace O3DE::ProjectManager
// Show undownloaded remote gem again // Show undownloaded remote gem again
Refresh(); Refresh();
// Select remote gem
QModelIndex remoteGemIndex = m_gemModel->FindIndexByNameString(selectedGemName);
QModelIndex proxyIndex = m_proxyModel->mapFromSource(remoteGemIndex);
m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect);
} }
} }
} }
@ -564,7 +575,8 @@ namespace O3DE::ProjectManager
if (succeeded) if (succeeded)
{ {
// refresh the information for downloaded gems // refresh the information for downloaded gems
const AZ::Outcome<QVector<GemInfo>, AZStd::string>& allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(m_projectPath); const AZ::Outcome<QVector<GemInfo>, AZStd::string>& allGemInfosResult =
PythonBindingsInterface::Get()->GetAllGemInfos(m_projectPath);
if (allGemInfosResult.IsSuccess()) if (allGemInfosResult.IsSuccess())
{ {
// we should find the gem name now in all gem infos // we should find the gem name now in all gem infos
@ -572,15 +584,33 @@ namespace O3DE::ProjectManager
{ {
if (gemInfo.m_name == gemName) if (gemInfo.m_name == gemName)
{ {
QModelIndex index = m_gemModel->FindIndexByNameString(gemName); QModelIndex oldIndex = m_gemModel->FindIndexByNameString(gemName);
if (index.isValid()) if (oldIndex.isValid())
{ {
m_proxyModel->setData(m_proxyModel->mapFromSource(index), GemInfo::DownloadSuccessful, GemModel::RoleDownloadStatus); // Check if old gem is selected
m_gemModel->setData(index, gemInfo.m_path, GemModel::RolePath); bool oldGemSelected = false;
m_gemModel->setData(index, gemInfo.m_path, GemModel::RoleDirectoryLink); 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;
} }
} }
} }
@ -590,7 +620,7 @@ namespace O3DE::ProjectManager
QModelIndex index = m_gemModel->FindIndexByNameString(gemName); QModelIndex index = m_gemModel->FindIndexByNameString(gemName);
if (index.isValid()) if (index.isValid())
{ {
m_proxyModel->setData(m_proxyModel->mapFromSource(index), GemInfo::DownloadFailed, GemModel::RoleDownloadStatus); GemModel::SetDownloadStatus(*m_gemModel, index, GemInfo::DownloadFailed);
} }
} }
} }

@ -26,14 +26,14 @@ namespace O3DE::ProjectManager
return m_selectionModel; return m_selectionModel;
} }
void GemModel::AddGem(const GemInfo& gemInfo) QModelIndex GemModel::AddGem(const GemInfo& gemInfo)
{ {
if (FindIndexByNameString(gemInfo.m_name).isValid()) if (FindIndexByNameString(gemInfo.m_name).isValid())
{ {
// do not add gems with duplicate names // 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 // 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()); AZ_TracePrintf("GemModel", "Ignoring duplicate gem: %s", gemInfo.m_name.toUtf8().constData());
return; return QModelIndex();
} }
QStandardItem* item = new QStandardItem(); QStandardItem* item = new QStandardItem();
@ -67,6 +67,22 @@ namespace O3DE::ProjectManager
const QModelIndex modelIndex = index(rowCount()-1, 0); const QModelIndex modelIndex = index(rowCount()-1, 0);
m_nameToIndexMap[gemInfo.m_name] = modelIndex; 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() void GemModel::Clear()
@ -391,11 +407,11 @@ namespace O3DE::ProjectManager
// Select a valid row if currently selected row was removed // Select a valid row if currently selected row was removed
if (selectedRowRemoved) if (selectedRowRemoved)
{ {
for (const QModelIndex& index : m_nameToIndexMap) for (const QModelIndex& index : m_nameToIndexMap)
{ {
if (index.isValid()) if (index.isValid())
{ {
GetSelectionModel()->select(index, QItemSelectionModel::ClearAndSelect); GetSelectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
break; break;
} }
} }

@ -55,7 +55,9 @@ namespace O3DE::ProjectManager
RoleRepoUri RoleRepoUri
}; };
void AddGem(const GemInfo& gemInfo); QModelIndex AddGem(const GemInfo& gemInfo);
void RemoveGem(const QModelIndex& modelIndex);
void RemoveGem(const QString& gemName);
void Clear(); void Clear();
void UpdateGemDependencies(); void UpdateGemDependencies();

@ -75,7 +75,7 @@ namespace O3DE::ProjectManager
// Select the first entry after everything got correctly sized // Select the first entry after everything got correctly sized
QTimer::singleShot(200, [=]{ QTimer::singleShot(200, [=]{
QModelIndex firstModelIndex = m_gemRepoListView->model()->index(0,0); QModelIndex firstModelIndex = m_gemRepoListView->model()->index(0,0);
m_gemRepoListView->selectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect); m_gemRepoListView->selectionModel()->setCurrentIndex(firstModelIndex, QItemSelectionModel::ClearAndSelect);
}); });
} }

@ -8,7 +8,11 @@
#include <ProjectButtonWidget.h> #include <ProjectButtonWidget.h>
#include <ProjectManagerDefs.h> #include <ProjectManagerDefs.h>
#include <ProjectUtils.h>
#include <ProjectManager_Traits_Platform.h>
#include <AzQtComponents/Utilities/DesktopUtilities.h> #include <AzQtComponents/Utilities/DesktopUtilities.h>
#include <AzCore/IO/SystemFile.h>
#include <AzCore/IO/Path/Path.h>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QHBoxLayout> #include <QHBoxLayout>
@ -23,6 +27,7 @@
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
#include <QDesktopServices> #include <QDesktopServices>
#include <QMessageBox>
namespace O3DE::ProjectManager namespace O3DE::ProjectManager
{ {
@ -205,6 +210,29 @@ namespace O3DE::ProjectManager
{ {
AzQtComponents::ShowFileOnDesktop(m_projectInfo.m_path); 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->addSeparator();
menu->addAction(tr("Duplicate"), this, [this]() { emit CopyProject(m_projectInfo); }); menu->addAction(tr("Duplicate"), this, [this]() { emit CopyProject(m_projectInfo); });
menu->addSeparator(); menu->addSeparator();

@ -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)); return AZ::Failure(QObject::tr("Process for command '%1' timed out at %2 seconds").arg(cmd).arg(commandTimeoutSeconds));
} }
int resultCode = execProcess.exitCode(); int resultCode = execProcess.exitCode();
QString resultOutput = execProcess.readAllStandardOutput();
if (resultCode != 0) 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); return AZ::Success(resultOutput);
} }

@ -68,6 +68,15 @@ namespace O3DE::ProjectManager
AZ::Outcome<QString, QString> GetProjectBuildPath(const QString& projectPath); AZ::Outcome<QString, QString> GetProjectBuildPath(const QString& projectPath);
AZ::Outcome<void, QString> OpenCMakeGUI(const QString& projectPath); AZ::Outcome<void, QString> OpenCMakeGUI(const QString& projectPath);
AZ::Outcome<QString, QString> RunGetPythonScript(const QString& enginePath); AZ::Outcome<QString, QString> 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<QString, QString> CreateDesktopShortcut(const QString& filename, const QString& targetPath, const QStringList& arguments);
AZ::IO::FixedMaxPath GetEditorDirectory(); AZ::IO::FixedMaxPath GetEditorDirectory();

@ -68,7 +68,7 @@ namespace AWSCore
}, },
"AccountIdString": { "AccountIdString": {
"type": "string", "type": "string",
"pattern": "^[0-9]{12}$|EMPTY" "pattern": "^[0-9]{12}$|EMPTY|^$"
}, },
"NonEmptyString": { "NonEmptyString": {
"type": "string", "type": "string",

@ -59,6 +59,34 @@ R"({
"Version": "1.0.0" "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[] = static constexpr const char TEST_INVALID_RESOURCE_MAPPING_CONFIG_FILE[] =
R"({ R"({
"AWSResourceMappings": {}, "AWSResourceMappings": {},
@ -237,6 +265,21 @@ TEST_F(AWSResourceMappingManagerTest, ActivateManager_ParseValidConfigFile_Confi
EXPECT_TRUE(actualEbusCalls == testThreadNumber); 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) TEST_F(AWSResourceMappingManagerTest, DeactivateManager_AfterActivatingWithValidConfigFile_ConfigDataGetCleanedUp)
{ {
CreateTestConfigFile(TEST_VALID_RESOURCE_MAPPING_CONFIG_FILE); CreateTestConfigFile(TEST_VALID_RESOURCE_MAPPING_CONFIG_FILE);

@ -82,7 +82,7 @@ namespace AZ
// Register Shader Asset Builder // Register Shader Asset Builder
AssetBuilderSDK::AssetBuilderDesc shaderAssetBuilderDescriptor; AssetBuilderSDK::AssetBuilderDesc shaderAssetBuilderDescriptor;
shaderAssetBuilderDescriptor.m_name = "Shader Asset Builder"; 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 // .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_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern( AZStd::string::format("*.%s", RPI::ShaderSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard));
shaderAssetBuilderDescriptor.m_busId = azrtti_typeid<ShaderAssetBuilder>(); shaderAssetBuilderDescriptor.m_busId = azrtti_typeid<ShaderAssetBuilder>();
@ -108,7 +108,7 @@ namespace AZ
shaderVariantAssetBuilderDescriptor.m_name = "Shader Variant Asset Builder"; shaderVariantAssetBuilderDescriptor.m_name = "Shader Variant Asset Builder";
// Both "Shader Variant Asset Builder" and "Shader Asset Builder" produce ShaderVariantAsset products. If you update // 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". // 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_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern(AZStd::string::format("*.%s", RPI::ShaderVariantListSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard));
shaderVariantAssetBuilderDescriptor.m_busId = azrtti_typeid<ShaderVariantAssetBuilder>(); shaderVariantAssetBuilderDescriptor.m_busId = azrtti_typeid<ShaderVariantAssetBuilder>();
shaderVariantAssetBuilderDescriptor.m_createJobFunction = AZStd::bind(&ShaderVariantAssetBuilder::CreateJobs, &m_shaderVariantAssetBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); shaderVariantAssetBuilderDescriptor.m_createJobFunction = AZStd::bind(&ShaderVariantAssetBuilder::CreateJobs, &m_shaderVariantAssetBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);

@ -162,7 +162,7 @@ namespace AZ
// has the same value, because later the ShaderVariantTreeAsset job will fetch this value from the local ShaderAsset // 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 // which could cross platforms (i.e. building an android ShaderVariantTreeAsset on PC would fetch the tiemstamp from
// the PC's ShaderAsset). // 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. // 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. // and the macro options to preprocess.
@ -229,8 +229,8 @@ namespace AZ
} // for all request.m_enabledPlatforms } // for all request.m_enabledPlatforms
AZ_TracePrintf( AZ_TracePrintf(
ShaderAssetBuilderName, "CreateJobs for %s took %llu microseconds", shaderAssetSourceFileFullPath.c_str(), ShaderAssetBuilderName, "CreateJobs for %s took %llu milliseconds", shaderAssetSourceFileFullPath.c_str(),
AZStd::GetTimeNowMicroSecond() - shaderAssetBuildTimestamp); AZStd::GetTimeUTCMilliSecond() - shaderAssetBuildTimestamp);
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success; response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
} }
@ -355,8 +355,8 @@ namespace AZ
return; return;
} }
// Get the time stamp string as sys_time_t, and also convert back to string to make sure it was converted correctly. // Get the time stamp string as u64, and also convert back to string to make sure it was converted correctly.
AZStd::sys_time_t shaderAssetBuildTimestamp = 0; AZ::u64 shaderAssetBuildTimestamp = 0;
auto shaderAssetBuildTimestampIterator = request.m_jobDescription.m_jobParameters.find(ShaderAssetBuildTimestampParam); auto shaderAssetBuildTimestampIterator = request.m_jobDescription.m_jobParameters.find(ShaderAssetBuildTimestampParam);
if (shaderAssetBuildTimestampIterator != request.m_jobDescription.m_jobParameters.end()) if (shaderAssetBuildTimestampIterator != request.m_jobDescription.m_jobParameters.end())
{ {

@ -765,7 +765,7 @@ namespace AZ
return; return;
} }
const AZStd::sys_time_t shaderVariantAssetBuildTimestamp = AZStd::GetTimeNowMicroSecond(); const AZ::u64 shaderVariantAssetBuildTimestamp = AZStd::GetTimeUTCMilliSecond();
auto supervariantList = ShaderBuilderUtility::GetSupervariantListFromShaderSourceData(shaderSourceDescriptor); auto supervariantList = ShaderBuilderUtility::GetSupervariantListFromShaderSourceData(shaderSourceDescriptor);

@ -38,7 +38,7 @@ namespace AZ
const AZStd::string& m_tempDirPath; const AZStd::string& m_tempDirPath;
//! Used to synchronize versions of the ShaderAsset and ShaderVariantAsset, //! Used to synchronize versions of the ShaderAsset and ShaderVariantAsset,
//! especially during hot-reload. A (ShaderVariantAsset.timestamp) >= (ShaderAsset.timestamp). //! 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::ShaderSourceData& m_shaderSourceDataDescriptor;
const RPI::ShaderOptionGroupLayout& m_shaderOptionGroupLayout; const RPI::ShaderOptionGroupLayout& m_shaderOptionGroupLayout;
const MapOfStringToStageType& m_shaderEntryPoints; const MapOfStringToStageType& m_shaderEntryPoints;

@ -166,7 +166,7 @@ float DirectionalLightShadow::GetThickness(uint lightIndex, float3 shadowCoords[
bool2 DirectionalLightShadow::IsShadowed(float3 shadowCoord, uint indexOfCascade) bool2 DirectionalLightShadow::IsShadowed(float3 shadowCoord, uint indexOfCascade)
{ {
static const float PixelMargin = 1.5; // avoiding artifact between cascade levels. 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. // size is the shadowap's width and height.
const uint size = ViewSrg::m_directionalLightShadows[m_lightIndex].m_shadowmapSize; const uint size = ViewSrg::m_directionalLightShadows[m_lightIndex].m_shadowmapSize;
@ -210,8 +210,8 @@ float DirectionalLightShadow::GetVisibilityFromLightNoFilter()
float DirectionalLightShadow::GetVisibilityFromLightPcf() 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 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 size = ViewSrg::m_directionalLightShadows[m_lightIndex].m_shadowmapSize;
const uint cascadeCount = ViewSrg::m_directionalLightShadows[m_lightIndex].m_cascadeCount; const uint cascadeCount = ViewSrg::m_directionalLightShadows[m_lightIndex].m_cascadeCount;

@ -1248,6 +1248,32 @@ namespace AZ
property.m_shadowmapViewNeedsUpdate = true; 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<float>(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) void DirectionalLightFeatureProcessor::UpdateShadowmapViews(LightHandle handle)
{ {
ShadowProperty& property = m_shadowProperties.GetData(handle.GetIndex()); ShadowProperty& property = m_shadowProperties.GetData(handle.GetIndex());
@ -1259,18 +1285,26 @@ namespace AZ
for (auto& segmentIt : property.m_segments) 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) for (uint16_t cascadeIndex = 0; cascadeIndex < segmentIt.second.size(); ++cascadeIndex)
{ {
const Aabb viewAabb = CalculateShadowViewAabb( const Aabb viewAabb = CalculateShadowViewAabb(handle, segmentIt.first, cascadeIndex, lightTransform);
handle, segmentIt.first, cascadeIndex, lightTransform);
if (viewAabb.IsValid() && viewAabb.IsFinite()) 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(); Matrix4x4 viewToClipMatrix = Matrix4x4::CreateIdentity();
MakeOrthographicMatrixRH(viewToClipMatrix, MakeOrthographicMatrixRH(
viewAabb.GetMin().GetElement(0), viewAabb.GetMax().GetElement(0), viewToClipMatrix, snappedAabbMin.GetElement(0), snappedAabbMax.GetElement(0), snappedAabbMin.GetElement(2),
viewAabb.GetMin().GetElement(2), viewAabb.GetMax().GetElement(2), snappedAabbMax.GetElement(2), cascadeNear, cascadeFar);
viewAabb.GetMin().GetElement(1), viewAabb.GetMax().GetElement(1));
CascadeSegment& segment = segmentIt.second[cascadeIndex]; CascadeSegment& segment = segmentIt.second[cascadeIndex];
segment.m_aabb = viewAabb; segment.m_aabb = viewAabb;

@ -341,6 +341,9 @@ namespace AZ
//! This draws bounding boxes of cascades. //! This draws bounding boxes of cascades.
void DrawCascadeBoundingBoxes(LightHandle handle); void DrawCascadeBoundingBoxes(LightHandle handle);
float GetShadowmapSizeFromCameraView(const LightHandle handle, const RPI::View* cameraView) const;
void SnapAabbToPixelIncrements(const float invShadowmapSize, Vector3& orthoMin, Vector3& orthoMax);
IndexedDataVector<ShadowProperty> m_shadowProperties; IndexedDataVector<ShadowProperty> m_shadowProperties;
// [GFX TODO][ATOM-2012] shadow for multiple directional lights // [GFX TODO][ATOM-2012] shadow for multiple directional lights
LightHandle m_shadowingLightHandle; LightHandle m_shadowingLightHandle;

@ -33,12 +33,20 @@ namespace AZ
ID3D12DeviceX* dx12Device = device.GetDevice(); ID3D12DeviceX* dx12Device = device.GetDevice();
m_copyQueue = CommandQueue::Create(); m_copyQueue = CommandQueue::Create();
// The async upload queue should always use the primary copy queue,
// but because this change is being made in the stabilization branch
// we will put it behind a define out of an abundance of caution, and
// change it to always do this once the change gets back to development.
#if defined(AZ_DX12_USE_PRIMARY_COPY_QUEUE_FOR_ASYNC_UPLOAD_QUEUE)
m_copyQueue = &device.GetCommandQueueContext().GetCommandQueue(RHI::HardwareQueueClass::Copy);
#else
// Make a secondary Copy queue, the primary queue is owned by the CommandQueueContext // Make a secondary Copy queue, the primary queue is owned by the CommandQueueContext
CommandQueueDescriptor commandQueueDesc; CommandQueueDescriptor commandQueueDesc;
commandQueueDesc.m_hardwareQueueClass = RHI::HardwareQueueClass::Copy; commandQueueDesc.m_hardwareQueueClass = RHI::HardwareQueueClass::Copy;
commandQueueDesc.m_hardwareQueueSubclass = HardwareQueueSubclass::Secondary; commandQueueDesc.m_hardwareQueueSubclass = HardwareQueueSubclass::Secondary;
m_copyQueue->Init(device, commandQueueDesc); m_copyQueue->Init(device, commandQueueDesc);
#endif // defined(AZ_DX12_ASYNC_UPLOAD_QUEUE_USE_PRIMARY_COPY_QUEUE)
m_uploadFence.Init(dx12Device, RHI::FenceState::Signaled); m_uploadFence.Init(dx12Device, RHI::FenceState::Signaled);
for (size_t i = 0; i < descriptor.m_frameCount; ++i) for (size_t i = 0; i < descriptor.m_frameCount; ++i)

@ -160,6 +160,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
Gem::Atom_RPI.Public Gem::Atom_RPI.Public
Gem::Atom_RHI.Public Gem::Atom_RHI.Public
Gem::Atom_RPI.Edit Gem::Atom_RPI.Edit
Gem::Atom_Utils.TestUtils.Static
) )
ly_add_googletest( ly_add_googletest(
NAME Gem::Atom_RPI.Tests NAME Gem::Atom_RPI.Tests

@ -209,10 +209,6 @@ namespace AZ
//! Traversal will stop once all properties have been enumerated or the callback function returns false //! Traversal will stop once all properties have been enumerated or the callback function returns false
void EnumeratePropertiesInDisplayOrder(const EnumeratePropertiesCallback& callback) const; void EnumeratePropertiesInDisplayOrder(const EnumeratePropertiesCallback& callback) const;
//! Convert the property value into the format that will be stored in the source data
//! This is primarily needed to support conversions of special types like enums and images
bool ConvertPropertyValueToSourceDataFormat(const AZ::Name& propertyId, const PropertyDefinition& propertyDefinition, MaterialPropertyValue& propertyValue) const;
Outcome<Data::Asset<MaterialTypeAsset>> CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath = "", bool elevateWarnings = true) const; Outcome<Data::Asset<MaterialTypeAsset>> CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath = "", bool elevateWarnings = true) const;
//! Possibly renames @propertyId based on the material version update steps. //! Possibly renames @propertyId based on the material version update steps.

@ -40,7 +40,7 @@ namespace AZ
//! Set the timestamp value when the ProcessJob() started. //! Set the timestamp value when the ProcessJob() started.
//! This is needed to synchronize between the ShaderAsset and ShaderVariantAsset when hot-reloading shaders. //! This is needed to synchronize between the ShaderAsset and ShaderVariantAsset when hot-reloading shaders.
//! The idea is that this timestamp must be greater or equal than the ShaderAsset. //! The idea is that this timestamp must be greater or equal than the ShaderAsset.
void SetBuildTimestamp(AZStd::sys_time_t buildTimestamp); void SetBuildTimestamp(AZ::u64 buildTimestamp);
//! Assigns a shaderStageFunction, which contains the byte code, to the slot dictated by the shader stage. //! Assigns a shaderStageFunction, which contains the byte code, to the slot dictated by the shader stage.
void SetShaderFunction(RHI::ShaderStage shaderStage, RHI::Ptr<RHI::ShaderStageFunction> shaderStageFunction); void SetShaderFunction(RHI::ShaderStage shaderStage, RHI::Ptr<RHI::ShaderStageFunction> shaderStageFunction);

@ -294,7 +294,7 @@ namespace AZ
Name m_drawListName; Name m_drawListName;
//! Use to synchronize versions of the ShaderAsset and ShaderVariantTreeAsset, especially during hot-reload. //! Use to synchronize versions of the ShaderAsset and ShaderVariantTreeAsset, especially during hot-reload.
AZStd::sys_time_t m_shaderAssetBuildTimestamp = 0; AZ::u64 m_shaderAssetBuildTimestamp = 0;
/////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////

@ -61,7 +61,7 @@ namespace AZ
//! Return the timestamp when this asset was built, and it must be >= than the timestamp of the main ShaderAsset. //! Return the timestamp when this asset was built, and it must be >= than the timestamp of the main ShaderAsset.
//! This is used to synchronize versions of the ShaderAsset and ShaderVariantAsset, especially during hot-reload. //! This is used to synchronize versions of the ShaderAsset and ShaderVariantAsset, especially during hot-reload.
AZStd::sys_time_t GetBuildTimestamp() const; AZ::u64 GetBuildTimestamp() const;
bool IsRootVariant() const { return m_stableId == RPI::RootShaderVariantStableId; } bool IsRootVariant() const { return m_stableId == RPI::RootShaderVariantStableId; }
@ -80,7 +80,7 @@ namespace AZ
AZStd::array<RHI::Ptr<RHI::ShaderStageFunction>, RHI::ShaderStageCount> m_functionsByStage; AZStd::array<RHI::Ptr<RHI::ShaderStageFunction>, RHI::ShaderStageCount> m_functionsByStage;
//! Used to synchronize versions of the ShaderAsset and ShaderVariantAsset, especially during hot-reload. //! Used to synchronize versions of the ShaderAsset and ShaderVariantAsset, especially during hot-reload.
AZStd::sys_time_t m_buildTimestamp = 0; AZ::u64 m_buildTimestamp = 0;
}; };
class ShaderVariantAssetHandler final class ShaderVariantAssetHandler final

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save