NetworkWeaponsComponent.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  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 <Source/Components/NetworkWeaponsComponent.h>
  8. #include <Source/Components/NetworkAiComponent.h>
  9. #include <Source/Components/NetworkAnimationComponent.h>
  10. #include <Source/Components/NetworkHealthComponent.h>
  11. #include <Multiplayer/Components/NetworkRigidBodyComponent.h>
  12. #include <Source/Components/NetworkSimplePlayerCameraComponent.h>
  13. #include <Source/Weapons/BaseWeapon.h>
  14. #include <AzCore/Component/TransformBus.h>
  15. #if AZ_TRAIT_CLIENT
  16. #include <DebugDraw/DebugDrawBus.h>
  17. #endif
  18. namespace ${SanitizedCppName}
  19. {
  20. AZ_CVAR(bool, cl_WeaponsDrawDebug, true, nullptr, AZ::ConsoleFunctorFlags::Null, "If enabled, weapons will debug draw various important events");
  21. AZ_CVAR(float, cl_WeaponsDrawDebugSize, 0.25f, nullptr, AZ::ConsoleFunctorFlags::Null, "The size of sphere to debug draw during weapon events");
  22. AZ_CVAR(float, cl_WeaponsDrawDebugDurationSec, 10.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "The number of seconds to display debug draw data");
  23. AZ_CVAR(float, sv_WeaponsImpulseScalar, 750.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "A fudge factor for imparting impulses on rigid bodies due to weapon hits");
  24. AZ_CVAR(float, sv_WeaponsStartPositionClampRange, 1.f, nullptr, AZ::ConsoleFunctorFlags::Null, "A fudge factor between the where the client and server say a shot started");
  25. void NetworkWeaponsComponent::NetworkWeaponsComponent::Reflect(AZ::ReflectContext* context)
  26. {
  27. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  28. if (serializeContext)
  29. {
  30. serializeContext->Class<NetworkWeaponsComponent, NetworkWeaponsComponentBase>()
  31. ->Version(1);
  32. }
  33. NetworkWeaponsComponentBase::Reflect(context);
  34. }
  35. NetworkWeaponsComponent::NetworkWeaponsComponent()
  36. : NetworkWeaponsComponentBase()
  37. , m_activationCountHandler([this](int32_t index, uint8_t value) { OnUpdateActivationCounts(index, value); })
  38. {
  39. ;
  40. }
  41. void NetworkWeaponsComponent::OnInit()
  42. {
  43. AZStd::uninitialized_fill_n(m_fireBoneJointIds.data(), MaxWeaponsPerComponent, InvalidBoneId);
  44. }
  45. void NetworkWeaponsComponent::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  46. {
  47. for (uint32_t weaponIndex = 0; weaponIndex < MaxWeaponsPerComponent; ++weaponIndex)
  48. {
  49. const ConstructParams constructParams
  50. {
  51. GetEntityHandle(),
  52. aznumeric_cast<WeaponIndex>(weaponIndex),
  53. GetWeaponParams(weaponIndex),
  54. *this
  55. };
  56. m_weapons[weaponIndex] = AZStd::move(CreateWeapon(constructParams));
  57. }
  58. if (IsNetEntityRoleClient())
  59. {
  60. ActivationCountsAddEvent(m_activationCountHandler);
  61. }
  62. #if AZ_TRAIT_CLIENT
  63. if (m_debugDraw == nullptr)
  64. {
  65. m_debugDraw = DebugDraw::DebugDrawRequestBus::FindFirstHandler();
  66. }
  67. #endif
  68. }
  69. void NetworkWeaponsComponent::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  70. {
  71. ;
  72. }
  73. #if AZ_TRAIT_CLIENT
  74. void NetworkWeaponsComponent::HandleSendConfirmHit([[maybe_unused]] AzNetworking::IConnection* invokingConnection, const WeaponIndex& weaponIndex, const HitEvent& hitEvent)
  75. {
  76. if (GetWeapon(weaponIndex) == nullptr)
  77. {
  78. AZLOG_ERROR("Got confirmed hit for null weapon index");
  79. return;
  80. }
  81. WeaponHitInfo weaponHitInfo(*GetWeapon(weaponIndex), hitEvent);
  82. OnWeaponConfirmHit(weaponHitInfo);
  83. }
  84. #endif
  85. void NetworkWeaponsComponent::ActivateWeaponWithParams(WeaponIndex weaponIndex, WeaponState& weaponState, const FireParams& fireParams, bool validateActivations)
  86. {
  87. const AZ::Vector3 position = fireParams.m_sourcePosition;
  88. const AZ::Quaternion orientation = AZ::Quaternion::CreateShortestArc(AZ::Vector3::CreateAxisX(), (fireParams.m_targetPosition - position).GetNormalized());
  89. const AZ::Transform transform = AZ::Transform::CreateFromQuaternionAndTranslation(orientation, position);
  90. ActivateEvent activateEvent{ transform, fireParams.m_targetPosition, GetNetEntityId(), Multiplayer::InvalidNetEntityId };
  91. IWeapon* weapon = GetWeapon(weaponIndex);
  92. weapon->Activate(weaponState, GetEntityHandle(), activateEvent, validateActivations);
  93. }
  94. IWeapon* NetworkWeaponsComponent::GetWeapon(WeaponIndex weaponIndex) const
  95. {
  96. return m_weapons[aznumeric_cast<uint32_t>(weaponIndex)].get();
  97. }
  98. void NetworkWeaponsComponent::OnWeaponActivate([[maybe_unused]] const WeaponActivationInfo& activationInfo)
  99. {
  100. // If we're replaying inputs then early out
  101. if (GetNetBindComponent()->IsReprocessingInput())
  102. {
  103. return;
  104. }
  105. #if AZ_TRAIT_CLIENT
  106. if (cl_WeaponsDrawDebug && m_debugDraw)
  107. {
  108. m_debugDraw->DrawSphereAtLocation
  109. (
  110. activationInfo.m_activateEvent.m_initialTransform.GetTranslation(),
  111. cl_WeaponsDrawDebugSize,
  112. AZ::Colors::Green,
  113. cl_WeaponsDrawDebugDurationSec
  114. );
  115. m_debugDraw->DrawSphereAtLocation
  116. (
  117. activationInfo.m_activateEvent.m_targetPosition,
  118. cl_WeaponsDrawDebugSize,
  119. AZ::Colors::Yellow,
  120. cl_WeaponsDrawDebugDurationSec
  121. );
  122. }
  123. #endif
  124. }
  125. void NetworkWeaponsComponent::OnWeaponHit(const WeaponHitInfo& hitInfo)
  126. {
  127. if (IsNetEntityRoleAuthority())
  128. {
  129. #if AZ_TRAIT_SERVER
  130. OnWeaponConfirmHit(hitInfo);
  131. static_cast<NetworkWeaponsComponentController*>(GetController())->SendConfirmHit(hitInfo.m_weapon.GetWeaponIndex(), hitInfo.m_hitEvent);
  132. #endif
  133. }
  134. else
  135. {
  136. OnWeaponPredictHit(hitInfo);
  137. }
  138. }
  139. void NetworkWeaponsComponent::OnWeaponPredictHit(const WeaponHitInfo& hitInfo)
  140. {
  141. // If we're replaying inputs then early out
  142. if (GetNetBindComponent()->IsReprocessingInput())
  143. {
  144. return;
  145. }
  146. for (uint32_t i = 0; i < hitInfo.m_hitEvent.m_hitEntities.size(); ++i)
  147. {
  148. const HitEntity& hitEntity = hitInfo.m_hitEvent.m_hitEntities[i];
  149. #if AZ_TRAIT_CLIENT
  150. if (cl_WeaponsDrawDebug && m_debugDraw)
  151. {
  152. m_debugDraw->DrawSphereAtLocation
  153. (
  154. hitEntity.m_hitPosition,
  155. cl_WeaponsDrawDebugSize,
  156. AZ::Colors::Orange,
  157. cl_WeaponsDrawDebugDurationSec
  158. );
  159. }
  160. #endif
  161. AZLOG
  162. (
  163. NET_Weapons,
  164. "Predicted hit on entity %" PRIu64 " at position %f x %f x %f",
  165. hitEntity.m_hitNetEntityId,
  166. hitEntity.m_hitPosition.GetX(),
  167. hitEntity.m_hitPosition.GetY(),
  168. hitEntity.m_hitPosition.GetZ()
  169. );
  170. }
  171. }
  172. void NetworkWeaponsComponent::OnWeaponConfirmHit(const WeaponHitInfo& hitInfo)
  173. {
  174. #if AZ_TRAIT_SERVER
  175. if (IsNetEntityRoleAuthority())
  176. {
  177. for (const HitEntity& hitEntity : hitInfo.m_hitEvent.m_hitEntities)
  178. {
  179. Multiplayer::ConstNetworkEntityHandle entityHandle = Multiplayer::GetMultiplayer()->GetNetworkEntityManager()->GetEntity(hitEntity.m_hitNetEntityId);
  180. if (entityHandle != nullptr && entityHandle.GetEntity() != nullptr)
  181. {
  182. [[maybe_unused]] const AZ::Vector3& hitCenter = hitInfo.m_hitEvent.m_hitTransform.GetTranslation();
  183. [[maybe_unused]] const AZ::Vector3& hitPoint = hitEntity.m_hitPosition;
  184. const WeaponParams& weaponParams = hitInfo.m_weapon.GetParams();
  185. const HitEffect effect = weaponParams.m_damageEffect;
  186. // Presently set to 1 until we capture falloff range
  187. float hitDistance = 1.f;
  188. float maxDistance = 1.f;
  189. float damage = effect.m_hitMagnitude * powf((effect.m_hitFalloff * (1.0f - hitDistance / maxDistance)), effect.m_hitExponent);
  190. // Look for physics rigid body component and make impact updates
  191. if (Multiplayer::NetworkRigidBodyComponent* rigidBodyComponent = entityHandle.GetEntity()->FindComponent<Multiplayer::NetworkRigidBodyComponent>())
  192. {
  193. const AZ::Vector3 hitLocation = hitInfo.m_hitEvent.m_hitTransform.GetTranslation();
  194. const AZ::Vector3 hitDelta = hitEntity.m_hitPosition - hitLocation;
  195. const AZ::Vector3 impulse = hitDelta.GetNormalized() * damage * sv_WeaponsImpulseScalar;
  196. rigidBodyComponent->SendApplyImpulse(impulse, hitLocation);
  197. }
  198. // Look for health component and directly update health based on hit parameters
  199. if (NetworkHealthComponent* healthComponent = entityHandle.GetEntity()->FindComponent<NetworkHealthComponent>())
  200. {
  201. healthComponent->SendHealthDelta(damage * -1.0f);
  202. }
  203. }
  204. }
  205. }
  206. #endif
  207. // If we're a simulated weapon, or if the weapon is not predictive, then issue material hit effects since the predicted callback above will not get triggered
  208. [[maybe_unused]] bool shouldIssueMaterialEffects = !HasController() || !hitInfo.m_weapon.GetParams().m_locallyPredicted;
  209. for (uint32_t i = 0; i < hitInfo.m_hitEvent.m_hitEntities.size(); ++i)
  210. {
  211. const HitEntity& hitEntity = hitInfo.m_hitEvent.m_hitEntities[i];
  212. #if AZ_TRAIT_CLIENT
  213. if (cl_WeaponsDrawDebug && m_debugDraw)
  214. {
  215. m_debugDraw->DrawSphereAtLocation
  216. (
  217. hitEntity.m_hitPosition,
  218. cl_WeaponsDrawDebugSize,
  219. AZ::Colors::Red,
  220. cl_WeaponsDrawDebugDurationSec
  221. );
  222. }
  223. #endif
  224. AZLOG
  225. (
  226. NET_Weapons,
  227. "Confirmed hit on entity %" PRIu64 " at position %f x %f x %f",
  228. hitEntity.m_hitNetEntityId,
  229. hitEntity.m_hitPosition.GetX(),
  230. hitEntity.m_hitPosition.GetY(),
  231. hitEntity.m_hitPosition.GetZ()
  232. );
  233. }
  234. }
  235. void NetworkWeaponsComponent::OnUpdateActivationCounts(int32_t index, uint8_t value)
  236. {
  237. IWeapon* weapon = GetWeapon(aznumeric_cast<WeaponIndex>(index));
  238. if (weapon == nullptr)
  239. {
  240. return;
  241. }
  242. if (HasController() && weapon->GetParams().m_locallyPredicted)
  243. {
  244. // If this is a predicted weapon, exit out because autonomous weapons predict activations
  245. return;
  246. }
  247. AZLOG(NET_Weapons, "Client activation event for weapon index %u", index);
  248. WeaponState& weaponState = m_simulatedWeaponStates[index];
  249. const FireParams& fireParams = GetActivationParams(index);
  250. weapon->SetFireParams(fireParams);
  251. while (weaponState.m_activationCount != value)
  252. {
  253. const bool validateActivations = false;
  254. ActivateWeaponWithParams(aznumeric_cast<WeaponIndex>(index), weaponState, fireParams, validateActivations);
  255. }
  256. }
  257. NetworkWeaponsComponentController::NetworkWeaponsComponentController(NetworkWeaponsComponent& parent)
  258. : NetworkWeaponsComponentControllerBase(parent)
  259. , m_updateAI{[this] { UpdateAI(); }, AZ::Name{ "WeaponsControllerAI" } }
  260. {
  261. ;
  262. }
  263. void NetworkWeaponsComponentController::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  264. {
  265. NetworkAiComponent* networkAiComponent = GetParent().GetNetworkAiComponent();
  266. m_aiEnabled = (networkAiComponent != nullptr) ? networkAiComponent->GetEnabled() : false;
  267. if (m_aiEnabled)
  268. {
  269. m_updateAI.Enqueue(AZ::TimeMs{ 0 }, true);
  270. m_networkAiComponentController = GetNetworkAiComponentController();
  271. }
  272. else if (IsNetEntityRoleAutonomous())
  273. {
  274. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(DrawEventId);
  275. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(FirePrimaryEventId);
  276. StartingPointInput::InputEventNotificationBus::MultiHandler::BusConnect(FireSecondaryEventId);
  277. }
  278. }
  279. void NetworkWeaponsComponentController::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
  280. {
  281. if (IsNetEntityRoleAutonomous() && !m_aiEnabled)
  282. {
  283. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(DrawEventId);
  284. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(FirePrimaryEventId);
  285. StartingPointInput::InputEventNotificationBus::MultiHandler::BusDisconnect(FireSecondaryEventId);
  286. }
  287. }
  288. void NetworkWeaponsComponentController::CreateInput(Multiplayer::NetworkInput& input, [[maybe_unused]] float deltaTime)
  289. {
  290. // Inputs for your own component always exist
  291. NetworkWeaponsComponentNetworkInput* weaponInput = input.FindComponentInput<NetworkWeaponsComponentNetworkInput>();
  292. weaponInput->m_draw = m_weaponDrawn;
  293. weaponInput->m_firing = m_weaponFiring;
  294. // All weapon indices point to the same bone so only send one instance
  295. uint32_t weaponIndexInt = 0;
  296. if (weaponInput->m_firing.GetBit(weaponIndexInt))
  297. {
  298. const char* fireBoneName = GetFireBoneNames(weaponIndexInt).c_str();
  299. int32_t boneIdx = GetNetworkAnimationComponentController()->GetParent().GetBoneIdByName(fireBoneName);
  300. AZ::Transform fireBoneTransform;
  301. if (!GetNetworkAnimationComponentController()->GetParent().GetJointTransformById(boneIdx, fireBoneTransform))
  302. {
  303. AZLOG_WARN("Failed to get transform for fire bone joint Id %u", boneIdx);
  304. }
  305. weaponInput->m_shotStartPosition = fireBoneTransform.GetTranslation();
  306. }
  307. }
  308. void NetworkWeaponsComponentController::ProcessInput(Multiplayer::NetworkInput& input, [[maybe_unused]] float deltaTime)
  309. {
  310. NetworkWeaponsComponentNetworkInput* weaponInput = input.FindComponentInput<NetworkWeaponsComponentNetworkInput>();
  311. GetNetworkAnimationComponentController()->ModifyActiveAnimStates().SetBit(
  312. aznumeric_cast<uint32_t>(CharacterAnimState::Aiming), weaponInput->m_draw);
  313. for (AZStd::size_t weaponIndex = 0; weaponIndex < MaxWeaponsPerComponent; ++weaponIndex)
  314. {
  315. const CharacterAnimState animState = CharacterAnimState::Shooting;
  316. GetNetworkAnimationComponentController()->ModifyActiveAnimStates().SetBit(
  317. aznumeric_cast<uint32_t>(animState), weaponInput->m_firing.GetBit(static_cast<uint32_t>(weaponIndex)));
  318. }
  319. const AZ::Transform worldTm = GetParent().GetEntity()->GetTransform()->GetWorldTM();
  320. for (uint32_t weaponIndexInt = 0; weaponIndexInt < MaxWeaponsPerComponent; ++weaponIndexInt)
  321. {
  322. if (weaponInput->m_firing.GetBit(weaponIndexInt))
  323. {
  324. const AZ::Vector3& aimAngles = GetNetworkSimplePlayerCameraComponentController()->GetAimAngles();
  325. const AZ::Quaternion aimRotation =
  326. AZ::Quaternion::CreateRotationZ(aimAngles.GetZ()) * AZ::Quaternion::CreateRotationX(aimAngles.GetX());
  327. // TODO: This should probably be a physx raycast out to some maxDistance
  328. const AZ::Vector3 fwd = AZ::Vector3::CreateAxisY();
  329. const AZ::Vector3 aimTarget = worldTm.GetTranslation() + aimRotation.TransformVector(fwd * 5.0f);
  330. AZ::Vector3 aimSource = weaponInput->m_shotStartPosition;
  331. const char* fireBoneName = GetFireBoneNames(weaponIndexInt).c_str();
  332. int32_t boneIdx = GetNetworkAnimationComponentController()->GetParent().GetBoneIdByName(fireBoneName);
  333. AZ::Transform fireBoneTransform;
  334. if (!GetNetworkAnimationComponentController()->GetParent().GetJointTransformById(boneIdx, fireBoneTransform))
  335. {
  336. AZLOG_WARN("Failed to get transform for fire bone joint Id %u", boneIdx);
  337. }
  338. // Validate the proposed start position is reasonably close to the related bone
  339. if ((fireBoneTransform.GetTranslation() - aimSource).GetLength() > sv_WeaponsStartPositionClampRange)
  340. {
  341. aimSource = fireBoneTransform.GetTranslation();
  342. AZLOG_WARN("Shot origin was outside of clamp range, resetting to bone position");
  343. }
  344. FireParams fireParams{ weaponInput->m_shotStartPosition, aimTarget, Multiplayer::InvalidNetEntityId };
  345. TryStartFire(aznumeric_cast<WeaponIndex>(weaponIndexInt), fireParams);
  346. }
  347. }
  348. UpdateWeaponFiring(deltaTime);
  349. }
  350. void NetworkWeaponsComponentController::UpdateWeaponFiring([[maybe_unused]] float deltaTime)
  351. {
  352. for (uint32_t weaponIndexInt = 0; weaponIndexInt < MaxWeaponsPerComponent; ++weaponIndexInt)
  353. {
  354. IWeapon* weapon = GetParent().GetWeapon(aznumeric_cast<WeaponIndex>(weaponIndexInt));
  355. if ((weapon == nullptr) || !weapon->GetParams().m_locallyPredicted)
  356. {
  357. continue;
  358. }
  359. WeaponState& weaponState = ModifyWeaponStates(weaponIndexInt);
  360. if ((weaponState.m_status == WeaponStatus::Firing) && (weaponState.m_cooldownTime <= 0.0f))
  361. {
  362. AZLOG(NET_Weapons, "Weapon predicted activation event for weapon index %u", weaponIndexInt);
  363. const bool validateActivations = true;
  364. const FireParams& fireParams = weapon->GetFireParams();
  365. GetParent().ActivateWeaponWithParams(
  366. aznumeric_cast<WeaponIndex>(weaponIndexInt), weaponState, fireParams, validateActivations);
  367. #if AZ_TRAIT_SERVER
  368. if (IsNetEntityRoleAuthority())
  369. {
  370. SetActivationParams(weaponIndexInt, fireParams);
  371. SetActivationCounts(weaponIndexInt, weaponState.m_activationCount);
  372. }
  373. #endif
  374. }
  375. weapon->UpdateWeaponState(weaponState, deltaTime);
  376. }
  377. }
  378. bool NetworkWeaponsComponentController::TryStartFire(WeaponIndex weaponIndex, const FireParams& fireParams)
  379. {
  380. const uint32_t weaponIndexInt = aznumeric_cast<uint32_t>(weaponIndex);
  381. AZLOG(NET_Weapons, "Weapon start fire on %u", weaponIndexInt);
  382. IWeapon* weapon = GetParent().GetWeapon(weaponIndex);
  383. if (weapon == nullptr)
  384. {
  385. return false;
  386. }
  387. WeaponState& weaponState = ModifyWeaponStates(weaponIndexInt);
  388. if (weapon->TryStartFire(weaponState, fireParams))
  389. {
  390. const uint32_t animBit = static_cast<uint32_t>(weapon->GetParams().m_animFlag);
  391. if (!GetNetworkAnimationComponentController()->GetActiveAnimStates().GetBit(animBit))
  392. {
  393. GetNetworkAnimationComponentController()->ModifyActiveAnimStates().SetBit(animBit, true);
  394. }
  395. return true;
  396. }
  397. return false;
  398. }
  399. void NetworkWeaponsComponentController::OnPressed([[maybe_unused]] float value)
  400. {
  401. const StartingPointInput::InputEventNotificationId* inputId = StartingPointInput::InputEventNotificationBus::GetCurrentBusId();
  402. if (inputId == nullptr)
  403. {
  404. return;
  405. }
  406. else if (*inputId == DrawEventId)
  407. {
  408. m_weaponDrawn = !m_weaponDrawn;
  409. }
  410. else if (*inputId == FirePrimaryEventId)
  411. {
  412. m_weaponFiring.SetBit(aznumeric_cast<uint32_t>(PrimaryWeaponIndex), true);
  413. }
  414. else if (*inputId == FireSecondaryEventId)
  415. {
  416. m_weaponFiring.SetBit(aznumeric_cast<uint32_t>(SecondaryWeaponIndex), true);
  417. }
  418. }
  419. void NetworkWeaponsComponentController::OnReleased([[maybe_unused]] float value)
  420. {
  421. const StartingPointInput::InputEventNotificationId* inputId = StartingPointInput::InputEventNotificationBus::GetCurrentBusId();
  422. if (inputId == nullptr)
  423. {
  424. return;
  425. }
  426. else if (*inputId == FirePrimaryEventId)
  427. {
  428. m_weaponFiring.SetBit(aznumeric_cast<uint32_t>(PrimaryWeaponIndex), false);
  429. }
  430. else if (*inputId == FireSecondaryEventId)
  431. {
  432. m_weaponFiring.SetBit(aznumeric_cast<uint32_t>(SecondaryWeaponIndex), false);
  433. }
  434. }
  435. void NetworkWeaponsComponentController::OnHeld([[maybe_unused]] float value)
  436. {
  437. ;
  438. }
  439. void NetworkWeaponsComponentController::UpdateAI()
  440. {
  441. #if AZ_TRAIT_SERVER
  442. float deltaTime = static_cast<float>(m_updateAI.TimeInQueueMs()) / 1000.f;
  443. if (m_networkAiComponentController != nullptr)
  444. {
  445. m_networkAiComponentController->TickWeapons(*this, deltaTime);
  446. }
  447. #endif
  448. }
  449. } // namespace ${SanitizedCppName}