Added new Rocket-Processing

This commit is contained in:
2026-08-14 16:54:09 +03:00
parent 3c490bdae8
commit b5eadea728
36 changed files with 17653 additions and 1984 deletions
@@ -18,6 +18,7 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
[SerializeField, Min(0.01f)] private float positionSmoothTime = 0.12f;
[SerializeField, Min(0.1f)] private float maximumFollowSpeed = 12f;
[SerializeField, Min(0.1f)] private float maximumFollowDistance = 1.25f;
[SerializeField, Min(0.5f)] private float maximumHoldDistance = 4.5f;
[SerializeField, Min(0.1f)] private float rotationFollowSpeed = 14f;
[Header("Throw")]
@@ -35,10 +36,11 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
NetworkVariableWritePermission.Server);
private readonly HashSet<Collider> ignoredPlayerColliders = new();
private readonly HashSet<Collider> desiredIgnoredColliders = new();
private readonly List<Collider> collidersToRestore = new();
private float nextCollisionRefreshTime;
private Vector3 followVelocity;
private Vector3 previousHolderPosition;
private bool hasPreviousHolderPosition;
private bool initialUseGravity;
private CollisionDetectionMode initialCollisionDetectionMode;
protected abstract Vector3 HoldingOffset { get; }
protected abstract string DropPrompt { get; }
@@ -68,6 +70,12 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
if (objectColliders == null || objectColliders.Length == 0)
objectColliders = GetComponentsInChildren<Collider>(true);
if (physicsBody != null)
{
initialUseGravity = physicsBody.useGravity;
initialCollisionDetectionMode = physicsBody.collisionDetectionMode;
}
}
public override void OnNetworkSpawn()
@@ -75,7 +83,7 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
SpawnedHeldObjects.Add(this);
holderClientId.OnValueChanged += HandleHolderChanged;
isExternallyControlled.OnValueChanged += HandleExternalControlChanged;
ApplyHoldingState(IsHeld || IsExternallyControlled);
ApplyHoldingState();
}
public override void OnNetworkDespawn()
@@ -83,12 +91,24 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
holderClientId.OnValueChanged -= HandleHolderChanged;
isExternallyControlled.OnValueChanged -= HandleExternalControlChanged;
SpawnedHeldObjects.Remove(this);
ApplyHoldingState(false);
RestorePlayerCollisions();
}
private void LateUpdate()
private void Update()
{
if (!IsSpawned || !IsHeld)
if (!IsSpawned || !IsHeld || IsExternallyControlled ||
Time.time < nextCollisionRefreshTime)
{
return;
}
nextCollisionRefreshTime = Time.time + collisionRefreshInterval;
RefreshHolderCollisions();
}
private void FixedUpdate()
{
if (!IsServer || !IsSpawned || !IsHeld || IsExternallyControlled || physicsBody == null)
return;
if (!TryGetPlayerObject(holderClientId.Value, out NetworkObject holder))
@@ -99,15 +119,10 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
return;
}
FollowHolderTranslation(holder.transform.position);
Transform anchor = ResolveHoldingAnchor(holder);
FollowHoldingAnchor(anchor);
if (!DriveTowardAnchor(anchor))
return;
if (Time.time >= nextCollisionRefreshTime)
{
nextCollisionRefreshTime = Time.time + collisionRefreshInterval;
IgnoreCollisionsWithPlayers();
}
}
public void RequestThrow()
@@ -126,7 +141,7 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
if (IsHeld)
holderClientId.Value = NoHolder;
ApplyHoldingState(true);
ApplyHoldingState();
return true;
}
@@ -136,7 +151,23 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
return false;
isExternallyControlled.Value = false;
ApplyHoldingState(IsHeld);
ApplyHoldingState();
return true;
}
public bool TryReleaseExternalControlToPlayer(ulong clientId)
{
if (!IsServer || !IsSpawned || !IsExternallyControlled ||
TryGetHeldObject(clientId, out _) ||
NetworkHandItemInteractable.TryGetHeldItem(clientId, out _) ||
!TryGetPlayerObject(clientId, out _))
{
return false;
}
isExternallyControlled.Value = false;
holderClientId.Value = clientId;
ApplyHoldingState();
return true;
}
@@ -208,13 +239,13 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
return;
holderClientId.Value = clientId;
ApplyHoldingState(true);
ApplyHoldingState();
}
private void StopHolding()
{
holderClientId.Value = NoHolder;
ApplyHoldingState(IsExternallyControlled);
ApplyHoldingState();
}
private Transform ResolveHoldingAnchor(NetworkObject holder)
@@ -224,94 +255,134 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
return cameraController != null ? cameraController.AimTransform : holder.transform;
}
private void FollowHoldingAnchor(Transform anchor)
private bool DriveTowardAnchor(Transform anchor)
{
Vector3 targetPosition = anchor.TransformPoint(HoldingOffset);
Vector3 targetDelta = targetPosition - transform.position;
Vector3 targetDelta = targetPosition - physicsBody.position;
if (targetDelta.sqrMagnitude > maximumFollowDistance * maximumFollowDistance)
if (targetDelta.sqrMagnitude > maximumHoldDistance * maximumHoldDistance)
{
transform.position = targetPosition -
targetDelta.normalized * maximumFollowDistance;
followVelocity = Vector3.zero;
StopHolding();
return false;
}
transform.position = Vector3.SmoothDamp(
transform.position,
targetPosition,
ref followVelocity,
positionSmoothTime,
maximumFollowSpeed,
Time.deltaTime);
float distance = targetDelta.magnitude;
float speedDistance = Mathf.Max(maximumFollowDistance, 0.01f);
float desiredSpeed = maximumFollowSpeed * Mathf.Clamp01(distance / speedDistance);
Vector3 desiredVelocity = distance > 0.0001f
? targetDelta / distance * desiredSpeed
: Vector3.zero;
float maximumAcceleration = maximumFollowSpeed / Mathf.Max(positionSmoothTime, 0.01f);
Vector3 velocityChange = Vector3.ClampMagnitude(
desiredVelocity - physicsBody.linearVelocity,
maximumAcceleration * Time.fixedDeltaTime);
physicsBody.AddForce(velocityChange, ForceMode.VelocityChange);
float rotationBlend = 1f - Mathf.Exp(-rotationFollowSpeed * Time.deltaTime);
transform.rotation = Quaternion.Slerp(
transform.rotation,
anchor.rotation,
rotationBlend);
DriveRotation(anchor.rotation);
return true;
}
private void FollowHolderTranslation(Vector3 holderPosition)
private void DriveRotation(Quaternion targetRotation)
{
if (!hasPreviousHolderPosition)
{
previousHolderPosition = holderPosition;
hasPreviousHolderPosition = true;
Quaternion rotationDelta = targetRotation * Quaternion.Inverse(physicsBody.rotation);
rotationDelta.ToAngleAxis(out float angle, out Vector3 axis);
if (axis.sqrMagnitude < 0.0001f || float.IsNaN(axis.x))
return;
}
Vector3 holderDelta = holderPosition - previousHolderPosition;
previousHolderPosition = holderPosition;
if (angle > 180f)
angle -= 360f;
transform.position += holderDelta;
Vector3 desiredAngularVelocity = axis.normalized *
(angle * Mathf.Deg2Rad * rotationFollowSpeed);
desiredAngularVelocity = Vector3.ClampMagnitude(
desiredAngularVelocity,
rotationFollowSpeed);
Vector3 angularVelocityChange = Vector3.ClampMagnitude(
desiredAngularVelocity - physicsBody.angularVelocity,
rotationFollowSpeed * 4f * Time.fixedDeltaTime);
physicsBody.AddTorque(angularVelocityChange, ForceMode.VelocityChange);
}
private void HandleHolderChanged(ulong _, ulong currentHolder) =>
ApplyHoldingState(currentHolder != NoHolder || IsExternallyControlled);
private void HandleHolderChanged(ulong _, ulong __) => ApplyHoldingState();
private void HandleExternalControlChanged(bool _, bool isControlled) =>
ApplyHoldingState(IsHeld || isControlled);
private void HandleExternalControlChanged(bool _, bool __) => ApplyHoldingState();
private void ApplyHoldingState(bool isHeld)
private void ApplyHoldingState()
{
followVelocity = Vector3.zero;
hasPreviousHolderPosition = false;
if (physicsBody != null)
{
bool shouldBeKinematic = isHeld || !IsServer;
bool isPhysicallyHeld = IsHeld && !IsExternallyControlled;
bool shouldBeKinematic = IsExternallyControlled || !IsServer;
if (physicsBody.isKinematic && !shouldBeKinematic)
if (shouldBeKinematic)
{
physicsBody.collisionDetectionMode = CollisionDetectionMode.ContinuousSpeculative;
physicsBody.isKinematic = true;
physicsBody.useGravity = false;
}
else
{
physicsBody.isKinematic = false;
physicsBody.useGravity = isPhysicallyHeld ? false : initialUseGravity;
physicsBody.collisionDetectionMode = ResolveDynamicCollisionDetectionMode();
}
if (!physicsBody.isKinematic)
if (!isPhysicallyHeld)
{
physicsBody.linearVelocity = Vector3.zero;
physicsBody.angularVelocity = Vector3.zero;
}
physicsBody.isKinematic = shouldBeKinematic;
}
if (isHeld)
IgnoreCollisionsWithPlayers();
if (IsHeld && !IsExternallyControlled)
RefreshHolderCollisions();
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)
Physics.IgnoreCollision(objectCollider, playerCollider, true);
}
private CollisionDetectionMode ResolveDynamicCollisionDetectionMode() =>
initialCollisionDetectionMode == CollisionDetectionMode.Discrete
? CollisionDetectionMode.ContinuousDynamic
: initialCollisionDetectionMode;
ignoredPlayerColliders.Add(playerCollider);
private void RefreshHolderCollisions()
{
desiredIgnoredColliders.Clear();
if (TryGetPlayerObject(holderClientId.Value, out NetworkObject holder))
{
foreach (Collider holderCollider in holder.GetComponentsInChildren<Collider>(true))
desiredIgnoredColliders.Add(holderCollider);
}
collidersToRestore.Clear();
foreach (Collider ignoredCollider in ignoredPlayerColliders)
{
if (ignoredCollider == null || !desiredIgnoredColliders.Contains(ignoredCollider))
collidersToRestore.Add(ignoredCollider);
}
foreach (Collider colliderToRestore in collidersToRestore)
{
SetCollisionIgnored(colliderToRestore, false);
ignoredPlayerColliders.Remove(colliderToRestore);
}
foreach (Collider desiredCollider in desiredIgnoredColliders)
{
if (desiredCollider != null && ignoredPlayerColliders.Add(desiredCollider))
SetCollisionIgnored(desiredCollider, true);
}
}
private void SetCollisionIgnored(Collider playerCollider, bool ignored)
{
if (playerCollider == null)
return;
foreach (Collider objectCollider in objectColliders)
{
if (objectCollider != null)
Physics.IgnoreCollision(objectCollider, playerCollider, ignored);
}
}
@@ -322,13 +393,11 @@ public abstract class NetworkHeldInteractable : NetworkInteractable, IWorkstatio
if (playerCollider == null)
continue;
foreach (Collider objectCollider in objectColliders)
{
if (objectCollider != null)
Physics.IgnoreCollision(objectCollider, playerCollider, false);
}
SetCollisionIgnored(playerCollider, false);
}
ignoredPlayerColliders.Clear();
desiredIgnoredColliders.Clear();
collidersToRestore.Clear();
}
}