Merge branch 'main' into jckand/FoundationAuto

This commit is contained in:
jckand-amzn
2021-05-26 07:57:28 -05:00
74 changed files with 1671 additions and 761 deletions
+666
View File
@@ -0,0 +1,666 @@
{
"Source": "Default_Level.prefab",
"ContainerEntity": {
"Id": "Entity_[1146574390643]",
"Name": "Level",
"Components": {
"Component_[10641544592923449938]": {
"$type": "EditorInspectorComponent",
"Id": 10641544592923449938
},
"Component_[12039882709170782873]": {
"$type": "EditorOnlyEntityComponent",
"Id": 12039882709170782873
},
"Component_[12265484671603697631]": {
"$type": "EditorPendingCompositionComponent",
"Id": 12265484671603697631
},
"Component_[14126657869720434043]": {
"$type": "EditorEntitySortComponent",
"Id": 14126657869720434043
},
"Component_[15230859088967841193]": {
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
"Id": 15230859088967841193,
"Parent Entity": "",
"Cached World Transform Parent": ""
},
"Component_[16239496886950819870]": {
"$type": "EditorDisabledCompositionComponent",
"Id": 16239496886950819870
},
"Component_[5688118765544765547]": {
"$type": "EditorEntityIconComponent",
"Id": 5688118765544765547
},
"Component_[6545738857812235305]": {
"$type": "SelectionComponent",
"Id": 6545738857812235305
},
"Component_[7247035804068349658]": {
"$type": "EditorPrefabComponent",
"Id": 7247035804068349658
},
"Component_[9307224322037797205]": {
"$type": "EditorLockComponent",
"Id": 9307224322037797205
},
"Component_[9562516168917670048]": {
"$type": "EditorVisibilityComponent",
"Id": 9562516168917670048
}
},
"IsDependencyReady": true
},
"Entities": {
"Entity_[1155164325235]": {
"Id": "Entity_[1155164325235]",
"Name": "Sun",
"Components": {
"Component_[10440557478882592717]": {
"$type": "SelectionComponent",
"Id": 10440557478882592717
},
"Component_[13620450453324765907]": {
"$type": "EditorLockComponent",
"Id": 13620450453324765907
},
"Component_[2134313378593666258]": {
"$type": "EditorInspectorComponent",
"Id": 2134313378593666258
},
"Component_[234010807770404186]": {
"$type": "EditorVisibilityComponent",
"Id": 234010807770404186
},
"Component_[2970359110423865725]": {
"$type": "EditorEntityIconComponent",
"Id": 2970359110423865725
},
"Component_[3722854130373041803]": {
"$type": "EditorOnlyEntityComponent",
"Id": 3722854130373041803
},
"Component_[5992533738676323195]": {
"$type": "EditorDisabledCompositionComponent",
"Id": 5992533738676323195
},
"Component_[7378860763541895402]": {
"$type": "AZ::Render::EditorDirectionalLightComponent",
"Id": 7378860763541895402,
"Controller": {
"Configuration": {
"Intensity": 1.0,
"CameraEntityId": "",
"ShadowFilterMethod": 1,
"ShadowmapSize": "Size1024",
"Pcf Method": 1
}
}
},
"Component_[7892834440890947578]": {
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
"Id": 7892834440890947578,
"Parent Entity": "Entity_[1176639161715]",
"Transform Data": {
"Translate": [
0.0,
0.0,
13.487043380737305
],
"Rotate": [
-76.13099670410156,
-0.847000002861023,
-15.8100004196167
]
},
"Cached World Transform": {
"Translation": [
0.0,
0.0,
9.442070960998536
],
"Rotation": [
-0.6098860502243042,
-0.09055805951356888,
-0.10376212745904924,
0.7804304361343384
]
},
"Cached World Transform Parent": "Entity_[1176639161715]"
},
"Component_[8599729549570828259]": {
"$type": "EditorEntitySortComponent",
"Id": 8599729549570828259
},
"Component_[952797371922080273]": {
"$type": "EditorPendingCompositionComponent",
"Id": 952797371922080273
}
},
"IsDependencyReady": true
},
"Entity_[1159459292531]": {
"Id": "Entity_[1159459292531]",
"Name": "Ground",
"Components": {
"Component_[11701138785793981042]": {
"$type": "SelectionComponent",
"Id": 11701138785793981042
},
"Component_[12260880513256986252]": {
"$type": "EditorEntityIconComponent",
"Id": 12260880513256986252
},
"Component_[13711420870643673468]": {
"$type": "EditorDisabledCompositionComponent",
"Id": 13711420870643673468
},
"Component_[138002849734991713]": {
"$type": "EditorOnlyEntityComponent",
"Id": 138002849734991713
},
"Component_[16578565737331764849]": {
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
"Id": 16578565737331764849,
"Parent Entity": "Entity_[1176639161715]",
"Cached World Transform": {
"Translation": [
0.0,
0.0,
0.0
]
},
"Cached World Transform Parent": "Entity_[1176639161715]"
},
"Component_[16919232076966545697]": {
"$type": "EditorInspectorComponent",
"Id": 16919232076966545697
},
"Component_[5182430712893438093]": {
"$type": "EditorMaterialComponent",
"Id": 5182430712893438093,
"materialSlots": [
{
"id": {
"materialAssetId": {
"guid": "{935F694A-8639-515B-8133-81CDC7948E5B}",
"subId": 803645540
}
}
}
],
"materialSlotsByLod": [
[
{
"id": {
"lodIndex": 0,
"materialAssetId": {
"guid": "{935F694A-8639-515B-8133-81CDC7948E5B}",
"subId": 803645540
}
}
}
]
]
},
"Component_[5675108321710651991]": {
"$type": "AZ::Render::EditorMeshComponent",
"Id": 5675108321710651991,
"Controller": {
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{935F694A-8639-515B-8133-81CDC7948E5B}",
"subId": 277333723
},
"assetHint": "objects/groudplane/groundplane_521x521m.azmodel"
}
}
}
},
"Component_[5681893399601237518]": {
"$type": "EditorEntitySortComponent",
"Id": 5681893399601237518
},
"Component_[592692962543397545]": {
"$type": "EditorPendingCompositionComponent",
"Id": 592692962543397545
},
"Component_[7090012899106946164]": {
"$type": "EditorLockComponent",
"Id": 7090012899106946164
},
"Component_[9410832619875640998]": {
"$type": "EditorVisibilityComponent",
"Id": 9410832619875640998
}
},
"IsDependencyReady": true
},
"Entity_[1163754259827]": {
"Id": "Entity_[1163754259827]",
"Name": "Camera",
"Components": {
"Component_[11895140916889160460]": {
"$type": "EditorEntityIconComponent",
"Id": 11895140916889160460
},
"Component_[16880285896855930892]": {
"$type": "{CA11DA46-29FF-4083-B5F6-E02C3A8C3A3D} EditorCameraComponent",
"Id": 16880285896855930892,
"Controller": {
"Configuration": {
"Field of View": 55.0,
"EditorEntityId": 8929576024571800510
}
}
},
"Component_[17187464423780271193]": {
"$type": "EditorLockComponent",
"Id": 17187464423780271193
},
"Component_[17495696818315413311]": {
"$type": "EditorEntitySortComponent",
"Id": 17495696818315413311
},
"Component_[18086214374043522055]": {
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
"Id": 18086214374043522055,
"Parent Entity": "Entity_[1176639161715]",
"Transform Data": {
"Translate": [
-2.300000190734864,
-3.9368600845336916,
1.0
],
"Rotate": [
-2.050307512283325,
1.9552897214889529,
-43.62335586547852
]
},
"Cached World Transform": {
"Translation": [
-11.904647827148438,
13.392678260803223,
-3.0449724197387697
],
"Rotation": [
-0.02294669672846794,
0.00919158011674881,
-0.37172695994377139,
0.9280129671096802
]
},
"Cached World Transform Parent": "Entity_[1176639161715]"
},
"Component_[18387556550380114975]": {
"$type": "SelectionComponent",
"Id": 18387556550380114975
},
"Component_[2654521436129313160]": {
"$type": "EditorVisibilityComponent",
"Id": 2654521436129313160
},
"Component_[5265045084611556958]": {
"$type": "EditorDisabledCompositionComponent",
"Id": 5265045084611556958
},
"Component_[7169798125182238623]": {
"$type": "EditorPendingCompositionComponent",
"Id": 7169798125182238623
},
"Component_[8866210352157164042]": {
"$type": "EditorInspectorComponent",
"Id": 8866210352157164042
},
"Component_[9129253381063760879]": {
"$type": "EditorOnlyEntityComponent",
"Id": 9129253381063760879
}
},
"IsDependencyReady": true
},
"Entity_[1168049227123]": {
"Id": "Entity_[1168049227123]",
"Name": "Grid",
"Components": {
"Component_[11443347433215807130]": {
"$type": "EditorEntityIconComponent",
"Id": 11443347433215807130
},
"Component_[11779275529534764488]": {
"$type": "SelectionComponent",
"Id": 11779275529534764488
},
"Component_[14249419413039427459]": {
"$type": "EditorInspectorComponent",
"Id": 14249419413039427459
},
"Component_[15448581635946161318]": {
"$type": "AZ::Render::EditorGridComponent",
"Id": 15448581635946161318,
"Controller": {
"Configuration": {
"primarySpacing": 4.0,
"primaryColor": [
0.501960813999176,
0.501960813999176,
0.501960813999176
],
"secondarySpacing": 0.5,
"secondaryColor": [
0.250980406999588,
0.250980406999588,
0.250980406999588
]
}
}
},
"Component_[1843303322527297409]": {
"$type": "EditorDisabledCompositionComponent",
"Id": 1843303322527297409
},
"Component_[380249072065273654]": {
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
"Id": 380249072065273654,
"Parent Entity": "Entity_[1176639161715]",
"Cached World Transform": {
"Translation": [
0.0,
0.0,
0.0
]
},
"Cached World Transform Parent": "Entity_[1176639161715]"
},
"Component_[7476660583684339787]": {
"$type": "EditorPendingCompositionComponent",
"Id": 7476660583684339787
},
"Component_[7557626501215118375]": {
"$type": "EditorEntitySortComponent",
"Id": 7557626501215118375
},
"Component_[7984048488947365511]": {
"$type": "EditorVisibilityComponent",
"Id": 7984048488947365511
},
"Component_[8118181039276487398]": {
"$type": "EditorOnlyEntityComponent",
"Id": 8118181039276487398
},
"Component_[9189909764215270515]": {
"$type": "EditorLockComponent",
"Id": 9189909764215270515
}
},
"IsDependencyReady": true
},
"Entity_[1172344194419]": {
"Id": "Entity_[1172344194419]",
"Name": "Shader Ball",
"Components": {
"Component_[10789351944715265527]": {
"$type": "EditorOnlyEntityComponent",
"Id": 10789351944715265527
},
"Component_[12037033284781049225]": {
"$type": "EditorEntitySortComponent",
"Id": 12037033284781049225
},
"Component_[13759153306105970079]": {
"$type": "EditorPendingCompositionComponent",
"Id": 13759153306105970079
},
"Component_[14135560884830586279]": {
"$type": "EditorInspectorComponent",
"Id": 14135560884830586279
},
"Component_[16247165675903986673]": {
"$type": "EditorVisibilityComponent",
"Id": 16247165675903986673
},
"Component_[18082433625958885247]": {
"$type": "EditorDisabledCompositionComponent",
"Id": 18082433625958885247
},
"Component_[6472623349872972660]": {
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
"Id": 6472623349872972660,
"Parent Entity": "Entity_[1176639161715]",
"Transform Data": {
"Rotate": [
0.0,
0.10000000149011612,
180.0
]
},
"Cached World Transform": {
"Translation": [
0.0,
0.0,
0.0
],
"Rotation": [
0.0008726645028218627,
0.0,
0.9999996423721314,
0.0
]
},
"Cached World Transform Parent": "Entity_[1176639161715]"
},
"Component_[6495255223970673916]": {
"$type": "AZ::Render::EditorMeshComponent",
"Id": 6495255223970673916,
"Controller": {
"Configuration": {
"ModelAsset": {
"assetId": {
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
"subId": 281415304
},
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
}
}
}
},
"Component_[8056625192494070973]": {
"$type": "SelectionComponent",
"Id": 8056625192494070973
},
"Component_[8550141614185782969]": {
"$type": "EditorEntityIconComponent",
"Id": 8550141614185782969
},
"Component_[9439770997198325425]": {
"$type": "EditorLockComponent",
"Id": 9439770997198325425
}
},
"IsDependencyReady": true
},
"Entity_[1176639161715]": {
"Id": "Entity_[1176639161715]",
"Name": "Atom Default Environment",
"Components": {
"Component_[10757302973393310045]": {
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
"Id": 10757302973393310045,
"Parent Entity": "Entity_[1146574390643]",
"Cached World Transform": {
"Translation": [
0.0,
0.0,
0.0
]
},
"Cached World Transform Parent": "Entity_[1146574390643]"
},
"Component_[14505817420424255464]": {
"$type": "EditorInspectorComponent",
"Id": 14505817420424255464,
"ComponentOrderEntryArray": [
{
"ComponentId": 10757302973393310045
}
]
},
"Component_[14988041764659020032]": {
"$type": "EditorLockComponent",
"Id": 14988041764659020032
},
"Component_[15808690248755038124]": {
"$type": "SelectionComponent",
"Id": 15808690248755038124
},
"Component_[15900837685796817138]": {
"$type": "EditorVisibilityComponent",
"Id": 15900837685796817138
},
"Component_[3298767348226484884]": {
"$type": "EditorOnlyEntityComponent",
"Id": 3298767348226484884
},
"Component_[4076975109609220594]": {
"$type": "EditorPendingCompositionComponent",
"Id": 4076975109609220594
},
"Component_[5679760548946028854]": {
"$type": "EditorDisabledCompositionComponent",
"Id": 5679760548946028854
},
"Component_[5855590796136709437]": {
"$type": "EditorEntitySortComponent",
"Id": 5855590796136709437,
"ChildEntityOrderEntryArray": [
{
"EntityId": "Entity_[1155164325235]"
},
{
"EntityId": "Entity_[1180934129011]",
"SortIndex": 1
},
{
"EntityId": "Entity_[1172344194419]",
"SortIndex": 2
},
{
"EntityId": "Entity_[1168049227123]",
"SortIndex": 3
},
{
"EntityId": "Entity_[1163754259827]",
"SortIndex": 4
},
{
"EntityId": "Entity_[1159459292531]",
"SortIndex": 5
}
]
},
"Component_[9277695270015777859]": {
"$type": "EditorEntityIconComponent",
"Id": 9277695270015777859
}
},
"IsDependencyReady": true
},
"Entity_[1180934129011]": {
"Id": "Entity_[1180934129011]",
"Name": "Global Sky",
"Components": {
"Component_[11231930600558681245]": {
"$type": "AZ::Render::EditorHDRiSkyboxComponent",
"Id": 11231930600558681245,
"Controller": {
"Configuration": {
"CubemapAsset": {
"assetId": {
"guid": "{215E47FD-D181-5832-B1AB-91673ABF6399}",
"subId": 1000
},
"assetHint": "lightingpresets/highcontrast/goegap_4k_skyboxcm.exr.streamingimage"
}
}
}
},
"Component_[11980494120202836095]": {
"$type": "SelectionComponent",
"Id": 11980494120202836095
},
"Component_[1428633914413949476]": {
"$type": "EditorLockComponent",
"Id": 1428633914413949476
},
"Component_[14936200426671614999]": {
"$type": "AZ::Render::EditorImageBasedLightComponent",
"Id": 14936200426671614999,
"Controller": {
"Configuration": {
"diffuseImageAsset": {
"assetId": {
"guid": "{3FD09945-D0F2-55C8-B9AF-B2FD421FE3BE}",
"subId": 3000
},
"assetHint": "lightingpresets/highcontrast/goegap_4k_iblglobalcm_ibldiffuse.exr.streamingimage"
},
"specularImageAsset": {
"assetId": {
"guid": "{3FD09945-D0F2-55C8-B9AF-B2FD421FE3BE}",
"subId": 2000
},
"assetHint": "lightingpresets/highcontrast/goegap_4k_iblglobalcm_iblspecular.exr.streamingimage"
}
}
}
},
"Component_[14994774102579326069]": {
"$type": "EditorDisabledCompositionComponent",
"Id": 14994774102579326069
},
"Component_[15417479889044493340]": {
"$type": "EditorPendingCompositionComponent",
"Id": 15417479889044493340
},
"Component_[15826613364991382688]": {
"$type": "EditorEntitySortComponent",
"Id": 15826613364991382688
},
"Component_[1665003113283562343]": {
"$type": "EditorOnlyEntityComponent",
"Id": 1665003113283562343
},
"Component_[3704934735944502280]": {
"$type": "EditorEntityIconComponent",
"Id": 3704934735944502280
},
"Component_[5698542331457326479]": {
"$type": "EditorVisibilityComponent",
"Id": 5698542331457326479
},
"Component_[6644513399057217122]": {
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
"Id": 6644513399057217122,
"Parent Entity": "Entity_[1176639161715]",
"Cached World Transform": {
"Translation": [
0.0,
0.0,
0.0
]
},
"Cached World Transform Parent": "Entity_[1176639161715]"
},
"Component_[931091830724002070]": {
"$type": "EditorInspectorComponent",
"Id": 931091830724002070
}
},
"IsDependencyReady": true
}
}
}
@@ -12,7 +12,7 @@
# Extracted from Editor.xml
set(GEM_DEPENDENCIES
Gem::Maestro.Editor
Gem::TextureAtlas
Gem::TextureAtlas.Editor
Gem::LmbrCentral.Editor
Gem::LyShine.Editor
Gem::HttpRequestor
@@ -1020,29 +1020,60 @@ namespace AZ
}
};
/// OnDemand reflection for AZStd::set
template<class t_Key, class t_Hasher, class t_EqualKey, class t_Allocator>
class Iterator_VM<AZStd::unordered_set<t_Key, t_Hasher, t_EqualKey, t_Allocator>>
{
public:
using ContainerType = AZStd::unordered_set<t_Key, t_Hasher, t_EqualKey, t_Allocator>;
using IteratorType = typename ContainerType::iterator;
Iterator_VM(ContainerType& container)
: m_iterator(container.begin())
, m_end(container.end())
{}
const t_Key& GetKeyUnchecked() const
{
return *m_iterator;
}
bool IsNotAtEnd() const
{
return m_iterator != m_end;
}
t_Key& ModValueUnchecked()
{
return *m_iterator;
}
void Next()
{
++m_iterator;
}
private:
IteratorType m_iterator;
IteratorType m_end;
};
/// OnDemand reflection for AZStd::unordered_set
template<class Key, class Hasher, class EqualKey, class Allocator>
struct OnDemandReflection< AZStd::unordered_set<Key, Hasher, EqualKey, Allocator> >
{
using ContainerType = AZStd::unordered_set<Key, Hasher, EqualKey, Allocator>;
using KeyListType = AZStd::vector<Key, Allocator>;
static AZ::Outcome<void, void> Erase(ContainerType& thisMap, Key& key)
using ValueIteratorType = Iterator_VM<ContainerType>;
static bool EraseCheck_VM(ContainerType& thisSet, Key& key)
{
const auto result = thisMap.erase(key);
if (result)
{
return AZ::Success();
}
else
{
return AZ::Failure();
}
return thisSet.erase(key) != 0;
}
static void Insert(ContainerType& thisSet, Key& key)
static ContainerType& ErasePost_VM(ContainerType& thisSet, [[maybe_unused]] Key&)
{
thisSet.insert(key);
return thisSet;
}
static KeyListType GetKeys(ContainerType& thisSet)
@@ -1055,6 +1086,17 @@ namespace AZ
return keys;
}
static ContainerType& Insert(ContainerType& thisSet, Key& key)
{
thisSet.insert(key);
return thisSet;
}
static ValueIteratorType Iterate_VM(ContainerType& thisContainer)
{
return ValueIteratorType(thisContainer);
}
static void Swap(ContainerType& thisSet, ContainerType& otherSet)
{
thisSet.swap(otherSet);
@@ -1064,33 +1106,68 @@ namespace AZ
{
if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
BranchOnResultInfo emptyBranchInfo;
emptyBranchInfo.m_returnResultInBranches = true;
emptyBranchInfo.m_trueToolTip = "The container is empty";
emptyBranchInfo.m_falseToolTip = "The container is not empty";
auto ContainsTransparent = [](const ContainerType& containerType, typename ContainerType::key_type& key)->bool
{
return containerType.contains(key);
};
ExplicitOverloadInfo explicitOverloadInfo;
behaviorContext->Class<ContainerType>()
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::ListOnly)
->Attribute(AZ::ScriptCanvasAttributes::PrettyName, ScriptCanvasOnDemandReflection::OnDemandPrettyName<ContainerType>::Get(*behaviorContext))
->Attribute(AZ::Script::Attributes::ToolTip, ScriptCanvasOnDemandReflection::OnDemandToolTip<ContainerType>::Get(*behaviorContext))
->Attribute(AZ::Script::Attributes::Category, ScriptCanvasOnDemandReflection::OnDemandCategoryName<ContainerType>::Get(*behaviorContext))
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::ScriptOwn)
->Method("BucketCount", static_cast<typename ContainerType::size_type(ContainerType::*)() const>(&ContainerType::bucket_count))
->Method("Erase", &Erase)
->Method("Empty", [](ContainerType& thisSet)->bool { return thisSet.empty(); })
->Method("Empty", static_cast<bool(ContainerType::*)() const>(&ContainerType::empty), { { { "Container", "The container to check if it is empty", nullptr, {} } } })
->Attribute(AZ::ScriptCanvasAttributes::ExplicitOverloadCrc, ExplicitOverloadInfo("Is Empty", "Containers"))
->Attribute(AZ::ScriptCanvasAttributes::BranchOnResult, emptyBranchInfo)
->Method("EraseCheck_VM", &EraseCheck_VM)
->Attribute(AZ::Script::Attributes::TreatAsMemberFunction, AZ::AttributeIsValid::IfPresent)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Method("Erase", &ErasePost_VM)
->Attribute(AZ::Script::Attributes::TreatAsMemberFunction, AZ::AttributeIsValid::IfPresent)
->Attribute(AZ::ScriptCanvasAttributes::ExplicitOverloadCrc, ExplicitOverloadInfo("Erase", "Containers"))
->Attribute(AZ::ScriptCanvasAttributes::CheckedOperation, CheckedOperationInfo("EraseCheck_VM", {}, "Out", "Key Not Found", true))
->Attribute(AZ::ScriptCanvasAttributes::OverloadArgumentGroup, AZ::OverloadArgumentGroupInfo({ "ContainerGroup", "" }, { "ContainerGroup" }))
->Method("contains", ContainsTransparent)
->Attribute(AZ::ScriptCanvasAttributes::ExplicitOverloadCrc, ExplicitOverloadInfo("Has Key", "Containers"))
->Attribute(AZ::Script::Attributes::TreatAsMemberFunction, AZ::AttributeIsValid::IfPresent)
->Method("Insert", &Insert)
->Attribute(AZ::Script::Attributes::TreatAsMemberFunction, AZ::AttributeIsValid::IfPresent)
->Attribute(AZ::ScriptCanvasAttributes::ExplicitOverloadCrc, ExplicitOverloadInfo("Insert", "Containers"))
->Attribute(AZ::ScriptCanvasAttributes::OverloadArgumentGroup, AZ::OverloadArgumentGroupInfo({ "ContainerGroup", "", "" }, { "ContainerGroup" }))
->Method(k_sizeName, [](ContainerType* thisPtr) { return aznumeric_cast<int>(thisPtr->size()); })
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Length)
->Method("GetKeys", &GetKeys)
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
->Method("GetSize", [](ContainerType& thisPtr) { return aznumeric_cast<int>(thisPtr.size()); })
->Attribute(AZ::ScriptCanvasAttributes::ExplicitOverloadCrc, ExplicitOverloadInfo("Get Size", "Containers"))
->Attribute(AZ::Script::Attributes::TreatAsMemberFunction, AZ::AttributeIsValid::IfPresent)
->Method("Reserve", static_cast<void(ContainerType::*)(typename ContainerType::size_type)>(&ContainerType::reserve))
->Method("Swap", &Swap)
->Method("Clear", [](ContainerType& thisContainer)->ContainerType& { thisContainer.clear(); return thisContainer; })
->Attribute(AZ::Script::Attributes::TreatAsMemberFunction, AZ::AttributeIsValid::IfPresent)
->Attribute(AZ::ScriptCanvasAttributes::ExplicitOverloadCrc, ExplicitOverloadInfo("Clear All Elements", "Containers"))
->Attribute(AZ::ScriptCanvasAttributes::OverloadArgumentGroup, AZ::OverloadArgumentGroupInfo({ "ContainerGroup" }, { "ContainerGroup" }))
->Method(k_iteratorConstructorName, &Iterate_VM)
;
behaviorContext->Class<ValueIteratorType>()
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::ListOnly)
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::ScriptOwn)
->Method(k_iteratorGetKeyName, &ValueIteratorType::GetKeyUnchecked)
->Method(k_iteratorModValueName, &ValueIteratorType::ModValueUnchecked)
->Method(k_iteratorIsNotAtEndName, &ValueIteratorType::IsNotAtEnd)
->Method(k_iteratorNextName, &ValueIteratorType::Next)
;
}
}
};
template <>
@@ -165,7 +165,7 @@ namespace AZ
if (HasResult() != overload->HasResult())
{
AZ_Error("Reflection", false, "Overload failure, all methods must have the same result, or none at all");
AZ_Error("Reflection", false, "Overload failure, all methods must have the same result, or none at all: %s", m_name.c_str());
return false;
}
@@ -176,7 +176,7 @@ namespace AZ
if (!(methodResult->m_typeId == overloadResult->m_typeId && methodResult->m_traits == overloadResult->m_traits))
{
AZ_Error("Reflection", false, "Overload failure, all methods must have the same result, or none at all");
AZ_Error("Reflection", false, "Overload failure, all methods must have the same result, or none at all: %s", m_name.c_str());
return false;
}
}
@@ -575,7 +575,7 @@ namespace AZ
}
else
{
AZ_Error("BehaviorContext", false, "safety check declared for method %s but it was not found in the class");
AZ_Error("BehaviorContext", false, "Method: %s, declared safety check: %s, but it was not found in class: %s", method.m_name.c_str(), m_name.c_str(), checkedOperationInfo.m_safetyCheckName.c_str());
}
}
}
@@ -34,10 +34,17 @@ namespace BehaviorContextUtilitiesCPP
using argument_type = const BehaviorParameter*;
using result_type = size_t;
result_type operator()(const argument_type& value) const
{
result_type result = AZStd::hash<Uuid>()(value->m_typeId);
AZStd::hash_combine(result, CleanTraits(value->m_traits));
return result;
{
if (value)
{
result_type result = AZStd::hash<Uuid>()(value->m_typeId);
AZStd::hash_combine(result, CleanTraits(value->m_traits));
return result;
}
else
{
return 0;
}
}
};
@@ -45,7 +52,11 @@ namespace BehaviorContextUtilitiesCPP
{
bool operator()(const BehaviorParameter* left, const BehaviorParameter* right) const
{
return left->m_typeId == right->m_typeId && CleanTraits(left->m_traits) == CleanTraits(right->m_traits);
return (left == nullptr && right == nullptr)
|| (left != nullptr
&& right != nullptr
&& left->m_typeId == right->m_typeId
&& CleanTraits(left->m_traits) == CleanTraits(right->m_traits));
}
};
@@ -137,7 +148,7 @@ namespace AZ
for (size_t argIndex = 0, argSentinel = overload.GetNumArguments(); argIndex < argSentinel; ++argIndex)
{
auto overloadedArgIter = variance.m_input.find(argIndex);
if (overloadedArgIter != variance.m_input.end())
if (overloadedArgIter != variance.m_input.end() && overloadedArgIter->second[overloadIndex])
{
// if this doesn't work try the type name
overloadName += ReplaceCppArtifacts(overloadedArgIter->second[overloadIndex]->m_name);
@@ -185,16 +196,24 @@ namespace AZ
{
auto argument = overloads[overloadIndex].first->GetArgument(0);
const bool isThisPointer
= (argument->m_traits & AZ::BehaviorParameter::Traits::TR_THIS_PTR) != 0
|| AZ::FindAttribute(AZ::Script::Attributes::TreatAsMemberFunction, overloads[overloadIndex].first->m_attributes);
if (argument)
{
const bool isThisPointer
= (argument->m_traits & AZ::BehaviorParameter::Traits::TR_THIS_PTR) != 0
|| AZ::FindAttribute(AZ::Script::Attributes::TreatAsMemberFunction, overloads[overloadIndex].first->m_attributes);
oneArgIsThisPointer = oneArgIsThisPointer || isThisPointer;
oneArgIsThisPointer = oneArgIsThisPointer || isThisPointer;
}
types.insert(argument);
stripedArgs.emplace_back(argument);
}
if (types.size() == overloads.size())
{
variance.m_unambiguousInput.insert(0);
}
if (types.size() > 1 && (onThis == VariantOnThis::Yes || !oneArgIsThisPointer))
{
variance.m_input.insert(AZStd::make_pair(0, stripedArgs));
@@ -210,11 +229,15 @@ namespace AZ
for (size_t overloadIndex = 0, overloadSentinel = overloads.size(); overloadIndex < overloadSentinel; ++overloadIndex)
{
auto argument = overloads[overloadIndex].first->GetArgument(argIndex);
types.insert(argument);
stripedArgs.emplace_back(argument);
}
if (types.size() == overloads.size())
{
variance.m_unambiguousInput.insert(0);
}
if (types.size() > 1)
{
variance.m_input.insert(AZStd::make_pair(argIndex, stripedArgs));
@@ -27,6 +27,8 @@ namespace AZ
struct OverloadVariance
{
AZStd::unordered_map<size_t, AZStd::vector<const BehaviorParameter*>> m_input;
// the indices of inputs that make selection of overload unambiguous
AZStd::unordered_set<size_t> m_unambiguousInput;
AZStd::vector<const BehaviorParameter*> m_output;
};
@@ -2048,10 +2048,6 @@ LUA_API const Node* lua_getDummyNode()
return true;
}
else
{
AZ_Warning("Script", false, "Index %d is not a function!", functionIndex);
}
return false;
}
@@ -2078,7 +2074,6 @@ LUA_API const Node* lua_getDummyNode()
}
else
{
AZ_Warning("Script", lua_isnil(m_nativeContext, -1), "Name %s exists but is not a function!", functionName);
lua_pop(m_nativeContext, 1);
}
@@ -5888,7 +5883,6 @@ LUA_API const Node* lua_getDummyNode()
else
{
lua_pop(m_impl->m_lua, 1);
AZ_Warning("Script", false, "%s is not a function!", functionName);
}
return false;
}
@@ -5906,7 +5900,6 @@ LUA_API const Node* lua_getDummyNode()
else
{
lua_pop(m_impl->m_lua, 1);
AZ_Warning("Script", false, "CacheIndex %d is not a function!", cachedIndex);
}
return false;
}
@@ -10,6 +10,7 @@
*
*/
#include "AzCore/RTTI/TypeInfo.h"
#include <AzCore/Math/UuidSerializer.h>
#include <AzCore/RTTI/AttributeReader.h>
#include <AzCore/Serialization/Json/CastingHelpers.h>
@@ -61,6 +62,13 @@ namespace AZ
if (classData->m_azRtti && classData->m_azRtti->GetGenericTypeId() != typeId)
{
if (((classData->m_azRtti->GetTypeTraits() & (AZ::TypeTraits::is_signed | AZ::TypeTraits::is_unsigned)) != AZ::TypeTraits{0}) &&
context.GetSerializeContext()->GetUnderlyingTypeId(typeId) == classData->m_typeId)
{
// This value is from an enum, where a field has been reflected using ClassBuilder::Field, but the enum
// type itself has not been reflected using EnumBuilder. Treat it as an enum.
return LoadEnum(object, *classData, value, context);
}
serializer = context.GetRegistrationContext()->GetSerializerForType(classData->m_azRtti->GetGenericTypeId());
if (serializer)
{
@@ -77,21 +85,18 @@ namespace AZ
{
return LoadEnum(object, *classData, value, context);
}
else if (classData->m_container)
if (classData->m_container)
{
return context.Report(Tasks::ReadField, Outcomes::Unsupported,
"The Json Serializer uses custom serializers to load containers. If this message is encountered "
"then a serializer for the target containers is missing, isn't registered or doesn't exist.");
}
else if (value.IsObject())
if (value.IsObject())
{
return LoadClass(object, *classData, value, context);
}
else
{
return context.Report(Tasks::ReadField, Outcomes::Unsupported,
AZStd::string::format("Reading into targets of type '%s' is not supported.", classData->m_name));
}
return context.Report(Tasks::ReadField, Outcomes::Unsupported,
AZStd::string::format("Reading into targets of type '%s' is not supported.", classData->m_name));
}
JsonSerializationResult::ResultCode JsonDeserializer::LoadToPointer(void* object, const Uuid& typeId,
@@ -233,8 +238,16 @@ namespace AZ
AZ::TypeId underlyingTypeId = AZ::TypeId::CreateNull();
if (!attributeReader.Read<AZ::TypeId>(underlyingTypeId))
{
return context.Report(Tasks::RetrieveInfo, Outcomes::Unknown,
"Unable to find underlying type of enum in class data.");
// for non-reflected enums, the passed-in classData already represents the enum's underlying type
if (context.GetSerializeContext()->GetUnderlyingTypeId(classData.m_typeId) == classData.m_typeId)
{
underlyingTypeId = classData.m_typeId;
}
else
{
return context.Report(Tasks::RetrieveInfo, Outcomes::Unknown,
"Unable to find underlying type of enum in class data.");
}
}
const SerializeContext::ClassData* underlyingClassData = context.GetSerializeContext()->FindClassData(underlyingTypeId);
@@ -21,7 +21,7 @@ namespace JsonSerializationTests
{
using JsonSerializationTestCases = ::testing::Types<
// Structures
SimpleClass, SimpleInheritence, MultipleInheritence, SimpleNested, SimpleEnumWrapper,
SimpleClass, SimpleInheritence, MultipleInheritence, SimpleNested, SimpleEnumWrapper, NonReflectedEnumWrapper,
// Pointers
SimpleNullPointer, SimpleAssignedPointer, ComplexAssignedPointer, ComplexNullInheritedPointer,
ComplexAssignedDifferentInheritedPointer, ComplexAssignedSameInheritedPointer,
@@ -373,6 +373,57 @@ namespace JsonSerializationTests
return MakeInstanceWithoutDefaults(AZStd::move(instance), json);
}
// NonReflectedEnumWrapper
bool NonReflectedEnumWrapper::Equals(const NonReflectedEnumWrapper& rhs, bool fullReflection) const
{
return !fullReflection || (m_enumClass == rhs.m_enumClass && m_rawEnum== rhs.m_rawEnum);
}
void NonReflectedEnumWrapper::Reflect(AZStd::unique_ptr<AZ::SerializeContext>& context, bool fullReflection)
{
if (fullReflection)
{
// Note that the enums are not reflected using context->Enum<>
context->Class<NonReflectedEnumWrapper>()
->Field("enumClass", &NonReflectedEnumWrapper::m_enumClass)
->Field("rawEnum", &NonReflectedEnumWrapper::m_rawEnum);
}
}
InstanceWithSomeDefaults<NonReflectedEnumWrapper> NonReflectedEnumWrapper::GetInstanceWithSomeDefaults()
{
auto instance = AZStd::make_unique<NonReflectedEnumWrapper>();
instance->m_enumClass = NonReflectedEnumWrapper::SimpleEnumClass::Option2;
const char* strippedDefaults = R"(
{
"enumClass": 2
})";
const char* keptDefaults = R"(
{
"enumClass": 2,
"rawEnum": 0
})";
return MakeInstanceWithSomeDefaults(AZStd::move(instance),
strippedDefaults, keptDefaults);
}
InstanceWithoutDefaults<NonReflectedEnumWrapper> NonReflectedEnumWrapper::GetInstanceWithoutDefaults()
{
auto instance = AZStd::make_unique<NonReflectedEnumWrapper>();
instance->m_enumClass = NonReflectedEnumWrapper::SimpleEnumClass::Option2;
instance->m_rawEnum = NonReflectedEnumWrapper::SimpleRawEnum::RawOption1;
const char* json = R"(
{
"enumClass": 2,
"rawEnum": 1
})";
return MakeInstanceWithoutDefaults(AZStd::move(instance), json);
}
// TemplatedClass<int>
bool TemplatedClass<int>::Equals(const TemplatedClass<int>& rhs, bool fullReflection) const
@@ -134,6 +134,35 @@ namespace JsonSerializationTests
SimpleRawEnum m_rawEnum{};
};
struct NonReflectedEnumWrapper
{
enum class SimpleEnumClass
{
Option1 = 1,
Option2,
};
enum SimpleRawEnum
{
RawOption1 = 1,
RawOption2,
};
AZ_CLASS_ALLOCATOR(NonReflectedEnumWrapper, AZ::SystemAllocator, 0);
AZ_RTTI(NonReflectedEnumWrapper, "{A80D5B6B-2FD1-46E9-A7A9-44C5E2650526}");
static constexpr bool SupportsPartialDefaults = true;
NonReflectedEnumWrapper() = default;
virtual ~NonReflectedEnumWrapper() = default;
bool Equals(const NonReflectedEnumWrapper& rhs, bool fullReflection) const;
static void Reflect(AZStd::unique_ptr<AZ::SerializeContext>& context, bool fullReflection);
static InstanceWithSomeDefaults<NonReflectedEnumWrapper> GetInstanceWithSomeDefaults();
static InstanceWithoutDefaults<NonReflectedEnumWrapper> GetInstanceWithoutDefaults();
SimpleEnumClass m_enumClass{};
SimpleRawEnum m_rawEnum{};
};
template<typename T>
struct TemplatedClass
{
@@ -158,5 +187,7 @@ namespace AZ
{
AZ_TYPE_INFO_SPECIALIZE(JsonSerializationTests::SimpleEnumWrapper::SimpleEnumClass, "{AF6F1964-5B20-4689-BF23-F36B9C9AAE6A}");
AZ_TYPE_INFO_SPECIALIZE(JsonSerializationTests::SimpleEnumWrapper::SimpleRawEnum, "{EB24207F-B48F-4D8B-940D-3CD06A371739}");
AZ_TYPE_INFO_SPECIALIZE(JsonSerializationTests::NonReflectedEnumWrapper::SimpleEnumClass, "{E80E4A41-B29E-4B7C-B630-3B599172C837}");
AZ_TYPE_INFO_SPECIALIZE(JsonSerializationTests::NonReflectedEnumWrapper::SimpleRawEnum, "{C42AF28D-4F84-4540-972A-5B6EEFAB13FF}");
AZ_TYPE_INFO_TEMPLATE(JsonSerializationTests::TemplatedClass, "{CA4ADF74-66E7-4D16-B4AC-F71278C60EC7}", AZ_TYPE_INFO_TYPENAME);
}
@@ -99,51 +99,18 @@ namespace AzFramework::ProjectManager
AZ::AllocatorInstance<AZ::SystemAllocator>::Create();
}
{
const char projectsScript[] = "projects.py";
AZStd::string filename = "o3de";
AZ::IO::FixedMaxPath executablePath = AZ::Utils::GetExecutableDirectory();
executablePath /= filename + AZ_TRAIT_OS_EXECUTABLE_EXTENSION;
AZ_Warning("ProjectManager", false, "No project provided - launching project selector.");
if (engineRootPath.empty())
if (!AZ::IO::SystemFile::Exists(executablePath.c_str()))
{
AZ_Error("ProjectManager", false, "Couldn't find engine root");
AZ_Error("ProjectManager", false, "%s not found", executablePath.c_str());
return false;
}
auto projectManagerPath = engineRootPath / "scripts" / "project_manager";
if (!AZ::IO::SystemFile::Exists((projectManagerPath / projectsScript).c_str()))
{
AZ_Error("ProjectManager", false, "%s not found at %s!", projectsScript, projectManagerPath.c_str());
return false;
}
AZ::IO::FixedMaxPathString executablePath;
AZ::Utils::GetExecutablePathReturnType result = AZ::Utils::GetExecutablePath(executablePath.data(), executablePath.capacity());
if (result.m_pathStored != AZ::Utils::ExecutablePathResult::Success)
{
AZ_Error("ProjectManager", false, "Could not determine executable path!");
return false;
}
AZ::IO::FixedMaxPath parentPath(executablePath.c_str());
auto exeFolder = parentPath.ParentPath();
AZStd::fixed_string<8> debugOption;
auto lastSep = exeFolder.Native().find_last_of(AZ_CORRECT_FILESYSTEM_SEPARATOR);
if (lastSep != AZStd::string_view::npos)
{
exeFolder = exeFolder.Native().substr(lastSep + 1);
}
if (exeFolder == "debug")
{
// We need to use the debug version of the python interpreter to load up our debug version of our libraries which work with the debug version of QT living in this folder
debugOption = "debug ";
}
AZ::IO::FixedMaxPath pythonPath = engineRootPath / "python";
pythonPath /= AZ_TRAIT_AZFRAMEWORK_PYTHON_SHELL;
auto cmdPath = AZ::IO::FixedMaxPathString::format("%s %s%s --executable_path=%s --parent_pid=%" PRIu32, pythonPath.Native().c_str(),
debugOption.c_str(), (projectManagerPath / projectsScript).c_str(), executablePath.c_str(), AZ::Platform::GetCurrentProcessId());
AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
processLaunchInfo.m_commandlineParameters = cmdPath;
processLaunchInfo.m_showWindow = false;
processLaunchInfo.m_commandlineParameters = executablePath.String();
launchSuccess = AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo);
}
if (ownsSystemAllocator)
@@ -65,5 +65,12 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_googletest(
NAME AZ::AzNetworking.Tests
)
ly_add_googletest(
NAME AZ::AzNetworking.Tests.Sandbox
TARGET AZ::AzNetworking.Tests
TEST_SUITE sandbox
)
endif()
@@ -129,7 +129,7 @@ namespace UnitTest
#if AZ_TRAIT_DISABLE_FAILED_NETWORKING_TESTS
TEST_F(TcpTransportTests, DISABLED_TestSingleClient)
#else
TEST_F(TcpTransportTests, TestSingleClient)
TEST_F(TcpTransportTests, SUITE_sandbox_TestSingleClient)
#endif // AZ_TRAIT_DISABLE_FAILED_NETWORKING_TESTS
{
TestTcpServer testServer;
@@ -157,7 +157,7 @@ namespace UnitTest
#if AZ_TRAIT_DISABLE_FAILED_NETWORKING_TESTS
TEST_F(TcpTransportTests, DISABLED_TestMultipleClients)
#else
TEST_F(TcpTransportTests, TestMultipleClients)
TEST_F(TcpTransportTests, SUITE_sandbox_TestMultipleClients)
#endif // AZ_TRAIT_DISABLE_FAILED_NETWORKING_TESTS
{
constexpr uint32_t NumTestClients = 50;
@@ -14,9 +14,11 @@
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Script/ScriptSystemBus.h>
#include <AzCore/Serialization/Utils.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <AzFramework/Entity/GameEntityContextBus.h>
#include <AzFramework/Spawnable/RootSpawnableInterface.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.h>
#include <AzToolsFramework/Prefab/EditorPrefabComponent.h>
@@ -222,21 +224,52 @@ namespace AzToolsFramework
AzToolsFramework::Prefab::TemplateId templateId = m_prefabSystemComponent->GetTemplateIdFromFilePath(relativePath);
m_rootInstance->SetTemplateSourcePath(relativePath);
bool newLevelFromTemplate = false;
if (templateId == AzToolsFramework::Prefab::InvalidTemplateId)
{
// This has not been loaded yet, this is the case of being saved with a different name.
// Create it
m_rootInstance->m_containerEntity->AddComponent(aznew Prefab::EditorPrefabComponent());
HandleEntitiesAdded({m_rootInstance->m_containerEntity.get()});
AZStd::string watchFolder;
AZ::Data::AssetInfo assetInfo;
bool sourceInfoFound = false;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, DefaultLevelTemplateName,
assetInfo, watchFolder);
AzToolsFramework::Prefab::PrefabDom dom;
bool success = AzToolsFramework::Prefab::PrefabDomUtils::StoreInstanceInPrefabDom(*m_rootInstance, dom);
if (!success)
if (sourceInfoFound)
{
AZ_Error("Prefab", false, "Failed to convert current root instance into a DOM when saving file '%.*s'", AZ_STRING_ARG(filename));
return false;
AZStd::string fullPath;
AZ::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), fullPath);
// Get the default prefab and copy the Dom over to the new template being saved
Prefab::TemplateId defaultId = m_loaderInterface->LoadTemplateFromFile(fullPath.c_str());
Prefab::PrefabDom& dom = m_prefabSystemComponent->FindTemplateDom(defaultId);
Prefab::PrefabDom levelDefaultDom;
levelDefaultDom.CopyFrom(dom, levelDefaultDom.GetAllocator());
Prefab::PrefabDomPath sourcePath("/Source");
sourcePath.Set(levelDefaultDom, relativePath.c_str());
templateId = m_prefabSystemComponent->AddTemplate(relativePath, std::move(levelDefaultDom));
newLevelFromTemplate = true;
}
templateId = m_prefabSystemComponent->AddTemplate(relativePath, std::move(dom));
else
{
// Create an empty level since we couldn't find the default template
m_rootInstance->m_containerEntity->AddComponent(aznew Prefab::EditorPrefabComponent());
HandleEntitiesAdded({ m_rootInstance->m_containerEntity.get() });
AzToolsFramework::Prefab::PrefabDom dom;
bool success = AzToolsFramework::Prefab::PrefabDomUtils::StoreInstanceInPrefabDom(*m_rootInstance, dom);
if (!success)
{
AZ_Error("Prefab", false, "Failed to convert current root instance into a DOM when saving file '%.*s'", AZ_STRING_ARG(filename));
return false;
}
templateId = m_prefabSystemComponent->AddTemplate(relativePath, std::move(dom));
}
if (templateId == AzToolsFramework::Prefab::InvalidTemplateId)
{
AZ_Error("Prefab", false, "Couldn't add new template id '%i' when saving file '%.*s'", templateId, AZ_STRING_ARG(filename));
@@ -253,6 +286,13 @@ namespace AzToolsFramework
m_prefabSystemComponent->RemoveTemplate(prevTemplateId);
}
// If we have a new level from a template, we need to make sure to propagate the changes here otherwise
// the entities from the new template won't show up
if (newLevelFromTemplate)
{
m_prefabSystemComponent->PropagateTemplateChanges(templateId);
}
AZStd::string out;
if (m_loaderInterface->SaveTemplateToString(m_rootInstance->GetTemplateId(), out))
{
@@ -216,5 +216,7 @@ namespace AzToolsFramework
Prefab::PrefabLoaderInterface* m_loaderInterface;
AzFramework::EntityContextId m_entityContextId;
AZ::SerializeContext m_serializeContext;
static inline constexpr const char* DefaultLevelTemplateName = "Prefabs/Default_Level.prefab";
};
}
@@ -83,7 +83,7 @@ namespace AzToolsFramework
protected:
QWidget* GetFirstInTabOrder() override;
QWidget* GetLastInTabOrder() override;
void UpdateTabOrder() override;
void UpdateTabOrder() override;
void onChildComboBoxValueChange(int comboBoxIndex) override;
@@ -93,7 +93,7 @@ namespace AzToolsFramework
void addElementImpl(const AZStd::pair<T, AZStd::string>& genericValue);
QLabel* m_warningLabel = nullptr;
QLabel* m_warningLabel = nullptr;
DHQComboBox* m_pComboBox;
AZStd::vector<AZStd::pair<T, AZStd::string>> m_values;
AZ::AttributeFunction <void(const T&)>* m_postChangeNotifyCB{};
@@ -131,6 +131,11 @@ namespace AzToolsFramework
template<typename T>
AzToolsFramework::PropertyHandlerBase* RegisterGenericComboBoxHandler()
{
if (!AzToolsFramework::PropertyTypeRegistrationMessages::Bus::FindFirstHandler())
{
return nullptr;
}
auto propertyHandler = aznew GenericComboBoxHandler<T>();
AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Broadcast(&AzToolsFramework::PropertyTypeRegistrationMessages::RegisterPropertyType, propertyHandler);
return propertyHandler;
@@ -24,7 +24,7 @@ function Process(context)
local shadowMap = context:GetShaderByTag("Shadowmap")
local forwardPassEDS = context:GetShaderByTag("ForwardPass_EDS")
local depthPassWithPS = context:GetShaderByTag("DepthPass_WithPS")
local shadowMapWitPS = context:GetShaderByTag("Shadowmap_WithPS")
local shadowMapWithPS = context:GetShaderByTag("Shadowmap_WithPS")
local forwardPass = context:GetShaderByTag("ForwardPass")
local shadingAffectsDepth = parallaxEnabled and parallaxPdoEnabled;
@@ -34,6 +34,6 @@ function Process(context)
forwardPassEDS:SetEnabled(not shadingAffectsDepth)
depthPassWithPS:SetEnabled(shadingAffectsDepth)
shadowMapWitPS:SetEnabled(shadingAffectsDepth)
shadowMapWithPS:SetEnabled(shadingAffectsDepth)
forwardPass:SetEnabled(shadingAffectsDepth)
end
@@ -32,7 +32,7 @@ function Process(context)
local lowEndForwardEDS = context:GetShaderByTag("LowEndForward_EDS")
local depthPassWithPS = context:GetShaderByTag("DepthPass_WithPS")
local shadowMapWitPS = context:GetShaderByTag("Shadowmap_WithPS")
local shadowMapWithPS = context:GetShaderByTag("Shadowmap_WithPS")
local forwardPass = context:GetShaderByTag("ForwardPass")
local lowEndForward = context:GetShaderByTag("LowEndForward")
@@ -43,7 +43,7 @@ function Process(context)
lowEndForwardEDS:SetEnabled(false)
depthPassWithPS:SetEnabled(true)
shadowMapWitPS:SetEnabled(true)
shadowMapWithPS:SetEnabled(true)
forwardPass:SetEnabled(true)
lowEndForward:SetEnabled(true)
else
@@ -53,7 +53,7 @@ function Process(context)
lowEndForwardEDS:SetEnabled((opacityMode == OpacityMode_Opaque) or (opacityMode == OpacityMode_Blended) or (opacityMode == OpacityMode_TintedTransparent))
depthPassWithPS:SetEnabled(opacityMode == OpacityMode_Cutout)
shadowMapWitPS:SetEnabled(opacityMode == OpacityMode_Cutout)
shadowMapWithPS:SetEnabled(opacityMode == OpacityMode_Cutout)
forwardPass:SetEnabled(opacityMode == OpacityMode_Cutout)
lowEndForward:SetEnabled(opacityMode == OpacityMode_Cutout)
end
@@ -203,7 +203,7 @@ namespace AZ
if (m_shadowingLightHandle.IsValid())
{
uint32_t shadowFilterMethod = m_shadowData.at(nullptr).GetData(m_shadowingLightHandle.GetIndex()).m_shadowFilterMethod;
RPI::ShaderSystemInterface::Get()->SetGlobalShaderOption(AZ::Name{"o_directional_shadow_filtering_method"}, AZ::RPI::ShaderOptionValue{shadowFilterMethod});
RPI::ShaderSystemInterface::Get()->SetGlobalShaderOption(m_directionalShadowFilteringMethodName, AZ::RPI::ShaderOptionValue{shadowFilterMethod});
const uint32_t cascadeCount = m_shadowData.at(nullptr).GetData(m_shadowingLightHandle.GetIndex()).m_cascadeCount;
ShadowProperty& property = m_shadowProperties.GetData(m_shadowingLightHandle.GetIndex());
@@ -656,6 +656,7 @@ namespace AZ
CacheRenderPipelineIdsForPersistentView();
SetConfigurationToPasses();
SetCameraViewNameToPass();
UpdateViewsOfCascadeSegments();
}
void DirectionalLightFeatureProcessor::CacheCascadedShadowmapsPass() {
@@ -1344,6 +1345,15 @@ namespace AZ
}
}
void DirectionalLightFeatureProcessor::UpdateViewsOfCascadeSegments()
{
if (m_shadowingLightHandle.IsValid())
{
const uint16_t cascadeCount = GetCascadeCount(m_shadowingLightHandle);
UpdateViewsOfCascadeSegments(m_shadowingLightHandle, cascadeCount);
}
}
Aabb DirectionalLightFeatureProcessor::CalculateShadowViewAabb(
LightHandle handle,
const RPI::View* cameraView,
@@ -296,6 +296,8 @@ namespace AZ
//! This updates the shadowmap view.
void UpdateShadowmapViews(LightHandle handle);
void UpdateViewsOfCascadeSegments();
//! This calculate shadow view AABB.
Aabb CalculateShadowViewAabb(
LightHandle handle,
@@ -372,6 +374,7 @@ namespace AZ
uint32_t m_shadowmapIndexTableBufferNameIndex = 0;
Name m_lightTypeName = Name("directional");
Name m_directionalShadowFilteringMethodName = Name("o_directional_shadow_filtering_method");
static constexpr const char* FeatureProcessorName = "DirectionalLightFeatureProcessor";
};
} // namespace Render
@@ -890,7 +890,7 @@ namespace EMotionFX
#if AZ_TRAIT_EMOTIONFX_MAIN_WINDOW_DETACHED
emotionFXWindowOptions.detachedWindow = true;
#endif
emotionFXWindowOptions.optionalMenuText = "Animation Editor (PREVIEW)";
emotionFXWindowOptions.optionalMenuText = "Animation Editor";
EditorRequests::Bus::Broadcast(&EditorRequests::RegisterViewPane, EMStudio::MainWindow::GetEMotionFXPaneName(), LyViewPane::CategoryTools, emotionFXWindowOptions, windowCreationFunc);
}
+4 -4
View File
@@ -86,7 +86,7 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
Gem::LyShine.Static
Legacy::CryCommon
Gem::LmbrCentral
Gem::TextureAtlas
Gem::TextureAtlas.Editor
Gem::AtomToolsFramework.Static
Gem::AtomToolsFramework.Editor
${additional_dependencies}
@@ -118,10 +118,10 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
AZ::AssetBuilderSDK
Gem::LyShine.Editor.Static
Gem::LmbrCentral
Gem::TextureAtlas
Gem::TextureAtlas.Editor
RUNTIME_DEPENDENCIES
Gem::LmbrCentral.Editor
Gem::TextureAtlas
Gem::TextureAtlas.Editor
)
endif()
@@ -176,7 +176,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
Legacy::CryCommon
AZ::AssetBuilderSDK
Gem::LmbrCentral
Gem::TextureAtlas
Gem::TextureAtlas.Editor
Gem::LyShine.Editor.Static
)
ly_add_googletest(
+22 -61
View File
@@ -40,6 +40,7 @@
#include "RenderGraph.h"
#include <AtomLyIntegration/AtomFont/FFont.h>
#include <Atom/RPI.Public/Image/ImageSystemInterface.h>
namespace
{
@@ -1076,7 +1077,7 @@ UiTextComponent::InlineImage::InlineImage(const AZStd::string& texturePathname,
{
m_filepath = texturePathname;
AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::NormalizePath, m_filepath);
m_texture = nullptr;
m_texture.reset();
m_size = AZ::Vector2(0.0f, 0.0f);
m_vAlign = vAlign;
m_yOffset = yOffset;
@@ -1094,24 +1095,11 @@ UiTextComponent::InlineImage::InlineImage(const AZStd::string& texturePathname,
else
{
// Load the texture
uint32 loadTextureFlags = (FT_USAGE_ALLOWREADSRGB | FT_DONT_STREAM);
ITexture* texture = gEnv->pRenderer->EF_LoadTexture(texturePathname.c_str(), loadTextureFlags);
if (!texture || !texture->IsTextureLoaded())
m_texture = CDraw2d::LoadTexture(m_filepath);
if (m_texture)
{
gEnv->pSystem->Warning(
VALIDATOR_MODULE_SHINE,
VALIDATOR_WARNING,
VALIDATOR_FLAG_FILE | VALIDATOR_FLAG_TEXTURE,
texturePathname.c_str(),
"No texture file found for image: %s. "
"NOTE: File must be in current project or a gem.",
texturePathname.c_str());
}
else
{
m_texture = texture;
m_size = AZ::Vector2(static_cast<float>(m_texture->GetWidth()), static_cast<float>(m_texture->GetHeight()));
AZ::RHI::Size size = m_texture->GetDescriptor().m_size;
m_size = AZ::Vector2(size.m_width, size.m_height);
}
}
@@ -1127,17 +1115,6 @@ UiTextComponent::InlineImage::InlineImage(const AZStd::string& texturePathname,
////////////////////////////////////////////////////////////////////////////////////////////////////
UiTextComponent::InlineImage::~InlineImage()
{
// In order to avoid the texture being deleted while there are still commands on the render
// thread command queue that use it, we queue a command to delete the texture onto the
// command queue.
if (m_texture && !m_atlas)
{
SResourceAsync* pInfo = new SResourceAsync();
pInfo->eClassName = eRCN_Texture;
pInfo->pResource = m_texture;
gEnv->pRenderer->ReleaseResourceAsync(pInfo);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1148,13 +1125,6 @@ bool UiTextComponent::InlineImage::OnAtlasLoaded(const TextureAtlasNamespace::Te
m_coordinates = atlas->GetAtlasCoordinates(m_filepath);
if (m_coordinates.GetWidth() > 0)
{
if (m_texture)
{
SResourceAsync* pInfo = new SResourceAsync();
pInfo->eClassName = eRCN_Texture;
pInfo->pResource = m_texture;
gEnv->pRenderer->ReleaseResourceAsync(pInfo);
}
m_atlas = atlas;
m_texture = m_atlas->GetTexture();
return true;
@@ -1177,25 +1147,7 @@ bool UiTextComponent::InlineImage::OnAtlasUnloaded(const TextureAtlasNamespace::
else
{
// Load the texture
uint32 loadTextureFlags = (FT_USAGE_ALLOWREADSRGB | FT_DONT_STREAM);
ITexture* texture = gEnv->pRenderer->EF_LoadTexture(m_filepath.c_str(), loadTextureFlags);
if (!texture || !texture->IsTextureLoaded())
{
gEnv->pSystem->Warning(
VALIDATOR_MODULE_SHINE,
VALIDATOR_WARNING,
VALIDATOR_FLAG_FILE | VALIDATOR_FLAG_TEXTURE,
m_filepath.c_str(),
"No texture file found for image: %s. "
"NOTE: File must be in current project or a gem.",
m_filepath.c_str());
m_texture = nullptr;
}
else
{
m_texture = texture;
}
m_texture = CDraw2d::LoadTexture(m_filepath);
}
return true;
}
@@ -1869,7 +1821,7 @@ void UiTextComponent::Render(LyShine::IRenderGraph* renderGraph)
UiTransformInterface::RectPointsArray rectPoints;
GetTextBoundingBoxPrivate(GetDrawBatchLines(), m_selectionStart, m_selectionEnd, rectPoints);
ITexture* whiteTexture = gEnv->pRenderer->GetWhiteTexture();
auto systemImage = AZ::RPI::ImageSystemInterface::Get()->GetSystemImage(AZ::RPI::SystemImage::White);
bool isClampTextureMode = true;
uint32 packedColor = (m_textSelectionColor.GetA8() << 24) | (m_textSelectionColor.GetR8() << 16) | (m_textSelectionColor.GetG8() << 8) | m_textSelectionColor.GetB8();
@@ -1878,7 +1830,12 @@ void UiTextComponent::Render(LyShine::IRenderGraph* renderGraph)
{
IRenderer::DynUiPrimitive* primitive = renderGraph->GetDynamicQuadPrimitive(rect.pt, packedColor);
primitive->m_next = nullptr;
renderGraph->AddPrimitive(primitive, whiteTexture, isClampTextureMode, isTextureSRGB, isTexturePremultipliedAlpha, blendMode);
LyShine::RenderGraph* lyRenderGraph = dynamic_cast<LyShine::RenderGraph*>(renderGraph);
if (lyRenderGraph)
{
lyRenderGraph->AddPrimitiveAtom(primitive, systemImage, isClampTextureMode, isTextureSRGB, isTexturePremultipliedAlpha, blendMode);
}
}
}
@@ -1887,21 +1844,25 @@ void UiTextComponent::Render(LyShine::IRenderGraph* renderGraph)
{
for (auto batch : m_renderCache.m_imageBatches)
{
ITexture* texture = batch->m_texture;
AZ::Data::Instance<AZ::RPI::Image> texture = batch->m_texture;
// If the fade value has changed we need to update the alpha values in the vertex colors but we do
// not want to touch or recompute the RGB values
if (batch->m_cachedPrimitive.m_vertices[0].color.a != finalAlphaByte)
{
for (int i=0; i < 4; ++i)
for (int i = 0; i < 4; ++i)
{
batch->m_cachedPrimitive.m_vertices[i].color.a = finalAlphaByte;
}
}
bool isClampTextureMode = true;
renderGraph->AddPrimitive(&batch->m_cachedPrimitive, texture,
isClampTextureMode, isTextureSRGB, isTexturePremultipliedAlpha, blendMode);
LyShine::RenderGraph* lyRenderGraph = dynamic_cast<LyShine::RenderGraph*>(renderGraph);
if (lyRenderGraph)
{
lyRenderGraph->AddPrimitiveAtom(&batch->m_cachedPrimitive, texture,
isClampTextureMode, isTextureSRGB, isTexturePremultipliedAlpha, blendMode);
}
}
}
+6 -5
View File
@@ -21,13 +21,14 @@
#include <LyShine/Bus/UiLayoutCellDefaultBus.h>
#include <LyShine/Bus/UiElementBus.h>
#include <LyShine/Bus/UiCanvasBus.h>
#include <LyShine/Bus/UiAnimateEntityBus.h>
#include <LyShine/UiAssetTypes.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/containers/set.h>
#include <LyShine/Bus/UiAnimateEntityBus.h>
#include <LyShine/UiAssetTypes.h>
#include <Atom/RPI.Reflect/Image/Image.h>
// Only needed for internal unit-testing
#include <LyShine.h>
@@ -91,7 +92,7 @@ public: //types
bool OnAtlasLoaded(const TextureAtlasNamespace::TextureAtlas* atlas);
bool OnAtlasUnloaded(const TextureAtlasNamespace::TextureAtlas* atlas);
ITexture* m_texture;
AZ::Data::Instance<AZ::RPI::Image> m_texture;
AZ::Vector2 m_size;
VAlign m_vAlign;
float m_yOffset;
@@ -616,8 +617,8 @@ private: // types
struct RenderCacheImageBatch
{
ITexture* m_texture;
IRenderer::DynUiPrimitive m_cachedPrimitive;
AZ::Data::Instance<AZ::RPI::Image> m_texture;
IRenderer::DynUiPrimitive m_cachedPrimitive;
};
struct RenderCacheData
@@ -1450,13 +1450,17 @@ void UiTextInputComponent::CheckStartTextInput()
EBUS_EVENT_ID_RESULT(textString, m_textEntity, UiTextBus, GetText);
options.m_initialText = Utf8SubString(textString, m_textCursorPos, m_textSelectionStartPos);
AZ::EntityId canvasEntityId;
EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId);
// Calculate height available for virtual keyboard. In game mode, canvas size is the same as viewport size
AZ::Vector2 canvasSize;
EBUS_EVENT_ID_RESULT(canvasSize, canvasEntityId, UiCanvasBus, GetCanvasSize);
UiTransformInterface::RectPoints rectPoints;
EBUS_EVENT_ID(GetEntityId(), UiTransformBus, GetViewportSpacePoints, rectPoints);
const AZ::Vector2 bottomRight = rectPoints.GetAxisAlignedBottomRight();
options.m_normalizedMinY = bottomRight.GetY() / static_cast<float>(gEnv->pRenderer->GetHeight());
options.m_normalizedMinY = (canvasSize.GetY() > 0.0f) ? bottomRight.GetY() / canvasSize.GetY() : 0.0f;
AZ::EntityId canvasEntityId;
EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId);
EBUS_EVENT_ID_RESULT(options.m_localUserId, canvasEntityId, UiCanvasBus, GetLocalUserIdInputFilter);
AzFramework::InputTextEntryRequestBus::Broadcast(&AzFramework::InputTextEntryRequests::TextEntryStart, options);
@@ -512,7 +512,7 @@ namespace ScriptCanvasEditor
}
}
bool Graph::SanityCheckNodeReplacement(ScriptCanvas::Node* oldNode, ScriptCanvas::Node* newNode, AZStd::unordered_map<ScriptCanvas::SlotId, AZStd::vector<ScriptCanvas::SlotId>>& outSlotIdMap)
bool Graph::SanityCheckNodeReplacement(ScriptCanvas::Node* oldNode, ScriptCanvas::Node* newNode, ScriptCanvas::NodeUpdateSlotReport& nodeUpdateSlotReport)
{
auto findReplacementMatch = [](const ScriptCanvas::Slot* oldSlot, const AZStd::vector<const ScriptCanvas::Slot*>& newSlots)->ScriptCanvas::SlotId
{
@@ -529,14 +529,14 @@ namespace ScriptCanvasEditor
return {};
};
oldNode->CustomizeReplacementNode(newNode, outSlotIdMap);
if (!newNode)
{
AZ_Warning("ScriptCanvas", false, "Replacement node can not be null.");
return false;
}
oldNode->CustomizeReplacementNode(newNode, nodeUpdateSlotReport.m_oldSlotsToNewSlots);
AZStd::unordered_map<AZStd::string, AZStd::vector<AZStd::string>> slotNameMap = oldNode->GetReplacementSlotsMap();
const auto newSlots = newNode->GetAllSlots();
@@ -544,16 +544,19 @@ namespace ScriptCanvasEditor
bool usingDefaults = true;
size_t defaultMatchesFound = 0;
auto& oldSlotsToNewSlots = nodeUpdateSlotReport.m_oldSlotsToNewSlots;
for (auto oldSlot : oldSlots)
{
const ScriptCanvas::SlotId oldSlotId = oldSlot->GetId();
const AZStd::string oldSlotName = oldSlot->GetName();
auto slotIdsIter = outSlotIdMap.find(oldSlotId);
auto slotIdsIter = oldSlotsToNewSlots.find(oldSlotId);
auto slotNamesIter = slotNameMap.find(oldSlotName);
// For old node slot remapping, we should get:
// 1. if old slot name is not static, we should find the mapping in user provided slot id map
// 2. if old slot name is static, we should find the mapping in codegen generated map (case 1 can override case 2)
if (slotIdsIter != outSlotIdMap.end())
if (slotIdsIter != oldSlotsToNewSlots.end())
{
for (auto newSlotId : slotIdsIter->second)
{
@@ -581,9 +584,10 @@ namespace ScriptCanvasEditor
if (!newSlotName.empty())
{
auto newSlot = newNode->GetSlotByName(newSlotName);
if (!newSlot)
{
AZ_Warning("ScriptCanvas", false, "Failed to find slot with name %s in replacement Node(%s).", newSlotName.c_str(), newNode->GetNodeName().c_str());
AZ_Warning("ScriptCanvas", false, "Failed to find slot with name %s in replacement Node (%s).", newSlotName.c_str(), newNode->GetNodeName().c_str());
return false;
}
else if (newSlot && oldSlot->GetType() != newSlot->GetType())
@@ -591,10 +595,11 @@ namespace ScriptCanvasEditor
AZ_Warning("ScriptCanvas", false, "Failed to map deprecated Node (%s) Slot (%s) to replacement Node (%s) Slot (%s).", oldNode->GetNodeName().c_str(), oldSlot->GetName().c_str(), newNode->GetNodeName().c_str(), newSlot->GetName().c_str());
return false;
}
newSlotIds.push_back(newSlot->GetId());
}
}
outSlotIdMap.emplace(oldSlot->GetId(), newSlotIds);
oldSlotsToNewSlots.emplace(oldSlot->GetId(), newSlotIds);
}
else if (slotNameMap.empty())
{
@@ -605,7 +610,7 @@ namespace ScriptCanvasEditor
{
++defaultMatchesFound;
AZStd::vector<ScriptCanvas::SlotId> slotIds{ newSlotId };
outSlotIdMap.emplace(oldSlot->GetId(), slotIds);
oldSlotsToNewSlots.emplace(oldSlot->GetId(), slotIds);
}
}
else
@@ -615,7 +620,7 @@ namespace ScriptCanvasEditor
}
}
if (usingDefaults && defaultMatchesFound != oldSlots.size())
if (usingDefaults && oldSlotsToNewSlots.size() != oldSlots.size())
{
AZ_Warning("ScriptCanvas", false, "Failed to remap deprecated Node(%s) not all old slots were present in the new node.", oldNode->GetNodeName().c_str());
}
@@ -690,8 +695,10 @@ namespace ScriptCanvasEditor
}
}
AZ::Outcome<ScriptCanvas::Node*> Graph::ReplaceNodeByConfig(ScriptCanvas::Node* oldNode, const ScriptCanvas::NodeConfiguration& nodeConfig,
ScriptCanvas::ReplacementConnectionMap& remapConnections)
AZ::Outcome<ScriptCanvas::Node*> Graph::ReplaceNodeByConfig
( ScriptCanvas::Node* oldNode
, const ScriptCanvas::NodeConfiguration& nodeConfig
, ScriptCanvas::NodeUpdateSlotReport& nodeUpdateSlotReport)
{
auto nodeEntity = oldNode->GetEntity();
if (!nodeEntity)
@@ -731,8 +738,8 @@ namespace ScriptCanvasEditor
AddNode(newNode->GetEntityId());
ScriptCanvas::NodeUtils::InitializeNode(newNode, nodeConfig);
AZStd::unordered_map<ScriptCanvas::SlotId, AZStd::vector<ScriptCanvas::SlotId>> slotIdMap;
rollbackRequired = !SanityCheckNodeReplacement(oldNode, newNode, slotIdMap);
rollbackRequired = !SanityCheckNodeReplacement(oldNode, newNode, nodeUpdateSlotReport);
auto& slotIdMap = nodeUpdateSlotReport.m_oldSlotsToNewSlots;
if (rollbackRequired)
{
@@ -748,25 +755,15 @@ namespace ScriptCanvasEditor
else
{
nodeEntity->Activate();
newNode->SignalReconfigurationBegin();
newNode->SetNodeDisabledFlag(oldNode->GetNodeDisabledFlag());
for (auto slotIdIter : slotIdMap)
{
ScriptCanvas::Slot* oldSlot = oldNode->GetSlot(slotIdIter.first);
const ScriptCanvas::Endpoint oldEndpoint{ nodeEntity->GetId(), oldSlot->GetId() };
if (slotIdIter.second.size() == 0)
{
// If remap id is empty, then we should just cache the old slot connection for delete
if (oldSlot->IsInput())
{
ScriptCanvas::VersioningUtils::CreateRemapConnectionsForTargetEndpoint(*this, oldEndpoint, ScriptCanvas::Endpoint(), remapConnections);
}
else
{
ScriptCanvas::VersioningUtils::CreateRemapConnectionsForSourceEndpoint(*this, oldEndpoint, ScriptCanvas::Endpoint(), remapConnections);
}
continue;
}
@@ -808,35 +805,11 @@ namespace ScriptCanvasEditor
ScriptCanvas::VersioningUtils::CopyOldValueToDataSlot(newSlot, oldSlot->GetVariableReference(), oldSlot->FindDatum());
}
// if old slot is visible, we need to check its connections for remapping
if (oldSlot->IsVisible())
{
ScriptCanvas::Endpoint newEndpoint;
if (newSlot)
{
newEndpoint = { nodeEntity->GetId(), newSlot->GetId() };
}
else
{
AZ_Warning("ScriptCanvas", false, "Invalid slot! Unable to create new connection for Node (%s).", newNode->GetNodeName().c_str());
}
if (oldSlot->IsInput())
{
ScriptCanvas::VersioningUtils::CreateRemapConnectionsForTargetEndpoint(*this, oldEndpoint, newEndpoint, remapConnections);
}
else
{
ScriptCanvas::VersioningUtils::CreateRemapConnectionsForSourceEndpoint(*this, oldEndpoint, newEndpoint, remapConnections);
}
}
}
}
delete oldNode;
newNode->SignalReconfigurationEnd();
return AZ::Success(newNode);
}
}
@@ -3634,8 +3607,7 @@ namespace ScriptCanvasEditor
AZStd::unordered_map< AZ::EntityId, AZ::EntityId > scriptCanvasToGraphCanvasMapping;
bool graphNeedsDirtying = false;
bool graphNeedsDirtying = !GetVersion().IsLatest();
{
QScopedValueRollback<bool> ignoreRequests(m_ignoreSaveRequests, true);
@@ -3659,7 +3631,8 @@ namespace ScriptCanvasEditor
AZStd::unordered_set<AZ::EntityId> deletedNodes;
AZStd::unordered_set<AZ::EntityId> assetSanitizationSet;
AZStd::unordered_set<ScriptCanvas::Node*> sanityCheckRequiredNodes;
ScriptCanvas::ReplacementConnectionMap remapConnections;
ScriptCanvas::GraphUpdateSlotReport graphUpdateSlotReport;
for (const AZ::EntityId& scriptCanvasNodeId : nodeList)
{
@@ -3674,12 +3647,15 @@ namespace ScriptCanvasEditor
ScriptCanvas::NodeConfiguration nodeConfig = scriptCanvasNode->GetReplacementNodeConfiguration();
if (nodeConfig.IsValid())
{
auto nodeOutcome = ReplaceNodeByConfig(scriptCanvasNode, nodeConfig, remapConnections);
ScriptCanvas::NodeUpdateSlotReport nodeUpdateSlotReport;
auto nodeOutcome = ReplaceNodeByConfig(scriptCanvasNode, nodeConfig, nodeUpdateSlotReport);
if (nodeOutcome.IsSuccess())
{
graphNeedsDirtying = true;
scriptCanvasNode = nodeOutcome.GetValue();
m_updateStrings.insert(AZStd::string::format("Replaced node (%s)", scriptCanvasNode->GetNodeName().c_str()));
ScriptCanvas::MergeUpdateSlotReport(scriptCanvasNodeId, graphUpdateSlotReport, nodeUpdateSlotReport);
}
}
}
@@ -3688,7 +3664,6 @@ namespace ScriptCanvasEditor
scriptCanvasToGraphCanvasMapping[scriptCanvasNodeId] = graphCanvasNodeId;
auto saveDataIter2 = m_graphCanvasSaveData.find(scriptCanvasNodeId);
if (saveDataIter2 != m_graphCanvasSaveData.end())
{
GraphCanvas::EntitySaveDataRequestBus::Event(graphCanvasNodeId, &GraphCanvas::EntitySaveDataRequests::ReadSaveData, (*saveDataIter2->second));
@@ -3699,7 +3674,7 @@ namespace ScriptCanvasEditor
GraphCanvas::SceneRequestBus::Event(graphCanvasGraphId, &GraphCanvas::SceneRequests::AddNode, graphCanvasNodeId, position, false);
// If the node is deprecated, we want to stomp whatever style it had saved and apply the deperecated style
// If the node is deprecated, we want to stomp whatever style it had saved and apply the deprecated style
if (scriptCanvasNode->IsDeprecated())
{
GraphCanvas::NodeTitleRequestBus::Event(graphCanvasNodeId, &GraphCanvas::NodeTitleRequests::SetPaletteOverride, "DeprecatedNodeTitlePalette");
@@ -3719,27 +3694,13 @@ namespace ScriptCanvasEditor
}
}
// Remap connections step should be done before editor processing connections for graph
//
// Delete underlying data conenections.
for (auto remapConnection : remapConnections)
if (!graphUpdateSlotReport.IsEmpty())
{
RemoveConnection(remapConnection.first);
// currently, it is expected that there are no deleted old slots, those need manual correction
AZ_Error("ScriptCanvas", graphUpdateSlotReport.m_deletedOldSlots.empty(), "Graph upgrade path: If old slots are deleted, manual upgrading is required");
UpdateConnectionStatus(*this, graphUpdateSlotReport);
}
// Recreate connections in a separate pass to avoid triggering display updates for invalid slot ids.
for (auto remapConnection : remapConnections)
{
for (auto newEndpointPair : remapConnection.second)
{
if (newEndpointPair.first.IsValid() && newEndpointPair.second.IsValid())
{
ConnectByEndpoint(newEndpointPair.first, newEndpointPair.second);
}
}
}
////
AZStd::unordered_set<AZ::EntityId> graphCanvasNodesToDelete;
for (auto scriptCanvasNode : outOfDateNodes)
@@ -424,24 +424,11 @@ namespace ScriptCanvasEditor
EditorGraphUpgradeMachine* sm = GetStateMachine<EditorGraphUpgradeMachine>();
auto* graph = sm->m_graph;
// Delete underlying data connections.
for (auto remapConnection : sm->m_replacementConnections)
if (!sm->m_updateReport.IsEmpty())
{
graph->RemoveConnection(remapConnection.first);
}
// Recreate connections in a separate pass to avoid triggering display updates for invalid slot ids.
for (auto remapConnection : sm->m_replacementConnections)
{
for (auto newEndpointPair : remapConnection.second)
{
if (newEndpointPair.first.IsValid() && newEndpointPair.second.IsValid())
{
graph->ConnectByEndpoint(newEndpointPair.first, newEndpointPair.second);
Log("Replaced Connection: %s\n", Helpers::ConnectionToText(graph, newEndpointPair.first, newEndpointPair.second).c_str());
}
}
// currently, it is expected that there are no deleted old slots, those need manual correction
AZ_Error("ScriptCanvas", sm->m_updateReport.m_deletedOldSlots.empty(), "Graph upgrade path: If old slots are deleted, manual upgrading is required");
UpdateConnectionStatus(*graph, sm->m_updateReport);
}
}
@@ -455,16 +442,18 @@ namespace ScriptCanvasEditor
ScriptCanvas::NodeConfiguration nodeConfig = node->GetReplacementNodeConfiguration();
if (nodeConfig.IsValid())
{
auto nodeOutcome = graph->ReplaceNodeByConfig(node, nodeConfig, sm->m_replacementConnections);
ScriptCanvas::NodeUpdateSlotReport nodeUpdateSlotReport;
auto nodeOutcome = graph->ReplaceNodeByConfig(node, nodeConfig, nodeUpdateSlotReport);
if (nodeOutcome.IsSuccess())
{
ScriptCanvas::MergeUpdateSlotReport(node->GetEntityId(), sm->m_updateReport, nodeUpdateSlotReport);
sm->m_allNodes.erase(node);
sm->m_outOfDateNodes.erase(node);
sm->m_sanityCheckRequiredNodes.erase(node);
sm->m_graphNeedsDirtying = true;
auto replacedNode = nodeOutcome.GetValue();
auto replacedNode = nodeOutcome.GetValue();
sm->m_allNodes.insert(replacedNode);
if (replacedNode->IsOutOfDate(graph->GetVersion()))
@@ -42,6 +42,7 @@
namespace ScriptCanvas
{
struct NodeConfiguration;
struct NodeUpdateSlotReport;
}
namespace ScriptCanvasEditor
@@ -361,8 +362,8 @@ namespace ScriptCanvasEditor
void HandleFunctionDefinitionExtension(ScriptCanvas::Node* node, GraphCanvas::SlotId graphCanvasSlotId, const GraphCanvas::NodeId& nodeId);
//// Version Update code
AZ::Outcome<ScriptCanvas::Node*> ReplaceNodeByConfig(ScriptCanvas::Node*, const ScriptCanvas::NodeConfiguration&, ScriptCanvas::ReplacementConnectionMap&);
bool SanityCheckNodeReplacement(ScriptCanvas::Node*, ScriptCanvas::Node*, AZStd::unordered_map<ScriptCanvas::SlotId, AZStd::vector<ScriptCanvas::SlotId>>&);
AZ::Outcome<ScriptCanvas::Node*> ReplaceNodeByConfig(ScriptCanvas::Node*, const ScriptCanvas::NodeConfiguration&, ScriptCanvas::NodeUpdateSlotReport& nodeUpdateSlotReport);
bool SanityCheckNodeReplacement(ScriptCanvas::Node*, ScriptCanvas::Node*, ScriptCanvas::NodeUpdateSlotReport& nodeUpdateSlotReport);
bool m_allowVersionUpdate = false;
AZStd::unordered_set< AZ::EntityId > m_queuedConvertingNodes;
@@ -159,7 +159,7 @@ namespace ScriptCanvasEditor
AZStd::unordered_set<AZ::EntityId> m_deletedNodes;
AZStd::unordered_set<AZ::EntityId> m_assetSanitizationSet;
ScriptCanvas::ReplacementConnectionMap m_replacementConnections;
ScriptCanvas::GraphUpdateSlotReport m_updateReport;
AZStd::unordered_map< AZ::EntityId, AZ::EntityId > m_scriptCanvasToGraphCanvasMapping;
@@ -123,6 +123,11 @@ namespace ScriptCanvasEditor
template<typename T>
AzToolsFramework::PropertyHandlerBase* RegisterGenericLineEditHandler(const EditCtrl::PropertyToStringCB<T>& propertyToStringCB, const EditCtrl::StringToPropertyCB<T>& stringToPropertyCB)
{
if (!AzToolsFramework::PropertyTypeRegistrationMessages::Bus::FindFirstHandler())
{
return nullptr;
}
auto propertyHandler(aznew GenericLineEditHandler<T>(propertyToStringCB, stringToPropertyCB));
AzToolsFramework::PropertyTypeRegistrationMessages::Bus::Broadcast(&AzToolsFramework::PropertyTypeRegistrationMessages::RegisterPropertyType, propertyHandler);
return propertyHandler;
@@ -75,7 +75,7 @@ public: \
void ConfigureSlots() override; \
bool RequiresDynamicSlotOrdering() const override; \
bool IsDeprecated() const override; \
{% if deprecationUuid is defined %} NodeConfiguration GetReplacementNodeConfiguration() const override; \
{% if deprecationUuid is defined %} ScriptCanvas::NodeConfiguration GetReplacementNodeConfiguration() const override; \
{% endif %}
using Node::FindDatum; \
{% if Class.attrib['GraphEntryPoint'] is defined %} bool IsEntryPoint() const override { return {%if Class.attrib['GraphEntryPoint'] == "True" %}true{%else%}false{%endif%}; } \
@@ -168,4 +168,4 @@ struct {{ className | replace(' ','') }}Property
{% endfor %}
{% endfor %}
{% endfor %}
@@ -22,6 +22,7 @@
namespace ScriptCanvas
{
class Slot;
struct NodeUpdateSlotReport;
class Connection
: public AZ::Component
@@ -64,6 +65,8 @@ namespace ScriptCanvas
// GraphNotificationBus
void OnNodeRemoved(const ID& nodeId) override;
void UpdateConnectionStatus(NodeUpdateSlotReport& report);
protected:
//-------------------------------------------------------------------------
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
@@ -33,7 +33,7 @@ namespace ScriptCanvas
{
if (m_availableIndexes.empty())
{
return -1;
return std::numeric_limits<AZ::u32>::max();
}
return (*m_availableIndexes.begin());
@@ -151,19 +151,22 @@ namespace ScriptCanvas
for (const AZ::BehaviorParameter* behaviorParameter : paramTypes.second)
{
ScriptCanvas::Data::Type dataType = ScriptCanvas::Data::FromAZType(behaviorParameter->m_typeId);
if (ScriptCanvas::Data::IsValueType(dataType))
if (behaviorParameter)
{
isValueType = true;
}
else if (ScriptCanvas::Data::IsContainerType(dataType))
{
isContainerType = true;
}
ScriptCanvas::Data::Type dataType = ScriptCanvas::Data::FromAZType(behaviorParameter->m_typeId);
if (ScriptCanvas::Data::IsValueType(dataType))
{
isValueType = true;
}
else if (ScriptCanvas::Data::IsContainerType(dataType))
{
isContainerType = true;
}
if (isValueType && isContainerType)
{
break;
if (isValueType && isContainerType)
{
break;
}
}
}
@@ -616,6 +616,34 @@ namespace ScriptCanvas
return false;
}
void Graph::RemoveAllConnections()
{
for (auto connectionEntity : m_graphData.m_connections)
{
if (auto connection = connectionEntity ? AZ::EntityUtils::FindFirstDerivedComponent<Connection>(connectionEntity) : nullptr)
{
if (connection->GetSourceEndpoint().IsValid())
{
EndpointNotificationBus::Event(connection->GetSourceEndpoint(), &EndpointNotifications::OnEndpointDisconnected, connection->GetTargetEndpoint());
}
if (connection->GetTargetEndpoint().IsValid())
{
EndpointNotificationBus::Event(connection->GetTargetEndpoint(), &EndpointNotifications::OnEndpointDisconnected, connection->GetSourceEndpoint());
}
}
GraphNotificationBus::Event(GetScriptCanvasId(), &GraphNotifications::OnConnectionRemoved, connectionEntity->GetId());
}
for (auto& connectionRef : m_graphData.m_connections)
{
delete connectionRef;
}
m_graphData.m_connections.clear();
}
bool Graph::RemoveConnection(const AZ::EntityId& connectionId)
{
if (connectionId.IsValid())
@@ -752,7 +780,6 @@ namespace ScriptCanvas
auto* connectionEntity = aznew AZ::Entity("Connection");
connectionEntity->CreateComponent<Connection>(sourceEndpoint, targetEndpoint);
AZ::Entity* nodeEntity{};
AZ::ComponentApplicationBus::BroadcastResult(nodeEntity, &AZ::ComponentApplicationRequests::FindEntity, sourceEndpoint.GetNodeId());
auto node = nodeEntity ? AZ::EntityUtils::FindFirstDerivedComponent<Node>(nodeEntity) : nullptr;
@@ -87,6 +87,7 @@ namespace ScriptCanvas
Slot* FindSlot(const Endpoint& endpoint) const override;
bool AddConnection(const AZ::EntityId&) override;
void RemoveAllConnections();
bool RemoveConnection(const AZ::EntityId& connectionId) override;
AZStd::vector<AZ::EntityId> GetConnections() const override;
AZStd::vector<Endpoint> GetConnectedEndpoints(const Endpoint& firstEndpoint) const override;
@@ -53,7 +53,9 @@ namespace ScriptCanvas
template<typename DatumType>
void AddDefaultInputAndOutputTypeSlot(DatumType&& defaultValue);
void AddInputTypeAndOutputTypeSlot(const Data::Type& type);
bool IsDeprecated() const override { return true; }
void OnActivate() override;
void OnInputChanged(const Datum& input, const SlotId& id) override;
void MarkDefaultableInput() override {}
@@ -347,6 +347,11 @@ namespace ScriptCanvas
}
}
void Slot::ClearDynamicGroup()
{
m_dynamicGroup = AZ::Crc32{};
}
void Slot::ConvertToLatentExecutionOut()
{
if (IsExecution() && IsOutput())
@@ -68,6 +68,8 @@ namespace ScriptCanvas
void AddContract(const ContractDescriptor& contractDesc);
void ClearDynamicGroup();
template<typename T>
T* FindContract()
{
@@ -1036,12 +1036,12 @@ namespace ScriptCanvas
if (azrtti_istypeof<ScriptCanvas::Nodes::NodeableNodeOverloaded*>(&node))
{
// todo Add node to these errors
AddError(nullptr, ValidationConstPtr(aznew NotYetImplemented(node.GetEntityId(), AZStd::string::format("NodeableNodeOverloaded doesn't have enough data connected to select a valid overload: %s", node.GetDebugName().data()))));
AddError(nullptr, ValidationConstPtr(aznew Internal::ParseError(node.GetEntityId(), AZStd::string::format("%s: %s", ParseErrors::NodeableNodeOverloadAmbiguous, node.GetDebugName().data()))));
}
else
{
// todo Add node to these errors
AddError(nullptr, ValidationConstPtr(aznew NotYetImplemented(node.GetEntityId(), AZStd::string::format("NodeableNode did not construct its internal node: %s", node.GetDebugName().data()))));
AddError(nullptr, ValidationConstPtr(aznew Internal::ParseError(node.GetEntityId(), AZStd::string::format("%s: %s", ParseErrors::NodeableNodeDidNotConstructInternalNodeable, node.GetDebugName().data()))));
}
}
}
@@ -2535,7 +2535,7 @@ namespace ScriptCanvas
if (IsInfiniteVariableWriteHandlingLoop(*this, variableHandling, variableHandling->m_function, true))
{
AddError(variableHandling->m_function, aznew NotYetImplemented(AZ::EntityId(), ScriptCanvas::ParseErrors::InfiniteLoopWritingToVariable));
AddError(variableHandling->m_function, aznew Internal::ParseError(AZ::EntityId(), ScriptCanvas::ParseErrors::InfiniteLoopWritingToVariable));
return false;
}
@@ -3312,7 +3312,7 @@ namespace ScriptCanvas
}
else
{
AddError(execution, aznew NotYetImplemented(execution->GetNodeId(), childOutSlotsOutcome.TakeError()));
AddError(execution, aznew Internal::ParseError(execution->GetNodeId(), childOutSlotsOutcome.TakeError()));
}
}
}
@@ -3615,9 +3615,11 @@ namespace ScriptCanvas
void AbstractCodeModel::ParseExecutionMultipleOutSyntaxSugar(ExecutionTreePtr execution, const EndpointsResolved& executionOutNodes, const AZStd::vector<const Slot*>& outSlots)
{
const auto executionNodeId = execution->GetId().m_node ? execution->GetId().m_node->GetEntityId() : AZ::EntityId();
if (executionOutNodes.size() != outSlots.size())
{
AddError(AZ::EntityId(), execution, ParseErrors::ParseExecutionMultipleOutSyntaxSugarMismatchOutSize);
AddError(executionNodeId, execution, ParseErrors::ParseExecutionMultipleOutSyntaxSugarMismatchOutSize);
}
if (execution->GetSymbol() != Symbol::Sequence)
@@ -3630,13 +3632,13 @@ namespace ScriptCanvas
if (!child)
{
AddError(AZ::EntityId(), execution, ParseErrors::ParseExecutionMultipleOutSyntaxSugarNullChildFound);
AddError(executionNodeId, execution, ParseErrors::ParseExecutionMultipleOutSyntaxSugarNullChildFound);
return;
}
if (child->m_execution)
{
AddError(AZ::EntityId(), execution, ParseErrors::ParseExecutionMultipleOutSyntaxSugarNonNullChildExecutionFound);
AddError(executionNodeId, execution, ParseErrors::ParseExecutionMultipleOutSyntaxSugarNonNullChildExecutionFound);
return;
}
@@ -3660,7 +3662,7 @@ namespace ScriptCanvas
if (execution->GetChildrenCount() != executionOutNodes.size())
{
AddError(AZ::EntityId(), execution, ParseErrors::ParseExecutionMultipleOutSyntaxSugarChildExecutionRemovedAndNotReplaced);
AddError(executionNodeId, execution, ParseErrors::ParseExecutionMultipleOutSyntaxSugarChildExecutionRemovedAndNotReplaced);
return;
}
}
@@ -4187,7 +4189,7 @@ namespace ScriptCanvas
}
else
{
AddError(nullptr, aznew NotYetImplemented(execution->GetNodeId(), dataSlotsOutcome.TakeError()));
AddError(nullptr, aznew Internal::ParseError(execution->GetNodeId(), dataSlotsOutcome.TakeError()));
}
}
}
@@ -4494,13 +4496,13 @@ namespace ScriptCanvas
}
else
{
AddError(execution, aznew NotYetImplemented(execution->GetNodeId(), returnSlotsOutcome.TakeError()));
AddError(execution, aznew Internal::ParseError(execution->GetNodeId(), returnSlotsOutcome.TakeError()));
}
}
}
else
{
AddError(execution, aznew NotYetImplemented(execution->GetNodeId(), outputSlotsOutcome.TakeError()));
AddError(execution, aznew Internal::ParseError(execution->GetNodeId(), outputSlotsOutcome.TakeError()));
}
}
@@ -35,15 +35,6 @@ namespace ScriptCanvas
}
}
AZStd::unordered_map<AZStd::string, AZStd::vector<AZStd::string>> ArithmeticExpression::GetReplacementSlotsMap() const
{
AZStd::unordered_map<AZStd::string, AZStd::vector<AZStd::string>> slotsMap;
slotsMap.emplace(k_evaluateName, AZStd::vector<AZStd::string>{ "In" });
slotsMap.emplace(k_outName, AZStd::vector<AZStd::string>{ "Out" });
slotsMap.emplace(k_resultName, AZStd::vector<AZStd::string>{ "Result" });
return slotsMap;
}
void ArithmeticExpression::OnInit()
{
{
@@ -72,7 +72,6 @@ namespace ScriptCanvas
bool IsDeprecated() const override { return true; }
AZStd::unordered_map<AZStd::string, AZStd::vector<AZStd::string>> GetReplacementSlotsMap() const override;
void CustomizeReplacementNode(Node* replacementNode, AZStd::unordered_map<SlotId, AZStd::vector<SlotId>>& outSlotIdMap) const override;
protected:
@@ -94,8 +94,6 @@ namespace ScriptCanvas
void ForEach::OnInit()
{
ResetLoop();
if (!m_sourceSlot.IsValid())
{
DynamicDataSlotConfiguration slotConfiguration;
@@ -130,33 +128,6 @@ namespace ScriptCanvas
EndpointNotificationBus::Handler::BusConnect({ GetEntityId(), m_sourceSlot });
}
void ForEach::OnInputSignal(const SlotId& slotId)
{
auto inSlotId = ForEachProperty::GetInSlotId(this);
if (slotId == inSlotId || slotId == SlotId{})
{
if (slotId == inSlotId)
{
if (!InitializeLoop())
{
// Loop initialization failed
SignalOutput(ForEachProperty::GetFinishedSlotId(this));
return;
}
}
if (!m_breakCalled)
{
Iterate();
}
}
else if (slotId == ForEachProperty::GetBreakSlotId(this))
{
m_breakCalled = true;
SignalOutput(ForEachProperty::GetFinishedSlotId(this));
}
}
UpdateResult ForEach::OnUpdateNode()
{
if (auto continueSlot = GetSlotByNameAndType("Continue", CombinedSlotType::ExecutionIn))
@@ -167,161 +138,6 @@ namespace ScriptCanvas
return UpdateResult::DirtyGraph;
}
bool ForEach::InitializeLoop()
{
ResetLoop();
const Datum* input = FindDatum(m_sourceSlot);
if (input && !input->Empty())
{
if (!Data::IsContainerType(input->GetType()))
{
SCRIPTCANVAS_REPORT_ERROR((*this), "Iteration not supported on this type: %s", Data::GetName(m_sourceContainer.GetType()).c_str());
return false;
}
// Make a copy of the source datum
m_sourceContainer = *input;
// Get the size of the container
auto sizeOutcome = BehaviorContextMethodHelper::CallMethodOnDatum(m_sourceContainer, "Size");
if (!sizeOutcome)
{
SCRIPTCANVAS_REPORT_ERROR((*this), "Failed to get size of container: %s", sizeOutcome.GetError().c_str());
return false;
}
Datum sizeResult = sizeOutcome.TakeValue();
const size_t* sizePtr = sizeResult.GetAs<size_t>();
m_size = sizePtr ? *sizePtr : 0;
if (Data::IsSetContainerType(m_sourceContainer.GetType()) || Data::IsMapContainerType(m_sourceContainer.GetType()))
{
// If it's a map or set, get the vector of keys
auto keysVectorOutcome = BehaviorContextMethodHelper::CallMethodOnDatum(m_sourceContainer, "GetKeys");
if (!keysVectorOutcome)
{
SCRIPTCANVAS_REPORT_ERROR((*this), "Failed to get vector of keys: %s", keysVectorOutcome.GetError().c_str());
return false;
}
m_keysVector = keysVectorOutcome.TakeValue();
// Check size of vector of keys for safety
auto keysSizeOutcome = BehaviorContextMethodHelper::CallMethodOnDatum(m_keysVector, "Size");
if (!keysSizeOutcome)
{
SCRIPTCANVAS_REPORT_ERROR((*this), "Failed to get size of vector of keys: %s", keysSizeOutcome.GetError().c_str());
return false;
}
Datum keysSizeResult = keysSizeOutcome.TakeValue();
const size_t* keysSizePtr = keysSizeResult.GetAs<size_t>();
size_t keysSize = keysSizePtr ? *keysSizePtr : 0;
if (m_size != keysSize)
{
// This shouldn't happen
SCRIPTCANVAS_REPORT_ERROR((*this), "Container size and vector of keys size mismatch.");
return false;
}
}
return true;
}
return false;
}
void ForEach::Iterate()
{
if (m_sourceContainer.Empty() || m_index >= m_size)
{
SignalOutput(ForEachProperty::GetFinishedSlotId(this));
return;
}
Datum& container = Data::IsVectorContainerType(m_sourceContainer.GetType()) ? m_sourceContainer : m_keysVector;
auto keyAtOutcome = BehaviorContextMethodHelper::CallMethodOnDatumUnpackOutcomeSuccess(container, "At", m_index);
if (!keyAtOutcome)
{
SCRIPTCANVAS_REPORT_ERROR((*this), "Failed to get key in container: %s", keyAtOutcome.GetError().c_str());
return;
}
Datum keyAtResult = keyAtOutcome.TakeValue();
if (!SetPropertySlotData(keyAtResult, k_keySlotIndex))
{
// Unable to set property slot
SCRIPTCANVAS_REPORT_ERROR((*this), "Unable to set one of the property slots on this node.");
SignalOutput(ForEachProperty::GetFinishedSlotId(this));
return;
}
if (Data::IsMapContainerType(m_sourceContainer.GetType()))
{
// If the container is a map, we want to get the value for the current key
auto valueAtOutcome = BehaviorContextMethodHelper::CallMethodOnDatumUnpackOutcomeSuccess(m_sourceContainer, "At", keyAtResult);
if (!valueAtOutcome)
{
SCRIPTCANVAS_REPORT_ERROR((*this), "Failed to get value for key in container: %s", valueAtOutcome.GetError().c_str());
return;
}
Datum valueAtResult = valueAtOutcome.TakeValue();
if (!SetPropertySlotData(valueAtResult, k_valueSlotIndex))
{
// Unable to set property slot
SCRIPTCANVAS_REPORT_ERROR((*this), "Unable to set one of the property slots on this node.");
SignalOutput(ForEachProperty::GetFinishedSlotId(this));
return;
}
}
++m_index;
SignalOutput(ForEachProperty::GetEachSlotId(this));
}
bool ForEach::SetPropertySlotData(Datum& atResult, size_t propertyIndex)
{
if (atResult.Empty())
{
// Something went wrong with the Behavior Context call
SCRIPTCANVAS_REPORT_ERROR((*this), "Behavior Context call failed; unable to retrieve element from container.");
return false;
}
if (m_propertySlots.size() <= propertyIndex)
{
// Missing a property slot
SCRIPTCANVAS_REPORT_ERROR((*this), "Node in invalid state; missing a property slot.");
return false;
}
PushOutput(atResult, *GetSlot(m_propertySlots[propertyIndex].m_propertySlotId));
return true;
}
void ForEach::ResetLoop()
{
// Reset node state
m_index = 0;
m_size = 0;
m_breakCalled = false;
m_sourceContainer = Datum();
m_keysVector = Datum();
}
void ForEach::OnDynamicGroupDisplayTypeChanged(const AZ::Crc32& dynamicGroup, const Data::Type& dataType)
{
if (dynamicGroup == GetContainerGroupId() && dataType.IsValid())
@@ -56,44 +56,29 @@ namespace ScriptCanvas
bool IsBreakSlot(const SlotId&) const;
bool IsOutOfDate(const VersionData& graphVersion) const override;
bool IsOutOfDate(const VersionData& graphVersion) const override;
UpdateResult OnUpdateNode() override;
protected:
ExecutionNameMap GetExecutionNameMap() const override;
void OnInit() override;
void OnInputSignal(const SlotId&) override;
bool InitializeLoop();
void Iterate();
bool SetPropertySlotData(Datum& atResult, size_t propertyIndex);
void ResetLoop();
void OnDynamicGroupDisplayTypeChanged(const AZ::Crc32& dynamicGroup, const Data::Type& dataType) override;
void ClearPropertySlots();
void AddPropertySlotsFromType(const Data::Type& dataType);
static AZ::Crc32 GetContainerGroupId() { return AZ_CRC("ContainerGroup", 0xb81ed451); }
SlotId m_sourceSlot;
AZ::TypeId m_previousTypeId;
AZStd::vector<Data::PropertyMetadata> m_propertySlots;
private:
static const size_t k_keySlotIndex;
static const size_t k_valueSlotIndex;
size_t m_index;
size_t m_size;
static AZ::Crc32 GetContainerGroupId() { return AZ_CRC("ContainerGroup", 0xb81ed451); }
bool m_breakCalled;
void AddPropertySlotsFromType(const Data::Type& dataType);
Datum m_sourceContainer;
Datum m_keysVector;
void ClearPropertySlots();
ExecutionNameMap GetExecutionNameMap() const override;
void OnInit() override;
void OnDynamicGroupDisplayTypeChanged(const AZ::Crc32& dynamicGroup, const Data::Type& dataType) override;
SlotId m_sourceSlot;
AZ::TypeId m_previousTypeId;
AZStd::vector<Data::PropertyMetadata> m_propertySlots;
};
}
}
@@ -410,6 +410,11 @@ namespace ScriptCanvas
return m_asset.GetId();
}
const AZStd::string& FunctionCallNode::GetAssetHint() const
{
return m_asset.GetHint();
}
AZ::Outcome<DependencyReport, void> FunctionCallNode::GetDependencies() const
{
DependencyReport report;
@@ -70,6 +70,8 @@ namespace ScriptCanvas
AZ::Data::AssetId GetAssetId() const;
const AZStd::string& GetAssetHint() const;
const AZStd::string& GetName() const;
void Initialize(AZ::Data::AssetId assetId, const ScriptCanvas::Grammar::FunctionSourceId& sourceId);
@@ -19,6 +19,32 @@
#include <ScriptCanvas/Debugger/ValidationEvents/DataValidation/InvalidPropertyEvent.h>
namespace FunctionDefinitionNodeCpp
{
void VersionUpdateRemoveDefaultDisplayGroup(ScriptCanvas::Nodes::Core::FunctionDefinitionNode& node)
{
using namespace ScriptCanvas;
using namespace ScriptCanvas::Nodes::Core;
AZ::SerializeContext* serializeContext{};
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
if (serializeContext)
{
const auto& classData = serializeContext->FindClassData(azrtti_typeid<FunctionDefinitionNode>());
if (classData && classData->m_version < FunctionDefinitionNode::NodeVersion::RemoveDefaultDisplayGroup)
{
for (auto& slot : node.ModAllSlots())
{
if (slot->GetType() == CombinedSlotType::DataIn || slot->GetType() == CombinedSlotType::DataOut)
{
slot->ClearDynamicGroup();
}
}
}
}
}
}
namespace ScriptCanvas
{
namespace Nodes
@@ -113,6 +139,12 @@ namespace ScriptCanvas
}
}
void FunctionDefinitionNode::OnInit()
{
Nodeling::OnInit();
FunctionDefinitionNodeCpp::VersionUpdateRemoveDefaultDisplayGroup(*this);
}
void FunctionDefinitionNode::SetupSlots()
{
auto groupedSlots = GetSlotsWithDisplayGroup(GetSlotDisplayGroup());
@@ -208,7 +240,6 @@ namespace ScriptCanvas
slotConfiguration.SetConnectionType(connectionType);
slotConfiguration.m_displayGroup = GetDataDisplayGroup();
slotConfiguration.m_dynamicGroup = GetDataDynamicTypeGroup();
slotConfiguration.m_dynamicDataType = DynamicDataType::Any;
slotConfiguration.m_isUserAdded = true;
@@ -29,14 +29,13 @@ namespace ScriptCanvas
class FunctionDefinitionNode
: public Internal::Nodeling
{
private:
public:
enum NodeVersion
{
Initial = 1
Initial = 1,
RemoveDefaultDisplayGroup,
};
public:
SCRIPTCANVAS_NODE(FunctionDefinitionNode);
FunctionDefinitionNode() = default;
@@ -78,14 +77,15 @@ namespace ScriptCanvas
static constexpr AZ::Crc32 GetAddNodelingInputDataSlot() { return AZ_CRC_CE("AddNodelingInputDataSlot"); }
static constexpr AZ::Crc32 GetAddNodelingOutputDataSlot() { return AZ_CRC_CE("AddNodelingOutputDataSlot"); }
static constexpr AZ::Crc32 GetDataDynamicTypeGroup() { return AZ_CRC_CE("DataGroup"); }
AZStd::string GetDataDisplayGroup() const { return "DataDisplayGroup"; }
SlotId HandleExtension(AZ::Crc32 extensionId) override;
void ConfigureVisualExtensions() override;
void OnInit() override;
void OnSetup() override;
private:
@@ -208,7 +208,6 @@ namespace ScriptCanvas
}
}
void Method::InitializeMethod(const MethodConfiguration& config)
{
m_namespaces = config.m_namespaces ? *config.m_namespaces : m_namespaces;
@@ -239,7 +238,11 @@ namespace ScriptCanvas
for (size_t argIndex(0), sentinel(config.m_method.GetNumArguments()); argIndex != sentinel; ++argIndex)
{
SlotId addedSlot = AddMethodInputSlot(config, argIndex);
MethodHelper::SetSlotToDefaultValue(*this, addedSlot, config, argIndex);
if (addedSlot.IsValid())
{
MethodHelper::SetSlotToDefaultValue(*this, addedSlot, config, argIndex);
}
}
}
@@ -132,6 +132,8 @@ namespace ScriptCanvas
const Slot* GetIfBranchSlot(bool branch) const;
AZ_INLINE const AZStd::string& GetLookupName() const { return m_lookupName; }
AZ_INLINE AZStd::recursive_mutex& GetMutex() { return m_mutex; }
ConstSlotsOutcome GetSlotsInExecutionThreadByTypeImpl(const Slot& executionSlot, CombinedSlotType targetSlotType, const Slot* executionChildSlot) const override;
@@ -160,6 +162,8 @@ namespace ScriptCanvas
bool SanityCheckBranchOnResultMethod(const AZ::BehaviorMethod& branchOnResultMethod) const;
AZ_INLINE void SetClassNamePretty(AZStd::string_view classNamePretty) { m_classNamePretty = classNamePretty; }
void SetMethodUnchecked(const AZ::BehaviorMethod* method, const AZ::BehaviorClass* behaviorClass);
AZ_INLINE void SetWarnOnMissingFunction(bool enabled) { m_warnOnMissingFunction = enabled; }
@@ -94,7 +94,7 @@ namespace ScriptCanvas
{
if (!m_updatingDisplay)
{
RefreshActiveIndexes();
RefreshActiveIndexes(true, true);
UpdateSlotDisplay();
}
}
@@ -135,10 +135,8 @@ namespace ScriptCanvas
return Data::Type::Invalid();
}
AZ::Outcome<AZStd::string, void> MethodOverloaded::GetFunctionCallName(const Slot* slot) const
AZ::Outcome<AZStd::string, void> MethodOverloaded::GetFunctionCallName([[maybe_unused]] const Slot* slot) const
{
AZ_UNUSED(slot);
AZStd::string overloadName;
int activeIndex = GetActiveIndex();
@@ -188,7 +186,7 @@ namespace ScriptCanvas
// this prevents repeated updates based on changes to slots
Method::InitializeMethod(config);
SetClassNamePretty("");
RefreshActiveIndexes();
ConfigureContracts();
@@ -197,7 +195,12 @@ namespace ScriptCanvas
SlotId MethodOverloaded::AddMethodInputSlot(const MethodConfiguration& config, size_t argumentIndex)
{
const AZ::BehaviorParameter* argumentPtr = config.m_method.GetArgument(argumentIndex);
AZ_Assert(argumentPtr, "Method: %s had a null argument at index: %d", config.m_lookupName->data(), argumentIndex);
if (!argumentPtr)
{
return SlotId{};
}
const auto& argument = *argumentPtr;
auto nameAndToolTip = MethodHelper::GetArgumentNameAndToolTip(config, argumentIndex);
@@ -507,7 +510,7 @@ namespace ScriptCanvas
}
}
void MethodOverloaded::RefreshActiveIndexes(bool checkForConnections)
void MethodOverloaded::RefreshActiveIndexes(bool checkForConnections, bool adjustSlots)
{
DataIndexMapping concreteInputTypes;
DataIndexMapping concreteOutputTypes;
@@ -519,6 +522,35 @@ namespace ScriptCanvas
if (m_overloadSelection.m_availableIndexes.size() == 1)
{
auto methodOverload = m_overloadConfiguration.m_overloads[(*m_overloadSelection.m_availableIndexes.begin())];
if (adjustSlots)
{
const size_t numArguments = methodOverload.first->GetNumArguments();
const size_t numInputSlots = m_orderedInputSlotIds.size();
if (numArguments > numInputSlots)
{
MethodConfiguration config(*methodOverload.first, GetMethodType());
AZStd::string_view lookupName = GetLookupName();
config.m_lookupName = &lookupName;
for (size_t index = numInputSlots; index != numArguments; ++index)
{
AddMethodInputSlot(config, index);
}
}
else if (numArguments < numInputSlots)
{
const size_t removeCount = numInputSlots - numArguments;
// remove extra slots, assuming remaining ones are of valid type (if not valid name)
for (size_t count = 0; count != removeCount; ++count)
{
RemoveSlot(m_orderedInputSlotIds.back());
m_orderedInputSlotIds.pop_back();
}
}
}
SetMethodUnchecked(methodOverload.first, methodOverload.second);
}
}
@@ -681,9 +713,6 @@ namespace ScriptCanvas
return AZ::Success();
}
}
}
}
@@ -106,7 +106,7 @@ namespace ScriptCanvas
void SetupMethodData(const AZ::BehaviorMethod* lookupMethod, const AZ::BehaviorClass* lookupClass);
void ConfigureContracts();
void RefreshActiveIndexes(bool checkForConnections = true);
void RefreshActiveIndexes(bool checkForConnections = true, bool adjustSlots = false);
void FindDataIndexMappings(DataIndexMapping& inputMapping, DataIndexMapping& outputMapping, bool checkForConnections) const;
void UpdateSlotDisplay();
@@ -393,14 +393,6 @@ namespace ScriptCanvas
AZ_UNUSED(sourceType);
}
AZStd::unordered_map<AZStd::string, AZStd::vector<AZStd::string>> OperatorBase::GetReplacementSlotsMap() const
{
AZStd::unordered_map<AZStd::string, AZStd::vector<AZStd::string>> slotsMap;
slotsMap.emplace("In", AZStd::vector<AZStd::string>{ "In" });
slotsMap.emplace("Out", AZStd::vector<AZStd::string>{ "Out" });
return slotsMap;
}
void OperatorBase::CustomizeReplacementNode(Node* replacementNode, AZStd::unordered_map<SlotId, AZStd::vector<SlotId>>& outSlotIdMap) const
{
auto newDataInSlots = replacementNode->GetSlotsByType(ScriptCanvas::CombinedSlotType::DataIn);
@@ -57,7 +57,6 @@ namespace ScriptCanvas
AZStd::vector< SourceSlotConfiguration > m_sourceSlotConfigurations;
};
AZStd::unordered_map<AZStd::string, AZStd::vector<AZStd::string>> GetReplacementSlotsMap() const override;
void CustomizeReplacementNode(Node* replacementNode, AZStd::unordered_map<SlotId, AZStd::vector<SlotId>>& outSlotIdMap) const override;
using TypeList = AZStd::vector<AZ::TypeId>;
@@ -8,7 +8,7 @@
Base="ScriptCanvas::Node"
Version="2"
GeneratePropertyFriend="True"
DeprecationUUID="32A4BEDC-C207-4472-61DE-9A716402620A"
DeprecationUUID="{32A4BEDC-C207-4472-61DE-9A716402620A}"
Deprecated="This node has been deprecated in favor of the nodeable form"
Description="Provides a time value.">
<In Name="Start" Description="Starts the timer."/>
@@ -25,4 +25,4 @@
IsInput="False"
IsOutput="True" />
</Class>
</ScriptCanvas>
</ScriptCanvas>
@@ -62,6 +62,8 @@ namespace ScriptCanvas
constexpr const char* NoChildrenAfterRoot = "No children after parsing function root";
constexpr const char* NoChildrenInExtraction = "No children found in property extraction node";
constexpr const char* NoDataPresent = "Could not construct from graph, no graph data was present";
constexpr const char* NodeableNodeOverloadAmbiguous = "NodeableNodeOverloaded doesn't have enough data connected to select a valid overload";
constexpr const char* NodeableNodeDidNotConstructInternalNodeable = "NodeableNode did not construct its internal Nodeable";
constexpr const char* NoInputToForEach = "No Input To For Each Loop";
constexpr const char* NoOutForExecution = "No out slot for execution root";
constexpr const char* NoOutSlotInFunctionDefinitionStart = "No 'Out' slot in start of function definition";
@@ -12,9 +12,26 @@
#include "VersioningUtils.h"
#include <ScriptCanvas/Core/Graph.h>
#include <ScriptCanvas/Core/Connection.h>
namespace ScriptCanvas
{
AZStd::vector<Endpoint> GraphUpdateSlotReport::Convert(const Endpoint& oldEndpoint) const
{
auto iter = m_oldSlotsToNewSlots.find(oldEndpoint);
return iter != m_oldSlotsToNewSlots.end() ? iter->second : AZStd::vector<Endpoint>{ oldEndpoint };
}
bool GraphUpdateSlotReport::IsEmpty() const
{
return m_deletedOldSlots.empty() && m_oldSlotsToNewSlots.empty();
}
bool NodeUpdateSlotReport::IsEmpty() const
{
return m_deletedOldSlots.empty() && m_oldSlotsToNewSlots.empty();
}
void VersioningUtils::CopyOldValueToDataSlot(Slot* newSlot, const VariableId& oldVariableReference, const Datum* oldDatum)
{
if (oldVariableReference.IsValid())
@@ -36,6 +53,99 @@ namespace ScriptCanvas
}
}
void MergeUpdateSlotReport(const AZ::EntityId& scriptCanvasNodeId, GraphUpdateSlotReport& report, const NodeUpdateSlotReport& source)
{
report.m_deletedOldSlots.reserve(source.m_deletedOldSlots.size());
for (auto& slotId : source.m_deletedOldSlots)
{
report.m_deletedOldSlots.insert({ scriptCanvasNodeId, slotId });
}
report.m_oldSlotsToNewSlots.reserve(source.m_oldSlotsToNewSlots.size());
for (auto& oldToNewIter : source.m_oldSlotsToNewSlots)
{
AZStd::vector<Endpoint> newEndpoints;
newEndpoints.reserve(oldToNewIter.second.size());
for (auto& targetSlotId : oldToNewIter.second)
{
newEndpoints.push_back({ scriptCanvasNodeId, targetSlotId });
}
report.m_oldSlotsToNewSlots[{ scriptCanvasNodeId, oldToNewIter.first}] = AZStd::move(newEndpoints);
}
}
AZStd::vector<AZStd::pair<Endpoint, Endpoint>> CollectEndpoints(const AZStd::vector<AZ::Entity*>& connections, bool logEntityNames)
{
AZStd::vector<AZStd::string> names;
AZStd::vector<AZStd::pair<Endpoint, Endpoint>> endpoints;
for (auto& connectionEntity : connections)
{
if (logEntityNames)
{
names.push_back(connectionEntity->GetName());
}
if (auto connection = AZ::EntityUtils::FindFirstDerivedComponent<ScriptCanvas::Connection>(connectionEntity->GetId()))
{
endpoints.push_back(AZStd::make_pair(connection->GetSourceEndpoint(), connection->GetTargetEndpoint()));
}
}
if (logEntityNames)
{
AZStd::sort(names.begin(), names.end());
AZStd::string result = "\nConnection Name list:\n";
for (auto& name : names)
{
result += "\n";
result += name;
}
AZ_TracePrintf("ScriptCanvas", result.c_str());
}
return endpoints;
}
void UpdateConnectionStatus(Graph& graph, const GraphUpdateSlotReport& report)
{
GraphData* graphData = graph.GetGraphData();
if (!graphData)
{
AZ_Error("ScriptCanvas", false, "Graph was missing graph data to update");
return;
}
AZStd::unordered_set<SlotId> oldConnectedSlots;
AZ_TracePrintf("ScriptCanvas", "Connections list before: ");
auto endpoints = CollectEndpoints(graphData->m_connections, true);
graph.RemoveAllConnections();
for (auto& iter : endpoints)
{
const AZStd::vector<Endpoint>& sources = report.Convert(iter.first);
const AZStd::vector<Endpoint>& targets = report.Convert(iter.second);
for (const auto& source : sources)
{
for (const auto& target : targets)
{
graph.ConnectByEndpoint(source, target);
}
}
}
graphData->BuildEndpointMap();
AZ_TracePrintf("ScriptCanvas", "Connections list after: ");
CollectEndpoints(graphData->m_connections, true);
}
void VersioningUtils::CreateRemapConnectionsForSourceEndpoint(const Graph& graph, const Endpoint& oldSourceEndpoint, const Endpoint& newSourceEndpoint,
ReplacementConnectionMap& connectionMap)
{
@@ -15,6 +15,8 @@
#include <AzCore/std/containers/unordered_set.h>
#include <AzCore/std/utils.h>
#include <ScriptCanvas/Core/Core.h>
#include <ScriptCanvas/Core/Endpoint.h>
#include <ScriptCanvas/Variable/VariableCore.h>
namespace AZ
@@ -25,13 +27,36 @@ namespace AZ
namespace ScriptCanvas
{
class Datum;
class Endpoint;
class Graph;
class Slot;
using ReplacementEndpointPairs = AZStd::unordered_set<AZStd::pair<ScriptCanvas::Endpoint, ScriptCanvas::Endpoint>>;
using ReplacementEndpointPairs = AZStd::unordered_set<AZStd::pair<Endpoint, Endpoint>>;
using ReplacementConnectionMap = AZStd::unordered_map<AZ::EntityId, ReplacementEndpointPairs>;
struct NodeUpdateSlotReport
{
AZStd::unordered_set<SlotId> m_deletedOldSlots;
AZStd::unordered_map<SlotId, AZStd::vector<SlotId>> m_oldSlotsToNewSlots;
bool IsEmpty() const;
};
struct GraphUpdateSlotReport
{
AZStd::unordered_set<Endpoint> m_deletedOldSlots;
AZStd::unordered_map<Endpoint, AZStd::vector<Endpoint>> m_oldSlotsToNewSlots;
AZStd::vector<Endpoint> Convert(const Endpoint& oldEndpoint) const;
bool IsEmpty() const;
};
void MergeUpdateSlotReport(const AZ::EntityId& scriptCanvasNodeId, GraphUpdateSlotReport& report, const NodeUpdateSlotReport& source);
AZStd::vector<AZStd::pair<Endpoint, Endpoint>> CollectEndpoints(const AZStd::vector<AZ::Entity*>& connections, bool logEntityNames = false);
void UpdateConnectionStatus(Graph& graph, const GraphUpdateSlotReport& report);
class VersioningUtils
{
public:
@@ -6,8 +6,10 @@
PreferredClassName="Input Handler"
Uuid="{0B0AC61B-4BBA-42BF-BDCD-DAF2D3CA41A8}"
Base="ScriptCanvas::Node"
Icon="Icons/ScriptCanvas/Bus.png"
Icon="Editor/Icons/ScriptCanvas/Bus.png"
EditAttributes="AZ::Edit::Attributes::Category@Gameplay/Input"
DeprecationUUID="{0A2EB488-5A6A-E166-BB62-23FF81499E33}"
Deprecated="This node has been deprecated in favor of the nodeable form"
GraphEntryPoint="True"
GeneratePropertyFriend="True"
Description="Handle processed input events found in input binding assets">
@@ -25,4 +27,4 @@
IsInput="False"
IsOutput="True" />
</Class>
</ScriptCanvas>
</ScriptCanvas>
+43 -1
View File
@@ -10,7 +10,7 @@
#
ly_add_target(
NAME TextureAtlas ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
NAME TextureAtlas.Static STATIC
NAMESPACE Gem
FILES_CMAKE
textureatlas_files.cmake
@@ -21,4 +21,46 @@ ly_add_target(
PRIVATE
Legacy::CryCommon
AZ::AzFramework
PUBLIC
Gem::Atom_RPI.Public
AZ::AtomCore
)
ly_add_target(
NAME TextureAtlas ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
NAMESPACE Gem
FILES_CMAKE
textureatlas_module_files.cmake
INCLUDE_DIRECTORIES
PUBLIC
Include
BUILD_DEPENDENCIES
PRIVATE
Legacy::CryCommon
Gem::TextureAtlas.Static
)
if(PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_target(
NAME TextureAtlas.Editor GEM_MODULE
NAMESPACE Gem
FILES_CMAKE
textureatlas_module_files.cmake
textureatlas_builder_files.cmake
COMPILE_DEFINITIONS
PRIVATE
TEXTUREATLAS_EDITOR
INCLUDE_DIRECTORIES
PUBLIC
Include
BUILD_DEPENDENCIES
PRIVATE
Legacy::CryCommon
AZ::AzCore
AZ::AzFramework
AZ::AssetBuilderSDK
Gem::TextureAtlas.Static
Gem::ImageProcessingAtom.Headers
)
endif()
@@ -16,7 +16,8 @@
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Asset/AssetCommon.h>
class ITexture;
#include <Atom/RPI.Reflect/Image/Image.h>
#include <AtomCore/Instance/Instance.h>
namespace TextureAtlasNamespace
{
@@ -77,9 +78,9 @@ namespace TextureAtlasNamespace
//! Retrieve a coordinate set from the Atlas by its handle
virtual AtlasCoordinates GetAtlasCoordinates(const AZStd::string& handle) const = 0;
//! Links this atlas to an image pointer
virtual void SetTexture(ITexture* image) = 0;
virtual void SetTexture(AZ::Data::Instance<AZ::RPI::Image> image) = 0;
//! Returns the image linked to this atlas
virtual ITexture* GetTexture() const = 0;
virtual AZ::Data::Instance<AZ::RPI::Image> GetTexture() const = 0;
//! Returns the width of the atlas
virtual int GetWidth() const = 0;
//! Returns the height of the atlas
@@ -10,7 +10,6 @@
*
*/
#include "ImageProcessing_precompiled.h"
#include "AtlasBuilderComponent.h"
#include <AzCore/Serialization/SerializeContext.h>
@@ -10,7 +10,6 @@
*
*/
#include "ImageProcessing_precompiled.h"
#include "AtlasBuilderWorker.h"
#include <AzCore/Math/MathIntrinsics.h>
@@ -19,22 +18,17 @@
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/sort.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/IO/SystemFile.h>
#include <AzCore/std/string/regex.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <AzFramework/IO/LocalFileIO.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <ImageProcessing/ImageObject.h>
#include <Processing/ImageConvert.h>
#include <Processing/ImageConvertJob.h>
#include <ImageLoader/ImageLoaders.h>
#include <Processing/ImageObjectImpl.h>
#include <Processing/PixelFormatInfo.h>
#include <BuilderSettings/PresetSettings.h>
#include <BuilderSettings/TextureSettings.h>
#include <BuilderSettings/BuilderSettingManager.h>
#include <Atom/ImageProcessing/ImageObject.h>
#include <Atom/ImageProcessing/ImageProcessingBus.h>
#include <Atom/ImageProcessing/PixelFormats.h>
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
#include <qimage.h>
#include <QString>
@@ -44,13 +38,13 @@
namespace TextureAtlasBuilder
{
//! Counts leading zeros
uint32 CountLeadingZeros32(uint32 x)
uint32_t CountLeadingZeros32(uint32_t x)
{
return x == 0 ? 32 : az_clz_u32(x);
}
//! Integer log2
uint32 IntegerLog2(uint32 x)
uint32_t IntegerLog2(uint32_t x)
{
return 31 - CountLeadingZeros32(x);
}
@@ -113,13 +107,24 @@ namespace TextureAtlasBuilder
{
bool resolved = false;
// Get full path by appending the relative path to the watch directory
AZStd::string fullPath = watchDirectory;
fullPath.append("/");
fullPath.append(relativePath);
if (relativePath[0] == '@')
{
// Get full path by resolving the alias at the front of the path
char resolvedPath[AZ_MAX_PATH_LEN];
AZ::IO::FileIOBase::GetInstance()->ResolvePath(relativePath.c_str(), resolvedPath, AZ_MAX_PATH_LEN);
resolvedFullPathOut = resolvedPath;
resolved = true;
}
else
{
// Get full path by appending the relative path to the watch directory
AZStd::string fullPath = watchDirectory;
fullPath.append("/");
fullPath.append(relativePath);
// Resolve to canonical path (remove "./" and "../")
resolved = GetCanonicalPathFromFullPath(fullPath, resolvedFullPathOut);
// Resolve to canonical path (remove "./" and "../")
resolved = GetCanonicalPathFromFullPath(fullPath, resolvedFullPathOut);
}
return resolved;
}
@@ -140,23 +145,6 @@ namespace TextureAtlasBuilder
return result;
}
const ImageProcessing::PresetSettings* GetImageProcessPresetSettings(const AZStd::string& presetName, const AZStd::string& platformIdentifier)
{
// Get the specified presetId
AZ::Uuid presetId = ImageProcessing::BuilderSettingManager::Instance()->GetPresetIdFromName(presetName);
if (presetId.IsNull())
{
AZ_Error("Texture Editor", false, "Texture Preset %s has no associated UUID.", presetName.c_str());
return nullptr;
}
// Get the preset settings for the platform this job is building for
const ImageProcessing::PresetSettings* presetSettings = ImageProcessing::BuilderSettingManager::Instance()->GetPreset(
presetId, platformIdentifier);
return presetSettings;
}
// Reflect the input parameters
void AtlasBuilderInput::Reflect(AZ::ReflectContext* context)
{
@@ -474,7 +462,7 @@ namespace TextureAtlasBuilder
{
AZStd::string ext;
AzFramework::StringFunc::Path::GetExtension(candidates[i].c_str(), ext, false);
if (ImageProcessing::IsExtensionSupported(ext.c_str()) && ext != "dds")
if (ext != "dds")
{
bool duplicate = false;
for (size_t j = 0; j < paths.size() && !duplicate; ++j)
@@ -589,7 +577,7 @@ namespace TextureAtlasBuilder
{
AddFolderContents(paths, child, valid);
}
else if (ImageProcessing::IsExtensionSupported(ext.c_str()) && ext != "dds")
else if (ext != "dds")
{
AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::NormalizePathKeepCase, child);
bool duplicate = false;
@@ -652,7 +640,11 @@ namespace TextureAtlasBuilder
// We process the same file for all platforms
for (const AssetBuilderSDK::PlatformInfo& info : request.m_enabledPlatforms)
{
if (ImageProcessing::BuilderSettingManager::Instance()->DoesSupportPlatform(info.m_identifier))
bool doesSupportPlatform = false;
ImageProcessingAtom::ImageBuilderRequestBus::BroadcastResult(doesSupportPlatform,
&ImageProcessingAtom::ImageBuilderRequests::DoesSupportPlatform,
info.m_identifier);
if (doesSupportPlatform)
{
AssetBuilderSDK::JobDescriptor descriptor = GetJobDescriptor(request.m_sourceFile, input);
descriptor.SetPlatformIdentifier(info.m_identifier.c_str());
@@ -707,12 +699,8 @@ namespace TextureAtlasBuilder
// Before we begin, let's make sure we are not meant to abort.
AssetBuilderSDK::JobCancelListener jobCancelListener(request.m_jobId);
AZStd::vector<AZStd::string> productFilepaths;
const AZStd::string path = request.m_fullPath;
bool imageProcessingSuccessful = false;
// read in settings/filepaths
AtlasBuilderInput input;
input.m_forceSquare = AzFramework::StringFunc::ToBool(request.m_jobDescription.m_jobParameters.find(AZ_CRC("forceSquare"))->second.c_str());
@@ -752,43 +740,37 @@ namespace TextureAtlasBuilder
// Default to the TextureAtlas preset which is currently set to use compression for all platforms except for iOS.
// Currently the only fully supported compression for iOS is PVRTC which requires the texture to be square and a power of 2.
// Due to this limitation, we default to using no compression for iOS until ASTC is fully supported
const AZStd::string defaultPresetName = "TextureAtlas";
const AZStd::string defaultPresetName = "UserInterface_Compressed";
input.m_presetName = defaultPresetName;
}
// Get a preset to use for the output image
const ImageProcessing::PresetSettings* preset = GetImageProcessPresetSettings(input.m_presetName, request.m_platformInfo.m_identifier);
if (preset)
bool isFormatSquarePow2 = false;
ImageProcessingAtom::ImageBuilderRequestBus::BroadcastResult(isFormatSquarePow2,
&ImageProcessingAtom::ImageBuilderRequests::IsPresetFormatSquarePow2,
input.m_presetName, request.m_platformInfo.m_identifier);
if (isFormatSquarePow2)
{
// Check the preset's pixel format requirements
const ImageProcessing::PixelFormatInfo* pixelFormatInfo = ImageProcessing::CPixelFormats::GetInstance().GetPixelFormatInfo(preset->m_pixelFormat);
if (pixelFormatInfo && pixelFormatInfo->bSquarePow2)
{
// Override the user config settings to force square and power of 2.
// Otherwise the image conversion process will stretch the image to satisfy these requirements
input.m_forceSquare = true;
input.m_forcePowerOf2 = true;
}
}
else
{
AZ_Error("AtlasBuilder", false, "Could not find a preset setting for the output image.");
return;
// Override the user config settings to force square and power of 2.
// Otherwise the image conversion process will stretch the image to satisfy these requirements
input.m_forceSquare = true;
input.m_forcePowerOf2 = true;
}
// Read in images
AZStd::vector<ImageProcessing::IImageObjectPtr> images;
AZStd::vector<ImageProcessingAtom::IImageObjectPtr> images;
AZ::u64 totalArea = 0;
int maxArea = input.m_maxDimension * input.m_maxDimension;
bool sizeFailure = false;
for (int i = 0; i < input.m_filePaths.size() && !jobCancelListener.IsCancelled(); ++i)
{
ImageProcessing::IImageObject* inputImage = ImageProcessing::LoadImageFromFile(input.m_filePaths[i]);
ImageProcessingAtom::IImageObjectPtr inputImage;
ImageProcessingAtom::ImageProcessingRequestBus::BroadcastResult(inputImage, &ImageProcessingAtom::ImageProcessingRequests::LoadImage, input.m_filePaths[i]);
// Check if we were able to load the image
if (inputImage)
{
ImageProcessing::IImageObjectPtr image = ImageProcessing::IImageObjectPtr(inputImage);
images.push_back(image);
images.push_back(inputImage);
totalArea += inputImage->GetWidth(0) * inputImage->GetHeight(0);
}
else
@@ -837,8 +819,13 @@ namespace TextureAtlasBuilder
// Add white texture if we need to
if (input.m_includeWhiteTexture)
{
ImageProcessing::IImageObjectPtr texture(ImageProcessing::IImageObject::CreateImage(
cellSize, cellSize, 1, ImageProcessing::EPixelFormat::ePixelFormat_R8G8B8A8));
ImageProcessingAtom::IImageObjectPtr texture;
ImageProcessingAtom::ImageBuilderRequestBus::BroadcastResult(texture,
&ImageProcessingAtom::ImageBuilderRequests::CreateImage,
aznumeric_cast<AZ::u32>(cellSize),
aznumeric_cast<AZ::u32>(cellSize),
1,
ImageProcessingAtom::EPixelFormat::ePixelFormat_R8G8B8A8);
// Make the texture white
texture->ClearColor(1, 1, 1, 1);
@@ -897,8 +884,8 @@ namespace TextureAtlasBuilder
}
if (input.m_forcePowerOf2)
{
resultWidth = aznumeric_cast<int>(pow(2, 1 + IntegerLog2(static_cast<uint32>(resultWidth - 1))));
resultHeight = aznumeric_cast<int>(pow(2, 1 + IntegerLog2(static_cast<uint32>(resultHeight - 1))));
resultWidth = aznumeric_cast<int>(pow(2, 1 + IntegerLog2(static_cast<uint32_t>(resultWidth - 1))));
resultHeight = aznumeric_cast<int>(pow(2, 1 + IntegerLog2(static_cast<uint32_t>(resultHeight - 1))));
}
else
{
@@ -918,8 +905,13 @@ namespace TextureAtlasBuilder
}
// Process texture sheet
ImageProcessing::IImageObjectPtr outImage(ImageProcessing::IImageObject::CreateImage(
resultWidth, resultHeight, 1, ImageProcessing::EPixelFormat::ePixelFormat_R8G8B8A8));
ImageProcessingAtom::IImageObjectPtr outImage;
ImageProcessingAtom::ImageBuilderRequestBus::BroadcastResult(outImage,
&ImageProcessingAtom::ImageBuilderRequests::CreateImage,
aznumeric_cast<AZ::u32>(resultWidth),
aznumeric_cast<AZ::u32>(resultHeight),
1,
ImageProcessingAtom::EPixelFormat::ePixelFormat_R8G8B8A8);
// Clear the sheet
outImage->ClearColor(input.m_unusedColor.GetR(), input.m_unusedColor.GetG(), input.m_unusedColor.GetB(), input.m_unusedColor.GetA());
@@ -1010,54 +1002,21 @@ namespace TextureAtlasBuilder
// Output texture sheet
AZStd::string imageFileName, imageOutputPath;
AzFramework::StringFunc::Path::GetFileName(request.m_sourceFile.c_str(), imageFileName);
imageFileName += ".dds";
imageFileName += ".texatlas";
AzFramework::StringFunc::Path::Join(
request.m_tempDirPath.c_str(), imageFileName.c_str(), imageOutputPath, true, true);
// Let the ImageProcessor do the rest of the work.
ImageProcessing::TextureSettings textureSettings;
textureSettings.m_preset = preset->m_uuid;
AZStd::vector<AssetBuilderSDK::JobProduct> outProducts;
ImageProcessingAtom::ImageBuilderRequestBus::BroadcastResult(outProducts,
&ImageProcessingAtom::ImageBuilderRequests::ConvertImageObject,
outImage,
input.m_presetName,
request.m_platformInfo.m_identifier,
imageOutputPath,
request.m_sourceFileUUID,
request.m_sourceFile);
// Mipmaps for the texture atlas would require more work than the Image Processor does. This is because if we
// let the Image Processor make mipmaps, it might bleed the textures in the atlas together.
textureSettings.m_enableMipmap = false;
// Check if the ImageBuilder wants to enable streaming
bool isStreaming = ImageProcessing::BuilderSettingManager::Instance()
->GetBuilderSetting(request.m_platformInfo.m_identifier)
->m_enableStreaming;
bool canOverridePreset = false;
ImageProcessing::ImageConvertProcess* process =
new ImageProcessing::ImageConvertProcess(outImage,
textureSettings,
*preset,
false,
isStreaming,
canOverridePreset,
imageOutputPath,
request.m_platformInfo.m_identifier);
if (process != nullptr)
{
// the process can be stopped if the job is cancelled or the worker is shutting down
while (!process->IsFinished() && !m_isShuttingDown && !jobCancelListener.IsCancelled())
{
process->UpdateProcess();
}
// get process result
imageProcessingSuccessful = process->IsSucceed();
process->GetAppendOutputFilePaths(productFilepaths);
delete process;
}
else
{
imageProcessingSuccessful = false;
}
if (imageProcessingSuccessful)
if (!outProducts.empty())
{
TextureAtlasNamespace::TextureAtlasRequestBus::Broadcast(
&TextureAtlasNamespace::TextureAtlasRequests::SaveAtlasToFile, outputPath, output, resultWidth, resultHeight);
@@ -1067,27 +1026,23 @@ namespace TextureAtlasBuilder
// The Image Processing Gem can produce multiple output files under certain
// circumstances, but the texture atlas is not expected to produce such output
if (productFilepaths.size() > 1)
if (outProducts.size() > 1)
{
AZ_Error("AtlasBuilder", false, "Image processing resulted in multiple output files. Texture atlas is expected to produce one output.");
response.m_outputProducts.clear();
return;
}
if (productFilepaths.size() > 0)
{
response.m_outputProducts.push_back(AssetBuilderSDK::JobProduct(productFilepaths[0]));
response.m_outputProducts.back().m_productAssetType = azrtti_typeid<TextureAtlasNamespace::TextureAtlasAsset>();
response.m_outputProducts.back().m_productSubID = 1;
response.m_outputProducts.push_back(outProducts[0]);
// The texatlasidx file is a data file that indicates where the original parts are inside the atlas,
// and this would usually imply that it refers to its dds file in some way or needs it to function.
// The texatlasidx file should be the one that depends on the DDS because it's possible to use the DDS
// without the texatlasid, but not the other way around
AZ::Data::AssetId productAssetId(request.m_sourceFileUUID, response.m_outputProducts.back().m_productSubID);
response.m_outputProducts[static_cast<int>(Product::TexatlasidxProduct)].m_dependencies.push_back(AssetBuilderSDK::ProductDependency(productAssetId, 0));
response.m_outputProducts[static_cast<int>(Product::TexatlasidxProduct)].m_dependenciesHandled = true; // We've populated the dependencies immediately above so it's OK to tell the AP we've handled dependencies
// The texatlasidx file is a data file that indicates where the original parts are inside the atlas,
// and this would usually imply that it refers to its dds file in some way or needs it to function.
// The texatlasidx file should be the one that depends on the DDS because its possible to use the DDS
// without the texatlasid, but not the other way around
AZ::Data::AssetId productAssetId(request.m_sourceFileUUID, response.m_outputProducts.back().m_productSubID);
response.m_outputProducts[static_cast<int>(Product::TexatlasidxProduct)].m_dependencies.push_back(AssetBuilderSDK::ProductDependency(productAssetId, 0));
response.m_outputProducts[static_cast<int>(Product::TexatlasidxProduct)].m_dependenciesHandled = true; // We've populated the dependencies immediately above so it's OK to tell the AP we've handled dependencies
}
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
}
}
@@ -1315,7 +1270,7 @@ namespace TextureAtlasBuilder
if (powerOfTwo)
{
// Starting dimension needs to be rounded up to the nearest power of two
dimension = aznumeric_cast<int>(pow(2, 1 + IntegerLog2(static_cast<uint32>(dimension - 1))));
dimension = aznumeric_cast<int>(pow(2, 1 + IntegerLog2(static_cast<uint32_t>(dimension - 1))));
}
AZStd::vector<AtlasCoordinates> track;
@@ -1363,7 +1318,7 @@ namespace TextureAtlasBuilder
if (powerOfTwo)
{
// Starting dimension needs to be rounded up to the nearest power of two
minWidth = aznumeric_cast<AZ::u32>(pow(2, 1 + IntegerLog2(static_cast<uint32>(minWidth - 1))));
minWidth = aznumeric_cast<AZ::u32>(pow(2, 1 + IntegerLog2(static_cast<uint32_t>(minWidth - 1))));
}
// Round min width up to the nearest compression unit
@@ -1400,7 +1355,7 @@ namespace TextureAtlasBuilder
// Find the height of the solution
for (int i = 0; i < track.size(); ++i)
{
uint32 bottom = static_cast<uint32>(AZStd::max(0, track[i].GetBottom()));
uint32_t bottom = static_cast<uint32_t>(AZStd::max(0, track[i].GetBottom()));
if (height < bottom)
{
height = bottom;
@@ -1411,7 +1366,7 @@ namespace TextureAtlasBuilder
if (powerOfTwo)
{
// Starting dimensions need to be rounded up to the nearest power of two
height = aznumeric_cast<AZ::u32>(pow(2, 1 + IntegerLog2(static_cast<uint32>(height - 1))));
height = aznumeric_cast<AZ::u32>(pow(2, 1 + IntegerLog2(static_cast<uint32_t>(height - 1))));
}
AZ::u32 resultArea = height * width;
@@ -13,6 +13,7 @@
#pragma once
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/Math/Color.h>
#include <AssetBuilderSDK/AssetBuilderSDK.h>
#include <AssetBuilderSDK/AssetBuilderBusses.h>
#include <qimage.h>
@@ -110,7 +111,7 @@ namespace TextureAtlasBuilder
enum class Product
{
TexatlasidxProduct = 0,
DdsProduct = 1
StreamingImageProduct = 1
};
//! An asset builder for texture atlases
@@ -120,14 +120,14 @@ namespace TextureAtlasNamespace
}
// Links this atlas to an image pointer
void TextureAtlasImpl::SetTexture(ITexture* image)
void TextureAtlasImpl::SetTexture(AZ::Data::Instance<AZ::RPI::Image> image)
{
// We don't need to delete the old value because the pointer is handled elsewhere
m_image = image;
}
// Returns the image linked to this atlas
ITexture* TextureAtlasImpl::GetTexture() const
AZ::Data::Instance<AZ::RPI::Image> TextureAtlasImpl::GetTexture() const
{
return m_image;
}
@@ -20,7 +20,8 @@
#include "TextureAtlas/TextureAtlas.h"
#include "TextureAtlas/TextureAtlasBus.h"
#include <ITexture.h>
#include <Atom/RPI.Reflect/Image/Image.h>
#include <AtomCore/Instance/Instance.h>
namespace TextureAtlasNamespace
{
@@ -61,10 +62,10 @@ namespace TextureAtlasNamespace
AtlasCoordinates GetAtlasCoordinates(const AZStd::string& handle) const override;
//! Links this atlas to an image pointer
void SetTexture(ITexture* image) override;
void SetTexture(AZ::Data::Instance<AZ::RPI::Image> image) override;
//! Returns the image linked to this atlas
ITexture* GetTexture() const override;
AZ::Data::Instance<AZ::RPI::Image> GetTexture() const override;
//! Replaces the mappings of this Texture Atlas Object, with the source's mappings
void OverwriteMappings(TextureAtlasImpl* source);
@@ -80,7 +81,7 @@ namespace TextureAtlasNamespace
private:
AZStd::unordered_map<AZStd::string, AtlasCoordinates, hash_case_insensitive, equal_to_case_insensitive> m_data;
ITexture* m_image;
AZ::Data::Instance<AZ::RPI::Image> m_image;
int m_width;
int m_height;
};
@@ -16,6 +16,10 @@
#include "TextureAtlasSystemComponent.h"
#ifdef TEXTUREATLAS_EDITOR
#include "Editor/AtlasBuilderComponent.h"
#endif
#include <IGem.h>
namespace TextureAtlasNamespace
@@ -33,6 +37,9 @@ namespace TextureAtlasNamespace
// Push results of [MyComponent]::CreateDescriptor() into m_descriptors here.
m_descriptors.insert(m_descriptors.end(), {
TextureAtlasSystemComponent::CreateDescriptor(),
#ifdef TEXTUREATLAS_EDITOR
TextureAtlasBuilder::AtlasBuilderComponent::CreateDescriptor(), //builder component for texture atlas
#endif
});
}
@@ -22,7 +22,25 @@
#include <AzCore/Asset/AssetManagerBus.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <IRenderer.h>
#include <Atom/RPI.Public/Image/StreamingImage.h>
namespace
{
AZ::Data::Instance<AZ::RPI::Image> LoadAtlasImage(const AZStd::string& imagePath)
{
// The file may not be in the AssetCatalog at this point if it is still processing or doesn't exist on disk.
// Use GenerateAssetIdTEMP instead of GetAssetIdByPath so that it will return a valid AssetId anyways
AZ::Data::AssetId streamingImageAssetId;
AZ::Data::AssetCatalogRequestBus::BroadcastResult(
streamingImageAssetId, &AZ::Data::AssetCatalogRequestBus::Events::GenerateAssetIdTEMP,
imagePath.c_str());
streamingImageAssetId.m_subId = AZ::RPI::StreamingImageAsset::GetImageAssetSubId();
auto streamingImageAsset = AZ::Data::AssetManager::Instance().FindOrCreateAsset<AZ::RPI::StreamingImageAsset>(streamingImageAssetId, AZ::Data::AssetLoadBehavior::PreLoad);
AZ::Data::Instance<AZ::RPI::Image> image = AZ::RPI::StreamingImage::FindOrCreate(streamingImageAsset);
return image;
}
}
namespace TextureAtlasNamespace
{
@@ -95,27 +113,15 @@ namespace TextureAtlasNamespace
// We reload the image here to prevent stuttering in the editor
if (iterator->second.m_atlas && iterator->second.m_atlas->GetTexture())
{
SResourceAsync* pInfo = new SResourceAsync();
pInfo->eClassName = eRCN_Texture;
pInfo->pResource = iterator->second.m_atlas->GetTexture();
// ToDo: Update to work with Atom? LYN-3680
// ???->ReleaseResourceAsync(pInfo);
iterator->second.m_atlas->GetTexture().reset();
}
// Reload Texture
AZStd::string imagePath = iterator->second.m_path.substr(0, iterator->second.m_path.find_last_of('.'));
imagePath.append(".dds");
// ToDo: Update to work with Atom? LYN-3680
// uint32 loadTextureFlags = (FT_USAGE_ALLOWREADSRGB | FT_DONT_STREAM);
ITexture* texture = nullptr;
if (!texture || !texture->IsTextureLoaded())
AZStd::string imagePath = iterator->second.m_path;
AZ::Data::Instance<AZ::RPI::Image> texture = LoadAtlasImage(imagePath);
if (!texture)
{
gEnv->pSystem->Warning(VALIDATOR_MODULE_UNKNOWN,
VALIDATOR_WARNING,
VALIDATOR_FLAG_FILE | VALIDATOR_FLAG_TEXTURE,
imagePath.c_str(),
"No texture file found for texture atlas: %s. "
AZ_Error("TextureAtlasSystemComponent",
false,
"Failed to find or create an image instance for texture atlas '%s'"
"NOTE: File must be in current project or a gem.",
imagePath.c_str());
TextureAtlas* temp = iterator->second.m_atlas;
@@ -123,6 +129,7 @@ namespace TextureAtlasNamespace
TextureAtlasNotificationBus::Broadcast(&TextureAtlasNotifications::OnAtlasUnloaded, temp);
return;
}
iterator->second.m_atlas->SetTexture(texture);
TextureAtlasNotificationBus::Broadcast(&TextureAtlasNotifications::OnAtlasReloaded, iterator->second.m_atlas);
break;
@@ -186,30 +193,23 @@ namespace TextureAtlasNamespace
delete[] buffer;
if (loadedAtlas)
{
// Get the image path based on the atlas path
// Convert to image path based on the atlas path
AZStd::string imagePath = path;
AzFramework::StringFunc::Path::ReplaceExtension(imagePath, "dds");
// Load the image in
// ToDo: Update to work with Atom? LYN-3680
// uint32 loadTextureFlags = (FT_USAGE_ALLOWREADSRGB | FT_DONT_STREAM);
ITexture* texture = nullptr;
if (!texture || !texture->IsTextureLoaded())
AzFramework::StringFunc::Path::ReplaceExtension(imagePath, "texatlas");
AZ::Data::Instance<AZ::RPI::Image> texture = LoadAtlasImage(imagePath);
if (!texture)
{
gEnv->pSystem->Warning(VALIDATOR_MODULE_UNKNOWN,
VALIDATOR_WARNING,
VALIDATOR_FLAG_FILE | VALIDATOR_FLAG_TEXTURE,
imagePath.c_str(),
"No texture file found for texture atlas: %s. "
AZ_Error("TextureAtlasSystemComponent",
false,
"Failed to find or create an image instance for texture atlas '%s'"
"NOTE: File must be in current project or a gem.",
imagePath.c_str());
path.c_str());
delete loadedAtlas;
return nullptr;
}
else
{
texture->SetFilter(FILTER_LINEAR);
// Add the atlas to the list
AtlasInfo info(loadedAtlas, assetPath);
++info.m_refs;
@@ -241,11 +241,7 @@ namespace TextureAtlasNamespace
// Tell the renderer to release the texture.
if (temp.m_atlas && temp.m_atlas->GetTexture())
{
SResourceAsync* pInfo = new SResourceAsync();
pInfo->eClassName = eRCN_Texture;
pInfo->pResource = temp.m_atlas->GetTexture();
// ToDo: Update to work with Atom? LYN-3680
// ???->ReleaseResourceAsync(pInfo);
temp.m_atlas->GetTexture().reset();
}
// Delete the atlas
SAFE_DELETE(temp.m_atlas);
@@ -0,0 +1,17 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
Source/Editor/AtlasBuilderComponent.h
Source/Editor/AtlasBuilderComponent.cpp
Source/Editor/AtlasBuilderWorker.h
Source/Editor/AtlasBuilderWorker.cpp
)
@@ -15,7 +15,6 @@ set(FILES
Include/TextureAtlas/TextureAtlasBus.h
Include/TextureAtlas/TextureAtlasNotificationBus.h
Include/TextureAtlas/TextureAtlas.h
Source/TextureAtlasModule.cpp
Source/TextureAtlasSystemComponent.cpp
Source/TextureAtlasSystemComponent.h
Source/TextureAtlasImpl.h
@@ -0,0 +1,14 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
Source/TextureAtlasModule.cpp
)
+12 -5
View File
@@ -370,6 +370,7 @@ endfunction()
#! ly_add_googletest: Adds a new RUN_TEST using for the specified target using the supplied command or fallback to running
# googletest tests through AzTestRunner
# \arg:NAME Name to for the test run target
# \arg:TARGET Name of the target module that is being run for tests. If not provided, will default to 'NAME'
# \arg:TEST_REQUIRES(optional) List of system resources that are required to run this test.
# Only available option is "gpu"
# \arg:TEST_SUITE(optional) - "smoke" or "periodic" or "sandbox" - prevents the test from running normally
@@ -384,14 +385,20 @@ function(ly_add_googletest)
message(FATAL_ERROR "Platform does not support test targets")
endif()
set(one_value_args NAME TEST_SUITE)
set(one_value_args NAME TARGET TEST_SUITE)
set(multi_value_args TEST_COMMAND COMPONENT)
cmake_parse_arguments(ly_add_googletest "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN})
if (ly_add_googletest_TARGET)
set(target_name ${ly_add_googletest_TARGET})
else()
set(target_name ${ly_add_googletest_NAME})
endif()
# AzTestRunner modules only supports google test libraries, regardless of whether or not
# google test suites are supported
set_property(GLOBAL APPEND PROPERTY LY_AZTESTRUNNER_TEST_MODULES "${ly_add_googletest_NAME}")
set_property(GLOBAL APPEND PROPERTY LY_AZTESTRUNNER_TEST_MODULES "${target_name}")
if(NOT PAL_TRAIT_TEST_GOOGLE_TEST_SUPPORTED)
return()
@@ -400,7 +407,7 @@ function(ly_add_googletest)
if (ly_add_googletest_TEST_SUITE AND NOT ly_add_googletest_TEST_SUITE STREQUAL "main")
# if a suite is specified, we filter to only accept things which match that suite (in c++)
set(non_ide_params "-gtest_filter=*SUITE_${ly_add_googletest_TEST_SUITE}*")
set(non_ide_params "--gtest_filter=*SUITE_${ly_add_googletest_TEST_SUITE}*")
else()
# otherwise, if its the main suite we only runs things that dont have any of the other suites.
# Note: it doesn't do AND, only 'or' - so specifying SUITE_main:REQUIRES_gpu
@@ -412,11 +419,11 @@ function(ly_add_googletest)
if(NOT ly_add_googletest_TEST_COMMAND)
# Use the NAME parameter as the build target
set(build_target ${ly_add_googletest_NAME})
set(build_target ${target_name})
ly_strip_target_namespace(TARGET ${build_target} OUTPUT_VARIABLE build_target)
if(NOT TARGET ${build_target})
message(FATAL_ERROR "A valid build target \"${build_target}\" for test run \"${ly_add_googletest_NAME}\" has not been found.\
message(FATAL_ERROR "A valid build target \"${build_target}\" for test run \"${target_name}\" has not been found.\
A valid target via the TARGET parameter or a custom TEST_COMMAND must be supplied")
endif()
+23 -4
View File
@@ -83,7 +83,7 @@
"CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE",
"CMAKE_LY_PROJECTS": "AutomatedTesting",
"CMAKE_TARGET": "all",
"CTEST_OPTIONS": "-E (Gem::EMotionFX.Editor.Tests|Gem::AWSClientAuth.Tests|Gem::AWSCore.Editor.Tests) -L FRAMEWORK_googletest --repeat until-pass:5"
"CTEST_OPTIONS": "-E (Gem::EMotionFX.Editor.Tests|Gem::AWSClientAuth.Tests|Gem::AWSCore.Editor.Tests) -L FRAMEWORK_googletest"
}
},
"test_profile_nounity": {
@@ -95,7 +95,7 @@
"CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE",
"CMAKE_LY_PROJECTS": "AutomatedTesting",
"CMAKE_TARGET": "all",
"CTEST_OPTIONS": "-E (Gem::EMotionFX.Editor.Tests|Gem::AWSClientAuth.Tests|Gem::AWSCore.Editor.Tests) -L FRAMEWORK_googletest --repeat until-pass:5"
"CTEST_OPTIONS": "-E (Gem::EMotionFX.Editor.Tests|Gem::AWSClientAuth.Tests|Gem::AWSCore.Editor.Tests) -L FRAMEWORK_googletest"
}
},
"asset_profile": {
@@ -143,7 +143,26 @@
"CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE",
"CMAKE_LY_PROJECTS": "AutomatedTesting",
"CMAKE_TARGET": "TEST_SUITE_periodic",
"CTEST_OPTIONS": "-L \"(SUITE_periodic)\""
"CTEST_OPTIONS": "-L (SUITE_periodic)"
}
},
"sandbox_test_profile": {
"TAGS": [
"nightly-incremental",
"nightly-clean",
"weekly-build-metrics"
],
"PIPELINE_ENV": {
"ON_FAILURE_MARK": "UNSTABLE"
},
"COMMAND": "build_test_linux.sh",
"PARAMETERS": {
"CONFIGURATION": "profile",
"OUTPUT_DIRECTORY": "build/linux",
"CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE",
"CMAKE_LY_PROJECTS": "AutomatedTesting",
"CMAKE_TARGET": "all",
"CTEST_OPTIONS": "-L (SUITE_sandbox)"
}
},
"benchmark_test_profile": {
@@ -159,7 +178,7 @@
"CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE",
"CMAKE_LY_PROJECTS": "AutomatedTesting",
"CMAKE_TARGET": "TEST_SUITE_benchmark",
"CTEST_OPTIONS": "-L \"(SUITE_benchmark)\""
"CTEST_OPTIONS": "-L (SUITE_benchmark)"
}
},
"release": {
+1 -1
View File
@@ -34,7 +34,7 @@ from cmake.Tools import registration
o3de_folder = registration.get_o3de_folder()
o3de_logs_folder = registration.get_o3de_logs_folder()
project_manager_log_file_path = o3de_log_folder / "project_manager.log"
project_manager_log_file_path = o3de_logs_folder / "project_manager.log"
log_file_handler = RotatingFileHandler(filename=project_manager_log_file_path, maxBytes=1024 * 1024, backupCount=1)
formatter = logging.Formatter('%(asctime)s | %(levelname)s : %(message)s')
log_file_handler.setFormatter(formatter)