轨迹插件引入
This commit is contained in:
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -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:
|
||||
Reference in new issue
Block a user