GameplayEffectsComponent.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0 OR MIT
  5. *
  6. */
  7. #include <AzCore/Component/TransformBus.h>
  8. #include <AzCore/Serialization/SerializeContext.h>
  9. #include <AzFramework/Components/CameraBus.h>
  10. #include <Components/PerfTest/NetworkPrefabSpawnerComponent.h>
  11. #include <LmbrCentral/Audio/AudioTriggerComponentBus.h>
  12. #include <Source/Components/Multiplayer/GameplayEffectsComponent.h>
  13. AZ_CVAR(bool, mps_enableMissingAudioTriggerWarnings, false, nullptr, AZ::ConsoleFunctorFlags::Null,
  14. "Reports warnings whenever a game effect is missing an audio trigger defined in Game Playe Effects component.");
  15. namespace MultiplayerSample
  16. {
  17. void GameplayEffectsComponent::Reflect(AZ::ReflectContext* context)
  18. {
  19. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  20. if (serializeContext)
  21. {
  22. serializeContext->Class<GameplayEffectsComponent, GameplayEffectsComponentBase>()
  23. ->Version(1);
  24. }
  25. GameplayEffectsComponentBase::Reflect(context);
  26. }
  27. void GameplayEffectsComponent::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  28. {
  29. if (IsNetEntityRoleClient())
  30. {
  31. LocalOnlyGameplayEffectsNotificationBus::Handler::BusConnect();
  32. }
  33. m_soundTriggerNames.clear();
  34. m_soundTriggerNames.resize(SoundEffectNamespace::SoundEffectCount);
  35. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::PlayerFootSteps)] = GetPlayerFootSteps();
  36. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::PlayerExertion)] = GetPlayerExertion();
  37. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::PlayerKnockedDown)] = GetPlayerKnockedDown();
  38. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::ArmorBreaking)] = GetArmorBreaking();
  39. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::ArmorMend)] = GetArmorMend();
  40. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::PlayerOuch)] = GetPlayerOuch();
  41. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::LadderClimb)] = GetLadderClimb();
  42. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::ShutDown)] = GetShutDown();
  43. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::CountDown)] = GetCountDown();
  44. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::GemPickup)] = GetGemPickup();
  45. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::VictoryFanfare)] = GetVictoryFanfare();
  46. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::LosingFanfare)] = GetLosingFanfare();
  47. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::RoundStart)] = GetRoundStart();
  48. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::RoundEnd)] = GetRoundEnd();
  49. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::GameEnd)] = GetGameEnd();
  50. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::LaserPistolMuzzleFlash)] = GetLaserPistolMuzzleFlash();
  51. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::LaserPistolImpact)] = GetLaserPistolImpact();
  52. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::BubbleGunBuildup)] = GetBubbleGunBuildup();
  53. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::BubbleGunMuzzleFlash)] = GetBubbleGunMuzzleFlash();
  54. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::BubbleGunProjectile)] = GetBubbleGunProjectile();
  55. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::BubbleGunImpact)] = GetBubbleGunImpact();
  56. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::JumpPadLaunch)] = GetJumpPadLaunch();
  57. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::TeleporterUse)] = GetTeleporterUse();
  58. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::EnergyBallTrapRisingOutOfTheGround)] = GetEnergyBallTrapRisingOutOfTheGround();
  59. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::EnergyBallTrapBuildup)] = GetEnergyBallTrapBuildup();
  60. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::EnergyBallTrapProjectile)] = GetEnergyBallTrapProjectile();
  61. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::EnergyBallTrapImpact)] = GetEnergyBallTrapImpact();
  62. m_soundTriggerNames[aznumeric_cast<int>(SoundEffect::EnergyBallTrapOnCooldown)] = GetEnergyBallTrapOnCooldown();
  63. }
  64. void GameplayEffectsComponent::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  65. {
  66. Audio::AudioTriggerNotificationBus::MultiHandler::BusDisconnect();
  67. LocalOnlyGameplayEffectsNotificationBus::Handler::BusDisconnect();
  68. }
  69. #if AZ_TRAIT_CLIENT
  70. void GameplayEffectsComponent::HandleRPC_OnEffect([[maybe_unused]] AzNetworking::IConnection* invokingConnection,
  71. const SoundEffect& effect)
  72. {
  73. // Spawn at the local camera position
  74. AZ::EntityId camera;
  75. Camera::CameraSystemRequestBus::BroadcastResult(camera, &Camera::CameraSystemRequestBus::Events::GetActiveCamera);
  76. if (camera.IsValid())
  77. {
  78. AZ::Vector3 cameraPosition = AZ::Vector3::CreateZero();
  79. AZ::TransformBus::EventResult(cameraPosition, camera, &AZ::TransformBus::Events::GetWorldTranslation);
  80. SpawnEffect(effect, cameraPosition);
  81. }
  82. }
  83. void GameplayEffectsComponent::HandleRPC_OnPositionalEffect([[maybe_unused]] AzNetworking::IConnection* invokingConnection,
  84. const SoundEffect& effect, const AZ::Vector3& soundLocation)
  85. {
  86. SpawnEffect(effect, soundLocation);
  87. }
  88. #endif
  89. void GameplayEffectsComponent::ReportTriggerFinished([[maybe_unused]] Audio::TAudioControlID triggerId)
  90. {
  91. const Audio::TriggerNotificationIdType busId = *Audio::AudioTriggerNotificationBus::GetCurrentBusId();
  92. const AZ::EntityId entityId = aznumeric_cast<AZ::EntityId>(busId.m_owner);
  93. Audio::AudioTriggerNotificationBus::MultiHandler::BusDisconnect(busId);
  94. // Remove the prefab that played the sound trigger
  95. const auto iterator = m_spawnedEffects.find(entityId);
  96. if (iterator != m_spawnedEffects.end())
  97. {
  98. m_spawnedEffects.erase(iterator);
  99. }
  100. }
  101. #if AZ_TRAIT_CLIENT
  102. void GameplayEffectsComponent::OnPositionalEffect(SoundEffect effect, const AZ::Vector3& position)
  103. {
  104. HandleRPC_OnPositionalEffect(nullptr, effect, position);
  105. }
  106. void GameplayEffectsComponent::OnEffect(SoundEffect effect)
  107. {
  108. HandleRPC_OnEffect(nullptr, effect);
  109. }
  110. #endif
  111. void GameplayEffectsComponent::SpawnEffect(SoundEffect effect, const AZ::Vector3& position)
  112. {
  113. if (effect == SoundEffect::Unused)
  114. {
  115. return;
  116. }
  117. const char* triggerName = nullptr;
  118. const AZStd::size_t effectId = aznumeric_cast<AZStd::size_t>(effect);
  119. if (effectId < m_soundTriggerNames.size())
  120. {
  121. triggerName = m_soundTriggerNames[effectId].c_str();
  122. }
  123. if (!triggerName || strlen(triggerName) == 0)
  124. {
  125. if (mps_enableMissingAudioTriggerWarnings)
  126. {
  127. const AZStd::string eventName(SoundEffectNamespace::ToString(effect));
  128. AZ_Warning("MultiplayerSample", false, "Audio trigger wasn't specified for effect [%s] on GameplayEffectsComponent", eventName.c_str());
  129. }
  130. return;
  131. }
  132. PrefabCallbacks callbacks;
  133. callbacks.m_onActivateCallback = [this, triggerName](
  134. AZStd::shared_ptr<AzFramework::EntitySpawnTicket>&& ticket,
  135. [[maybe_unused]] AzFramework::SpawnableConstEntityContainerView view)
  136. {
  137. for (const AZ::Entity* entity : view)
  138. {
  139. LmbrCentral::AudioTriggerComponentRequests* audioTrigger =
  140. LmbrCentral::AudioTriggerComponentRequestBus::FindFirstHandler(entity->GetId());
  141. if (audioTrigger)
  142. {
  143. Audio::AudioTriggerNotificationBus::MultiHandler::BusConnect(Audio::TriggerNotificationIdType{ entity->GetId() });
  144. m_spawnedEffects.emplace(entity->GetId(), move(ticket));
  145. audioTrigger->ExecuteTrigger(triggerName);
  146. break;
  147. }
  148. }
  149. };
  150. // Spawn a prefab with an audio trigger, play the effect and clean it up when it finishes.
  151. const AZ::Transform t = AZ::Transform::CreateFromQuaternionAndTranslation(AZ::Quaternion::CreateIdentity(), position);
  152. GetNetworkPrefabSpawnerComponent()->SpawnDefaultPrefab(t, callbacks);
  153. }
  154. GameplayEffectsComponentController::GameplayEffectsComponentController(GameplayEffectsComponent& parent)
  155. : GameplayEffectsComponentControllerBase(parent)
  156. {
  157. }
  158. void GameplayEffectsComponentController::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  159. {
  160. GameplayEffectsNotificationBus::Handler::BusConnect();
  161. }
  162. void GameplayEffectsComponentController::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  163. {
  164. GameplayEffectsNotificationBus::Handler::BusDisconnect();
  165. }
  166. #if AZ_TRAIT_SERVER
  167. void GameplayEffectsComponentController::OnEffect(SoundEffect effect)
  168. {
  169. RPC_OnEffect(effect);
  170. }
  171. void GameplayEffectsComponentController::OnPositionalEffect(SoundEffect effect, const AZ::Vector3& position)
  172. {
  173. RPC_OnPositionalEffect(effect, position);
  174. }
  175. #endif
  176. }