using Unity.Netcode; using UnityEngine; using UnityEngine.InputSystem; public sealed class PlayerInteractionController : NetworkBehaviour, IPlayerSystem { [SerializeField, Min(0.1f)] private float interactionDistance = 3f; [SerializeField] private LayerMask interactionMask = ~0; private Camera playerCamera; private IInteractable focusedInteractable; private IPlayerInteractionSession activeSession; private bool activeSessionReleaseRequested; private bool isInitialized; public void Initialize(PlayerFacade facade) { playerCamera = GetComponentInChildren(true); isInitialized = playerCamera != null; } private void Update() { if (!isInitialized || !IsOwner || Keyboard.current == null) return; if (PlayerInteractionSessionRegistry.TryGetControlledSession( OwnerClientId, out activeSession)) { focusedInteractable = null; if (!Keyboard.current.eKey.isPressed && !activeSessionReleaseRequested) { activeSessionReleaseRequested = true; activeSession.RequestRelease(); } return; } activeSession = null; activeSessionReleaseRequested = false; focusedInteractable = FindFocusedInteractable(); if (Keyboard.current.eKey.wasPressedThisFrame && focusedInteractable != null && focusedInteractable.IsInteractionAvailable) { focusedInteractable.RequestInteraction(); } } private IInteractable FindFocusedInteractable() { Ray ray = new(playerCamera.transform.position, playerCamera.transform.forward); if (!Physics.Raycast(ray, out RaycastHit hit, interactionDistance, interactionMask, QueryTriggerInteraction.Collide)) return null; foreach (MonoBehaviour component in hit.collider.GetComponentsInParent()) { if (component is IInteractable interactable) return interactable; } return null; } private void OnGUI() { if (!IsOwner) return; if (activeSession != null) { DrawPrompt(activeSession.ReleasePrompt); return; } if (focusedInteractable == null) return; string prompt = focusedInteractable.IsInteractionAvailable ? "[E] " + focusedInteractable.InteractionPrompt : "In use"; DrawPrompt(prompt); } private static void DrawPrompt(string prompt) { GUIStyle style = new(GUI.skin.label) { alignment = TextAnchor.MiddleCenter, fontSize = 16, normal = { textColor = Color.white } }; Rect area = new(0f, Screen.height * 0.62f, Screen.width, 28f); GUI.Label(area, prompt, style); } }