169 lines
5.3 KiB
C#
169 lines
5.3 KiB
C#
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();
|
|
}
|
|
}
|