private void DetachChildRecyclableObject(RecyclablePrefab r)
        {
            r.OnCleanup -= DetachChildRecyclableObject;
            bool successful = attachedChildRecycables_.Remove(r);

            if (!successful)
            {
                Debug.LogWarning("DetachChildRecyclableObject - failed to find child recyclablePrefab in attachedCleanupSubscribers!");
            }
        }
        public void AttachChildRecyclableObject(GameObject child)
        {
            RecyclablePrefab r = child.GetRequiredComponent <RecyclablePrefab>();
            bool             addedSuccessfully = attachedChildRecycables_.Add(r);

            if (!addedSuccessfully)
            {
                Debug.LogWarning("AttachChildRecyclableObject - child recyclablePrefab already in attachedCleanupSubscribers!");
                return;
            }

            r.OnCleanup += DetachChildRecyclableObject;
        }
        private GameObject CreateInternal(string prefabName, GameObject parent = null, bool worldPositionStays = false, Func <string, GameObject> prefabProvider = null, Vector3?position = null, Quaternion?rotation = null)
        {
            prefabName = prefabName.ToLower();

            GameObject instantiatedPrefab = GetGameObjectForPrefabName(prefabName, prefabProvider, position, rotation);

            if (parent != null)
            {
                instantiatedPrefab.transform.SetParent(parent.transform, worldPositionStays);
            }
            else
            {
                instantiatedPrefab.transform.SetParent(null);
                SceneManager.MoveGameObjectToScene(instantiatedPrefab, SceneManager.GetActiveScene());
            }

            RecyclablePrefab recycleData = instantiatedPrefab.GetOrAddComponent <RecyclablePrefab>();

            recycleData.Setup();

            return(instantiatedPrefab);
        }
        private void RecycleInternal(GameObject usedObject, bool worldPositionStays = false)
        {
            if (usedObject == null)
            {
                Debug.LogWarning("Recycle: called on null object!");
                return;
            }

            RecyclablePrefab recycleData = usedObject.GetComponent <RecyclablePrefab>();

            if (recycleData == null)
            {
                Debug.LogWarning("Recycle: usedObject - (" + usedObject + ") does not have RecyclablePrefab script!");
                // Because the recycle lifecycle wasn't set up properly, just destroy this object instead of recycling
                GameObject.Destroy(usedObject);
                return;
            }

            if (objectsBeingCleanedUp_.Contains(usedObject))
            {
                return;
            }

            objectsBeingCleanedUp_.Add(usedObject);
            recycleData.Cleanup();
            usedObject.transform.SetParent(this.transform, worldPositionStays);
            this.DoAfterFrame(() => {
                this.DoAfterFrame(() => {
                    usedObject.SetActive(false);

                    Stack <GameObject> recycledObjects = ObjectPoolForPrefabName(recycleData.PrefabName);
                    recycledObjects.Push(usedObject);

                    objectsBeingCleanedUp_.Remove(usedObject);
                });
            });
        }
        private bool ValidateRecycledObject(GameObject recycledObject, string prefabName)
        {
            if (recycledObject.activeSelf)
            {
                Debug.LogError("ValidateRecycledObject: recycled object: (" + recycledObject + ") is still active, is someone else using it?");
                return(false);
            }

            RecyclablePrefab recycleData = recycledObject.GetComponent <RecyclablePrefab>();

            if (recycleData == null)
            {
                Debug.LogError("ValidateRecycledObject: recycled object: (" + recycledObject + ") doesn't have a recyclable prefab script!");
                return(false);
            }

            if (recycleData.PrefabName != prefabName)
            {
                Debug.LogError("ValidateRecycledObject: recycled object: (" + recycledObject + ") doesn't match prefab name: " + prefabName + "!");
                return(false);
            }

            return(true);
        }
        private GameObject GetGameObjectForPrefabName(string prefabName, Func <string, GameObject> prefabProvider, Vector3?position, Quaternion?rotation)
        {
            Stack <GameObject> recycledObjects = ObjectPoolForPrefabName(prefabName);

            // try to find a recycled object that is usable
            while (recycledObjects.Count > 0)
            {
                GameObject recycledObj = recycledObjects.Pop();
                if (objectsBeingCleanedUp_.Contains(recycledObj))
                {
                    Debug.LogError("ObjectPoolManager - instantiating object that is being recycled (did you forget to clear references to recycled objects?)");
                }

                if (recycledObj != null)
                {
                    if (!ValidateRecycledObject(recycledObj, prefabName))
                    {
                        return(null);
                    }

                    if (position != null)
                    {
                        recycledObj.transform.position = (Vector3)position;
                    }

                    if (rotation != null)
                    {
                        recycledObj.transform.rotation = (Quaternion)rotation;
                    }

                    recycledObj.SetActive(true);
                    return(recycledObj);
                }
            }

            // if no recycled object is found, instantiate one
            if (prefabProvider == null)
            {
                prefabProvider = PrefabList.PrefabForName;
            }
            GameObject prefab = prefabProvider.Invoke(prefabName);

            if (prefab == null)
            {
                return(null);
            }

            GameObject instantiatedPrefab = null;

            if (position != null && rotation != null)
            {
                instantiatedPrefab = GameObject.Instantiate(prefab, (Vector3)position, (Quaternion)rotation);
            }
            else
            {
                instantiatedPrefab = GameObject.Instantiate(prefab);
            }

            RecyclablePrefab recycleData = instantiatedPrefab.GetOrAddComponent <RecyclablePrefab>();

            recycleData.PrefabName = prefabName;

            OnGameObjectCreated.Invoke(instantiatedPrefab);
            return(instantiatedPrefab);
        }