using FishNet.Connection;
using FishNet.Object;
using FishNet.Observing;
using FishNet.Utility.Extension;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;
namespace FishNet.Component.Observing
{
///
/// When this observer condition is placed on an object, a client must be within the specified distance to view the object.
///
[CreateAssetMenu(menuName = "FishNet/Observers/Distance Condition", fileName = "New Distance Condition")]
public class DistanceCondition : ObserverCondition
{
#region Serialized.
///
///
///
[Tooltip("Maximum distance a client must be within this object to see it.")]
[SerializeField]
private float _maximumDistance = 100f;
///
/// Maximum distance a client must be within this object to see it.
///
public float MaximumDistance { get => _maximumDistance; set => _maximumDistance = value; }
///
/// Additional percent of distance client must be until this object is hidden. For example, if distance was 100f and percent was 0.5f the client must be 150f units away before this object is hidden again. This can be useful for keeping objects from regularly appearing and disappearing.
///
[Tooltip("Additional percent of distance client must be until this object is hidden. For example, if distance was 100f and percent was 0.5f the client must be 150f units away before this object is hidden again. This can be useful for keeping objects from regularly appearing and disappearing.")]
[Range(0f, 1f)]
[SerializeField]
private float _hideDistancePercent = 0.1f;
///
///
///
[Tooltip("How often this condition may change for a connection. This prevents objects from appearing and disappearing rapidly. A value of 0f will cause the object the update quickly as possible while any other value will be used as a delay.")]
[Range(0f, 60f)]
[SerializeField]
private float _updateFrequency;
///
/// How often this condition may change for a connection. This prevents objects from appearing and disappearing rapidly. A value of 0f will cause the object the update quickly as possible while any other value will be used as a delay.
///
public float UpdateFrequency { get => _updateFrequency; set => _updateFrequency = value; }
#endregion
#region Private.
///
/// Tracks when connections may be updated for this object.
///
private Dictionary _timedUpdates = new Dictionary();
#endregion
public void ConditionConstructor(float maximumDistance, float updateFrequency)
{
MaximumDistance = maximumDistance;
_updateFrequency = updateFrequency;
}
///
/// Returns if the object which this condition resides should be visible to connection.
///
/// Connection which the condition is being checked for.
/// True if the connection currently has visibility of this object.
/// True if the condition was not processed. This can be used to skip processing for performance. While output as true this condition result assumes the previous ConditionMet value.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool ConditionMet(NetworkConnection connection, bool currentlyAdded, out bool notProcessed)
{
if (_updateFrequency > 0f)
{
float nextAllowedUpdate;
float currentTime = Time.time;
if (!_timedUpdates.TryGetValueIL2CPP(connection, out nextAllowedUpdate))
{
_timedUpdates[connection] = (currentTime + _updateFrequency);
}
else
{
//Not enough time to process again.
if (currentTime < nextAllowedUpdate)
{
notProcessed = true;
//The return does not really matter since notProcessed is returned.
return false;
}
//Can process again.
else
{
_timedUpdates[connection] = (currentTime + _updateFrequency);
}
}
}
//If here then checks are being processed.
notProcessed = false;
float sqrMaximumDistance;
/* If already visible then use additional
* distance to determine when to hide. */
if (currentlyAdded)
{
float maxModified = (MaximumDistance * (1f + _hideDistancePercent));
sqrMaximumDistance = (maxModified * maxModified);
}
//Not visible, use normal distance.
else
{
sqrMaximumDistance = (MaximumDistance * MaximumDistance);
}
Vector3 thisPosition = NetworkObject.transform.position;
foreach (NetworkObject nob in connection.Objects)
{
//If within distance.
if (Vector3.SqrMagnitude(nob.transform.position - thisPosition) <= sqrMaximumDistance)
return true;
}
/* If here no client objects are within distance. */
return false;
}
///
/// True if the condition requires regular updates.
///
///
public override bool Timed()
{
return true;
}
///
/// Clones referenced ObserverCondition. This must be populated with your conditions settings.
///
///
public override ObserverCondition Clone()
{
DistanceCondition copy = ScriptableObject.CreateInstance();
copy.ConditionConstructor(MaximumDistance, _updateFrequency);
return copy;
}
}
}