Started make greybox for main location

This commit is contained in:
2026-08-05 17:49:42 +03:00
parent a259a64e80
commit 90934eca22
648 changed files with 314989 additions and 578 deletions
@@ -0,0 +1,38 @@
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Events;
public sealed class NetworkButtonInteractable : NetworkInteractable
{
[SerializeField] private UnityEvent<bool> buttonStateChanged;
private readonly NetworkVariable<bool> isPressed = new(
false,
NetworkVariableReadPermission.Everyone,
NetworkVariableWritePermission.Server);
public bool IsPressed => isPressed.Value;
public override void OnNetworkSpawn()
{
isPressed.OnValueChanged += HandleStateChanged;
ApplyState(isPressed.Value);
}
public override void OnNetworkDespawn()
{
isPressed.OnValueChanged -= HandleStateChanged;
}
protected override bool CanInteractOnServer(ulong senderClientId) => true;
protected override void InteractOnServer(ulong senderClientId, NetworkObject playerObject)
{
isPressed.Value = !isPressed.Value;
ApplyState(isPressed.Value);
}
private void HandleStateChanged(bool _, bool currentValue) => ApplyState(currentValue);
private void ApplyState(bool currentValue) => buttonStateChanged?.Invoke(currentValue);
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 43cd66292a303c3478352a33bc74db87
@@ -0,0 +1,9 @@
using UnityEngine;
public sealed class NetworkCarryableInteractable : NetworkHeldInteractable
{
[SerializeField] private Vector3 carryOffset = new(0f, 1.15f, 0.75f);
protected override Vector3 HoldingOffset => carryOffset;
protected override string DropPrompt => "Put down";
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: fad79bb3d620ffb46b527a9e361c28ae
@@ -0,0 +1,109 @@
using DG.Tweening;
using Unity.Netcode;
using UnityEngine;
[RequireComponent(typeof(NetworkObject))]
public sealed class NetworkDoorController : NetworkBehaviour
{
[Header("Visual")]
[SerializeField] private Transform doorVisual;
[SerializeField] private Vector3 openLocalPositionOffset = new(0f, 2.5f, 0f);
[SerializeField] private Vector3 openLocalRotationOffset;
[SerializeField, Min(0.01f)] private float animationDuration = 0.65f;
[SerializeField] private Ease animationEase = Ease.OutCubic;
private readonly NetworkVariable<bool> isOpen = new(
false,
NetworkVariableReadPermission.Everyone,
NetworkVariableWritePermission.Server);
private Vector3 closedLocalPosition;
private Vector3 closedLocalEulerAngles;
private Tween doorTween;
public bool IsOpen => isOpen.Value;
private void Awake()
{
if (doorVisual == null)
doorVisual = transform;
closedLocalPosition = doorVisual.localPosition;
closedLocalEulerAngles = doorVisual.localEulerAngles;
}
public override void OnNetworkSpawn()
{
isOpen.OnValueChanged += HandleOpenStateChanged;
ApplyVisualState(isOpen.Value, true);
}
public override void OnNetworkDespawn()
{
isOpen.OnValueChanged -= HandleOpenStateChanged;
}
private void OnDisable()
{
doorTween?.Kill();
}
public void SetOpen(bool shouldOpen)
{
if (!IsServer)
return;
isOpen.Value = shouldOpen;
ApplyVisualState(shouldOpen, false);
}
public void Toggle()
{
SetOpen(!isOpen.Value);
}
[ContextMenu("Preview/Open")]
private void PreviewOpen() => PreviewVisual(true);
[ContextMenu("Preview/Close")]
private void PreviewClose() => PreviewVisual(false);
[ContextMenu("Preview/Toggle")]
private void PreviewToggle() =>
PreviewVisual(doorVisual != null && doorVisual.localPosition == closedLocalPosition);
private void PreviewVisual(bool shouldOpen)
{
ApplyVisualState(shouldOpen, !Application.isPlaying);
}
private void HandleOpenStateChanged(bool _, bool currentValue) =>
ApplyVisualState(currentValue, false);
private void ApplyVisualState(bool shouldOpen, bool immediately)
{
if (doorVisual == null)
return;
doorTween?.Kill();
Vector3 targetPosition = closedLocalPosition +
(shouldOpen ? openLocalPositionOffset : Vector3.zero);
Vector3 targetRotation = closedLocalEulerAngles +
(shouldOpen ? openLocalRotationOffset : Vector3.zero);
if (immediately)
{
doorVisual.localPosition = targetPosition;
doorVisual.localEulerAngles = targetRotation;
return;
}
doorTween = DOTween.Sequence()
.Join(doorVisual.DOLocalMove(targetPosition, animationDuration))
.Join(doorVisual.DOLocalRotate(targetRotation, animationDuration))
.SetEase(animationEase)
.SetLink(gameObject);
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 402a356b266639c448f71cfce624ec90
@@ -0,0 +1,9 @@
using UnityEngine;
public sealed class NetworkDraggableInteractable : NetworkHeldInteractable
{
[SerializeField] private Vector3 dragOffset = new(0f, 0.35f, 1.8f);
protected override Vector3 HoldingOffset => dragOffset;
protected override string DropPrompt => "Release";
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e5e737931b3bc22468ea0fe857062359
@@ -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();
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 12231d0b12920fd468d1117aa9a3c59c
@@ -0,0 +1,61 @@
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;
float maximumDistanceSquared = maximumInteractionDistance * maximumInteractionDistance;
if ((playerObject.transform.position - transform.position).sqrMagnitude > maximumDistanceSquared)
return;
if (!CanInteractOnServer(senderClientId))
return;
InteractOnServer(senderClientId, playerObject);
}
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;
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2aecb06ed06d9e145acd3163b0bdda1c