Merge remote-tracking branch 'origin/stabilization/2110' into viewport/EditorModeUIBackButton
This commit is contained in:
@@ -62164,7 +62164,7 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro
|
||||
<message id="HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGADDED_OUTPUT0_NAME">
|
||||
<source>HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGADDED_OUTPUT0_NAME</source>
|
||||
<comment>Simple Type: EntityID C++ Type: const EntityId&</comment>
|
||||
<translation type="unfinished">Entity</translation>
|
||||
<translation type="unfinished">EntityID</translation>
|
||||
</message>
|
||||
<message id="HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGADDED_OUTPUT0_TOOLTIP">
|
||||
<source>HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGADDED_OUTPUT0_TOOLTIP</source>
|
||||
@@ -62202,7 +62202,7 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro
|
||||
<message id="HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGREMOVED_OUTPUT0_NAME">
|
||||
<source>HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGREMOVED_OUTPUT0_NAME</source>
|
||||
<comment>Simple Type: EntityID C++ Type: const EntityId&</comment>
|
||||
<translation type="unfinished">Entity</translation>
|
||||
<translation type="unfinished">EntityId</translation>
|
||||
</message>
|
||||
<message id="HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGREMOVED_OUTPUT0_TOOLTIP">
|
||||
<source>HANDLER_TAGGLOBALNOTIFICATIONBUS_ONENTITYTAGREMOVED_OUTPUT0_TOOLTIP</source>
|
||||
@@ -81852,7 +81852,7 @@ The element is removed from its current parent and added as a child of the new p
|
||||
<message id="HANDLER_SPAWNERCOMPONENTNOTIFICATIONBUS_ONENTITYSPAWNED_OUTPUT1_NAME">
|
||||
<source>HANDLER_SPAWNERCOMPONENTNOTIFICATIONBUS_ONENTITYSPAWNED_OUTPUT1_NAME</source>
|
||||
<comment>Simple Type: EntityID C++ Type: const EntityId&</comment>
|
||||
<translation type="unfinished">Entity</translation>
|
||||
<translation type="unfinished">EntityID</translation>
|
||||
</message>
|
||||
<message id="HANDLER_SPAWNERCOMPONENTNOTIFICATIONBUS_ONENTITYSPAWNED_OUTPUT1_TOOLTIP">
|
||||
<source>HANDLER_SPAWNERCOMPONENTNOTIFICATIONBUS_ONENTITYSPAWNED_OUTPUT1_TOOLTIP</source>
|
||||
@@ -89198,7 +89198,7 @@ The element is removed from its current parent and added as a child of the new p
|
||||
<message id="HANDLER_ENTITYBUS_ONENTITYACTIVATED_OUTPUT0_NAME">
|
||||
<source>HANDLER_ENTITYBUS_ONENTITYACTIVATED_OUTPUT0_NAME</source>
|
||||
<comment>Simple Type: EntityID C++ Type: const EntityId&</comment>
|
||||
<translation type="unfinished">Entity</translation>
|
||||
<translation type="unfinished">EntityID</translation>
|
||||
</message>
|
||||
<message id="HANDLER_ENTITYBUS_ONENTITYACTIVATED_OUTPUT0_TOOLTIP">
|
||||
<source>HANDLER_ENTITYBUS_ONENTITYACTIVATED_OUTPUT0_TOOLTIP</source>
|
||||
@@ -89236,7 +89236,7 @@ The element is removed from its current parent and added as a child of the new p
|
||||
<message id="HANDLER_ENTITYBUS_ONENTITYDEACTIVATED_OUTPUT0_NAME">
|
||||
<source>HANDLER_ENTITYBUS_ONENTITYDEACTIVATED_OUTPUT0_NAME</source>
|
||||
<comment>Simple Type: EntityID C++ Type: const EntityId&</comment>
|
||||
<translation type="unfinished">Entity</translation>
|
||||
<translation type="unfinished">EntityID</translation>
|
||||
</message>
|
||||
<message id="HANDLER_ENTITYBUS_ONENTITYDEACTIVATED_OUTPUT0_TOOLTIP">
|
||||
<source>HANDLER_ENTITYBUS_ONENTITYDEACTIVATED_OUTPUT0_TOOLTIP</source>
|
||||
|
||||
@@ -145,7 +145,7 @@
|
||||
<Class name="float" field="ProjectorNearPlane" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}" value="0.0000000" specializationTypeId="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
|
||||
<Class name="AzFramework::SimpleAssetReference<LmbrCentral::TextureAsset>" field="ProjectorTexture" type="{68E92460-5C0C-4031-9620-6F1A08763243}" version="1" specializationTypeId="{68E92460-5C0C-4031-9620-6F1A08763243}">
|
||||
<Class name="SimpleAssetReferenceBase" field="BaseClass1" type="{E16CA6C5-5C78-4AD9-8E9B-F8C1FB4D1DB8}" version="1" specializationTypeId="{E16CA6C5-5C78-4AD9-8E9B-F8C1FB4D1DB8}">
|
||||
<Class name="AZStd::string" field="AssetPath" type="{EF8FF807-DDEE-4EB0-B678-4CA3A2C490A4}" value="engineassets/textures/defaults/spot_default.dds" specializationTypeId="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
|
||||
<Class name="AZStd::string" field="AssetPath" type="{EF8FF807-DDEE-4EB0-B678-4CA3A2C490A4}" value="" specializationTypeId="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
|
||||
</Class>
|
||||
</Class>
|
||||
<Class name="AzFramework::SimpleAssetReference<LmbrCentral::MaterialAsset>" field="ProjectorMaterial" type="{B7B8ECC7-FF89-4A76-A50E-4C6CA2B6E6B4}" version="1" specializationTypeId="{B7B8ECC7-FF89-4A76-A50E-4C6CA2B6E6B4}">
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:cf441215a769562f88aa20711aee68dadcbf02597d1e2270547055e8e6aec6a3
|
||||
size 77
|
||||
@@ -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",
|
||||
},
|
||||
}
|
||||
+54
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -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())
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
# ******
|
||||
|
||||
+55
-222
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>General Availability</string>
|
||||
<string>Stable 21.11</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<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()
|
||||
|
||||
+10
-14
@@ -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();
|
||||
|
||||
@@ -212,6 +212,7 @@ public:
|
||||
void OnEditFetch();
|
||||
void OnFileExportToGameNoSurfaceTexture();
|
||||
void OnViewSwitchToGame();
|
||||
void OnViewSwitchToGameFullScreen();
|
||||
void OnViewDeploy();
|
||||
void DeleteSelectedEntities(bool includeDescendants);
|
||||
void OnMoveObject();
|
||||
|
||||
@@ -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/IBaseLibraryManager.h>
|
||||
#include <IMaterial.h>
|
||||
|
||||
|
||||
@@ -60,7 +60,6 @@ struct IFileUtil
|
||||
EFILE_TYPE_GEOMETRY,
|
||||
EFILE_TYPE_TEXTURE,
|
||||
EFILE_TYPE_SOUND,
|
||||
EFILE_TYPE_GEOMCACHE,
|
||||
EFILE_TYPE_LAST,
|
||||
};
|
||||
|
||||
|
||||
@@ -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<QAction*> actions = { m_actionManager->GetAction(ID_VIEW_SWITCHTOGAME), m_actionManager->GetAction(ID_VIEW_SWITCHTOGAME_FULLSCREEN) };
|
||||
AZStd::vector<QAction*> 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);
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -131,7 +131,6 @@ public:
|
||||
enum EAttachmentType
|
||||
{
|
||||
eAT_Pivot,
|
||||
eAT_GeomCacheNode,
|
||||
eAT_CharacterBone,
|
||||
};
|
||||
|
||||
|
||||
@@ -608,7 +608,7 @@ bool CObjectManager::AddObject(CBaseObject* obj)
|
||||
if (CEntityObject* entityObj = qobject_cast<CEntityObject*>(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);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
#include <LmbrCentral/Rendering/LensFlareAsset.h>
|
||||
#include <LmbrCentral/Rendering/MeshAsset.h>
|
||||
#include <LmbrCentral/Rendering/MaterialAsset.h>
|
||||
|
||||
#include <AzCore/Memory/Memory.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;
|
||||
EBUS_EVENT_RESULT(serializeContext, AZ::ComponentApplicationBus, GetSerializeContext);
|
||||
AZ_Assert(serializeContext, "Failed to acquire application serialize context.");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>General Availability</string>
|
||||
<string>Stable 21.11</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
#include <Atom/RPI.Public/View.h>
|
||||
#include <Atom/RPI.Reflect/System/RenderPipelineDescriptor.h>
|
||||
#include <PostProcess/PostProcessFeatureProcessor.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/Math/MatrixUtils.h>
|
||||
#include <AzCore/Name/Name.h>
|
||||
@@ -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<AZ::Render::PostProcessFeatureProcessor>())
|
||||
{
|
||||
// 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<AZ::Render::PostProcessFeatureProcessor>())
|
||||
{
|
||||
// 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<AZ::Render::PostProcessFeatureProcessor>())
|
||||
{
|
||||
fp->SetViewAlias(m_view, targetView);
|
||||
m_targetView = targetView;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_view->SetCameraTransform(cameraTransform);
|
||||
m_view->SetViewToClipMatrix(cameraProjection);
|
||||
}
|
||||
|
||||
@@ -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<AZStd::string> m_passHierarchy; //!< Pass hierarchy (includes pipelineName and CopyToSwapChain).
|
||||
CaptureFinishedCallback m_captureFinishedCallback; //!< Stored callback called from OnCaptureFinished.
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzFramework/Windowing/WindowBus.h>
|
||||
#include <Atom/RPI.Public/ViewProviderBus.h>
|
||||
|
||||
// Qt
|
||||
#include <QAction>
|
||||
@@ -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<float>(width), static_cast<float>(height)));
|
||||
TrackView::ProjectionFromCameraEntityId(activeCameraEntityId, aznumeric_cast<float>(width), aznumeric_cast<float>(height)),
|
||||
view);
|
||||
}
|
||||
|
||||
CSequenceBatchRenderDialog::CSequenceBatchRenderDialog(float fps, QWidget* pParent /* = nullptr */)
|
||||
|
||||
@@ -54,8 +54,8 @@
|
||||
#include <Shellapi.h>
|
||||
#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()
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<unsigned int>(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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,12 @@ namespace AZ
|
||||
|
||||
if (!s_instance)
|
||||
{
|
||||
s_instance = AZ::Environment::CreateVariable<NameDictionary>(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<NameDictionary>(NameDictionaryInstanceName, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +55,12 @@ namespace AZ
|
||||
|
||||
if (!s_instance)
|
||||
{
|
||||
s_instance = Environment::FindVariable<NameDictionary>(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<NameDictionary>(NameDictionaryInstanceName, true, false);
|
||||
}
|
||||
|
||||
return s_instance.IsConstructed();
|
||||
|
||||
@@ -104,6 +104,8 @@ namespace AZ
|
||||
->HandlesType<AZStd::variant>();
|
||||
jsonContext->Serializer<JsonOptionalSerializer>()
|
||||
->HandlesType<AZStd::optional>();
|
||||
jsonContext->Serializer<JsonBitsetSerializer>()
|
||||
->HandlesType<AZStd::bitset>();
|
||||
|
||||
MathReflect(jsonContext);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -30,8 +30,13 @@ namespace AZ
|
||||
|
||||
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.
|
||||
m_taskExecutor = aznew TaskExecutor(Threading::CalcNumWorkerThreads(cl_taskGraphThreadsConcurrencyRatio, cl_taskGraphThreadsMinNumber, cl_taskGraphThreadsNumReserved));
|
||||
m_taskExecutor = aznew TaskExecutor(numberOfWorkerThreads);
|
||||
TaskExecutor::SetInstance(m_taskExecutor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<AssetWithAssetReference> asset1 =
|
||||
m_testAssetManager->GetAsset(assetUuid, azrtti_typeid<AssetWithAssetReference>(), AZ::Data::AssetLoadBehavior::PreLoad);
|
||||
@@ -678,7 +678,7 @@ namespace UnitTest
|
||||
while (threadCount > 0 && !timedOut)
|
||||
{
|
||||
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.";
|
||||
@@ -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();
|
||||
|
||||
@@ -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 */) {}
|
||||
};
|
||||
|
||||
@@ -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<Internal::EditorEventsBusHandler>()
|
||||
->Event("NotifyRegisterViews", &EditorEvents::NotifyRegisterViews)
|
||||
->Event("NotifyEditorInitialized", &EditorEvents::NotifyEditorInitialized)
|
||||
;
|
||||
|
||||
behaviorContext->EBus<ViewPaneCallbackBus>("ViewPaneCallbackBus")
|
||||
|
||||
-5
@@ -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");
|
||||
|
||||
+5
-2
@@ -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<AzToolsFramework::QWidgetSavedState>(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);
|
||||
|
||||
+2
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -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()
|
||||
|
||||
+55
-32
@@ -45,6 +45,7 @@ AZ_POP_DISABLE_WARNING
|
||||
#include <AzToolsFramework/AssetBrowser/EBusFindAssetTypeByName.h>
|
||||
#include <AzToolsFramework/ComponentMode/ComponentModeDelegate.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusPublicInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
|
||||
#include <AzToolsFramework/Slice/SliceDataFlagsCommand.h>
|
||||
#include <AzToolsFramework/Slice/SliceMetadataEntityContextBus.h>
|
||||
@@ -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<AzToolsFramework::Prefab::PrefabFocusPublicInterface>::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<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.
|
||||
AssetBrowser::AssetBrowserEntry::ForEachEntryInMimeData<AssetBrowser::ProductAssetBrowserEntry>(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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+7
-5
@@ -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;
|
||||
|
||||
+15
-35
@@ -29,6 +29,7 @@
|
||||
#include <AzToolsFramework/Maths/TransformUtils.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusPublicInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabFocusPublicInterface.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorLockComponentBus.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorVisibilityBus.h>
|
||||
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
|
||||
@@ -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<AzToolsFramework::Prefab::PrefabFocusPublicInterface>::Get())
|
||||
{
|
||||
AzFramework::EntityContextId editorEntityContextId = GetEntityContextId();
|
||||
if (AZ::EntityId focusRoot = prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId); focusRoot.IsValid())
|
||||
{
|
||||
m_selectedEntityIds.erase(focusRoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EditorTransformComponentSelection::OnTransformChanged(
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -58,7 +58,6 @@ protected:
|
||||
AZStd::unique_ptr<AssetProcessorManager_Test> m_assetProcessorManager;
|
||||
AZStd::unique_ptr<AssetProcessor::MockApplicationManager> m_mockApplicationManager;
|
||||
AZStd::unique_ptr<AssetProcessor::PlatformConfiguration> 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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -9,3 +9,4 @@
|
||||
#pragma once
|
||||
|
||||
#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false
|
||||
#define AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT false
|
||||
|
||||
@@ -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<QProcessEnvironment, QString> 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. <br><br>"
|
||||
@@ -101,5 +96,10 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
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 O3DE::ProjectManager
|
||||
|
||||
@@ -9,3 +9,4 @@
|
||||
#pragma once
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
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 O3DE::ProjectManager
|
||||
|
||||
@@ -9,3 +9,4 @@
|
||||
#pragma once
|
||||
|
||||
#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR true
|
||||
#define AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT true
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
#include <QProcessEnvironment>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
|
||||
@@ -146,5 +147,26 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
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 O3DE::ProjectManager
|
||||
|
||||
@@ -41,5 +41,6 @@
|
||||
<file>Download.svg</file>
|
||||
<file>in_progress.gif</file>
|
||||
<file>gem.svg</file>
|
||||
<file>checkmark.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="15px" height="14px" viewBox="0 0 15 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Icons / Hub / Download Copy 5</title>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Screen-1-Copy-80" transform="translate(-425.000000, -251.000000)">
|
||||
<g id="Icons-/-Hub-/-Download-Copy-5" transform="translate(424.573941, 250.098705)">
|
||||
<rect id="Icon-Background" x="0" y="0" width="16" height="16"></rect>
|
||||
<path d="M8,1.33333333 C11.6818983,1.33333333 14.6666667,4.31810167 14.6666667,8 C14.6666667,11.6818983 11.6818983,14.6666667 8,14.6666667 C4.31810167,14.6666667 1.33333333,11.6818983 1.33333333,8 C1.33333333,4.31810167 4.31810167,1.33333333 8,1.33333333 Z M12.0947571,4 L5.96649831,10.1282588 L3.60947571,7.77123617 L2.66666667,8.71404521 L5.96649831,12.0138769 L13.0375661,4.94280904 L12.0947571,4 Z" id="Combined-Shape" fill="#58BC61"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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<QString> m_gemNames;
|
||||
|
||||
int m_lastProgress;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -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<void, AZStd::string> gemInfoResult = PythonBindingsInterface::Get()->DownloadGem(m_gemName, gemDownloadProgress);
|
||||
AZ::Outcome<void, AZStd::string> gemInfoResult =
|
||||
PythonBindingsInterface::Get()->DownloadGem(m_gemName, gemDownloadProgress, /*force*/true);
|
||||
|
||||
if (gemInfoResult.IsSuccess())
|
||||
{
|
||||
emit Done("");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include <QProgressBar>
|
||||
#include <TagWidget.h>
|
||||
#include <QMenu>
|
||||
#include <QLocale>
|
||||
#include <QMovie>
|
||||
|
||||
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<QWidget*>(gemName);
|
||||
if (gemToUpdate)
|
||||
{
|
||||
QLabel* progressLabel = gemToUpdate->findChild<QLabel*>("DownloadProgressLabel");
|
||||
if (progressLabel)
|
||||
{
|
||||
progressLabel->setText(QString("%1%").arg(percentage));
|
||||
}
|
||||
QProgressBar* progressBar = gemToUpdate->findChild<QProgressBar*>("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<int>((bytesDownloaded / static_cast<float>(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<Tag> CartOverlayWidget::GetTagsFromModelIndices(const QVector<QModelIndex>& gems) const
|
||||
{
|
||||
QVector<Tag> tags;
|
||||
@@ -389,7 +402,7 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
const QVector<QModelIndex> toBeAdded = m_gemModel->GatherGemsToBeAdded(/*includeDependencies=*/true);
|
||||
const QVector<QModelIndex> 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()
|
||||
|
||||
@@ -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<Tag> GetTagsFromModelIndices(const QVector<QModelIndex>& 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
|
||||
|
||||
@@ -12,7 +12,11 @@
|
||||
#include <GemCatalog/GemSortFilterProxyModel.h>
|
||||
#include <GemCatalog/GemRequirementDialog.h>
|
||||
#include <GemCatalog/GemDependenciesDialog.h>
|
||||
#include <GemCatalog/GemUpdateDialog.h>
|
||||
#include <GemCatalog/GemUninstallDialog.h>
|
||||
#include <DownloadController.h>
|
||||
#include <ProjectUtils.h>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
@@ -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<void, AZStd::string> refreshResult = PythonBindingsInterface::Get()->RefreshGemRepo(selectedGemRepoUri);
|
||||
if (refreshResult.IsSuccess())
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(
|
||||
this, tr("Operation failed"),
|
||||
tr("Failed to refresh gem repository %1<br>Error:<br>%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:<br>%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<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())
|
||||
{
|
||||
// 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()
|
||||
|
||||
@@ -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<QString> m_gemsToRegisterWithProject;
|
||||
QString m_projectPath = nullptr;
|
||||
QString m_projectPath;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <QSpacerItem>
|
||||
#include <QVBoxLayout>
|
||||
#include <QIcon>
|
||||
#include <QPushButton>
|
||||
|
||||
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
|
||||
|
||||
@@ -16,11 +16,12 @@
|
||||
|
||||
#include <QItemSelection>
|
||||
#include <QScrollArea>
|
||||
#include <QSpacerItem>
|
||||
#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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<GemSortFilterProxyModel*>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 = {};
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace O3DE::ProjectManager
|
||||
void SetFeatures(const QSet<QString>& features) { m_featureFilter = features; InvalidateFilter(); }
|
||||
|
||||
void InvalidateFilter();
|
||||
void ResetFilters();
|
||||
void ResetFilters(bool clearSearchString = true);
|
||||
|
||||
signals:
|
||||
void OnInvalidated();
|
||||
|
||||
@@ -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 <GemCatalog/GemUninstallDialog.h>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QPushButton>
|
||||
#include <QVariant>
|
||||
|
||||
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
|
||||
@@ -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 <QDialog>
|
||||
#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
|
||||
@@ -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 <GemCatalog/GemUpdateDialog.h>
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QVariant>
|
||||
|
||||
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
|
||||
@@ -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 <QDialog>
|
||||
#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
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,11 @@
|
||||
|
||||
#include <ProjectButtonWidget.h>
|
||||
#include <ProjectManagerDefs.h>
|
||||
#include <ProjectUtils.h>
|
||||
#include <ProjectManager_Traits_Platform.h>
|
||||
#include <AzQtComponents/Utilities/DesktopUtilities.h>
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
@@ -23,6 +27,7 @@
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QDesktopServices>
|
||||
#include <QMessageBox>
|
||||
|
||||
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();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user