using System.Threading.Tasks; using UnityEngine; using UnityEngine.InputSystem; namespace DDD.Restaurant { public class RestaurantPlayerInteraction : RestaurantCharacterInteraction { private RestaurantPlayerData _restaurantPlayerDataSo; private float _interactHeldTime; private bool _isInteracting; protected override void Start() { base.Start(); _ = Initialize(); } private Task Initialize() { _restaurantPlayerDataSo = RestaurantData.Instance.PlayerData; Debug.Assert(_restaurantPlayerDataSo != null, "_restaurantPlayerDataSo is null"); _restaurantPlayerDataSo!.InteractAction = InputManager.Instance.GetAction(InputActionMaps.Restaurant, nameof(RestaurantActions.Interact)); _restaurantPlayerDataSo.InteractAction.performed += OnInteractPerformed; _restaurantPlayerDataSo.InteractAction.canceled += OnInteractCanceled; _interactionRadius = _restaurantPlayerDataSo.InteractionRadius; _interactionLayerMask = _restaurantPlayerDataSo.InteractionLayerMask; EventBus.Register(this); return Task.CompletedTask; } protected override void OnDestroy() { base.OnDestroy(); if (_restaurantPlayerDataSo != null) { _restaurantPlayerDataSo.InteractAction.performed -= OnInteractPerformed; _restaurantPlayerDataSo.InteractAction.canceled -= OnInteractCanceled; } EventBus.Unregister(this); } protected virtual void Update() { _nearestInteractable = GetNearestInteractable(); if (_nearestInteractable != _previousInteractable) { _previousInteractable = _nearestInteractable; OnNearestInteractableChanged(_nearestInteractable); } if (_isInteracting) { if (_nearestInteractable != _interactingTarget || CanInteractTo(_interactingTarget) == false) { ResetInteractionState(); return; } _interactHeldTime += Time.deltaTime; float requiredHoldTime = _interactingTarget.GetExecutionParameters().HoldTime; float ratio = Mathf.Clamp01(_interactHeldTime / requiredHoldTime); if (_interactHeldTime >= requiredHoldTime) { TryInteraction(_nearestInteractable); OnInteractionCompleted(); ResetInteractionState(); OnInteractionHoldProgress(0f); } else { OnInteractionHoldProgress(ratio); } } } private void OnInteractPerformed(InputAction.CallbackContext context) { if (_nearestInteractable == null || CanInteractTo(_nearestInteractable) == false) return; float requiredHoldTime = _nearestInteractable.GetExecutionParameters().HoldTime; if (requiredHoldTime <= 0f) { TryInteraction(_nearestInteractable); } else { _isInteracting = true; _interactHeldTime = 0f; _interactingTarget = _nearestInteractable; } } private void OnInteractCanceled(InputAction.CallbackContext context) { OnInteractionHoldProgress(0f); ResetInteractionState(); } protected void OnNearestInteractableChanged(IInteractable newTarget) { if (newTarget != null) { BroadcastShowUi(newTarget, CanInteractTo(newTarget), 0f); } else { EventBus.Broadcast(GameEvents.HideInteractionUiEvent); } } protected void OnInteractionHoldProgress(float ratio) { if (_interactingTarget != null) { BroadcastShowUi(_interactingTarget, CanInteractTo(_interactingTarget), ratio); } } protected override void OnInteractionCompleted() { } private void BroadcastShowUi(IInteractable interactable, bool canInteract, float ratio) { var evt = GameEvents.ShowInteractionUiEvent; evt.CanInteract = canInteract; evt.TextKey = interactable.GetDisplayParameters().MessageKey; evt.HoldProgress = ratio; EventBus.Broadcast(evt); } protected void ResetInteractionState() { _interactingTarget = null; // Hold Progress _isInteracting = false; _interactingTarget = null; _interactHeldTime = 0f; OnInteractionHoldProgress(0f); } protected IInteractable GetNearestInteractable() { int colliderCount = Physics.OverlapSphereNonAlloc(transform.position, _interactionRadius, _nearColliders, _interactionLayerMask, QueryTriggerInteraction.Collide); float closestDistance = float.MaxValue; IInteractable closest = null; for (int i = 0; i < colliderCount; i++) { var col = _nearColliders[i]; if (col.TryGetComponent(out var interactable) == false) continue; var type = interactable.GetInteractionType(); if (interactable.IsInteractionHidden()) continue; if (CanSolveInteractionType(type) == false) continue; float distance = Vector3.Distance(transform.position, col.transform.position); if (distance < closestDistance) { closestDistance = distance; closest = interactable; } } return closest; } } }