using Unity.Netcode; using Unity.Netcode.Components; using UnityEngine; public interface IInteractable { string InteractionPrompt { get; } bool IsInteractionAvailable { get; } void RequestInteraction(); } [AddComponentMenu("")] [RequireComponent(typeof(NetworkObject), typeof(NetworkTransform))] public class NetworkInteractable : NetworkBehaviour, IInteractable { [Header("Interaction")] [SerializeField] private string interactionLabel = "Interact"; [SerializeField, Min(0.1f)] private float maximumInteractionDistance = 3f; protected string InteractionLabel => interactionLabel; public virtual string InteractionPrompt => interactionLabel; public virtual bool IsInteractionAvailable => IsSpawned; public void RequestInteraction() { if (!IsSpawned || !IsInteractionAvailable) return; RequestInteractionServerRpc(); } [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)] private void RequestInteractionServerRpc(RpcParams rpcParams = default) { ulong senderClientId = rpcParams.Receive.SenderClientId; if (!TryGetPlayerObject(senderClientId, out NetworkObject playerObject)) return; if (!IsWithinInteractionDistance(playerObject.transform.position)) return; if (!CanInteractOnServer(senderClientId)) return; InteractOnServer(senderClientId, playerObject); } private bool IsWithinInteractionDistance(Vector3 playerPosition) { float maximumDistanceSquared = maximumInteractionDistance * maximumInteractionDistance; if ((playerPosition - transform.position).sqrMagnitude <= maximumDistanceSquared) return true; foreach (Collider interactionCollider in GetComponentsInChildren(true)) { if (interactionCollider == null || !interactionCollider.enabled || !interactionCollider.gameObject.activeInHierarchy) { continue; } Vector3 closestPoint = interactionCollider.ClosestPoint(playerPosition); if ((playerPosition - closestPoint).sqrMagnitude <= maximumDistanceSquared) return true; } return false; } protected virtual bool CanInteractOnServer(ulong senderClientId) => false; protected virtual void InteractOnServer(ulong senderClientId, NetworkObject playerObject) { } protected bool TryGetPlayerObject(ulong clientId, out NetworkObject playerObject) { playerObject = NetworkManager != null ? NetworkManager.SpawnManager.GetPlayerNetworkObject(clientId) : null; return playerObject != null; } }