Started make greybox for main location
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
using System.Collections.Generic;
|
||||
using Unity.Netcode;
|
||||
using UnityEngine;
|
||||
|
||||
public abstract class NetworkHeldInteractable : NetworkInteractable
|
||||
{
|
||||
protected const ulong NoHolder = ulong.MaxValue;
|
||||
|
||||
[Header("Physics")]
|
||||
[SerializeField] private Rigidbody physicsBody;
|
||||
[SerializeField] private Collider[] objectColliders;
|
||||
[SerializeField, Min(0.05f)] private float collisionRefreshInterval = 0.25f;
|
||||
|
||||
private readonly NetworkVariable<ulong> holderClientId = new(
|
||||
NoHolder,
|
||||
NetworkVariableReadPermission.Everyone,
|
||||
NetworkVariableWritePermission.Server);
|
||||
|
||||
private readonly HashSet<Collider> ignoredPlayerColliders = new();
|
||||
private float nextCollisionRefreshTime;
|
||||
|
||||
protected abstract Vector3 HoldingOffset { get; }
|
||||
protected abstract string DropPrompt { get; }
|
||||
|
||||
private bool IsHeld => holderClientId.Value != NoHolder;
|
||||
private bool IsHeldByLocalPlayer =>
|
||||
NetworkManager != null && holderClientId.Value == NetworkManager.LocalClientId;
|
||||
|
||||
public override string InteractionPrompt => !IsHeld
|
||||
? InteractionLabel
|
||||
: IsHeldByLocalPlayer
|
||||
? DropPrompt
|
||||
: "In use";
|
||||
|
||||
public override bool IsInteractionAvailable => base.IsInteractionAvailable &&
|
||||
(!IsHeld || IsHeldByLocalPlayer);
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (physicsBody == null)
|
||||
physicsBody = GetComponent<Rigidbody>();
|
||||
|
||||
if (objectColliders == null || objectColliders.Length == 0)
|
||||
objectColliders = GetComponentsInChildren<Collider>(true);
|
||||
}
|
||||
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
holderClientId.OnValueChanged += HandleHolderChanged;
|
||||
ApplyHoldingState(IsHeld);
|
||||
}
|
||||
|
||||
public override void OnNetworkDespawn()
|
||||
{
|
||||
holderClientId.OnValueChanged -= HandleHolderChanged;
|
||||
ApplyHoldingState(false);
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (!IsSpawned || !IsHeld)
|
||||
return;
|
||||
|
||||
if (!TryGetPlayerObject(holderClientId.Value, out NetworkObject holder))
|
||||
{
|
||||
if (IsServer)
|
||||
StopHolding();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
transform.SetPositionAndRotation(
|
||||
holder.transform.TransformPoint(HoldingOffset),
|
||||
holder.transform.rotation);
|
||||
|
||||
if (Time.time >= nextCollisionRefreshTime)
|
||||
{
|
||||
nextCollisionRefreshTime = Time.time + collisionRefreshInterval;
|
||||
IgnoreCollisionsWithPlayers();
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool CanInteractOnServer(ulong senderClientId) =>
|
||||
!IsHeld || holderClientId.Value == senderClientId;
|
||||
|
||||
protected override void InteractOnServer(ulong senderClientId, NetworkObject playerObject)
|
||||
{
|
||||
if (holderClientId.Value == senderClientId)
|
||||
StopHolding();
|
||||
else if (!IsHeld)
|
||||
StartHolding(senderClientId);
|
||||
}
|
||||
|
||||
private void StartHolding(ulong clientId)
|
||||
{
|
||||
holderClientId.Value = clientId;
|
||||
ApplyHoldingState(true);
|
||||
}
|
||||
|
||||
private void StopHolding()
|
||||
{
|
||||
holderClientId.Value = NoHolder;
|
||||
ApplyHoldingState(false);
|
||||
}
|
||||
|
||||
private void HandleHolderChanged(ulong _, ulong currentHolder) =>
|
||||
ApplyHoldingState(currentHolder != NoHolder);
|
||||
|
||||
private void ApplyHoldingState(bool isHeld)
|
||||
{
|
||||
if (physicsBody != null)
|
||||
{
|
||||
physicsBody.isKinematic = isHeld;
|
||||
if (!isHeld)
|
||||
physicsBody.linearVelocity = Vector3.zero;
|
||||
}
|
||||
|
||||
if (isHeld)
|
||||
IgnoreCollisionsWithPlayers();
|
||||
else
|
||||
RestorePlayerCollisions();
|
||||
}
|
||||
|
||||
private void IgnoreCollisionsWithPlayers()
|
||||
{
|
||||
foreach (CharacterController playerCollider in FindObjectsByType<CharacterController>(
|
||||
FindObjectsInactive.Exclude,
|
||||
FindObjectsSortMode.None))
|
||||
{
|
||||
foreach (Collider objectCollider in objectColliders)
|
||||
{
|
||||
if (objectCollider == null || playerCollider == null)
|
||||
continue;
|
||||
|
||||
Physics.IgnoreCollision(objectCollider, playerCollider, true);
|
||||
}
|
||||
|
||||
ignoredPlayerColliders.Add(playerCollider);
|
||||
}
|
||||
}
|
||||
|
||||
private void RestorePlayerCollisions()
|
||||
{
|
||||
foreach (Collider playerCollider in ignoredPlayerColliders)
|
||||
{
|
||||
if (playerCollider == null)
|
||||
continue;
|
||||
|
||||
foreach (Collider objectCollider in objectColliders)
|
||||
{
|
||||
if (objectCollider != null)
|
||||
Physics.IgnoreCollision(objectCollider, playerCollider, false);
|
||||
}
|
||||
}
|
||||
|
||||
ignoredPlayerColliders.Clear();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user