7 enum SCR_NearbyContextDisplayMode
20 class SCR_InteractionHandlerComponent : InteractionHandlerComponent
25 [
Attribute(
"3", UIWidgets.ComboBox,
"Display mode",
"", ParamEnumArray.FromEnum(SCR_NearbyContextDisplayMode),
category:
"Nearby Context Properties" )]
26 protected SCR_NearbyContextDisplayMode m_eDisplayMode;
28 [
Attribute(
"", UIWidgets.EditBox,
"Action to listen for when SCR_NearbyContextDisplayMode is set to ON_INPUT_ACTION",
category:
"Nearby Context Properties")]
31 [
Attribute(
"", UIWidgets.EditBox,
"Context to activate when SCR_NearbyContextDisplayMode is set to ON_INPUT_ACTION. Mustn't be empty to be activated.",
category:
"Nearby Context Properties")]
32 protected string m_sActionContext;
41 protected int m_iSelectedActionIndex;
43 protected bool m_bIsPerforming;
44 protected bool m_bPerformAction;
45 protected bool m_bLastInput;
46 protected float m_fSelectAction;
47 protected float m_fCurrentProgress;
50 protected ref array<IEntity> m_aInspectedEntities = {};
52 protected IEntity m_ControlledEntity;
56 protected void RegisterActionListeners()
58 InputManager pInputManager =
GetGame().GetInputManager();
62 m_bPerformAction =
false;
64 pInputManager.AddActionListener(
"PerformAction", EActionTrigger.DOWN,
ActionPerform);
65 pInputManager.AddActionListener(
"PerformAction", EActionTrigger.UP,
ActionPerform);
66 pInputManager.AddActionListener(
"SelectAction", EActionTrigger.VALUE, ActionScroll);
72 InputManager pInputManager =
GetGame().GetInputManager();
76 m_bPerformAction =
false;
78 pInputManager.RemoveActionListener(
"PerformAction", EActionTrigger.DOWN,
ActionPerform);
79 pInputManager.RemoveActionListener(
"PerformAction", EActionTrigger.UP,
ActionPerform);
80 pInputManager.RemoveActionListener(
"SelectAction", EActionTrigger.VALUE, ActionScroll);
87 m_bPerformAction = reason == EActionTrigger.DOWN;
91 void ActionScroll(
float value, EActionTrigger reason)
96 m_fSelectAction = value;
106 PlayerController controller =
GetGame().GetPlayerController();
110 if (controller.FindComponent(SCR_InteractionHandlerComponent) !=
this)
117 RegisterActionListeners();
121 override void OnInit(IEntity owner)
123 DiagMenu.RegisterBool(
SCR_DebugMenuID.DEBUGUI_INTERACTION_SKIP_DURATION,
"",
"Skip action duration",
"User Actions");
129 PlayerController playerController = PlayerController.Cast(owner);
130 if (!playerController)
132 Print(
"InteractionHandler must be attached to a PlayerController!", LogLevel.ERROR);
136 HUDManagerComponent hudManager = HUDManagerComponent.Cast(playerController.FindComponent(HUDManagerComponent));
137 array<BaseInfoDisplay> displayInfos = {};
138 int count = hudManager.GetInfoDisplays(displayInfos);
139 for (
int i = 0; i < count; i++)
146 Print(
"InteractionDisplay not found! InteractionDisplay must be stored in HUDManagerComponent of a PlayerController!", LogLevel.WARNING);
159 protected void DoProcessInteraction(
160 ChimeraCharacter user,
169 action.SetActiveContext(context);
172 bool isOk = action && canPerform && action == m_pLastUserAction;
174 if (performInput && isOk)
178 if (!m_bIsPerforming && !m_bLastInput)
185 display.OnActionStart(user, action);
188 user.DoStartObjectAction(action);
191 m_bIsPerforming =
true;
192 m_fCurrentProgress = 0.0;
196 else if (m_bIsPerforming)
198 if (DiagMenu.GetValue(
SCR_DebugMenuID.DEBUGUI_INTERACTION_SKIP_DURATION))
199 timeSlice += Math.AbsFloat(action.GetActionDuration());
204 if (signalUserAction)
207 if (adjustAction && !adjustAction.IsManuallyAdjusted())
208 m_fCurrentProgress += timeSlice;
210 m_fCurrentProgress = signalUserAction.GetActionProgress();
212 else if (scriptedUserAction)
214 if (DiagMenu.GetValue(
SCR_DebugMenuID.DEBUGUI_INTERACTION_SKIP_DURATION))
215 timeSlice += scriptedUserAction.GetLoopActionHoldDuration();
217 m_fCurrentProgress = scriptedUserAction.GetActionProgress(m_fCurrentProgress, timeSlice);
220 m_fCurrentProgress += timeSlice;
223 if (action.ShouldPerformPerFrame())
224 user.DoPerformContinuousObjectAction(action, timeSlice);
227 float duration = action.GetActionDuration();
231 display.OnActionProgress(user, action, m_fCurrentProgress, Math.AbsFloat(duration));
234 if (m_fCurrentProgress >= duration && duration >= 0)
241 if (!action.ShouldPerformPerFrame())
242 user.DoPerformObjectAction(action);
245 m_fCurrentProgress = 0.0;
246 m_bIsPerforming =
false;
261 user.DoCancelObjectAction(action);
264 m_bIsPerforming =
false;
265 m_fCurrentProgress = 0.0;
273 ChimeraCharacter character = ChimeraCharacter.Cast(controlledEntity);
278 MenuManager menuManager =
GetGame().GetMenuManager();
279 if (menuManager && menuManager.IsAnyMenuOpen())
283 if (characterController && !characterController.CanInteract())
298 return m_pLastUserAction;
304 if (!controlledEntity)
307 ChimeraCharacter character = ChimeraCharacter.Cast(controlledEntity);
311 if (character.IsInVehicle())
314 if (character.GetCharacterController().GetInspect())
326 m_iSelectedActionIndex = 0;
328 m_pDisplay.HideDisplay();
332 if (m_pDisplay && newContext)
333 m_pDisplay.ShowDisplay();
343 if (!m_ControlledEntity)
348 if (dmg && dmg.IsDestroyed())
355 if (currentContext && m_ControlledEntity)
358 const float threshold = 1.1;
362 float maxSqDistance = (visRange * visRange) * 1.1;
364 float sqDistance = vector.DistanceSq(currentContext.GetOrigin(), m_ControlledEntity.GetOrigin());
366 if (sqDistance > maxSqDistance)
374 if (currentContext && m_bIsPerforming)
386 protected bool ShouldBeEnabledInFreelook(ChimeraCharacter character)
391 CharacterControllerComponent controller = character.GetCharacterController();
396 if (controller.GetInspect())
399 CompartmentAccessComponent compartmentAccess = character.GetCompartmentAccessComponent();
401 if (compartmentAccess && compartmentAccess.IsInCompartment() && controller.IsInThirdPersonView())
405 if (!controller.IsFreeLookEnforced() && controller.IsFreeLookEnabled())
410 if (compartmentAccess)
412 if (compartmentAccess.IsGettingIn() || compartmentAccess.IsGettingOut())
417 if (character.IsInVehicle())
419 if (controller.IsInThirdPersonView())
424 if (controller.IsFalling())
428 if (controller.IsClimbing())
432 if (controller.IsUnconscious())
439 protected bool ShouldBeEnabled(SCR_NearbyContextDisplayMode displayMode, ChimeraCharacter character,
bool playerCameraOnly =
true)
446 if (playerCameraOnly)
448 CameraManager cameraManager =
GetGame().GetCameraManager();
449 if (cameraManager && !PlayerCamera.Cast(cameraManager.CurrentCamera()))
457 case SCR_NearbyContextDisplayMode.DISABLED:
461 case SCR_NearbyContextDisplayMode.ALWAYS_ON:
465 case SCR_NearbyContextDisplayMode.ON_INPUT_ACTION:
470 InputManager inputManager =
GetGame().GetInputManager();
471 if (!m_sActionContext.IsEmpty())
472 inputManager.ActivateContext(m_sActionContext);
478 case SCR_NearbyContextDisplayMode.ON_FREELOOK:
480 if (!ShouldBeEnabledInFreelook(character))
483 return character.GetCharacterController().IsFreeLookEnabled();
494 CameraManager cameraManager =
GetGame().GetCameraManager();
497 CameraBase camera = cameraManager.CurrentCamera();
498 vector rayDir = camera.GetWorldTransformAxis(2);
499 vector rayStart = camera.GetOrigin();
500 referencePoint = rayStart + rayDir;
503 ChimeraCharacter character = ChimeraCharacter.Cast(m_ControlledEntity);
507 CharacterControllerComponent controller = character.GetCharacterController();
508 if (controller.GetInspect() && controller.GetInspectCurrentWeapon())
512 IEntity inspectedEntity = controller.GetInspectEntity();
514 vector origin = inspectedEntity.GetOrigin();
515 vector normal = -inspectedEntity.GetWorldTransformAxis(0);
517 referencePoint =
SCR_Math3D.IntersectPlane(rayStart, rayDir, origin, normal);
524 referencePoint = vector.Zero;
527 return m_aInspectedEntities;
531 protected void HandleInspection(notnull ChimeraCharacter character,
float timeSlice)
533 if (character.GetCharacterController().GetInspect())
536 m_aInspectedEntities.Clear();
539 CharacterControllerComponent ctrlComp = character.GetCharacterController();
540 if (ctrlComp.GetInspectCurrentWeapon())
543 BaseWeaponManagerComponent weaponManager = BaseWeaponManagerComponent.Cast(character.FindComponent(BaseWeaponManagerComponent));
549 m_aInspectedEntities.Insert(weapon.GetOwner());
551 array<AttachmentSlotComponent> attachments = {};
552 weapon.GetAttachments(attachments);
554 foreach (AttachmentSlotComponent
attachment : attachments)
556 IEntity attachedEntity =
attachment.GetAttachedEntity();
558 m_aInspectedEntities.Insert(attachedEntity);
561 BaseMagazineComponent magazineComp = weapon.GetCurrentMagazine();
563 m_aInspectedEntities.Insert(magazineComp.GetOwner());
570 IEntity inspectedItem = ctrlComp.GetInspectEntity();
573 m_aInspectedEntities.Insert(inspectedItem);
584 protected override void OnPostFrame(IEntity owner, IEntity controlledEntity,
float timeSlice)
588 m_pDisplay = FindDisplay(owner);
590 m_ControlledEntity = controlledEntity;
592 ChimeraCharacter character = ChimeraCharacter.Cast(controlledEntity);
595 bool enableNearbyCollection = ShouldBeEnabled(m_eDisplayMode, character,
true);
602 HandleInspection(character, timeSlice);
607 array<BaseUserAction> actions = {};
608 array<bool> canPerform = {};
611 GetGame().GetInputManager().ActivateContext(
"ActionMenuContext");
616 m_pDisplay.OnActionProgress(character, action, action.GetActionProgress(), action.GetActionDuration());
619 AggregateActions(actions, canPerform);
624 if (m_pLastUserAction)
627 for (
int i = 0, ac = actions.Count(); i < ac; i++)
630 if (action && action == m_pLastUserAction)
632 m_iSelectedActionIndex = i;
639 int iScrollAmount = 0;
640 int prevActionIndex = m_iSelectedActionIndex;
642 if (!m_bIsPerforming)
644 if (Math.AbsFloat(m_fSelectAction) > 0.5)
645 iScrollAmount = Math.Clamp(m_fSelectAction, -1.0, 1.0);
647 if (iScrollAmount != 0)
648 m_iSelectedActionIndex = m_iSelectedActionIndex - iScrollAmount;
652 int actionsCount = actions.Count();
653 m_iSelectedActionIndex = Math.Clamp(m_iSelectedActionIndex, 0, actionsCount - 1);
656 bool canPerformSelectedAction =
false;
660 selectedAction = m_pLastUserAction;
661 if (actions.Count() > prevActionIndex && actions[prevActionIndex] == m_pLastUserAction)
662 canPerformSelectedAction = canPerform[prevActionIndex];
663 else if (m_pLastUserAction)
664 canPerformSelectedAction = m_pLastUserAction.CanBeShown(character) && m_pLastUserAction.CanBePerformed(character);
666 else if (actionsCount > 0)
668 selectedAction = actions[m_iSelectedActionIndex];
669 canPerformSelectedAction = canPerform[m_iSelectedActionIndex];
674 canPerformSelectedAction = canPerformSelectedAction && selectedAction.CanBePerformed(character);
676 DoProcessInteraction(character, currentContext, selectedAction, canPerformSelectedAction, m_bPerformAction, timeSlice, m_pDisplay);
677 m_pLastUserAction = selectedAction;
686 if (canInteract || m_bIsPerforming)
688 pData.param1 = actions;
689 pData.param2 = canPerform;
697 pDisplayData.pUser = controlledEntity;
698 pDisplayData.pActionsData = pData;
699 pDisplayData.pSelectedAction = selectedAction;
700 pDisplayData.pCurrentContext = currentContext;
702 m_pDisplay.SetDisplayData(pDisplayData);
707 else if (m_pLastContext != currentContext)
710 if (m_pLastUserAction)
716 m_bIsPerforming =
false;
717 m_fCurrentProgress = 0.0;
720 character.DoCancelObjectAction(m_pLastUserAction);
724 m_pLastUserAction =
null;
730 m_bLastInput = m_bPerformAction;
734 if (!m_bIsPerforming)
735 m_bPerformAction =
false;
738 m_pLastContext = currentContext;
741 protected ref array<BaseUserAction> m_ActionsBuffer = {};
742 protected ref array<bool> m_PerformBuffer = {};
743 protected ref map<string, ref array<int>> m_IndicesBuffer =
new map<string, ref array<int>>();
749 protected void AggregateActions(array<BaseUserAction> actionsList, array<bool> canPerformList)
751 m_ActionsBuffer.Copy(actionsList);
752 m_PerformBuffer.Copy(canPerformList);
753 m_IndicesBuffer.Clear();
755 canPerformList.Clear();
758 for (
int i = 0, count = m_ActionsBuffer.Count(); i < count; i++)
765 bool canPerform = m_PerformBuffer[i];
766 if (!action.CanAggregate())
770 string actionName = action.GetActionName();
771 if (!m_IndicesBuffer.Contains(actionName))
772 m_IndicesBuffer.Insert(actionName, {});
774 m_IndicesBuffer[actionName].Insert(i);
778 for (
int i = 0, count = m_ActionsBuffer.Count(); i < count; i++)
785 bool canPerform = m_PerformBuffer[i];
786 if (!action.CanAggregate())
788 actionsList.Insert(action);
789 canPerformList.Insert(canPerform);
794 string actionName = action.GetActionName();
797 if (!m_IndicesBuffer.Contains(actionName))
801 int availableIndex = m_IndicesBuffer[actionName][0];
802 foreach (
int index : m_IndicesBuffer[actionName])
805 if (m_PerformBuffer[
index])
807 availableIndex =
index;
812 BaseUserAction aggregatedAction = m_ActionsBuffer[availableIndex];
813 bool aggregatedState = m_PerformBuffer[availableIndex];
814 actionsList.Insert(aggregatedAction);
815 canPerformList.Insert(aggregatedState);
817 m_IndicesBuffer.Remove(actionName);