EditorSequenceAgentComponent.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "EditorSequenceAgentComponent.h"
  9. #include "SequenceAgentComponent.h"
  10. #include <AzCore/RTTI/BehaviorContext.h>
  11. #include <AzCore/std/containers/set.h>
  12. #include <AzCore/Serialization/SerializeContext.h>
  13. #include <AzCore/Serialization/EditContext.h>
  14. #include <AzCore/Component/ComponentApplicationBus.h>
  15. #include <AzCore/Serialization/SerializeContext.h>
  16. #include <AzFramework/API/ApplicationAPI.h>
  17. #include <AzToolsFramework/ToolsComponents/GenericComponentWrapper.h>
  18. #include <AzCore/Component/Entity.h>
  19. #include <AzToolsFramework/API/EntityCompositionRequestBus.h>
  20. #include <Maestro/Types/AnimParamType.h>
  21. #include <AzToolsFramework/ToolsComponents/EditorDisabledCompositionBus.h>
  22. #include <AzToolsFramework/ToolsComponents/EditorPendingCompositionComponent.h>
  23. #include <AzToolsFramework/Undo/UndoCacheInterface.h>
  24. namespace Maestro
  25. {
  26. void EditorSequenceAgentComponent::Reflect(AZ::ReflectContext* context)
  27. {
  28. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  29. if (serializeContext)
  30. {
  31. serializeContext->Class<EditorSequenceAgentComponent, EditorComponentBase>()
  32. ->Field("SequenceComponentEntityIds", &EditorSequenceAgentComponent::m_sequenceEntityIds)
  33. ->Version(3);
  34. AZ::EditContext* editContext = serializeContext->GetEditContext();
  35. if (editContext)
  36. {
  37. editContext->Class<EditorSequenceAgentComponent>(
  38. "SequenceAgent", "Maps Director Component Animations to Behavior Properties on this Entity")
  39. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  40. ->Attribute(AZ::Edit::Attributes::Category, "Cinematics")
  41. ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/SequenceAgent.png")
  42. ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/SequenceAgent.png")
  43. ->Attribute(AZ::Edit::Attributes::AddableByUser, false) // SequenceAgents are only added by TrackView
  44. ->Attribute(AZ::Edit::Attributes::AutoExpand, true);
  45. }
  46. }
  47. }
  48. AZ::TypeId EditorSequenceAgentComponent::GetComponentTypeUuid(const AZ::Component& component) const
  49. {
  50. return AzToolsFramework::GetUnderlyingComponentType(component);
  51. }
  52. void EditorSequenceAgentComponent::GetEntityComponents(AZ::Entity::ComponentArrayType& entityComponents) const
  53. {
  54. AZ::Entity* entity = GetEntity();
  55. AZ_Assert(entity, "Expected valid entity.");
  56. if (entity)
  57. {
  58. // Add all enabled components
  59. const AZ::Entity::ComponentArrayType& enabledComponents = entity->GetComponents();
  60. for (AZ::Component* component : enabledComponents)
  61. {
  62. entityComponents.push_back(component);
  63. }
  64. // Add all disabled components
  65. AZ::Entity::ComponentArrayType disabledComponents;
  66. AzToolsFramework::EditorDisabledCompositionRequestBus::Event(entity->GetId(), &AzToolsFramework::EditorDisabledCompositionRequests::GetDisabledComponents, disabledComponents);
  67. for (AZ::Component* component : disabledComponents)
  68. {
  69. entityComponents.push_back(component);
  70. }
  71. // Add all pending components
  72. AZ::Entity::ComponentArrayType pendingComponents;
  73. AzToolsFramework::EditorPendingCompositionRequestBus::Event(entity->GetId(), &AzToolsFramework::EditorPendingCompositionRequests::GetPendingComponents, pendingComponents);
  74. for (AZ::Component* component : pendingComponents)
  75. {
  76. entityComponents.push_back(component);
  77. }
  78. }
  79. }
  80. void EditorSequenceAgentComponent::Activate()
  81. {
  82. // cache pointers and animatable addresses for animation
  83. //
  84. CacheAllVirtualPropertiesFromBehaviorContext();
  85. ConnectAllSequences();
  86. EditorComponentBase::Activate();
  87. // Notify the sequence agent was just connected to the sequence.
  88. EditorSequenceAgentComponentNotificationBus::Event(
  89. GetEntityId(),
  90. &EditorSequenceAgentComponentNotificationBus::Events::OnSequenceAgentConnected
  91. );
  92. }
  93. void EditorSequenceAgentComponent::Deactivate()
  94. {
  95. // invalidate all cached pointers and address
  96. m_addressToBehaviorVirtualPropertiesMap.clear();
  97. DisconnectAllSequences();
  98. EditorComponentBase::Deactivate();
  99. }
  100. void EditorSequenceAgentComponent::ConnectSequence(const AZ::EntityId& sequenceEntityId)
  101. {
  102. // check that we aren't already connected to this SequenceComponent - add it if we aren't
  103. if (m_sequenceEntityIds.find(sequenceEntityId) == m_sequenceEntityIds.end())
  104. {
  105. m_sequenceEntityIds.insert(sequenceEntityId);
  106. // connect to EBus between the given SequenceComponent and me
  107. SequenceAgentEventBusId busId(sequenceEntityId, GetEntityId());
  108. EditorSequenceAgentComponentRequestBus::MultiHandler::BusConnect(busId);
  109. SequenceAgentComponentRequestBus::MultiHandler::BusConnect(busId);
  110. }
  111. }
  112. void EditorSequenceAgentComponent::DisconnectSequence()
  113. {
  114. const SequenceAgentEventBusId* busIdToDisconnect = SequenceAgentComponentRequestBus::GetCurrentBusId();
  115. if (!busIdToDisconnect)
  116. {
  117. return;
  118. }
  119. const auto entity = GetEntity();
  120. if (!entity)
  121. {
  122. AZ_Assert(false, "EditorSequenceAgentComponent::DisconnectSequence() called for inactive entity.");
  123. return;
  124. }
  125. AZ::EntityId sequenceEntityId = busIdToDisconnect->first;
  126. // we only process DisconnectSequence events sent over an ID'ed bus - otherwise we don't know which SequenceComponent to disconnect
  127. [[maybe_unused]] auto findIter = m_sequenceEntityIds.find(sequenceEntityId);
  128. AZ_Assert(findIter != m_sequenceEntityIds.end(), "A sequence not connected to SequenceAgentComponent on %s is requesting a disconnection", GetEntity()->GetName().c_str());
  129. m_sequenceEntityIds.erase(sequenceEntityId);
  130. // Disconnect from the bus between the SequenceComponent and me
  131. // Make a copy because calling BusDisconnect destroy the current bus id
  132. const SequenceAgentEventBusId busIdToDisconnectCopy = *busIdToDisconnect;
  133. EditorSequenceAgentComponentRequestBus::MultiHandler::BusDisconnect(busIdToDisconnectCopy);
  134. SequenceAgentComponentRequestBus::MultiHandler::BusDisconnect(busIdToDisconnectCopy);
  135. if (m_sequenceEntityIds.size())
  136. {
  137. return;
  138. }
  139. AZ::EntityId curEntityId = GetEntityId();
  140. AZ_Trace("EditorSequenceAgentComponent","DisconnectSequence(): removing self from entity %s, %s.", curEntityId.ToString().c_str(), entity->GetName().c_str());
  141. // This component was created indirectly via user actions in EditorSequenceComponent,
  142. // so temporary disable undo / redo for its destruction adding EntityId to the ignored list, to bypass possible undo / redo errors.
  143. AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast(&AzToolsFramework::ToolsApplicationRequests::Bus::Events::AddIgnoredEntity, curEntityId);
  144. // remove this SequenceAgent from this entity if no sequenceComponents are connected to it
  145. AzToolsFramework::EntityCompositionRequestBus::Broadcast(&AzToolsFramework::EntityCompositionRequests::RemoveComponents, AZ::Entity::ComponentArrayType{this});
  146. // Remove EntityId from the ignored list to return to standard undo / redo pipeline.
  147. // This call is mandatory after the above AddIgnoredEntity() call which was intended to disable undo / redo only temporary.
  148. AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast(&AzToolsFramework::ToolsApplicationRequests::Bus::Events::RemoveIgnoredEntity, curEntityId);
  149. // Let any currently-active undo operations know that this entity has changed state.
  150. auto undoCacheInterface = AZ::Interface<AzToolsFramework::UndoSystem::UndoCacheInterface>::Get();
  151. if (undoCacheInterface)
  152. {
  153. undoCacheInterface->UpdateCache(curEntityId);
  154. }
  155. // CAUTION!
  156. // THIS CLASS INSTANCE IS NOW DEAD DUE TO DELETION BY THE ENTITY DURING RemoveComponents!
  157. }
  158. void EditorSequenceAgentComponent::ConnectAllSequences()
  159. {
  160. // Connect all buses
  161. for (auto iter = m_sequenceEntityIds.begin(); iter != m_sequenceEntityIds.end(); iter++)
  162. {
  163. SequenceAgentEventBusId busIdToConnect(*iter, GetEntityId());
  164. EditorSequenceAgentComponentRequestBus::MultiHandler::BusConnect(busIdToConnect);
  165. SequenceAgentComponentRequestBus::MultiHandler::BusConnect(busIdToConnect);
  166. }
  167. }
  168. void EditorSequenceAgentComponent::DisconnectAllSequences()
  169. {
  170. // disconnect all buses
  171. for (auto iter = m_sequenceEntityIds.begin(); iter != m_sequenceEntityIds.end(); iter++)
  172. {
  173. SequenceAgentEventBusId busIdToDisconnect(*iter, GetEntityId());
  174. EditorSequenceAgentComponentRequestBus::MultiHandler::BusDisconnect(busIdToDisconnect);
  175. SequenceAgentComponentRequestBus::MultiHandler::BusDisconnect(busIdToDisconnect);
  176. }
  177. }
  178. void EditorSequenceAgentComponent::BuildGameEntity(AZ::Entity* gameEntity)
  179. {
  180. SequenceAgentComponent *sequenceAgentComponent = gameEntity->CreateComponent<SequenceAgentComponent>();
  181. if (sequenceAgentComponent)
  182. {
  183. // TODO: when we have code which only allows animation of properties that are common between the SequenceAgent and EditorSequenceAgent,
  184. // transfer the mappings to the game behaviors here
  185. sequenceAgentComponent->m_sequenceEntityIds = m_sequenceEntityIds;
  186. }
  187. }
  188. void EditorSequenceAgentComponent::GetAllAnimatableProperties(IAnimNode::AnimParamInfos& properties, AZ::ComponentId componentId)
  189. {
  190. // add all properties found during Activate() that match the given componentId
  191. for (auto propertyIter = m_addressToBehaviorVirtualPropertiesMap.begin(); propertyIter != m_addressToBehaviorVirtualPropertiesMap.end(); propertyIter++)
  192. {
  193. if (propertyIter->first.GetComponentId() == componentId)
  194. {
  195. AZ::BehaviorEBus::VirtualProperty* virtualProperty = propertyIter->second;
  196. // all behavior properties as string params with the virtual property name as the string
  197. IAnimNode::SParamInfo paramInfo;
  198. // by default set up paramType as an AnimParamType::ByString with the name as the Virtual Property name
  199. paramInfo.paramType = propertyIter->first.GetVirtualPropertyName();
  200. // check for paramType specialization attributes on the getter method of the virtual property. if found, reset
  201. // to the eAnimParamType enum - this leaves the paramType name unchanged but changes the type.
  202. for (int i = static_cast<int>(virtualProperty->m_getter->m_attributes.size()); --i >= 0;)
  203. {
  204. if (virtualProperty->m_getter->m_attributes[i].first == AZ::Edit::Attributes::PropertyPosition)
  205. {
  206. paramInfo.paramType = AnimParamType::Position;
  207. break;
  208. }
  209. else if (virtualProperty->m_getter->m_attributes[i].first == AZ::Edit::Attributes::PropertyRotation)
  210. {
  211. paramInfo.paramType = AnimParamType::Rotation;
  212. break;
  213. }
  214. else if (virtualProperty->m_getter->m_attributes[i].first == AZ::Edit::Attributes::PropertyScale)
  215. {
  216. paramInfo.paramType = AnimParamType::Scale;
  217. break;
  218. }
  219. else if (virtualProperty->m_getter->m_attributes[i].first == AZ::Edit::Attributes::PropertyHidden)
  220. {
  221. paramInfo.flags = static_cast<IAnimNode::ESupportedParamFlags>(paramInfo.flags | IAnimNode::eSupportedParamFlags_Hidden);
  222. break;
  223. }
  224. }
  225. properties.push_back(paramInfo);
  226. }
  227. }
  228. }
  229. void EditorSequenceAgentComponent::GetAnimatableComponents(AZStd::vector<AZ::ComponentId>& animatableComponentIds)
  230. {
  231. AZStd::set<AZ::ComponentId> appendedComponentIds;
  232. // go through all known properties found during Activate() - insert all unique components found
  233. for (auto address = m_addressToBehaviorVirtualPropertiesMap.begin(); address != m_addressToBehaviorVirtualPropertiesMap.end(); address++)
  234. {
  235. // only append component if it's not already been appended
  236. auto findIter = appendedComponentIds.find(address->first.GetComponentId());
  237. if (findIter == appendedComponentIds.end())
  238. {
  239. animatableComponentIds.push_back(address->first.GetComponentId());
  240. appendedComponentIds.insert(address->first.GetComponentId());
  241. }
  242. }
  243. }
  244. AZ::Uuid EditorSequenceAgentComponent::GetAnimatedAddressTypeId(const AnimatablePropertyAddress& animatableAddress)
  245. {
  246. return GetVirtualPropertyTypeId(animatableAddress);
  247. }
  248. void EditorSequenceAgentComponent::GetAnimatedPropertyValue(AnimatedValue& returnValue, const AnimatablePropertyAddress& animatableAddress)
  249. {
  250. SequenceAgent::GetAnimatedPropertyValue(returnValue, GetEntityId(), animatableAddress);
  251. }
  252. bool EditorSequenceAgentComponent::SetAnimatedPropertyValue(const AnimatablePropertyAddress& animatableAddress, const AnimatedValue& value)
  253. {
  254. return SequenceAgent::SetAnimatedPropertyValue(GetEntityId(), animatableAddress, value);
  255. }
  256. void EditorSequenceAgentComponent::GetAssetDuration(AnimatedValue& returnValue, AZ::ComponentId componentId, const AZ::Data::AssetId& assetId)
  257. {
  258. SequenceAgent::GetAssetDuration(returnValue, componentId, assetId);
  259. }
  260. } // namespace Maestro