mirror of
https://github.com/Dadechin/Unity-WebSocket.git
synced 2025-07-03 20:04:33 +00:00
342 lines
13 KiB
C#
342 lines
13 KiB
C#
using FishNet.Managing.Object;
|
|
using FishNet.Object;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.CompilerServices;
|
|
using UnityEngine;
|
|
using UnityComponent = UnityEngine.Component;
|
|
|
|
|
|
namespace FishNet.Managing
|
|
{
|
|
public partial class NetworkManager : MonoBehaviour
|
|
{
|
|
#region Public.
|
|
#region Obsoletes
|
|
[Obsolete("Use IsClientOnlyStarted. Note the difference between IsClientOnlyInitialized and IsClientOnlyStarted.")]
|
|
public bool IsClientOnly => IsClientOnlyStarted;
|
|
[Obsolete("Use IsServerOnlyStarted. Note the difference between IsServerOnlyInitialized and IsServerOnlyStarted.")]
|
|
public bool IsServerOnly => IsServerOnlyStarted;
|
|
[Obsolete("Use IsHostStarted. Note the difference between IsHostInitialized and IsHostStarted.")]
|
|
public bool IsHost => IsHostStarted;
|
|
[Obsolete("Use IsClientStarted. Note the difference between IsClientInitialized and IsClientStarted.")]
|
|
public bool IsClient => IsClientStarted;
|
|
[Obsolete("Use IsServerStarted. Note the difference between IsServerInitialized and IsServerStarted.")]
|
|
public bool IsServer => IsServerStarted;
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// True if server is started.
|
|
/// </summary>
|
|
public bool IsServerStarted => ServerManager.Started;
|
|
/// <summary>
|
|
/// True if only the server is started.
|
|
/// </summary>
|
|
public bool IsServerOnlyStarted => (IsServerStarted && !IsClientStarted);
|
|
/// <summary>
|
|
/// True if the client is authenticated.
|
|
/// </summary>
|
|
public bool IsClientStarted => (ClientManager.Started && ClientManager.Connection.IsAuthenticated);
|
|
/// <summary>
|
|
/// True if only the client is authenticated.
|
|
/// </summary>
|
|
public bool IsClientOnlyStarted => (!IsServerStarted && IsClientStarted);
|
|
/// <summary>
|
|
/// True if client is authenticated, and the server is started.
|
|
/// </summary>
|
|
public bool IsHostStarted => (IsServerStarted && IsClientStarted);
|
|
/// <summary>
|
|
/// True if client nor server are started.
|
|
/// </summary>
|
|
public bool IsOffline => (!IsServerStarted && !IsClientStarted);
|
|
|
|
#endregion
|
|
|
|
#region Serialized.
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
[Tooltip("Collection to use for spawnable objects.")]
|
|
[SerializeField]
|
|
private PrefabObjects _spawnablePrefabs;
|
|
/// <summary>
|
|
/// Collection to use for spawnable objects.
|
|
/// </summary>
|
|
public PrefabObjects SpawnablePrefabs { get => _spawnablePrefabs; set => _spawnablePrefabs = value; }
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
private Dictionary<ushort, PrefabObjects> _runtimeSpawnablePrefabs = new();
|
|
/// <summary>
|
|
/// Collection to use for spawnable objects added at runtime, such as addressables.
|
|
/// </summary>
|
|
public IReadOnlyDictionary<ushort, PrefabObjects> RuntimeSpawnablePrefabs => _runtimeSpawnablePrefabs;
|
|
#endregion
|
|
|
|
#region Private.
|
|
/// <summary>
|
|
/// Delegates waiting to be invoked when a component is registered.
|
|
/// </summary>
|
|
private Dictionary<string, List<Action<UnityComponent>>> _pendingInvokes = new();
|
|
/// <summary>
|
|
/// Currently registered components.
|
|
/// </summary>
|
|
private Dictionary<string, UnityComponent> _registeredComponents = new();
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Gets the PrefabObjects to use for spawnableCollectionId.
|
|
/// </summary>
|
|
/// <typeparam name="T">Type of PrefabObjects to return. This is also used to create an instance of type when createIfMissing is true.</typeparam>
|
|
/// <param name="spawnableCollectionId">Id to use. 0 will return the configured SpawnablePrefabs.</param>
|
|
/// <param name="createIfMissing">True to create and assign a PrefabObjects if missing for the collectionId.</param>
|
|
/// <returns></returns>
|
|
public PrefabObjects GetPrefabObjects<T>(ushort spawnableCollectionId, bool createIfMissing) where T : PrefabObjects
|
|
{
|
|
if (spawnableCollectionId == 0)
|
|
{
|
|
if (createIfMissing)
|
|
{
|
|
InternalLogError($"SpawnableCollectionId cannot be 0 when create missing is true.");
|
|
return null;
|
|
}
|
|
else
|
|
{
|
|
return SpawnablePrefabs;
|
|
}
|
|
}
|
|
|
|
PrefabObjects po;
|
|
if (!_runtimeSpawnablePrefabs.TryGetValue(spawnableCollectionId, out po))
|
|
{
|
|
//Do not create missing, return null for not found.
|
|
if (!createIfMissing)
|
|
return null;
|
|
|
|
po = ScriptableObject.CreateInstance<T>();
|
|
po.SetCollectionId(spawnableCollectionId);
|
|
_runtimeSpawnablePrefabs[spawnableCollectionId] = po;
|
|
}
|
|
|
|
return po;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes the PrefabObjects collection from memory.
|
|
/// This should only be called after you properly disposed of it's contents properly.
|
|
/// </summary>
|
|
/// <param name="spawnableCollectionId">CollectionId to remove.</param>
|
|
/// <returns>True if collection was found and removed.</returns>
|
|
public bool RemoveSpawnableCollection(ushort spawnableCollectionId)
|
|
{
|
|
return _runtimeSpawnablePrefabs.Remove(spawnableCollectionId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the index a prefab uses. Can be used in conjuction with GetPrefab.
|
|
/// </summary>
|
|
/// <param name="prefab"></param>
|
|
/// <param name="asServer">True if to get from the server collection.</param>
|
|
/// <returns>Returns index if found, and -1 if not found.</returns>
|
|
public int GetPrefabIndex(GameObject prefab, bool asServer)
|
|
{
|
|
int count = SpawnablePrefabs.GetObjectCount();
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
GameObject go = SpawnablePrefabs.GetObject(asServer, i).gameObject;
|
|
if (go == prefab)
|
|
return i;
|
|
}
|
|
|
|
//Fall through, not found.
|
|
return -1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a prefab with prefabId.
|
|
/// This method will bypass object pooling.
|
|
/// </summary>
|
|
/// <param name="prefabId">PrefabId to get.</param>
|
|
/// <param name="asServer">True if getting the prefab asServer.</param>
|
|
public NetworkObject GetPrefab(int prefabId, bool asServer)
|
|
{
|
|
return SpawnablePrefabs.GetObject(asServer, prefabId);
|
|
}
|
|
|
|
|
|
#region Registered components
|
|
/// <summary>
|
|
/// Invokes an action when a specified component becomes registered. Action will invoke immediately if already registered.
|
|
/// </summary>
|
|
/// <typeparam name="T">Component type.</typeparam>
|
|
/// <param name="handler">Action to invoke.</param>
|
|
public void RegisterInvokeOnInstance<T>(Action<UnityComponent> handler) where T : UnityComponent
|
|
{
|
|
T result;
|
|
//If not found yet make a pending invoke.
|
|
if (!TryGetInstance(out result))
|
|
{
|
|
string tName = GetInstanceName<T>();
|
|
List<Action<UnityComponent>> handlers;
|
|
if (!_pendingInvokes.TryGetValue(tName, out handlers))
|
|
{
|
|
handlers = new();
|
|
_pendingInvokes[tName] = handlers;
|
|
}
|
|
|
|
handlers.Add(handler);
|
|
}
|
|
//Already exist, invoke right away.
|
|
else
|
|
{
|
|
handler.Invoke(result);
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Removes an action to be invokes when a specified component becomes registered.
|
|
/// </summary>
|
|
/// <typeparam name="T">Component type.</typeparam>
|
|
/// <param name="handler">Action to invoke.</param>
|
|
public void UnregisterInvokeOnInstance<T>(Action<UnityComponent> handler) where T : UnityComponent
|
|
{
|
|
string tName = GetInstanceName<T>();
|
|
List<Action<UnityComponent>> handlers;
|
|
if (!_pendingInvokes.TryGetValue(tName, out handlers))
|
|
return;
|
|
|
|
handlers.Remove(handler);
|
|
//Do not remove pending to prevent garbage collection later from recreation.
|
|
}
|
|
/// <summary>
|
|
/// Returns if an instance exists for type.
|
|
/// </summary>
|
|
/// <typeparam name="T">Type to check.</typeparam>
|
|
/// <returns></returns>
|
|
public bool HasInstance<T>() where T : UnityComponent
|
|
{
|
|
return TryGetInstance<T>(out _);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns class of type from registered instances.
|
|
/// A warning will display if not found.
|
|
/// </summary>
|
|
/// <typeparam name="T">Type to get.</typeparam>
|
|
/// <returns></returns>
|
|
public T GetInstance<T>() where T : UnityComponent
|
|
{
|
|
T result;
|
|
if (TryGetInstance(out result))
|
|
return result;
|
|
else
|
|
InternalLogWarning($"Component {GetInstanceName<T>()} is not registered. To avoid this warning use TryGetInstance(T).");
|
|
|
|
return default(T);
|
|
}
|
|
/// <summary>
|
|
/// Returns class of type from registered instances.
|
|
/// </summary>
|
|
/// <param name="component">Outputted component.</param>
|
|
/// <typeparam name="T">Type to get.</typeparam>
|
|
/// <returns>True if was able to get instance.</returns>
|
|
public bool TryGetInstance<T>(out T result) where T : UnityComponent
|
|
{
|
|
string tName = GetInstanceName<T>();
|
|
if (_registeredComponents.TryGetValue(tName, out UnityComponent v))
|
|
{
|
|
result = (T)v;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
result = default;
|
|
return false;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Registers a new component to this NetworkManager.
|
|
/// </summary>
|
|
/// <typeparam name="T">Type to register.</typeparam>
|
|
/// <param name="component">Reference of the component being registered.</param>
|
|
/// <param name="replace">True to replace existing references.</param>
|
|
public void RegisterInstance<T>(T component, bool replace = true) where T : UnityComponent
|
|
{
|
|
string tName = GetInstanceName<T>();
|
|
if (_registeredComponents.ContainsKey(tName) && !replace)
|
|
{
|
|
InternalLogWarning($"Component {tName} is already registered.");
|
|
}
|
|
else
|
|
{
|
|
_registeredComponents[tName] = component;
|
|
RemoveNullPendingDelegates();
|
|
//If in pending invokes also send these out.
|
|
if (_pendingInvokes.TryGetValue(tName, out List<Action<UnityComponent>> dels))
|
|
{
|
|
for (int i = 0; i < dels.Count; i++)
|
|
dels[i].Invoke(component);
|
|
/* Clear delegates but do not remove dictionary entry
|
|
* to prevent list from being re-initialized. */
|
|
dels.Clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tries to registers a new component to this NetworkManager.
|
|
/// This will not register the instance if another already exists.
|
|
/// </summary>
|
|
/// <typeparam name="T">Type to register.</typeparam>
|
|
/// <param name="component">Reference of the component being registered.</param>
|
|
/// <returns>True if was able to register, false if an instance is already registered.</returns>
|
|
|
|
public bool TryRegisterInstance<T>(T component) where T : UnityComponent
|
|
{
|
|
string tName = GetInstanceName<T>();
|
|
if (_registeredComponents.ContainsKey(tName))
|
|
return false;
|
|
else
|
|
RegisterInstance(component, false);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Unregisters a component from this NetworkManager.
|
|
/// </summary>
|
|
/// <typeparam name="T">Type to unregister.</typeparam>
|
|
public void UnregisterInstance<T>() where T : UnityComponent
|
|
{
|
|
string tName = GetInstanceName<T>();
|
|
_registeredComponents.Remove(tName);
|
|
}
|
|
/// <summary>
|
|
/// Removes delegates from pending invokes when may have gone missing.
|
|
/// </summary>
|
|
private void RemoveNullPendingDelegates()
|
|
{
|
|
foreach (List<Action<UnityComponent>> handlers in _pendingInvokes.Values)
|
|
{
|
|
for (int i = 0; i < handlers.Count; i++)
|
|
{
|
|
if (handlers[i] == null)
|
|
{
|
|
handlers.RemoveAt(i);
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Returns the name to use for T.
|
|
/// </summary>
|
|
private string GetInstanceName<T>()
|
|
{
|
|
return typeof(T).FullName;
|
|
}
|
|
#endregion
|
|
|
|
|
|
}
|
|
|
|
} |