轨迹插件引入

This commit is contained in:
lishuo committed 2022-09-06 13:47:45 +08:00
1 parent 89b5275efd
commit 195893a1b0
1023 files changed
+378944 -18404

No files matched your search

@@ -0,0 +1,388 @@
// =====================================================================
// Copyright 2013-2017 Fluffy Underware
// All rights reserved
//
// http://www.fluffyunderware.com
// =====================================================================
using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using FluffyUnderware.DevTools.Extensions;
#if CURVY_SANITY_CHECKS_PRIVATE
using UnityEngine.Assertions;
#endif
using UnityEngine.SceneManagement;
namespace FluffyUnderware.DevTools
{
/// <summary>
/// A pool of instances of the UnityEngine.Component class
/// </summary>
[HelpURL(DTUtility.HelpUrlBase + "dtcomponentpool")]
public class ComponentPool : DTVersionedMonoBehaviour, IPool, ISerializationCallbackReceiver
{
[SerializeField, HideInInspector]
private string m_Identifier;
[Inline]
[SerializeField]
private PoolSettings m_Settings;
public PoolSettings Settings
{
get { return m_Settings; }
set
{
if (m_Settings != value)
m_Settings = value;
if (m_Settings != null)
m_Settings.OnValidate();
}
}
private PoolManager mManager;
public PoolManager Manager
{
get
{
if (mManager == null)
mManager = GetComponent<PoolManager>();
return mManager;
}
}
/// <summary>
/// Due to bad design decisions, Identifier is used to store the type of the pooled objects. And the setter does nothing
/// </summary>
public string Identifier
{
get
{
#if CURVY_SANITY_CHECKS_PRIVATE
Assert.IsNotNull(m_Identifier);
#endif
return m_Identifier;
}
set
{
throw new InvalidOperationException("Component pool's identifier should always indicate the pooled type's assembly qualified name");
/*Here is why:
In the Initialize method, m_Identifier is set as a fully qualified type name.
The Type getter uses m_Identifier as a fully qualified type name.
If needed, add a field that contains the pooled type name, and use it instead of Identifier when you need to find the right pool for the right component type*/
}
}
/// <summary>
/// The type of the pooled objects
/// </summary>
public Type Type
{
get
{
Type type = null;
if (Identifier != null)
type = Type.GetType(Identifier);
if (type == null)
DTLog.LogWarning("[DevTools] ComponentPool's Type is an unknown type " + m_Identifier);
return type;
}
}
public int Count
{
get { return mObjects.Count; }
}
private List<Component> mObjects = new List<Component>();
private double mLastTime;
private double mDeltaTime;
public void Initialize(Type type, PoolSettings settings)
{
m_Identifier = type.AssemblyQualifiedName;
#if CURVY_SANITY_CHECKS_PRIVATE
Assert.IsNotNull(m_Identifier);
#endif
m_Settings = settings;
mLastTime = DTTime.TimeSinceStartup + UnityEngine.Random.Range(0, Settings.Speed);
if (Settings.Prewarm)
Reset();
}
private void Start()
{
if (Settings.Prewarm)
Reset();
}
#if UNITY_EDITOR
private void OnValidate()
{
Settings = m_Settings;
}
#endif
private void OnEnable()
{
SceneManager.sceneLoaded += OnSceneLoaded;
}
public void Update()
{
if (Application.isPlaying)
{
mDeltaTime += DTTime.TimeSinceStartup - mLastTime;
mLastTime = DTTime.TimeSinceStartup;
if (Settings.Speed > 0)
{
int c = (int)(mDeltaTime / Settings.Speed);
mDeltaTime -= c;
if (Count > Settings.Threshold)
{
c = Mathf.Min(c, Count - Settings.Threshold);
while (c-- > 0)
{
if (Settings.Debug)
log("Threshold exceeded: Deleting item");
destroy(mObjects[0]);
mObjects.RemoveAt(0);
}
}
else if (Count < Settings.MinItems)
{
c = Mathf.Min(c, Settings.MinItems - Count);
while (c-- > 0)
{
if (Settings.Debug)
log("Below MinItems: Adding item");
mObjects.Add(create());
}
}
}
else
mDeltaTime = 0;
}
}
public void Reset()
{
if (Application.isPlaying)
{
while (Count < Settings.MinItems)
{
mObjects.Add(create());
}
while (Count > Settings.Threshold)
{
destroy(mObjects[0]);
mObjects.RemoveAt(0);
}
if (Settings.Debug)
log("Prewarm/Reset");
}
}
public void OnSceneLoaded(Scene scn, LoadSceneMode mode)
{
for (int i = mObjects.Count - 1; i >= 0; i--)
if (mObjects[i] == null)
mObjects.RemoveAt(i);
}
public void Clear()
{
if (Settings.Debug)
log("Clear");
for (int i = 0; i < Count; i++)
destroy(mObjects[i]);
mObjects.Clear();
}
public void Push(Component item)
{
sendBeforePush(item);
#if UNITY_EDITOR
if (!Application.isPlaying)
{
item.gameObject.Destroy(false, true);
}
else
#endif
if (item != null)
{
mObjects.Add(item);
item.transform.parent = Manager.transform;
item.gameObject.hideFlags = (Settings.Debug)
? HideFlags.DontSave
: HideFlags.HideAndDontSave;
if (Settings.AutoEnableDisable)
item.gameObject.SetActive(false);
}
}
public Component Pop(Transform parent = null)
{
Component item = null;
if (Count > 0)
{
item = mObjects[0];
mObjects.RemoveAt(0);
}
else
{
if (Settings.AutoCreate || !Application.isPlaying)
{
if (Settings.Debug)
log("Auto create item");
item = create();
}
}
if (item)
{
item.gameObject.hideFlags = HideFlags.None;
item.transform.parent = parent;
if (Settings.AutoEnableDisable)
item.gameObject.SetActive(true);
sendAfterPop(item);
if (Settings.Debug)
log("Pop " + item);
}
return item;
}
public T Pop<T>(Transform parent) where T : Component
{
return Pop(parent) as T;
}
private Component create()
{
GameObject go = new GameObject();
go.name = Identifier;
go.transform.parent = Manager.transform;
if (Settings.AutoEnableDisable)
go.SetActive(false);
Type componentType = Type;
Component component = null;
if (componentType != null)
component = go.AddComponent(componentType);
else
DTLog.LogError(String.Format("[DevTools] ComponentPool {0} could not create component because the associated type is null", m_Identifier));
return component;
}
private void destroy(Component item)
{
if (item != null)
item.gameObject.Destroy(false, true);
}
private void setParent(Component item, Transform parent)
{
if (item != null)
item.transform.parent = parent;
}
private void sendAfterPop(Component item)
{
GameObject itemGameObject = item.gameObject;
if (itemGameObject.activeSelf && itemGameObject.activeInHierarchy)
//Send message works only for active game objects. Source: https://docs.unity3d.com/ScriptReference/GameObject.SendMessage.html
itemGameObject.SendMessage(nameof(IPoolable.OnAfterPop), SendMessageOptions.DontRequireReceiver);
else
{
if (item is IPoolable)
((IPoolable)item).OnAfterPop();
else
DTLog.LogWarning("[Curvy] sendAfterPop could not send message because the receiver " + item.name + " is not active");
}
}
private void sendBeforePush(Component item)
{
GameObject itemGameObject = item.gameObject;
if (itemGameObject.activeSelf && itemGameObject.activeInHierarchy)
//Send message works only for active game objects. Source: https://docs.unity3d.com/ScriptReference/GameObject.SendMessage.html
itemGameObject.SendMessage(nameof(IPoolable.OnBeforePush), SendMessageOptions.DontRequireReceiver);
else
{
if (item is IPoolable)
((IPoolable)item).OnBeforePush();
else
DTLog.LogWarning("[Curvy] sendBeforePush could not send message because the receiver " + item.name + " is not active");
}
}
private void log(string msg)
{
Debug.Log(string.Format("[{0}] ({1} items) {2}", Identifier, Count, msg));
}
#region ISerializationCallbackReceiver
/*! \cond PRIVATE */
/// <summary>
/// Implementation of UnityEngine.ISerializationCallbackReceiver
/// Called automatically by Unity, is not meant to be called by Curvy's users
/// </summary>
public void OnBeforeSerialize()
{
}
/// <summary>
/// Implementation of UnityEngine.ISerializationCallbackReceiver
/// Called automatically by Unity, is not meant to be called by Curvy's users
/// </summary>
public void OnAfterDeserialize()
{
if (Type.GetType(m_Identifier) == null)
{
//Handles cases where the component is migrated to another assembly (for example if using Unity's Assembly Definitions feature
const char separator = ',';
const string separatorString = ",";
string[] splittedAssemblyQualifiedName = m_Identifier.Split(separator);
if (splittedAssemblyQualifiedName.Length >= 5)
{
string typeName = String.Join(separatorString, splittedAssemblyQualifiedName.SubArray(0, splittedAssemblyQualifiedName.Length - 4));
//As you can see with this example:
//"FluffyUnderware.Curvy.CurvySplineSegment, ToolBuddy.Curvy, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
//the 4 last elements do not contain the type name. Keep in mind that a type name can include a ',' like Dictionary<int, List<double>>
#if UNITY_EDITOR
var knownTypes = UnityEditor.TypeCache.GetTypesDerivedFrom(typeof(System.Object));
#else
#if NETFX_CORE
Type[] knownTypes = this.GetType().GetAllTypes();
#else
Type[] knownTypes = TypeExt.GetLoadedTypes();
#endif
#endif
Type type = knownTypes.FirstOrDefault(t => t.FullName == typeName);
if (type != null)
{
m_Identifier = type.AssemblyQualifiedName;
#if CURVY_SANITY_CHECKS_PRIVATE
Assert.IsNotNull(m_Identifier);
#endif
}
}
}
}
/*! \endcond */
#endregion
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 62f98941b92097f49bd5ff480ec47122
timeCreated: 1441006208
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,98 @@
// =====================================================================
// Copyright 2013-2017 Fluffy Underware
// All rights reserved
//
// http://www.fluffyunderware.com
// =====================================================================
using System.Collections.Generic;
using System.Linq;
using FluffyUnderware.DevTools.Extensions;
using UnityEngine;
namespace FluffyUnderware.DevTools
{
public class DTSingleton<T> : MonoBehaviour, IDTSingleton where T : MonoBehaviour, IDTSingleton
{
static T _instance;
static object _lock = new object();
static bool applicationIsQuitting = false;
bool isDuplicateInstance = false;
public static bool HasInstance
{
get { return _instance != null; }
}
public static T Instance
{
get
{
if (!Application.isPlaying)
applicationIsQuitting = false;
if (applicationIsQuitting)
return null;
if (_instance == null)
lock (_lock)
if (_instance == null)
{
IEnumerable<Object> objectsOfTypeT = FindObjectsOfType(typeof(T)).Where(o => o != null);
#if CURVY_SANITY_CHECKS
if (objectsOfTypeT.Count() != FindObjectsOfType(typeof(T)).Length)
DTLog.LogError("[Curvy] DTSingleton.Instance : FindObjectsOfType " + typeof(T).FullName + " returned at least one null reference");
#endif
_instance = objectsOfTypeT.Any()
? (T)objectsOfTypeT.ElementAt(0)
: new GameObject().AddComponent<T>();
}
return _instance;
}
}
public virtual void Awake()
{
T instance = Instance;
lock (_lock)
{
if (instance == null)
DTLog.LogError("[DevTools] DTSingleton instance was null. This happens if the instance is destroyed by the user, which is not a supported operation. If you did not destroy the singleton's instance, then please fill a bug report.");
else
if (GetInstanceID() != instance.GetInstanceID())
{
instance.MergeDoubleLoaded((IDTSingleton)this);
this.isDuplicateInstance = true;
this.Invoke(nameof(DestroySelf), 0);
}
}
}
protected virtual void OnDestroy()
{
lock (_lock)
if (Application.isPlaying && !isDuplicateInstance)
{
applicationIsQuitting = true;
_instance = null;
}
}
public virtual void MergeDoubleLoaded(IDTSingleton newInstance)
{
}
void DestroySelf()
{
gameObject.Destroy(false, true);
}
}
public interface IDTSingleton
{
void MergeDoubleLoaded(IDTSingleton newInstance);
}
}
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: be97567edb4b04d4b864736d9e10f36f
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
@@ -0,0 +1,41 @@
// =====================================================================
// Copyright 2013-2017 Fluffy Underware
// All rights reserved
//
// http://www.fluffyunderware.com
// =====================================================================
using System;
using UnityEngine;
using System.Collections;
using FluffyUnderware.DevTools.Extensions;
namespace FluffyUnderware.DevTools
{
/// <summary>
/// A MonoBehaviour with a version number, useful to handle upgrades if needed
/// </summary>
public abstract class DTVersionedMonoBehaviour : MonoBehaviour
{
[SerializeField, HideInInspector]
string m_Version;
/// <summary>
/// Gets the version of this component
/// </summary>
public string Version
{
get { return m_Version; }
protected set { m_Version = value; }
}
/// <summary>
/// Destroys the gameobject
/// </summary>
[Obsolete("Use ObjectExt.Destroy(...) instead")]
public void Destroy()
{
gameObject.Destroy(false, true);
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b3c2cf93621e06d43b51fbde3128ce03
timeCreated: 1441701724
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,58 @@
// =====================================================================
// Copyright 2013-2017 Fluffy Underware
// All rights reserved
//
// http://www.fluffyunderware.com
// =====================================================================
using UnityEngine;
using System.Collections;
namespace FluffyUnderware.DevTools
{
/// <summary>
/// Add this script to a GameObject with a MeshFilter to ensure it will be properly duplicated in the editor!
/// </summary>
/// <remarks>On Duplicating, Awake() checks if the sharedMesh is already used in the scene. If yes, a new mesh will be created to ensure that each sharedMesh is unique</remarks>
[ExecuteAlways]
[RequireComponent(typeof(MeshFilter))]
public abstract class DuplicateEditorMesh : DTVersionedMonoBehaviour
{
MeshFilter mFilter;
public MeshFilter Filter
{
get {
if (mFilter == null)
mFilter = GetComponent<MeshFilter>();
return mFilter;
}
}
protected virtual void Awake()
{
if (!Application.isPlaying)
{
MeshFilter meshFilter = Filter;
if (meshFilter && meshFilter.sharedMesh != null)
{
DuplicateEditorMesh[] otherWatchdogs = GameObject.FindObjectsOfType<DuplicateEditorMesh>();
foreach (DuplicateEditorMesh dog in otherWatchdogs)
{
if (dog != this)
{
MeshFilter otherMF = dog.Filter;
if (otherMF && otherMF.sharedMesh == meshFilter.sharedMesh)
{
Mesh m = new Mesh();
m.name = otherMF.sharedMesh.name;
meshFilter.mesh = m;
}
}
}
}
}
}
}
}
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a648044f27666564a9cf38d201465713
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
@@ -0,0 +1,24 @@
// =====================================================================
// Copyright 2013-2017 Fluffy Underware
// All rights reserved
//
// http://www.fluffyunderware.com
// =====================================================================
using UnityEngine;
using System.Collections;
namespace FluffyUnderware.DevTools
{
/// <summary>
/// A component to display notes in the inspector
/// </summary>
[HelpURL(DTUtility.HelpUrlBase + "dtinspectornode")]
public class InspectorNote : DTVersionedMonoBehaviour
{
[TextArea(5,20)]
[SerializeField]
string m_Note;
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: eed5f71264f54224aaf071d6a2e69915
timeCreated: 1442489791
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,248 @@
// =====================================================================
// Copyright 2013-2017 Fluffy Underware
// All rights reserved
//
// http://www.fluffyunderware.com
// =====================================================================
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using FluffyUnderware.DevTools.Extensions;
namespace FluffyUnderware.DevTools
{
/// <summary>
/// Manages the object's pools components
/// </summary>
[HelpURL(DTUtility.HelpUrlBase + "dtpoolmanager")]
[ExecuteAlways]
[DisallowMultipleComponent]
public class PoolManager : DTVersionedMonoBehaviour
{
[Section("General")]
[SerializeField]
bool m_AutoCreatePools = true;
[AsGroup(Expanded = false)]
[SerializeField]
PoolSettings m_DefaultSettings = new PoolSettings();
public bool AutoCreatePools
{
get { return m_AutoCreatePools; }
set
{
if (m_AutoCreatePools != value)
m_AutoCreatePools = value;
}
}
public PoolSettings DefaultSettings
{
get { return m_DefaultSettings; }
set
{
if (m_DefaultSettings != value)
m_DefaultSettings = value;
if (m_DefaultSettings != null)
m_DefaultSettings.OnValidate();
}
}
public bool IsInitialized { get; private set; }
public int Count { get { return Pools.Count + TypePools.Count; } }
public Dictionary<string, IPool> Pools = new Dictionary<string, IPool>();
public Dictionary<Type, IPool> TypePools = new Dictionary<Type, IPool>();
IPool[] mPools = new IPool[0];
#if UNITY_EDITOR
void OnValidate()
{
DefaultSettings = m_DefaultSettings;
}
#endif
void OnDisable()
{
IsInitialized = false;
}
void Update()
{
#if UNITY_EDITOR
if (!Application.isPlaying)
Initialize();
#endif
if (!IsInitialized)
Initialize();
if (mPools.Length != TypePools.Count)
{
System.Array.Resize(ref mPools, TypePools.Count);
TypePools.Values.CopyTo(mPools, 0);
}
for (int i = 0; i < mPools.Length; i++)
mPools[i].Update();
}
void Initialize()
{
Pools.Clear();
IPool[] goPools = GetComponents<IPool>();
foreach (IPool p in goPools)
{
if (p is ComponentPool)
{
if(Pools.ContainsKey(p.Identifier) == false)
Pools.Add(p.Identifier, p);
else
{
DTLog.Log("[DevTools] Found a duplicated ComponentPool for type " + p.Identifier + ". The duplicated pool will be destroyed");
(p as ComponentPool).Destroy(false, false);
}
}
else
{
p.Identifier = GetUniqueIdentifier(p.Identifier);
Pools.Add(p.Identifier, p);
}
}
IsInitialized = true;
}
public string GetUniqueIdentifier(string ident)
{
int num = 0;
string id = ident;
while (Pools.ContainsKey(id))
id = ident + (++num).ToString();
return id;
}
public Pool<T> GetTypePool<T>()
{
IPool res = null;
if (!TypePools.TryGetValue(typeof(T), out res))
{
if (AutoCreatePools)
{
res = CreateTypePool<T>();
}
}
return (Pool<T>)res;
}
public ComponentPool GetComponentPool<T>() where T : Component
{
if (!IsInitialized)
Initialize();
IPool res = null;
if (!Pools.TryGetValue(typeof(T).AssemblyQualifiedName, out res))
{
if (AutoCreatePools)
{
res = CreateComponentPool<T>();
}
}
return (ComponentPool)res;
}
public PrefabPool GetPrefabPool(string identifier, params GameObject[] prefabs)
{
if (!IsInitialized)
Initialize();
IPool pool;
if (!Pools.TryGetValue(identifier, out pool))
{
if (AutoCreatePools)
pool = CreatePrefabPool(identifier, null, prefabs);
}
return (PrefabPool)pool;
}
public Pool<T> CreateTypePool<T>(PoolSettings settings = null)
{
PoolSettings s = settings ?? new PoolSettings(DefaultSettings);
IPool res = null;
if (!TypePools.TryGetValue(typeof(T), out res))
{
res = new Pool<T>(s);
TypePools.Add(typeof(T), res);
}
return (Pool<T>)res;
}
public ComponentPool CreateComponentPool<T>(PoolSettings settings = null) where T : Component
{
if (!IsInitialized)
Initialize();
PoolSettings s = settings ?? new PoolSettings(DefaultSettings);
IPool res = null;
if (!Pools.TryGetValue(typeof(T).AssemblyQualifiedName, out res))
{
res = gameObject.AddComponent<ComponentPool>();
((ComponentPool)res).Initialize(typeof(T), s);
Pools.Add(res.Identifier, res);
}
return (ComponentPool)res;
}
public PrefabPool CreatePrefabPool(string name, PoolSettings settings = null, params GameObject[] prefabs)
{
if (!IsInitialized)
Initialize();
PoolSettings s = settings ?? new PoolSettings(DefaultSettings);
IPool pool = null;
if (!Pools.TryGetValue(name, out pool))
{
PrefabPool p = gameObject.AddComponent<PrefabPool>();
p.Initialize(name, s, prefabs);
Pools.Add(name, p);
return p;
}
return (PrefabPool)pool;
}
public List<IPool> FindPools(string identifierStartsWith)
{
List<IPool> res = new List<IPool>();
foreach (KeyValuePair<string, IPool> kv in Pools)
if (kv.Key.StartsWith(identifierStartsWith))
res.Add(kv.Value);
return res;
}
public void DeletePools(string startsWith)
{
List<IPool> toDelete = FindPools(startsWith);
for (int i = toDelete.Count - 1; i >= 0; i--)
DeletePool(toDelete[i]);
}
public void DeletePool(IPool pool)
{
if (pool is PrefabPool || pool is ComponentPool)
{
((MonoBehaviour) pool).Destroy(false, false);
Pools.Remove(pool.Identifier);
}
}
public void DeletePool<T>()
{
TypePools.Remove(typeof(T));
}
}
}
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3d8a3277e999b164d99f199328dc5d2d
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
@@ -0,0 +1,307 @@
// =====================================================================
// Copyright 2013-2017 Fluffy Underware
// All rights reserved
//
// http://www.fluffyunderware.com
// =====================================================================
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
using System.Collections;
using System;
using System.Collections.Generic;
using FluffyUnderware.DevTools.Extensions;
namespace FluffyUnderware.DevTools
{
/// <summary>
/// A pool of instances of a prefab GameObject
/// </summary>
[RequireComponent(typeof(PoolManager))]
[HelpURL(DTUtility.HelpUrlBase + "dtprefabpool")]
public class PrefabPool : DTVersionedMonoBehaviour, IPool
{
[FieldCondition(nameof(m_Identifier), "", false, ActionAttribute.ActionEnum.ShowWarning, "Please enter an identifier! (Select a prefab to set automatically)")]
[SerializeField]
string m_Identifier;
[SerializeField]
List<GameObject> m_Prefabs = new List<GameObject>();
[Inline]
[SerializeField]
PoolSettings m_Settings;
PoolManager mManager;
public string Identifier
{
get { return m_Identifier; }
set
{
if (m_Identifier != value)
{
string v = value;
if (string.IsNullOrEmpty(m_Identifier))
v = Manager.GetUniqueIdentifier(v);
m_Identifier = value;
}
}
}
public List<GameObject> Prefabs
{
get { return m_Prefabs; }
set
{
if (m_Prefabs != value)
m_Prefabs = value;
}
}
public PoolSettings Settings
{
get { return m_Settings; }
set
{
if (m_Settings != value)
m_Settings = value;
if (m_Settings != null)
m_Settings.OnValidate();
}
}
public PoolManager Manager
{
get
{
if (mManager == null)
mManager = GetComponent<PoolManager>();
return mManager;
}
}
List<GameObject> mObjects = new List<GameObject>();
double mLastTime;
double mDeltaTime;
void Start()
{
if (Settings.Prewarm)
Reset();
}
#if UNITY_EDITOR
void OnValidate()
{
Settings = m_Settings;
}
#endif
public void Initialize(string ident, PoolSettings settings, params GameObject[] prefabs)
{
Identifier = ident;
m_Settings = settings;
Prefabs = new List<GameObject>(prefabs);
mLastTime = DTTime.TimeSinceStartup + UnityEngine.Random.Range(0, Settings.Speed);
if (Settings.Prewarm)
Reset();
}
public void Update()
{
if (Application.isPlaying)
{
mDeltaTime += DTTime.TimeSinceStartup - mLastTime;
mLastTime = DTTime.TimeSinceStartup;
if (Settings.Speed > 0)
{
int c = (int)(mDeltaTime / Settings.Speed);
mDeltaTime -= c;
if (Count > Settings.Threshold)
{
c = Mathf.Min(c, Count - Settings.Threshold);
while (c-- > 0)
{
if (Settings.Debug)
log("Threshold exceeded: Deleting item");
destroy(mObjects[0]);
mObjects.RemoveAt(0);
}
}
else if (Count < Settings.MinItems)
{
c = Mathf.Min(c, Settings.MinItems - Count);
while (c-- > 0)
{
if (Settings.Debug)
log("Below MinItems: Adding item");
mObjects.Add(create());
}
}
}
else
mDeltaTime = 0;
}
}
public void Reset()
{
if (Application.isPlaying)
{
while (Count < Settings.MinItems)
{
mObjects.Add(create());
}
while (Count > Settings.Threshold)
{
destroy(mObjects[0]);
mObjects.RemoveAt(0);
}
if (Settings.Debug)
log("Prewarm/Reset");
}
}
public void Clear()
{
if (Settings.Debug)
log("Clear");
for (int i = 0; i < Count; i++)
destroy(mObjects[i]);
mObjects.Clear();
}
public int Count
{
get { return mObjects.Count; }
}
public GameObject Pop(Transform parent = null)
{
GameObject item = null;
if (Count > 0)
{
item = mObjects[0];
mObjects.RemoveAt(0);
}
else
{
if (Settings.AutoCreate || !Application.isPlaying)
{
if (Settings.Debug)
log("Auto create item");
item = create();
}
}
if (item)
{
item.gameObject.hideFlags = HideFlags.None;
item.transform.parent = parent;
if (Settings.AutoEnableDisable)
item.SetActive(true);
sendAfterPop(item);
if (Settings.Debug)
log("Pop " + item);
}
return item;
}
public virtual void Push(GameObject item)
{
if (Settings.Debug)
log("Push " + item);
#if UNITY_EDITOR
if (!Application.isPlaying)
{
item.gameObject.Destroy(false, true);
}
else
#endif
if (item != null)
{
sendBeforePush(item);
mObjects.Add(item);
item.transform.parent = transform;
item.gameObject.hideFlags = (Settings.Debug) ? HideFlags.DontSave : HideFlags.HideAndDontSave;
if (Settings.AutoEnableDisable)
item.SetActive(false);
}
}
GameObject create()
{
if (Prefabs.Count == 0)
throw new InvalidOperationException(String.Format("[Curvy] The Prefab Pool '{0}' in game object '{1}' could not create a pool element because its Prefabs list is empty", this.Identifier, this.gameObject.name));
//TODO should this Random.Range call be deterministic?
GameObject prefab = Prefabs[UnityEngine.Random.Range(0, Prefabs.Count)];
GameObject result;
{
#if UNITY_EDITOR
bool isPrefabAsset;
//We have to check GetPrefabInstanceStatus first, because GetPrefabAssetType returns (as far as I understand) the same thing for both a prefab asset and a prefab instance
if (PrefabUtility.GetPrefabInstanceStatus(prefab) == PrefabInstanceStatus.NotAPrefab)
{
PrefabAssetType prefabAssetType = PrefabUtility.GetPrefabAssetType(prefab);
isPrefabAsset = prefabAssetType == PrefabAssetType.Regular || prefabAssetType == PrefabAssetType.Variant;
}
else
isPrefabAsset = false;
result = isPrefabAsset
? PrefabUtility.InstantiatePrefab(prefab) as GameObject
: Instantiate(prefab);
#else
result = Instantiate(prefab);
#endif
}
result.name = prefab.name;
result.transform.parent = transform;
if (Settings.AutoEnableDisable)
result.SetActive(false);
return result;
}
void destroy(GameObject go)
{
go.Destroy(false, true);
}
void log(string msg)
{
Debug.Log(string.Format("[{0}] ({1} items) {2}", Identifier, Count, msg));
}
void setParent(Transform item, Transform parent)
{
if (item != null)
item.parent = parent;
}
void sendAfterPop(GameObject item)
{
item.SendMessage(nameof(IPoolable.OnAfterPop), SendMessageOptions.DontRequireReceiver);
}
void sendBeforePush(GameObject item)
{
item.SendMessage(nameof(IPoolable.OnBeforePush), SendMessageOptions.DontRequireReceiver);
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 4f3bdfa960a223645a04f11686263106
timeCreated: 1440756755
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: