forked from cgvr/DeltaVR
		
	
		
			
				
	
	
		
			203 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			203 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using FishNet.Managing.Object;
 | 
						|
using FishNet.Object;
 | 
						|
using FishNet.Utility.Extension;
 | 
						|
using System.Collections.Generic;
 | 
						|
using System.Runtime.CompilerServices;
 | 
						|
using UnityEngine;
 | 
						|
 | 
						|
namespace FishNet.Utility.Performance
 | 
						|
{
 | 
						|
 | 
						|
 | 
						|
    public class DefaultObjectPool : ObjectPool
 | 
						|
    {
 | 
						|
        #region Public.
 | 
						|
        /// <summary>
 | 
						|
        /// Cache for pooled NetworkObjects.
 | 
						|
        /// </summary>
 | 
						|
        public IReadOnlyCollection<Dictionary<int, Stack<NetworkObject>>> Cache => _cache;
 | 
						|
        private List<Dictionary<int, Stack<NetworkObject>>> _cache = new List<Dictionary<int, Stack<NetworkObject>>>();
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region Serialized.
 | 
						|
        /// <summary>
 | 
						|
        /// True if to use object pooling.
 | 
						|
        /// </summary>
 | 
						|
        [Tooltip("True if to use object pooling.")]
 | 
						|
        [SerializeField]
 | 
						|
        private bool _enabled = true;
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region Private.
 | 
						|
        /// <summary>
 | 
						|
        /// Current count of the cache collection.
 | 
						|
        /// </summary>
 | 
						|
        private int _cacheCount = 0;
 | 
						|
        #endregion
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Returns an object that has been stored with a collectionId of 0. A new object will be created if no stored objects are available.
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="prefabId">PrefabId of the object to return.</param>
 | 
						|
        /// <param name="asServer">True if being called on the server side.</param>
 | 
						|
        /// <returns></returns>
 | 
						|
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
						|
        public override NetworkObject RetrieveObject(int prefabId, bool asServer)
 | 
						|
        {
 | 
						|
            return RetrieveObject(prefabId, 0, asServer);
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Returns an object that has been stored. A new object will be created if no stored objects are available.
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="prefabId">PrefabId of the object to return.</param>
 | 
						|
        /// <param name="collectionId">CollectionId of the prefab.</param>
 | 
						|
        /// <param name="asServer">True if being called on the server side.</param>
 | 
						|
        /// <returns></returns>
 | 
						|
        public override NetworkObject RetrieveObject(int prefabId, ushort collectionId, bool asServer)
 | 
						|
        {
 | 
						|
            PrefabObjects po = base.NetworkManager.GetPrefabObjects<PrefabObjects>(collectionId, false);
 | 
						|
            //Quick exit/normal retrieval when not using pooling.
 | 
						|
            if (!_enabled)
 | 
						|
            {
 | 
						|
                NetworkObject prefab = po.GetObject(asServer, prefabId);
 | 
						|
                return Instantiate(prefab);
 | 
						|
            }
 | 
						|
 | 
						|
            Stack<NetworkObject> cache = GetOrCreateCache(collectionId, prefabId);
 | 
						|
            NetworkObject nob;
 | 
						|
            //Iterate until nob is populated just in case cache entries have been destroyed.
 | 
						|
            do
 | 
						|
            {
 | 
						|
                if (cache.Count == 0)
 | 
						|
                {
 | 
						|
                    NetworkObject prefab = po.GetObject(asServer, prefabId);
 | 
						|
                    /* A null nob should never be returned from spawnables. This means something
 | 
						|
                     * else broke, likely unrelated to the object pool. */
 | 
						|
                    nob = Instantiate(prefab);
 | 
						|
                    //Can break instantly since we know nob is not null.
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    nob = cache.Pop();
 | 
						|
                }
 | 
						|
 | 
						|
            } while (nob == null);
 | 
						|
 | 
						|
            nob.gameObject.SetActive(true);
 | 
						|
            return nob;
 | 
						|
        }
 | 
						|
        /// <summary>
 | 
						|
        /// Stores an object into the pool.
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="instantiated">Object to store.</param>
 | 
						|
        /// <param name="asServer">True if being called on the server side.</param>
 | 
						|
        /// <returns></returns>
 | 
						|
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
						|
        public override void StoreObject(NetworkObject instantiated, bool asServer)
 | 
						|
        {
 | 
						|
            //Pooling is not enabled.
 | 
						|
            if (!_enabled)
 | 
						|
            {
 | 
						|
                Destroy(instantiated.gameObject);
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            instantiated.gameObject.SetActive(false);
 | 
						|
            instantiated.ResetForObjectPool();
 | 
						|
            Stack<NetworkObject> cache = GetOrCreateCache(instantiated.SpawnableCollectionId, instantiated.PrefabId);
 | 
						|
            cache.Push(instantiated);
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Instantiates a number of objects and adds them to the pool.
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="prefab">Prefab to cache.</param>
 | 
						|
        /// <param name="count">Quantity to spawn.</param>
 | 
						|
        /// <param name="asServer">True if storing prefabs for the server collection. This is only applicable when using DualPrefabObjects.</param>
 | 
						|
        public void CacheObjects(NetworkObject prefab, int count, bool asServer)
 | 
						|
        {
 | 
						|
            if (!_enabled)
 | 
						|
                return;
 | 
						|
            if (count <= 0)
 | 
						|
                return;
 | 
						|
            if (prefab == null)
 | 
						|
                return;
 | 
						|
            if (prefab.PrefabId == NetworkObject.UNSET_PREFABID_VALUE)
 | 
						|
            {
 | 
						|
                InstanceFinder.NetworkManager.LogError($"Pefab {prefab.name} has an invalid prefabId and cannot be cached.");
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            Stack<NetworkObject> cache = GetOrCreateCache(prefab.SpawnableCollectionId, prefab.PrefabId);
 | 
						|
            for (int i = 0; i < count; i++)
 | 
						|
            {
 | 
						|
                NetworkObject nob = Instantiate(prefab);
 | 
						|
                nob.gameObject.SetActive(false);
 | 
						|
                cache.Push(nob);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Clears pools for all collectionIds
 | 
						|
        /// </summary>
 | 
						|
        public void ClearPool()
 | 
						|
        {
 | 
						|
            int count = _cache.Count;
 | 
						|
            for (int i = 0; i < count; i++)
 | 
						|
                ClearPool(i);
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Clears a pool for collectionId.
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="collectionId">CollectionId to clear for.</param>
 | 
						|
        public void ClearPool(int collectionId)
 | 
						|
        {
 | 
						|
            if (collectionId >= _cacheCount)
 | 
						|
                return;
 | 
						|
 | 
						|
            Dictionary<int, Stack<NetworkObject>> dict = _cache[collectionId];
 | 
						|
            //Convert to a list from the stack so we do not modify the stack directly.
 | 
						|
            ListCache<NetworkObject> nobCache = ListCaches.GetNetworkObjectCache();
 | 
						|
            foreach (Stack<NetworkObject> item in dict.Values)
 | 
						|
            {
 | 
						|
                while (item.Count > 0)
 | 
						|
                    nobCache.AddValue(item.Pop());
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Gets a cache for an id or creates one if does not exist.
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="prefabId"></param>
 | 
						|
        /// <returns></returns>
 | 
						|
        private Stack<NetworkObject> GetOrCreateCache(int collectionId, int prefabId)
 | 
						|
        {
 | 
						|
            if (collectionId >= _cacheCount)
 | 
						|
            {
 | 
						|
                //Add more to the cache.
 | 
						|
                while (_cache.Count <= collectionId)
 | 
						|
                {
 | 
						|
                    Dictionary<int, Stack<NetworkObject>> dict = new Dictionary<int, Stack<NetworkObject>>();
 | 
						|
                    _cache.Add(dict);
 | 
						|
                }
 | 
						|
                _cacheCount = collectionId;
 | 
						|
            }
 | 
						|
 | 
						|
            Dictionary<int, Stack<NetworkObject>> dictionary = _cache[collectionId];
 | 
						|
            Stack<NetworkObject> cache;
 | 
						|
            //No cache for prefabId yet, make one.
 | 
						|
            if (!dictionary.TryGetValueIL2CPP(prefabId, out cache))
 | 
						|
            {
 | 
						|
                cache = new Stack<NetworkObject>();
 | 
						|
                dictionary[prefabId] = cache;
 | 
						|
            }
 | 
						|
            return cache;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
} |