using FishNet.Connection; using FishNet.Managing; using FishNet.Object; using FishNet.Serializing.Helping; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using UnityEngine; namespace FishNet.Utility.Performance { /// <summary> /// Various ListCache instances that may be used on the Unity thread. /// </summary> public static class ListCaches { /// <summary> /// Cache collection for NetworkObjects. /// </summary> private static Stack<ListCache<NetworkObject>> _networkObjectCaches = new Stack<ListCache<NetworkObject>>(); /// <summary> /// Cache collection for NetworkObjects. /// </summary> private static Stack<ListCache<NetworkBehaviour>> _networkBehaviourCaches = new Stack<ListCache<NetworkBehaviour>>(); /// <summary> /// Cache collection for NetworkObjects. /// </summary> private static Stack<ListCache<Transform>> _transformCaches = new Stack<ListCache<Transform>>(); /// <summary> /// Cache collection for NetworkConnections. /// </summary> private static Stack<ListCache<NetworkConnection>> _networkConnectionCaches = new Stack<ListCache<NetworkConnection>>(); /// <summary> /// Cache collection for ints. /// </summary> private static Stack<ListCache<int>> _intCaches = new Stack<ListCache<int>>(); #region GetCache. /// <summary> /// Returns a NetworkObject cache. Use StoreCache to return the cache. /// </summary> /// <returns></returns> public static ListCache<NetworkObject> GetNetworkObjectCache() { ListCache<NetworkObject> result; if (_networkObjectCaches.Count == 0) result = new ListCache<NetworkObject>(); else result = _networkObjectCaches.Pop(); return result; } /// <summary> /// Returns a NetworkConnection cache. Use StoreCache to return the cache. /// </summary> /// <returns></returns> public static ListCache<NetworkConnection> GetNetworkConnectionCache() { ListCache<NetworkConnection> result; if (_networkConnectionCaches.Count == 0) result = new ListCache<NetworkConnection>(); else result = _networkConnectionCaches.Pop(); return result; } /// <summary> /// Returns a Transform cache. Use StoreCache to return the cache. /// </summary> /// <returns></returns> public static ListCache<Transform> GetTransformCache() { ListCache<Transform> result; if (_transformCaches.Count == 0) result = new ListCache<Transform>(); else result = _transformCaches.Pop(); return result; } /// <summary> /// Returns a NetworkBehaviour cache. Use StoreCache to return the cache. /// </summary> /// <returns></returns> public static ListCache<NetworkBehaviour> GetNetworkBehaviourCache() { ListCache<NetworkBehaviour> result; if (_networkBehaviourCaches.Count == 0) result = new ListCache<NetworkBehaviour>(); else result = _networkBehaviourCaches.Pop(); return result; } /// <summary> /// Returns an int cache. Use StoreCache to return the cache. /// </summary> /// <returns></returns> public static ListCache<int> GetIntCache() { ListCache<int> result; if (_intCaches.Count == 0) result = new ListCache<int>(); else result = _intCaches.Pop(); return result; } #endregion #region StoreCache. /// <summary> /// Stores a NetworkObject cache. /// </summary> /// <param name="cache"></param> public static void StoreCache(ListCache<NetworkObject> cache) { cache.Reset(); _networkObjectCaches.Push(cache); } /// <summary> /// Stores a NetworkConnection cache. /// </summary> /// <param name="cache"></param> public static void StoreCache(ListCache<NetworkConnection> cache) { cache.Reset(); _networkConnectionCaches.Push(cache); } /// <summary> /// Stores a Transform cache. /// </summary> /// <param name="cache"></param> public static void StoreCache(ListCache<Transform> cache) { cache.Reset(); _transformCaches.Push(cache); } /// <summary> /// Stores a NetworkBehaviour cache. /// </summary> /// <param name="cache"></param> public static void StoreCache(ListCache<NetworkBehaviour> cache) { cache.Reset(); _networkBehaviourCaches.Push(cache); } /// <summary> /// Stores an int cache. /// </summary> /// <param name="cache"></param> public static void StoreCache(ListCache<int> cache) { cache.Reset(); _intCaches.Push(cache); } #endregion } /// <summary> /// Creates a reusable cache of T which auto expands. /// </summary> public class ListCache<T> { #region Public. /// <summary> /// Collection cache is for. /// </summary> public List<T> Collection = new List<T>(); /// <summary> /// Entries currently written. /// </summary> public int Written => Collection.Count; #endregion #region Private. /// <summary> /// Cache for type. /// </summary> private Stack<T> _cache = new Stack<T>(); #endregion public ListCache() { Collection = new List<T>(); } public ListCache(int capacity) { Collection = new List<T>(capacity); } /// <summary> /// Returns T from cache when possible, or creates a new object when not. /// </summary> /// <returns></returns> private T Retrieve() { if (_cache.Count > 0) return _cache.Pop(); else return Activator.CreateInstance<T>(); } /// <summary> /// Stores value into the cache. /// </summary> /// <param name="value"></param> private void Store(T value) { _cache.Push(value); } /// <summary> /// Adds a new value to Collection and returns it. /// </summary> /// <param name="value"></param> public T AddReference() { T next = Retrieve(); Collection.Add(next); return next; } /// <summary> /// Inserts an bject into Collection and returns it. /// </summary> /// <param name="value"></param> public T InsertReference(int index) { //Would just be at the end anyway. if (index >= Collection.Count) return AddReference(); T next = Retrieve(); Collection.Insert(index, next); return next; } /// <summary> /// Adds value to Collection. /// </summary> /// <param name="value"></param> public void AddValue(T value) { Collection.Add(value); } /// <summary> /// Inserts value into Collection. /// </summary> /// <param name="value"></param> public void InsertValue(int index, T value) { //Would just be at the end anyway. if (index >= Collection.Count) AddValue(value); else Collection.Insert(index, value); } /// <summary> /// Adds values to Collection. /// </summary> /// <param name="values"></param> [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AddValues(ListCache<T> values) { int w = values.Written; List<T> c = values.Collection; for (int i = 0; i < w; i++) AddValue(c[i]); } /// <summary> /// Adds values to Collection. /// </summary> /// <param name="value"></param> [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AddValues(T[] values) { for (int i = 0; i < values.Length; i++) AddValue(values[i]); } /// <summary> /// Adds values to Collection. /// </summary> /// <param name="value"></param> [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AddValues(List<T> values) { for (int i = 0; i < values.Count; i++) AddValue(values[i]); } /// <summary> /// Adds values to Collection. /// </summary> /// <param name="value"></param> [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AddValues(HashSet<T> values) { foreach (T item in values) AddValue(item); } /// <summary> /// Adds values to Collection. /// </summary> /// <param name="value"></param> [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AddValues(ISet<T> values) { foreach (T item in values) AddValue(item); } /// <summary> /// Adds values to Collection. /// </summary> /// <param name="value"></param> [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AddValues(IReadOnlyCollection<T> values) { foreach (T item in values) AddValue(item); } /// <summary> /// Resets cache. /// </summary> public void Reset() { foreach (T item in Collection) Store(item); Collection.Clear(); } } }