Added RocketAssemblyStation and ReadyRocket
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
using System;
|
||||
using Unity.Netcode;
|
||||
using UnityEngine;
|
||||
|
||||
public enum RocketAssemblyQuality : byte
|
||||
{
|
||||
Normal,
|
||||
Defective
|
||||
}
|
||||
|
||||
public struct RocketCriticalImpactState : INetworkSerializable,
|
||||
IEquatable<RocketCriticalImpactState>
|
||||
{
|
||||
public uint Sequence;
|
||||
public Vector3 Point;
|
||||
public float Speed;
|
||||
|
||||
public RocketCriticalImpactState(uint sequence, Vector3 point, float speed)
|
||||
{
|
||||
Sequence = sequence;
|
||||
Point = point;
|
||||
Speed = speed;
|
||||
}
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer)
|
||||
where T : IReaderWriter
|
||||
{
|
||||
serializer.SerializeValue(ref Sequence);
|
||||
serializer.SerializeValue(ref Point);
|
||||
serializer.SerializeValue(ref Speed);
|
||||
}
|
||||
|
||||
public bool Equals(RocketCriticalImpactState other) =>
|
||||
Sequence == other.Sequence && Point == other.Point && Speed.Equals(other.Speed);
|
||||
}
|
||||
|
||||
[DisallowMultipleComponent]
|
||||
[RequireComponent(typeof(NetworkItem), typeof(Rigidbody))]
|
||||
public sealed class NetworkRocketItem : NetworkBehaviour
|
||||
{
|
||||
[SerializeField] private NetworkItem networkItem;
|
||||
[SerializeField] private Rigidbody physicsBody;
|
||||
|
||||
private readonly NetworkVariable<RocketAssemblyQuality> assemblyQuality = new(
|
||||
RocketAssemblyQuality.Normal,
|
||||
NetworkVariableReadPermission.Everyone,
|
||||
NetworkVariableWritePermission.Server);
|
||||
|
||||
private readonly NetworkVariable<RocketCriticalImpactState> criticalImpactState = new(
|
||||
default,
|
||||
NetworkVariableReadPermission.Everyone,
|
||||
NetworkVariableWritePermission.Server);
|
||||
|
||||
public RocketItemDefinition Definition =>
|
||||
networkItem != null && networkItem.TryGetDefinition(out RocketItemDefinition definition)
|
||||
? definition
|
||||
: null;
|
||||
public string RocketTypeId => Definition != null ? Definition.RocketTypeId : string.Empty;
|
||||
public RocketAssemblyQuality AssemblyQuality => assemblyQuality.Value;
|
||||
public bool IsDefective => AssemblyQuality == RocketAssemblyQuality.Defective;
|
||||
public bool IsCriticallyDamaged => criticalImpactState.Value.Sequence > 0;
|
||||
public uint CriticalImpactSequence => criticalImpactState.Value.Sequence;
|
||||
public Vector3 LastCriticalImpactPoint => criticalImpactState.Value.Point;
|
||||
public float LastCriticalImpactSpeed => criticalImpactState.Value.Speed;
|
||||
|
||||
public event Action Changed;
|
||||
public event Action CriticalImpact;
|
||||
|
||||
private void Reset() => ResolveReferences();
|
||||
|
||||
private void Awake() => ResolveReferences();
|
||||
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
assemblyQuality.OnValueChanged += HandleAssemblyQualityChanged;
|
||||
criticalImpactState.OnValueChanged += HandleCriticalImpactChanged;
|
||||
|
||||
if (Definition == null)
|
||||
{
|
||||
Debug.LogError(
|
||||
$"{name} has NetworkRocketItem but its NetworkItem does not reference " +
|
||||
"a RocketItemDefinition.",
|
||||
this);
|
||||
}
|
||||
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
public override void OnNetworkDespawn()
|
||||
{
|
||||
assemblyQuality.OnValueChanged -= HandleAssemblyQualityChanged;
|
||||
criticalImpactState.OnValueChanged -= HandleCriticalImpactChanged;
|
||||
}
|
||||
|
||||
private void OnCollisionEnter(Collision collision)
|
||||
{
|
||||
if (!IsServer || !IsSpawned || IsCriticallyDamaged || Definition == null)
|
||||
return;
|
||||
|
||||
float impactSpeed = collision.relativeVelocity.magnitude;
|
||||
if (impactSpeed < Definition.CriticalImpactSpeed)
|
||||
return;
|
||||
|
||||
Vector3 impactPoint = collision.contactCount > 0
|
||||
? collision.GetContact(0).point
|
||||
: transform.position;
|
||||
TryTriggerCriticalImpact(impactPoint, impactSpeed);
|
||||
}
|
||||
|
||||
public bool TryTriggerCriticalImpact(Vector3 impactPoint, float impactSpeed)
|
||||
{
|
||||
if (!IsServer || !IsSpawned || IsCriticallyDamaged || Definition == null ||
|
||||
impactSpeed < Definition.CriticalImpactSpeed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
criticalImpactState.Value = new RocketCriticalImpactState(
|
||||
criticalImpactState.Value.Sequence + 1,
|
||||
impactPoint,
|
||||
impactSpeed);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryInitializeAssemblyQuality(bool isDefectiveResult)
|
||||
{
|
||||
if (!IsServer || !IsSpawned)
|
||||
return false;
|
||||
|
||||
assemblyQuality.Value = isDefectiveResult
|
||||
? RocketAssemblyQuality.Defective
|
||||
: RocketAssemblyQuality.Normal;
|
||||
return true;
|
||||
}
|
||||
|
||||
[ContextMenu("Debug/Trigger Critical Impact (Server Play Mode)")]
|
||||
private void TriggerCriticalImpactFromContextMenu()
|
||||
{
|
||||
if (Application.isPlaying && IsServer && IsSpawned && Definition != null)
|
||||
{
|
||||
TryTriggerCriticalImpact(
|
||||
transform.position,
|
||||
Definition.CriticalImpactSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
private void ResolveReferences()
|
||||
{
|
||||
if (networkItem == null)
|
||||
networkItem = GetComponent<NetworkItem>();
|
||||
|
||||
if (physicsBody == null)
|
||||
physicsBody = GetComponent<Rigidbody>();
|
||||
}
|
||||
|
||||
private void HandleAssemblyQualityChanged(
|
||||
RocketAssemblyQuality _,
|
||||
RocketAssemblyQuality __) => Changed?.Invoke();
|
||||
|
||||
private void HandleCriticalImpactChanged(
|
||||
RocketCriticalImpactState previous,
|
||||
RocketCriticalImpactState current)
|
||||
{
|
||||
Changed?.Invoke();
|
||||
if (current.Sequence != previous.Sequence)
|
||||
CriticalImpact?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d1e6d4d81ab34d2e9ee3a1bfa201f111
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,102 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
[DisallowMultipleComponent]
|
||||
public sealed class RocketItemView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private NetworkRocketItem rocket;
|
||||
|
||||
[Header("State")]
|
||||
[SerializeField] private UnityEvent onNormalQualityApplied;
|
||||
[SerializeField] private UnityEvent onDefectiveQualityApplied;
|
||||
[SerializeField] private UnityEvent onDamagedStateApplied;
|
||||
|
||||
[Header("Critical Impact")]
|
||||
[SerializeField] private UnityEvent onCriticalImpact;
|
||||
[SerializeField] private UnityEvent<Vector3> onCriticalImpactPoint;
|
||||
[SerializeField] private UnityEvent<float> onCriticalImpactSpeed;
|
||||
|
||||
private uint observedImpactSequence;
|
||||
private RocketAssemblyQuality observedQuality;
|
||||
private bool hasAppliedQuality;
|
||||
private bool hasAppliedDamagedState;
|
||||
|
||||
private void Reset() => rocket = GetComponentInParent<NetworkRocketItem>();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (rocket == null)
|
||||
rocket = GetComponentInParent<NetworkRocketItem>();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (rocket == null)
|
||||
return;
|
||||
|
||||
observedImpactSequence = rocket.CriticalImpactSequence;
|
||||
observedQuality = rocket.AssemblyQuality;
|
||||
hasAppliedQuality = false;
|
||||
hasAppliedDamagedState = false;
|
||||
rocket.Changed += ApplyState;
|
||||
rocket.CriticalImpact += HandleCriticalImpact;
|
||||
ApplyState();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (rocket == null)
|
||||
return;
|
||||
|
||||
rocket.Changed -= ApplyState;
|
||||
rocket.CriticalImpact -= HandleCriticalImpact;
|
||||
}
|
||||
|
||||
[ContextMenu("Preview/Critical Impact")]
|
||||
private void PreviewCriticalImpact()
|
||||
{
|
||||
onCriticalImpactPoint?.Invoke(transform.position);
|
||||
onCriticalImpactSpeed?.Invoke(7f);
|
||||
onCriticalImpact?.Invoke();
|
||||
onDamagedStateApplied?.Invoke();
|
||||
}
|
||||
|
||||
[ContextMenu("Preview/Normal Quality")]
|
||||
private void PreviewNormalQuality() => onNormalQualityApplied?.Invoke();
|
||||
|
||||
[ContextMenu("Preview/Defective Quality")]
|
||||
private void PreviewDefectiveQuality() => onDefectiveQualityApplied?.Invoke();
|
||||
|
||||
private void ApplyState()
|
||||
{
|
||||
if (rocket == null)
|
||||
return;
|
||||
|
||||
if (!hasAppliedQuality || observedQuality != rocket.AssemblyQuality)
|
||||
{
|
||||
observedQuality = rocket.AssemblyQuality;
|
||||
hasAppliedQuality = true;
|
||||
if (observedQuality == RocketAssemblyQuality.Defective)
|
||||
onDefectiveQualityApplied?.Invoke();
|
||||
else
|
||||
onNormalQualityApplied?.Invoke();
|
||||
}
|
||||
|
||||
if (rocket.IsCriticallyDamaged && !hasAppliedDamagedState)
|
||||
{
|
||||
hasAppliedDamagedState = true;
|
||||
onDamagedStateApplied?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCriticalImpact()
|
||||
{
|
||||
if (rocket == null || rocket.CriticalImpactSequence == observedImpactSequence)
|
||||
return;
|
||||
|
||||
observedImpactSequence = rocket.CriticalImpactSequence;
|
||||
onCriticalImpactPoint?.Invoke(rocket.LastCriticalImpactPoint);
|
||||
onCriticalImpactSpeed?.Invoke(rocket.LastCriticalImpactSpeed);
|
||||
onCriticalImpact?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d1e6d4d81ab34d2e9ee3a1bfa201f112
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user