using System; using UnityEngine; using UnityEngine.InputSystem; [RequireComponent(typeof(BoxCollider))] public sealed class KeyedStationProbe : MonoBehaviour { [SerializeField] private Camera viewCamera; [SerializeField] private GameObject closedVisual; [SerializeField] private LayerMask interactionLayers = ~0; [SerializeField, Min(0.01f)] private float range = 3f; private Collider stationCollider; private InputAction interact; private GateState state; private void Awake() { stationCollider = GetComponent(); state = new GateState(); interact = new InputAction("Interact", InputActionType.Button, "/e"); } private void OnEnable() { if (interact != null) { interact.performed += OnInteract; interact.Enable(); } } private void OnDisable() { if (interact != null) { interact.performed -= OnInteract; interact.Disable(); } } private void OnDestroy() { if (interact != null) interact.Dispose(); } [ContextMenu("Grant Key (Play Mode)")] public void GrantKey() { if (Application.isPlaying && state != null) { state.GrantKey(); Debug.Log("Key available: " + state.HasKey, this); } } private void OnInteract(InputAction.CallbackContext context) { if (!isActiveAndEnabled || state == null || viewCamera == null || stationCollider == null) return; if (range <= 0f || float.IsNaN(range) || float.IsInfinity(range)) return; Ray ray = viewCamera.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0f)); if (!Physics.Raycast(ray, out RaycastHit hit, range, interactionLayers, QueryTriggerInteraction.Ignore)) return; if (hit.collider != stationCollider || !state.TryOpen(true, hit.distance, range)) return; stationCollider.enabled = false; if (closedVisual != null && closedVisual != gameObject) closedVisual.SetActive(false); Debug.Log("Station opened once; key consumed", this); } public sealed class GateState { public bool HasKey { get; private set; } public bool Opened { get; private set; } public void GrantKey() { if (!Opened) HasKey = true; } public bool TryOpen(bool focused, float distance, float maximum) { if (maximum <= 0f || float.IsNaN(maximum) || float.IsInfinity(maximum)) throw new ArgumentOutOfRangeException(nameof(maximum)); if (distance < 0f || float.IsNaN(distance) || float.IsInfinity(distance)) throw new ArgumentOutOfRangeException(nameof(distance)); if (Opened || !HasKey || !focused || distance > maximum) return false; HasKey = false; Opened = true; return true; } } }