ok
This commit is contained in:
@@ -29,6 +29,11 @@ public abstract class NetworkHeldInteractable : NetworkInteractable
|
||||
NetworkVariableReadPermission.Everyone,
|
||||
NetworkVariableWritePermission.Server);
|
||||
|
||||
private readonly NetworkVariable<bool> isExternallyControlled = new(
|
||||
false,
|
||||
NetworkVariableReadPermission.Everyone,
|
||||
NetworkVariableWritePermission.Server);
|
||||
|
||||
private readonly HashSet<Collider> ignoredPlayerColliders = new();
|
||||
private float nextCollisionRefreshTime;
|
||||
private Vector3 followVelocity;
|
||||
@@ -39,17 +44,21 @@ public abstract class NetworkHeldInteractable : NetworkInteractable
|
||||
protected abstract string DropPrompt { get; }
|
||||
|
||||
public bool IsHeld => holderClientId.Value != NoHolder;
|
||||
public bool IsExternallyControlled => isExternallyControlled.Value;
|
||||
public bool IsHeldByLocalPlayer =>
|
||||
NetworkManager != null && holderClientId.Value == NetworkManager.LocalClientId;
|
||||
public string HeldObjectName => InteractionLabel;
|
||||
|
||||
public override string InteractionPrompt => !IsHeld
|
||||
public override string InteractionPrompt => IsExternallyControlled
|
||||
? "In machine"
|
||||
: !IsHeld
|
||||
? InteractionLabel
|
||||
: IsHeldByLocalPlayer
|
||||
? DropPrompt
|
||||
: "In use";
|
||||
|
||||
public override bool IsInteractionAvailable => base.IsInteractionAvailable &&
|
||||
!IsExternallyControlled &&
|
||||
(!IsHeld || IsHeldByLocalPlayer);
|
||||
|
||||
private void Awake()
|
||||
@@ -65,12 +74,14 @@ public abstract class NetworkHeldInteractable : NetworkInteractable
|
||||
{
|
||||
SpawnedHeldObjects.Add(this);
|
||||
holderClientId.OnValueChanged += HandleHolderChanged;
|
||||
ApplyHoldingState(IsHeld);
|
||||
isExternallyControlled.OnValueChanged += HandleExternalControlChanged;
|
||||
ApplyHoldingState(IsHeld || IsExternallyControlled);
|
||||
}
|
||||
|
||||
public override void OnNetworkDespawn()
|
||||
{
|
||||
holderClientId.OnValueChanged -= HandleHolderChanged;
|
||||
isExternallyControlled.OnValueChanged -= HandleExternalControlChanged;
|
||||
SpawnedHeldObjects.Remove(this);
|
||||
ApplyHoldingState(false);
|
||||
}
|
||||
@@ -105,6 +116,30 @@ public abstract class NetworkHeldInteractable : NetworkInteractable
|
||||
RequestThrowServerRpc();
|
||||
}
|
||||
|
||||
public bool TryAcquireExternalControl()
|
||||
{
|
||||
if (!IsServer || !IsSpawned || IsExternallyControlled)
|
||||
return false;
|
||||
|
||||
isExternallyControlled.Value = true;
|
||||
|
||||
if (IsHeld)
|
||||
holderClientId.Value = NoHolder;
|
||||
|
||||
ApplyHoldingState(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryReleaseExternalControl()
|
||||
{
|
||||
if (!IsServer || !IsSpawned || !IsExternallyControlled)
|
||||
return false;
|
||||
|
||||
isExternallyControlled.Value = false;
|
||||
ApplyHoldingState(IsHeld);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool TryGetHeldObject(
|
||||
ulong clientId,
|
||||
out NetworkHeldInteractable heldObject)
|
||||
@@ -124,6 +159,9 @@ public abstract class NetworkHeldInteractable : NetworkInteractable
|
||||
|
||||
protected override bool CanInteractOnServer(ulong senderClientId)
|
||||
{
|
||||
if (IsExternallyControlled)
|
||||
return false;
|
||||
|
||||
if (holderClientId.Value == senderClientId)
|
||||
return true;
|
||||
|
||||
@@ -166,6 +204,9 @@ public abstract class NetworkHeldInteractable : NetworkInteractable
|
||||
|
||||
private void StartHolding(ulong clientId)
|
||||
{
|
||||
if (IsExternallyControlled)
|
||||
return;
|
||||
|
||||
holderClientId.Value = clientId;
|
||||
ApplyHoldingState(true);
|
||||
}
|
||||
@@ -173,7 +214,7 @@ public abstract class NetworkHeldInteractable : NetworkInteractable
|
||||
private void StopHolding()
|
||||
{
|
||||
holderClientId.Value = NoHolder;
|
||||
ApplyHoldingState(false);
|
||||
ApplyHoldingState(IsExternallyControlled);
|
||||
}
|
||||
|
||||
private Transform ResolveHoldingAnchor(NetworkObject holder)
|
||||
@@ -226,7 +267,10 @@ public abstract class NetworkHeldInteractable : NetworkInteractable
|
||||
}
|
||||
|
||||
private void HandleHolderChanged(ulong _, ulong currentHolder) =>
|
||||
ApplyHoldingState(currentHolder != NoHolder);
|
||||
ApplyHoldingState(currentHolder != NoHolder || IsExternallyControlled);
|
||||
|
||||
private void HandleExternalControlChanged(bool _, bool isControlled) =>
|
||||
ApplyHoldingState(IsHeld || isControlled);
|
||||
|
||||
private void ApplyHoldingState(bool isHeld)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d3dd768e3784bc6bc270a1ce57ce345
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
using UnityEngine;
|
||||
|
||||
[CreateAssetMenu(
|
||||
fileName = "ItemProcessingRecipe",
|
||||
menuName = "FORT-BO/Workstations/Item Processing Recipe")]
|
||||
public sealed class ItemProcessingRecipe : ScriptableObject
|
||||
{
|
||||
[SerializeField] private string recipeId;
|
||||
[SerializeField] private ItemDefinition inputItem;
|
||||
[SerializeField] private ItemDefinition outputItem;
|
||||
[SerializeField, Min(0.05f)] private float processingDuration = 3f;
|
||||
|
||||
public string RecipeId => recipeId;
|
||||
public ItemDefinition InputItem => inputItem;
|
||||
public ItemDefinition OutputItem => outputItem;
|
||||
public float ProcessingDuration => processingDuration;
|
||||
|
||||
public bool Accepts(NetworkItem item)
|
||||
{
|
||||
if (item == null || item.Definition == null || inputItem == null)
|
||||
return false;
|
||||
|
||||
return item.Definition == inputItem ||
|
||||
(!string.IsNullOrEmpty(inputItem.ItemId) && item.ItemId == inputItem.ItemId);
|
||||
}
|
||||
|
||||
private void OnValidate() =>
|
||||
recipeId = recipeId?.Trim().ToLowerInvariant();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea07d1502f6f4abc96ea949c7e688857
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,124 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
[DisallowMultipleComponent]
|
||||
public class ItemProcessingWorkstationView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private NetworkItemProcessingWorkstation workstation;
|
||||
|
||||
[Header("State Events")]
|
||||
[SerializeField] private UnityEvent onEmpty;
|
||||
[SerializeField] private UnityEvent onProcessingStarted;
|
||||
[SerializeField] private UnityEvent onOutputReady;
|
||||
|
||||
[Header("Continuous Progress")]
|
||||
[SerializeField] private UnityEvent<float> onProcessingProgress;
|
||||
|
||||
private ItemProcessingWorkstationState previousState;
|
||||
private bool hasAppliedState;
|
||||
|
||||
public NetworkItemProcessingWorkstation Workstation => workstation;
|
||||
|
||||
protected virtual void Reset() =>
|
||||
workstation = GetComponentInParent<NetworkItemProcessingWorkstation>();
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
if (workstation == null)
|
||||
workstation = GetComponentInParent<NetworkItemProcessingWorkstation>();
|
||||
}
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
if (workstation != null)
|
||||
{
|
||||
workstation.Changed += HandleWorkstationChanged;
|
||||
ApplyState();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Start() => ApplyState();
|
||||
|
||||
protected virtual void OnDisable()
|
||||
{
|
||||
if (workstation != null)
|
||||
workstation.Changed -= HandleWorkstationChanged;
|
||||
|
||||
hasAppliedState = false;
|
||||
}
|
||||
|
||||
protected virtual void Update()
|
||||
{
|
||||
if (workstation != null &&
|
||||
workstation.State == ItemProcessingWorkstationState.Processing)
|
||||
{
|
||||
onProcessingProgress?.Invoke(workstation.ProcessProgress);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void HandleStateApplied(ItemProcessingWorkstationState state)
|
||||
{
|
||||
}
|
||||
|
||||
[ContextMenu("Preview/Empty")]
|
||||
private void PreviewEmpty()
|
||||
{
|
||||
onProcessingProgress?.Invoke(0f);
|
||||
onEmpty?.Invoke();
|
||||
HandleStateApplied(ItemProcessingWorkstationState.Empty);
|
||||
}
|
||||
|
||||
[ContextMenu("Preview/Processing Started")]
|
||||
private void PreviewProcessingStarted()
|
||||
{
|
||||
onProcessingProgress?.Invoke(0f);
|
||||
onProcessingStarted?.Invoke();
|
||||
HandleStateApplied(ItemProcessingWorkstationState.Processing);
|
||||
}
|
||||
|
||||
[ContextMenu("Preview/Processing 50 Percent")]
|
||||
private void PreviewProcessingHalfway() => onProcessingProgress?.Invoke(0.5f);
|
||||
|
||||
[ContextMenu("Preview/Output Ready")]
|
||||
private void PreviewOutputReady()
|
||||
{
|
||||
onProcessingProgress?.Invoke(1f);
|
||||
onOutputReady?.Invoke();
|
||||
HandleStateApplied(ItemProcessingWorkstationState.OutputReady);
|
||||
}
|
||||
|
||||
private void HandleWorkstationChanged() => ApplyState();
|
||||
|
||||
private void ApplyState()
|
||||
{
|
||||
if (workstation == null || !workstation.IsSpawned)
|
||||
return;
|
||||
|
||||
ItemProcessingWorkstationState currentState = workstation.State;
|
||||
if (hasAppliedState && currentState == previousState)
|
||||
return;
|
||||
|
||||
previousState = currentState;
|
||||
hasAppliedState = true;
|
||||
|
||||
switch (currentState)
|
||||
{
|
||||
case ItemProcessingWorkstationState.Processing:
|
||||
onProcessingStarted?.Invoke();
|
||||
onProcessingProgress?.Invoke(workstation.ProcessProgress);
|
||||
break;
|
||||
|
||||
case ItemProcessingWorkstationState.OutputReady:
|
||||
onProcessingProgress?.Invoke(1f);
|
||||
onOutputReady?.Invoke();
|
||||
break;
|
||||
|
||||
default:
|
||||
onProcessingProgress?.Invoke(0f);
|
||||
onEmpty?.Invoke();
|
||||
break;
|
||||
}
|
||||
|
||||
HandleStateApplied(currentState);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fddbd9f473234f27b85054ee55b89f69
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,79 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
[DisallowMultipleComponent]
|
||||
[RequireComponent(typeof(Collider))]
|
||||
public sealed class NetworkItemInputSlot : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private NetworkItemProcessingWorkstation workstation;
|
||||
|
||||
private readonly Dictionary<NetworkItem, HashSet<Collider>> overlaps = new();
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
workstation = GetComponentInParent<NetworkItemProcessingWorkstation>();
|
||||
GetComponent<Collider>().isTrigger = true;
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (workstation == null)
|
||||
workstation = GetComponentInParent<NetworkItemProcessingWorkstation>();
|
||||
}
|
||||
|
||||
private void OnDisable() => overlaps.Clear();
|
||||
|
||||
private void OnTriggerEnter(Collider other)
|
||||
{
|
||||
RegisterOverlap(other);
|
||||
TryAccept(other);
|
||||
}
|
||||
|
||||
private void OnTriggerStay(Collider other)
|
||||
{
|
||||
RegisterOverlap(other);
|
||||
TryAccept(other);
|
||||
}
|
||||
|
||||
private void OnTriggerExit(Collider other)
|
||||
{
|
||||
if (workstation == null || !workstation.IsServer)
|
||||
return;
|
||||
|
||||
NetworkItem item = other.GetComponentInParent<NetworkItem>();
|
||||
if (item == null || !overlaps.TryGetValue(item, out HashSet<Collider> colliders))
|
||||
return;
|
||||
|
||||
colliders.Remove(other);
|
||||
if (colliders.Count > 0)
|
||||
return;
|
||||
|
||||
overlaps.Remove(item);
|
||||
workstation.NotifyItemExited(item);
|
||||
}
|
||||
|
||||
private void TryAccept(Collider other)
|
||||
{
|
||||
if (workstation == null || !workstation.IsServer || !workstation.IsSpawned)
|
||||
return;
|
||||
|
||||
NetworkItem item = other.GetComponentInParent<NetworkItem>();
|
||||
if (item != null)
|
||||
workstation.TryAcceptItem(item);
|
||||
}
|
||||
|
||||
private void RegisterOverlap(Collider other)
|
||||
{
|
||||
NetworkItem item = other.GetComponentInParent<NetworkItem>();
|
||||
if (item == null)
|
||||
return;
|
||||
|
||||
if (!overlaps.TryGetValue(item, out HashSet<Collider> colliders))
|
||||
{
|
||||
colliders = new HashSet<Collider>();
|
||||
overlaps.Add(item, colliders);
|
||||
}
|
||||
|
||||
colliders.Add(other);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 67504197a13e4569ab17c8dcefaf8293
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
using System;
|
||||
using Unity.Netcode;
|
||||
using UnityEngine;
|
||||
|
||||
public enum ItemProcessingWorkstationState : byte
|
||||
{
|
||||
Empty,
|
||||
Processing,
|
||||
OutputReady
|
||||
}
|
||||
|
||||
public sealed class NetworkItemProcessingWorkstation : NetworkWorkstationController
|
||||
{
|
||||
[Header("Recipe")]
|
||||
[SerializeField] private ItemProcessingRecipe recipe;
|
||||
|
||||
[Header("Slot")]
|
||||
[SerializeField] private Transform inputPoint;
|
||||
|
||||
private readonly NetworkVariable<ItemProcessingWorkstationState> state = new(
|
||||
ItemProcessingWorkstationState.Empty,
|
||||
NetworkVariableReadPermission.Everyone,
|
||||
NetworkVariableWritePermission.Server);
|
||||
|
||||
private readonly NetworkVariable<double> processStartedAt = new(
|
||||
0d,
|
||||
NetworkVariableReadPermission.Everyone,
|
||||
NetworkVariableWritePermission.Server);
|
||||
|
||||
private readonly NetworkVariable<double> processEndsAt = new(
|
||||
0d,
|
||||
NetworkVariableReadPermission.Everyone,
|
||||
NetworkVariableWritePermission.Server);
|
||||
|
||||
private NetworkItem currentItem;
|
||||
|
||||
public override bool IsOperating => State == ItemProcessingWorkstationState.Processing;
|
||||
public ItemProcessingWorkstationState State => state.Value;
|
||||
public ItemProcessingRecipe Recipe => recipe;
|
||||
public NetworkItem CurrentItem => currentItem;
|
||||
public bool CanAcceptItem => IsServer && IsSpawned &&
|
||||
State == ItemProcessingWorkstationState.Empty &&
|
||||
recipe != null && recipe.InputItem != null &&
|
||||
recipe.OutputItem != null && recipe.OutputItem.WorldPrefab != null;
|
||||
|
||||
public float ProcessProgress
|
||||
{
|
||||
get
|
||||
{
|
||||
if (State == ItemProcessingWorkstationState.OutputReady)
|
||||
return 1f;
|
||||
|
||||
if (!IsOperating)
|
||||
return 0f;
|
||||
|
||||
double duration = processEndsAt.Value - processStartedAt.Value;
|
||||
if (duration <= 0d)
|
||||
return 1f;
|
||||
|
||||
return Mathf.Clamp01((float)((GetNetworkTime() - processStartedAt.Value) / duration));
|
||||
}
|
||||
}
|
||||
|
||||
public float RemainingSeconds => !IsOperating
|
||||
? 0f
|
||||
: Mathf.Max(0f, (float)(processEndsAt.Value - GetNetworkTime()));
|
||||
|
||||
public event Action Changed;
|
||||
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
state.OnValueChanged += HandleStateChanged;
|
||||
processStartedAt.OnValueChanged += HandleProcessTimeChanged;
|
||||
processEndsAt.OnValueChanged += HandleProcessTimeChanged;
|
||||
|
||||
if (IsServer)
|
||||
ResetWorkstationOnServer();
|
||||
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
public override void OnNetworkDespawn()
|
||||
{
|
||||
state.OnValueChanged -= HandleStateChanged;
|
||||
processStartedAt.OnValueChanged -= HandleProcessTimeChanged;
|
||||
processEndsAt.OnValueChanged -= HandleProcessTimeChanged;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!IsServer || !IsSpawned)
|
||||
return;
|
||||
|
||||
if (State == ItemProcessingWorkstationState.Processing)
|
||||
{
|
||||
if (currentItem == null || !currentItem.IsSpawned)
|
||||
{
|
||||
ResetWorkstationOnServer();
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetNetworkTime() >= processEndsAt.Value)
|
||||
CompleteProcessingOnServer();
|
||||
}
|
||||
else if (State == ItemProcessingWorkstationState.OutputReady &&
|
||||
(currentItem == null || !currentItem.IsSpawned))
|
||||
{
|
||||
ResetWorkstationOnServer();
|
||||
}
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (!IsServer || !IsSpawned ||
|
||||
State != ItemProcessingWorkstationState.Processing ||
|
||||
currentItem == null || inputPoint == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SnapToInputPoint(currentItem.transform);
|
||||
}
|
||||
|
||||
public bool TryAcceptItem(NetworkItem item)
|
||||
{
|
||||
if (!CanAcceptItem || item == null || !item.IsSpawned || !recipe.Accepts(item))
|
||||
return false;
|
||||
|
||||
NetworkCarryableInteractable carryable =
|
||||
item.GetComponent<NetworkCarryableInteractable>();
|
||||
if (carryable == null || !carryable.TryAcquireExternalControl())
|
||||
return false;
|
||||
|
||||
currentItem = item;
|
||||
SnapToInputPoint(item.transform);
|
||||
|
||||
double now = GetNetworkTime();
|
||||
processStartedAt.Value = now;
|
||||
processEndsAt.Value = now + recipe.ProcessingDuration;
|
||||
state.Value = ItemProcessingWorkstationState.Processing;
|
||||
Changed?.Invoke();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void NotifyItemExited(NetworkItem item)
|
||||
{
|
||||
if (!IsServer || !IsSpawned ||
|
||||
State != ItemProcessingWorkstationState.OutputReady ||
|
||||
item == null || item != currentItem)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ResetWorkstationOnServer();
|
||||
}
|
||||
|
||||
private void CompleteProcessingOnServer()
|
||||
{
|
||||
if (currentItem == null || recipe == null ||
|
||||
recipe.OutputItem == null || recipe.OutputItem.WorldPrefab == null)
|
||||
{
|
||||
ResetWorkstationOnServer();
|
||||
return;
|
||||
}
|
||||
|
||||
Transform slot = inputPoint != null ? inputPoint : transform;
|
||||
Vector3 outputPosition = slot.position;
|
||||
Quaternion outputRotation = slot.rotation;
|
||||
|
||||
NetworkObject inputObject = currentItem.NetworkObject;
|
||||
currentItem = null;
|
||||
|
||||
if (inputObject != null && inputObject.IsSpawned)
|
||||
inputObject.Despawn(true);
|
||||
|
||||
NetworkObject outputObject = Instantiate(
|
||||
recipe.OutputItem.WorldPrefab,
|
||||
outputPosition,
|
||||
outputRotation);
|
||||
outputObject.Spawn();
|
||||
|
||||
currentItem = outputObject.GetComponent<NetworkItem>();
|
||||
if (currentItem == null ||
|
||||
outputObject.GetComponent<NetworkCarryableInteractable>() == null)
|
||||
{
|
||||
Debug.LogError(
|
||||
$"{name} cannot produce '{recipe.OutputItem.DisplayName}': " +
|
||||
"the output prefab must contain NetworkItem and " +
|
||||
"NetworkCarryableInteractable.",
|
||||
this);
|
||||
outputObject.Despawn(true);
|
||||
currentItem = null;
|
||||
ResetWorkstationOnServer();
|
||||
return;
|
||||
}
|
||||
|
||||
processStartedAt.Value = 0d;
|
||||
processEndsAt.Value = 0d;
|
||||
state.Value = ItemProcessingWorkstationState.OutputReady;
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
private void ResetWorkstationOnServer()
|
||||
{
|
||||
if (!IsServer)
|
||||
return;
|
||||
|
||||
if (State == ItemProcessingWorkstationState.Processing && currentItem != null &&
|
||||
currentItem.TryGetComponent(out NetworkCarryableInteractable carryable))
|
||||
{
|
||||
carryable.TryReleaseExternalControl();
|
||||
}
|
||||
|
||||
currentItem = null;
|
||||
processStartedAt.Value = 0d;
|
||||
processEndsAt.Value = 0d;
|
||||
state.Value = ItemProcessingWorkstationState.Empty;
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
private void SnapToInputPoint(Transform itemTransform)
|
||||
{
|
||||
Transform slot = inputPoint != null ? inputPoint : transform;
|
||||
itemTransform.SetPositionAndRotation(slot.position, slot.rotation);
|
||||
}
|
||||
|
||||
private double GetNetworkTime() => NetworkManager != null
|
||||
? NetworkManager.ServerTime.Time
|
||||
: Time.timeAsDouble;
|
||||
|
||||
private void HandleStateChanged(
|
||||
ItemProcessingWorkstationState _,
|
||||
ItemProcessingWorkstationState __) => Changed?.Invoke();
|
||||
|
||||
private void HandleProcessTimeChanged(double _, double __) => Changed?.Invoke();
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90c3cd35b32140ac86dec106c4bb5035
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user