Files
SixShopSimulator/Assets/Scripts/Interaction/PlayerInteractor.cs
T
2026-08-11 20:17:42 +02:00

77 lines
2.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Unity.Netcode;
using UnityEngine;
namespace AfterHours.Interaction
{
/// <summary>
/// Raycast auf dem Owner-Client für den Prompt, Ausführung auf dem Server.
/// Der Server vertraut dem Client die Zielauswahl NICHT blind er prüft
/// Distanz und Sichtbarkeit erneut (siehe CLAUDE.md §3).
/// </summary>
[RequireComponent(typeof(NetworkObject))]
public sealed class PlayerInteractor : NetworkBehaviour
{
[SerializeField] private Transform _eyes;
[SerializeField] private float _reach = 2.5f;
[SerializeField] private LayerMask _interactableMask = ~0;
/// <summary>Toleranz, weil Client und Server nie exakt denselben Frame sehen.</summary>
private const float ServerReachTolerance = 1.5f;
private IInteractable _current;
public string CurrentPrompt { get; private set; }
private void Update()
{
if (!IsOwner) return;
RefreshTarget();
if (_current != null && Input.GetKeyDown(KeyCode.E))
{
var target = ((MonoBehaviour)_current).GetComponent<NetworkObject>();
if (target != null) RequestInteractRpc(target);
}
}
private void RefreshTarget()
{
var previous = _current;
_current = null;
CurrentPrompt = null;
if (Physics.Raycast(_eyes.position, _eyes.forward, out var hit, _reach, _interactableMask)
&& hit.collider.TryGetComponent<IInteractable>(out var interactable))
{
_current = interactable;
CurrentPrompt = interactable.GetPrompt(OwnerClientId);
}
// TODO: entfernen, sobald ein echter Prompt im UI angezeigt wird.
if (_current != previous)
{
Debug.Log(_current != null
? $"[PlayerInteractor] Ziel im Blick: {CurrentPrompt}"
: "[PlayerInteractor] Kein Ziel mehr im Blick.");
}
}
[Rpc(SendTo.Server)]
private void RequestInteractRpc(NetworkObjectReference targetRef)
{
if (!targetRef.TryGet(out var target)) return;
// Server-Validierung: ist der Spieler überhaupt in Reichweite?
float distance = Vector3.Distance(transform.position, target.transform.position);
if (distance > _reach + ServerReachTolerance)
{
Debug.LogWarning($"[PlayerInteractor] Client {OwnerClientId} zu weit entfernt ({distance:F1} m).");
return;
}
if (target.TryGetComponent<IInteractable>(out var interactable))
interactable.Interact(NetworkObject);
}
}
}