/* * 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. * */ #pragma once #include #include #include #include #include #include #include #include #include #include #include "UiEditorEntityContextBus.h" namespace AZ { class SerializeContext; } namespace AzFramework { class EntityContext; } class EditorWindow; //////////////////////////////////////////////////////////////////////////////////////////////////// //! The UIEditorEntityContext extends the UiEditorContext to add functionality only needed when //! a UI canvas is loaded in the UI Editor. class UiEditorEntityContext : public UiEntityContext , private UiEditorEntityContextRequestBus::Handler , private AzToolsFramework::EditorEntityContextPickingRequestBus::Handler , private AzFramework::AssetCatalogEventBus::Handler , private AzFramework::SliceInstantiationResultBus::MultiHandler { public: // member functions UiEditorEntityContext(EditorWindow* editorWindow); ~UiEditorEntityContext() override; // EntityContext bool HandleLoadedRootSliceEntity(AZ::Entity* rootEntity, bool remapIds, AZ::SliceComponent::EntityIdToEntityIdMap* idRemapTable = nullptr) override; // ~EntityContext // UiEntityContext void InitUiContext() override; void DestroyUiContext() override; bool SaveToStreamForGame(AZ::IO::GenericStream& stream, AZ::DataStream::StreamType streamType) override; bool SaveCanvasEntityToStreamForGame(AZ::Entity* canvasEntity, AZ::IO::GenericStream& stream, AZ::DataStream::StreamType streamType) override; // ~UiEntityContext // UiEntityContextRequestBus AZ::SliceComponent* GetUiRootSlice() override { return GetRootSlice(); } AZ::Entity* CreateUiEntity(const char* name) override; void AddUiEntity(AZ::Entity* entity) override; void AddUiEntities(const AzFramework::EntityContext::EntityList& entities) override; bool CloneUiEntities(const AZStd::vector& sourceEntities, AzFramework::EntityContext::EntityList& resultEntities) override; bool DestroyUiEntity(AZ::EntityId entityId) override; // ~UiEntityContextRequestBus // EditorEntityContextPickingRequestBus bool SupportsViewportEntityIdPicking() override; // ~EditorEntityContextPickingRequestBus // UiEditorEntityContextRequestBus AZ::SliceComponent::SliceInstanceAddress CloneEditorSliceInstance(AZ::SliceComponent::SliceInstanceAddress sourceInstance) override; AzFramework::SliceInstantiationTicket InstantiateEditorSlice(const AZ::Data::Asset& sliceAsset, AZ::Vector2 viewportPosition) override; AzFramework::SliceInstantiationTicket InstantiateEditorSliceAtChildIndex(const AZ::Data::Asset& sliceAsset, AZ::Vector2 viewportPosition, int childIndex) override; void RestoreSliceEntity(AZ::Entity* entity, const AZ::SliceComponent::EntityRestoreInfo& info) override; void QueueSliceReplacement(const char* targetPath, const AZStd::unordered_map& selectedToAssetMap, const AZStd::unordered_set& entitiesInSelection, AZ::Entity* commonParent, AZ::Entity* insertBefore) override; void DeleteElements(AzToolsFramework::EntityIdList elements) override; bool HasPendingRequests() override; bool IsInstantiatingSlices() override; void DetachSliceEntities(const AzToolsFramework::EntityIdList& entities) override; // ~UiEditorEntityContextRequestBus // AzFramework::SliceInstantiationResultBus void OnSlicePreInstantiate(const AZ::Data::AssetId& sliceAssetId, const AZ::SliceComponent::SliceInstanceAddress& sliceAddress) override; void OnSliceInstantiated(const AZ::Data::AssetId& sliceAssetId, const AZ::SliceComponent::SliceInstanceAddress& sliceAddress) override; void OnSliceInstantiationFailed(const AZ::Data::AssetId& sliceAssetId) override; // ~AzFramework::SliceInstantiationResultBus // AssetCatalogEventBus::Handler void OnCatalogAssetAdded(const AZ::Data::AssetId& assetId) override; // ~AssetCatalogEventBus::Handler // EntityContextRequestBus void ResetContext() override; // ~EntityContextRequestBus AZStd::string GetErrorMessage() const { return m_errorMessage; } protected: // types struct InstantiatingEditorSliceParams { InstantiatingEditorSliceParams(const AZ::Vector2& viewportPosition, int childIndex = -1) { m_viewportPosition = viewportPosition; m_childIndex = childIndex; } AZ::Vector2 m_viewportPosition; int m_childIndex; }; protected: // member functions void OnAssetReady(AZ::Data::Asset asset) override; void OnAssetReloaded(AZ::Data::Asset asset) override; void OnContextEntitiesAdded(const AzFramework::EntityContext::EntityList& entities) override; // Used to validate that the entities in an instantiated slice are valid entities for this context bool ValidateEntitiesAreValidForContext(const EntityList& entities) override; void SetupUiEntity(AZ::Entity* entity); void InitializeEntities(const AzFramework::EntityContext::EntityList& entities); protected: // data using InstantiatingSlicePair = AZStd::pair, InstantiatingEditorSliceParams>; AZStd::vector m_instantiatingSlices; private: // types //! Tracks a queued slice replacement, which is a deferred operation. //! If the asset has not yet been processed (a new asset), we need //! to defer before attempting a load. struct QueuedSliceReplacement { ~QueuedSliceReplacement() = default; QueuedSliceReplacement() = default; QueuedSliceReplacement(const QueuedSliceReplacement&) = delete; QueuedSliceReplacement& operator=(const QueuedSliceReplacement&) = delete; void Setup(const char* path, const AZStd::unordered_map& selectedToAssetMap, const AZStd::unordered_set& entitiesInSelection, AZ::Entity* commonParent, AZ::Entity* insertBefore) { m_path = path; m_selectedToAssetMap = selectedToAssetMap; m_entitiesInSelection.clear(); m_entitiesInSelection.insert(entitiesInSelection.begin(), entitiesInSelection.end()); m_commonParent = commonParent; m_insertBefore = insertBefore; } bool IsValid() const; void Reset(); void Finalize(const AZ::SliceComponent::SliceInstanceAddress& instanceAddress, EditorWindow* editorWindow); AZStd::string m_path; AZStd::unordered_map m_selectedToAssetMap; AZStd::unordered_set m_entitiesInSelection; AZ::Entity* m_commonParent; AZ::Entity* m_insertBefore; AzFramework::SliceInstantiationTicket m_ticket; }; private: // member functions void GetTopLevelEntities(const AZStd::unordered_set& entities, AZStd::unordered_set& topLevelEntities); private: // data EditorWindow* m_editorWindow; //! List of selected entities prior to entering game. AZStd::vector m_selectedBeforeStartingGame; QueuedSliceReplacement m_queuedSliceReplacement; //! Slice entity restore requests, which can be deferred if asset wasn't loaded at request time. struct SliceEntityRestoreRequest { AZ::Entity* m_entity; AZ::SliceComponent::EntityRestoreInfo m_restoreInfo; AZ::Data::Asset m_asset; }; AZStd::vector m_queuedSliceEntityRestores; AZ::ComponentTypeList m_requiredEditorComponentTypes; AZStd::string m_errorMessage; };