214 lines
7.5 KiB
C#
214 lines
7.5 KiB
C#
using FishNet.Connection;
|
|
using FishNet.Observing;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.CompilerServices;
|
|
using UnityEngine;
|
|
|
|
namespace FishNet.Object
|
|
{
|
|
public sealed partial class NetworkObject : MonoBehaviour
|
|
{
|
|
#region Public.
|
|
/// <summary>
|
|
/// Called when this NetworkObject losses all observers or gains observers while previously having none.
|
|
/// </summary>
|
|
public event Action<NetworkObject> OnObserversActive;
|
|
/// <summary>
|
|
/// NetworkObserver on this object.
|
|
/// </summary>
|
|
[HideInInspector]
|
|
public NetworkObserver NetworkObserver = null;
|
|
/// <summary>
|
|
/// Clients which can see and get messages from this NetworkObject.
|
|
/// </summary>
|
|
public HashSet<NetworkConnection> Observers = new HashSet<NetworkConnection>();
|
|
#endregion
|
|
|
|
#region Private.
|
|
/// <summary>
|
|
/// True if NetworkObserver has been initialized.
|
|
/// </summary>
|
|
private bool _networkObserverInitiliazed = false;
|
|
/// <summary>
|
|
/// Found renderers on the NetworkObject and it's children. This is only used as clientHost to hide non-observers objects.
|
|
/// </summary>
|
|
[System.NonSerialized]
|
|
private Renderer[] _renderers;
|
|
/// <summary>
|
|
/// True if renderers have been looked up.
|
|
/// </summary>
|
|
private bool _renderersPopulated;
|
|
/// <summary>
|
|
/// Last visibility value for clientHost on this object.
|
|
/// </summary>
|
|
private bool _lastClientHostVisibility;
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Updates cached renderers used to managing clientHost visibility.
|
|
/// </summary>
|
|
/// <param name="updateVisibility">True to also update visibility if clientHost.</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void UpdateRenderers(bool updateVisibility = true)
|
|
{
|
|
UpdateRenderers_Internal(updateVisibility);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the renderer visibility for clientHost.
|
|
/// </summary>
|
|
/// <param name="visible">True if renderers are to be visibile.</param>
|
|
/// <param name="force">True to skip blocking checks.</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void SetRenderersVisible(bool visible, bool force = false)
|
|
{
|
|
if (!force)
|
|
{
|
|
if (!NetworkObserver.UpdateHostVisibility)
|
|
return;
|
|
}
|
|
|
|
if (!_renderersPopulated)
|
|
{
|
|
UpdateRenderers_Internal(false);
|
|
_renderersPopulated = true;
|
|
}
|
|
|
|
UpdateRenderVisibility(visible);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clears and updates renderers.
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
private void UpdateRenderers_Internal(bool updateVisibility)
|
|
{
|
|
_renderers = GetComponentsInChildren<Renderer>(true);
|
|
List<Renderer> enabledRenderers = new List<Renderer>();
|
|
foreach (Renderer r in _renderers)
|
|
{
|
|
if (r.enabled)
|
|
enabledRenderers.Add(r);
|
|
}
|
|
//If there are any disabled renderers then change _renderers to cached values.
|
|
if (enabledRenderers.Count != _renderers.Length)
|
|
_renderers = enabledRenderers.ToArray();
|
|
|
|
if (updateVisibility)
|
|
UpdateRenderVisibility(_lastClientHostVisibility);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates visibilites on renders without checks.
|
|
/// </summary>
|
|
/// <param name="visible"></param>
|
|
private void UpdateRenderVisibility(bool visible)
|
|
{
|
|
bool rebuildRenderers = false;
|
|
|
|
Renderer[] rs = _renderers;
|
|
int count = rs.Length;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
Renderer r = rs[i];
|
|
if (r == null)
|
|
{
|
|
rebuildRenderers = true;
|
|
break;
|
|
}
|
|
|
|
r.enabled = visible;
|
|
}
|
|
|
|
_lastClientHostVisibility = visible;
|
|
//If to rebuild then do so, while updating visibility.
|
|
if (rebuildRenderers)
|
|
UpdateRenderers(true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds the default NetworkObserver conditions using the ObserverManager.
|
|
/// </summary>
|
|
private void AddDefaultNetworkObserverConditions()
|
|
{
|
|
if (_networkObserverInitiliazed)
|
|
return;
|
|
|
|
NetworkObserver = NetworkManager.ObserverManager.AddDefaultConditions(this);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Removes a connection from observers for this object returning if the connection was removed.
|
|
/// </summary>
|
|
/// <param name="connection"></param>
|
|
internal bool RemoveObserver(NetworkConnection connection)
|
|
{
|
|
int startCount = Observers.Count;
|
|
bool removed = Observers.Remove(connection);
|
|
if (removed)
|
|
TryInvokeOnObserversActive(startCount);
|
|
|
|
return removed;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds the connection to observers if conditions are met.
|
|
/// </summary>
|
|
/// <param name="connection"></param>
|
|
/// <returns>True if added to Observers.</returns>
|
|
internal ObserverStateChange RebuildObservers(NetworkConnection connection, bool timedOnly)
|
|
{
|
|
//If not a valid connection.
|
|
if (!connection.IsValid)
|
|
{
|
|
NetworkManager.LogWarning($"An invalid connection was used when rebuilding observers.");
|
|
return ObserverStateChange.Unchanged;
|
|
}
|
|
//Valid not not active.
|
|
else if (!connection.IsActive)
|
|
{
|
|
/* Just remove from observers since connection isn't active
|
|
* and return unchanged because nothing should process
|
|
* given the connection isnt active. */
|
|
Observers.Remove(connection);
|
|
return ObserverStateChange.Unchanged;
|
|
}
|
|
else if (IsDeinitializing)
|
|
{
|
|
/* If object is deinitializing it's either being despawned
|
|
* this frame or it's not spawned. If we've made it this far,
|
|
* it's most likely being despawned. */
|
|
return ObserverStateChange.Unchanged;
|
|
}
|
|
|
|
int startCount = Observers.Count;
|
|
ObserverStateChange osc = NetworkObserver.RebuildObservers(connection, timedOnly);
|
|
if (osc == ObserverStateChange.Added)
|
|
Observers.Add(connection);
|
|
else if (osc == ObserverStateChange.Removed)
|
|
Observers.Remove(connection);
|
|
|
|
if (osc != ObserverStateChange.Unchanged)
|
|
TryInvokeOnObserversActive(startCount);
|
|
|
|
return osc;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes OnObserversActive if observers are now 0 but previously were not, or if was previously 0 but now has observers.
|
|
/// </summary>
|
|
/// <param name="startCount"></param>
|
|
private void TryInvokeOnObserversActive(int startCount)
|
|
{
|
|
if ((Observers.Count > 0 && startCount == 0) ||
|
|
Observers.Count == 0 && startCount > 0)
|
|
OnObserversActive?.Invoke(this);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|