using AfterHours.Networking; using Unity.Netcode; using Unity.Netcode.Components; using UnityEngine; namespace AfterHours.Interaction { /// /// Macht ein Objekt aufheb- und tragbar. Reines Trage-Handwerkszeug ohne /// Fachwissen über Inhalt/Produkte – das bleibt beim jeweiligen Objekt /// (z. B. Lieferkarton). Positionierung beim Tragen ist rein kosmetisch /// und läuft auf jedem Peer selbst (siehe ShelfSlot.RefreshVisuals-Muster), /// kein NGO-Reparenting – siehe Plan-Begründung in Lieferkarton.cs. /// [RequireComponent(typeof(NetworkObject))] public sealed class Carryable : NetworkBehaviour { [SerializeField] private Collider[] _collidersToDisableWhileCarried; [SerializeField] private NetworkTransform _networkTransform; [SerializeField] private Rigidbody _rigidbody; private readonly NetworkVariable _isCarried = new( false, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server ); private readonly NetworkVariable _carriedBy = new( default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server ); public bool IsCarried => _isCarried.Value; public override void OnNetworkSpawn() { _isCarried.OnValueChanged += (_, current) => ApplyCarriedState(current); ApplyCarriedState(_isCarried.Value); } /// Server: Träger übernimmt das Objekt. False, wenn schon getragen. public bool TryPickUp(NetworkObject carrier) { if (!IsServer || _isCarried.Value) return false; _carriedBy.Value = carrier; _isCarried.Value = true; return true; } /// Server: Objekt an fester Position/Rotation ablegen. public void Drop(Vector3 position, Quaternion rotation) { if (!IsServer || !_isCarried.Value) return; transform.SetPositionAndRotation(position, rotation); _isCarried.Value = false; _carriedBy.Value = default; } private void ApplyCarriedState(bool carried) { foreach (var collider in _collidersToDisableWhileCarried) if (collider != null) collider.enabled = !carried; if (_networkTransform != null) _networkTransform.enabled = !carried; // Sonst kämpft die Physik gegen das kosmetische Tragen (LateUpdate unten). if (_rigidbody != null) { _rigidbody.isKinematic = carried; if (!carried) _rigidbody.linearVelocity = Vector3.zero; } } private void LateUpdate() { if (!_isCarried.Value) return; if (!_carriedBy.Value.TryGet(out var carrier)) return; if (!carrier.TryGetComponent(out var carry) || carry.HandSocket == null) return; transform.SetPositionAndRotation(carry.HandSocket.position, carry.HandSocket.rotation); } } }