BakeLight

This commit is contained in:
2026-08-11 10:19:29 +03:00
parent e3746e3e9d
commit f4c9326fb9
109 changed files with 21891 additions and 25217 deletions
@@ -488,10 +488,10 @@ MonoBehaviour:
maximumAngle: 55
movementSpeed: 140
maximumControlDistance: 4
returnToRestOnRelease: 0
restValue: 0
activationThreshold: 0.85
deactivationThreshold: 0.15
switchThreshold: 0.5
initialPositionIsMaximum: 0
returnToInitialPositionAfterSwitch: 0
automaticReturnDelay: 0.25
leverValueChanged:
m_PersistentCalls:
m_Calls: []
@@ -19,12 +19,12 @@ public sealed class NetworkPhysicalLeverInteractable :
[Header("Control")]
[SerializeField, Min(0.5f)] private float maximumControlDistance = 4f;
[SerializeField] private bool returnToRestOnRelease;
[SerializeField, Range(0f, 1f)] private float restValue;
[Header("Activation")]
[SerializeField, Range(0f, 1f)] private float activationThreshold = 0.85f;
[SerializeField, Range(0f, 1f)] private float deactivationThreshold = 0.15f;
[Header("Two positions")]
[SerializeField, Range(0.05f, 0.95f)] private float switchThreshold = 0.5f;
[SerializeField] private bool initialPositionIsMaximum;
[SerializeField] private bool returnToInitialPositionAfterSwitch;
[SerializeField, Min(0f)] private float automaticReturnDelay = 0.25f;
[SerializeField] private UnityEvent<float> leverValueChanged;
[SerializeField] private UnityEvent<bool> leverStateChanged;
@@ -43,6 +43,10 @@ public sealed class NetworkPhysicalLeverInteractable :
NetworkVariableReadPermission.Everyone,
NetworkVariableWritePermission.Server);
private bool hasSnapTarget;
private float snapTargetValue;
private float automaticReturnTime = -1f;
public float Value => synchronizedValue.Value;
public bool IsActivated => isActivated.Value;
public bool IsControlled => controllingClientId.Value != NoController;
@@ -66,6 +70,7 @@ public sealed class NetworkPhysicalLeverInteractable :
private Vector3 HandleDirection => localHandleDirection.sqrMagnitude > 0.0001f
? localHandleDirection.normalized
: Vector3.up;
private float InitialPositionValue => initialPositionIsMaximum ? 1f : 0f;
private void Reset()
{
@@ -77,13 +82,18 @@ public sealed class NetworkPhysicalLeverInteractable :
{
if (maximumAngle < minimumAngle)
maximumAngle = minimumAngle;
deactivationThreshold = Mathf.Min(deactivationThreshold, activationThreshold);
}
public override void OnNetworkSpawn()
{
PlayerInteractionSessionRegistry.Register(this);
if (IsServer)
{
synchronizedValue.Value = InitialPositionValue;
isActivated.Value = initialPositionIsMaximum;
}
synchronizedValue.OnValueChanged += HandleValueChanged;
isActivated.OnValueChanged += HandleActivationChanged;
ApplyVisual(synchronizedValue.Value);
@@ -108,17 +118,26 @@ public sealed class NetworkPhysicalLeverInteractable :
if (!TryGetPlayerObject(controllingClientId.Value, out NetworkObject playerObject) ||
!IsPlayerWithinControlDistance(playerObject))
{
controllingClientId.Value = NoController;
EndControl();
return;
}
if (TryCalculateTargetValue(playerObject, out float targetValue))
MoveTowardsValue(targetValue);
return;
}
else if (returnToRestOnRelease)
if (hasSnapTarget)
{
MoveTowardsValue(restValue);
if (MoveTowardsValue(snapTargetValue))
CompleteSnap();
return;
}
if (automaticReturnTime >= 0f && Time.time >= automaticReturnTime)
BeginSnap(InitialPositionValue);
}
public bool IsControlledBy(ulong clientId) =>
@@ -137,16 +156,57 @@ public sealed class NetworkPhysicalLeverInteractable :
ulong senderClientId,
NetworkObject playerObject)
{
controllingClientId.Value = IsControlledBy(senderClientId)
? NoController
: senderClientId;
if (IsControlledBy(senderClientId))
EndControl();
else
BeginControl(senderClientId);
}
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
private void RequestReleaseServerRpc(RpcParams rpcParams = default)
{
if (IsControlledBy(rpcParams.Receive.SenderClientId))
controllingClientId.Value = NoController;
EndControl();
}
private void BeginControl(ulong clientId)
{
hasSnapTarget = false;
automaticReturnTime = -1f;
controllingClientId.Value = clientId;
}
private void EndControl()
{
if (!IsControlled)
return;
controllingClientId.Value = NoController;
float targetPosition = synchronizedValue.Value >= switchThreshold ? 1f : 0f;
BeginSnap(targetPosition);
}
private void BeginSnap(float targetValue)
{
automaticReturnTime = -1f;
snapTargetValue = targetValue >= 0.5f ? 1f : 0f;
hasSnapTarget = true;
}
private void CompleteSnap()
{
hasSnapTarget = false;
bool snappedToMaximum = snapTargetValue >= 0.5f;
if (isActivated.Value != snappedToMaximum)
isActivated.Value = snappedToMaximum;
bool movedAwayFromInitialPosition =
!Mathf.Approximately(snapTargetValue, InitialPositionValue);
automaticReturnTime = returnToInitialPositionAfterSwitch &&
movedAwayFromInitialPosition
? Time.time + automaticReturnDelay
: -1f;
}
private bool IsPlayerWithinControlDistance(NetworkObject playerObject)
@@ -208,7 +268,7 @@ public sealed class NetworkPhysicalLeverInteractable :
return true;
}
private void MoveTowardsValue(float targetValue)
private bool MoveTowardsValue(float targetValue)
{
float angleRange = Mathf.Max(0.01f, maximumAngle - minimumAngle);
float valueStep = movementSpeed / angleRange * Time.fixedDeltaTime;
@@ -217,24 +277,10 @@ public sealed class NetworkPhysicalLeverInteractable :
Mathf.Clamp01(targetValue),
valueStep);
if (Mathf.Approximately(nextValue, synchronizedValue.Value))
return;
if (!Mathf.Approximately(nextValue, synchronizedValue.Value))
synchronizedValue.Value = nextValue;
synchronizedValue.Value = nextValue;
UpdateActivationState(nextValue);
}
private void UpdateActivationState(float currentValue)
{
bool nextState = isActivated.Value;
if (!nextState && currentValue >= activationThreshold)
nextState = true;
else if (nextState && currentValue <= deactivationThreshold)
nextState = false;
if (nextState != isActivated.Value)
isActivated.Value = nextState;
return Mathf.Approximately(nextValue, targetValue);
}
private void HandleValueChanged(float _, float currentValue)
@@ -259,8 +305,8 @@ public sealed class NetworkPhysicalLeverInteractable :
[ContextMenu("Preview/Minimum")]
private void PreviewMinimum() => ApplyVisual(0f);
[ContextMenu("Preview/Rest")]
private void PreviewRest() => ApplyVisual(restValue);
[ContextMenu("Preview/Initial Position")]
private void PreviewInitialPosition() => ApplyVisual(InitialPositionValue);
[ContextMenu("Preview/Maximum")]
private void PreviewMaximum() => ApplyVisual(1f);