IEnumerator LoadRoutine(int loadPointer, int mask)
        {
            if (loadTransition && loadTransitionTime>0 && snapshots[loadPointer].transitionMultiplier>0 && transitionAvailable && !isYieldRefreshing) {
                if (snapshots[loadPointer].loadMaterial && !snapshots[loadPointer].setMaterialAfterTransition && snapshots[loadPointer].settings.particleSystemRenderer.sharedMaterial!=null)
                    particleSystemRenderer.sharedMaterial = snapshots[loadPointer].settings.particleSystemRenderer.sharedMaterial;
                if (mask>0) {
                    mask = Mathf.Clamp (mask, 0, snapshots[loadPointer].settings.particleCount);
                    if (snapshots[loadPointer].settings.snapshotData.isMasked==null || snapshots[loadPointer].settings.snapshotData.isMasked.Length!=snapshots[loadPointer].settings.particleCount) {
                        snapshots[loadPointer].settings.snapshotData.isMasked = new bool[snapshots[loadPointer].settings.particleCount];
                        snapshots[loadPointer].settings.snapshotData.maskAlpha = new float[snapshots[loadPointer].settings.particleCount];
                    }
                    snapshots[loadPointer].settings.applyParticleMask = true;
                    snapshots[loadPointer].settings.particleMask = mask;
                    snapshots[loadPointer].settings.RefreshMaskSorting();
                    snapshots[loadPointer].settings.snapshotData.maskSorting = (int[])snapshots[loadPointer].settings.playgroundCache.maskSorting.Clone();
                    for (int i = 0; i<snapshots[loadPointer].settings.particleCount; i++) {
                        int maskedP = snapshots[loadPointer].settings.snapshotData.maskSorting[i];
                        snapshots[loadPointer].settings.snapshotData.isMasked[maskedP] = i<mask;
                        snapshots[loadPointer].settings.snapshotData.maskAlpha[maskedP] = i<mask?0:1f;
                    }
                }
                StartCoroutine(LoadTransition(loadPointer));
                while (inTransition) yield return null;
            }
            if (isLoading || inTransition || abortTransition)
                yield break;

            isLoading = true;
            int prevParticleCount = particleCount;
            if (prevParticleCount!=snapshots[loadPointer].settings.particleCount) {
                SetParticleCount(thisInstance, snapshots[loadPointer].settings.particleCount);
                while (isSettingParticleCount)
                    yield return null;
            }
            snapshots[loadPointer].Load(thisInstance);
            while (snapshots[loadPointer].IsLoading())
                yield return null;
            lastTimeUpdated = PlaygroundC.globalTime;
            localTime = PlaygroundC.globalTime;
            cameFromNonCalculatedFrame = false;
            cameFromNonEmissionFrame = false;
            if (snapshots[loadPointer].loadMode!=1) {
                if (loadFromStart && isYieldRefreshing)
                    yield return null;
                float tos = snapshots[loadPointer].settings.timeOfSnapshot<=0?snapshots[loadPointer].time:snapshots[loadPointer].settings.timeOfSnapshot;
                localTime = tos;
                for (int p = 0; p<particleCount; p++) {
                    playgroundCache.birth[p] = tos+(playgroundCache.birth[p]-tos);
                    playgroundCache.death[p] = tos+(playgroundCache.death[p]-tos);
                    playgroundCache.size[p] = snapshots[loadPointer].settings.snapshotData.size[p];
                    particleCache[p].size = playgroundCache.size[p];
                }
                lifetime = snapshots[loadPointer].settings.lifetime;
                previousLifetimeValueMethod = lifetimeValueMethod;
                previousLifetime = lifetime;
                previousLifetimeMin = lifetimeMin;
                previousLifetimeEmission = lifetimeEmission;
                previousNearestNeighborOrigin = nearestNeighborOrigin;
                previousNearestNeighborOriginMethod = nearestNeighborOriginMethod;
                previousNearestNeighborOriginVector3 = nearestNeighborOriginVector3;
                previousNearestNeighborOriginTransform = nearestNeighborOriginTransform;
                previousSorting = sorting;
                localDeltaTime = .001f;
                t = localDeltaTime;
            } else if (prevParticleCount!=particleCount) {
                SetLifetime(thisInstance, sorting, lifetime);
                yield return null;
                while (isSettingLifetime) {
                    yield return null;
                }
            }

            hasActiveParticles = true;
            threadHadNoActiveParticles = false;
            lastTimeUpdated = PlaygroundC.globalTime;
            cameFromNonCalculatedFrame = false;
            cameFromNonEmissionFrame = false;
            loopExceeded = false;
            loopExceededOnParticle = -1;
            isLoading = false;
            isDoneThread = true;
            transitionAvailable = true;
        }
        void OnEnable()
        {
            if (isSnapshot || isLoading) return;
            thisInstance = this;
            thisLayer = particleSystemGameObject.layer;
            initialized = false;
            isYieldRefreshing = false;
            isSettingParticleCount = false;
            isSettingLifetime = false;
            hasActiveParticles = true;
            threadHadNoActiveParticles = false;
            isDoneThread = true;
            calculate = true;

            lastTimeUpdated = PlaygroundC.globalTime;
            localTime = lastTimeUpdated;
            emissionStopped = 0;
            queueEmissionHalt = false;

            // Set new randoms
            RefreshSystemRandom();

            // Set 0 size to avoid one-frame flash
            shurikenParticleSystem.startSize = 0f;

            if (shurikenParticleSystem.isPaused || shurikenParticleSystem.isStopped)
                shurikenParticleSystem.Play();

            // Set initial values
            previousLifetimeValueMethod = lifetimeValueMethod;
            previousLifetime = lifetime;
            previousLifetimeMin = lifetimeMin;
            previousEmission = emit;
            previousLoop = loop;
            previousNearestNeighborOrigin = nearestNeighborOrigin;
            previousNearestNeighborOriginMethod = nearestNeighborOriginMethod;
            previousNearestNeighborOriginVector3 = nearestNeighborOriginVector3;
            previousNearestNeighborOriginTransform = nearestNeighborOriginTransform;
            previousSorting = sorting;
            previousParticleCount = particleCount;
            previousLifetimeEmission = lifetimeEmission;
            prevSource = source;
            loopExceeded = false;
            loopExceededOnParticle = -1;

            stRot = Quaternion.identity;
            stDir = new Vector3();

            // Initiate all arrays by setting particle count
            if (particleCache==null) {
                SetParticleCount(thisInstance, particleCount);
            } else {

                // Clean up particle positions
                SetInitialTargetPosition(thisInstance, PlaygroundC.initialTargetPosition, true);

                // Refresh
                StartCoroutine(YieldedRefresh());
            }
        }
        IEnumerator LoadRoutine(int loadPointer)
        {
            if (loadTransition && loadTransitionTime>0 && snapshots[loadPointer].transitionMultiplier>0 && transitionAvailable && !isYieldRefreshing) {
                if (snapshots[loadPointer].loadMaterial && !snapshots[loadPointer].setMaterialAfterTransition && snapshots[loadPointer].settings.particleSystemRenderer.sharedMaterial!=null)
                    particleSystemRenderer.sharedMaterial = snapshots[loadPointer].settings.particleSystemRenderer.sharedMaterial;
                StartCoroutine(LoadTransition(loadPointer));
                while (inTransition) yield return null;
            }
            if (isLoading || inTransition || abortTransition)
                yield break;

            isLoading = true;
            int prevParticleCount = particleCount;
            if (prevParticleCount!=snapshots[loadPointer].settings.particleCount) {
                SetParticleCount(thisInstance, snapshots[loadPointer].settings.particleCount);
                while (isSettingParticleCount)
                    yield return null;
            }
            snapshots[loadPointer].Load(thisInstance);
            while (snapshots[loadPointer].IsLoading())
                yield return null;
            lastTimeUpdated = PlaygroundC.globalTime;
            cameFromNonCalculatedFrame = false;
            cameFromNonEmissionFrame = false;
            //yield return null;
            if (snapshots[loadPointer].loadMode!=1) {
                if (loadFromStart && isYieldRefreshing)
                    yield return null;
                float tos = snapshots[loadPointer].settings.timeOfSnapshot<=0?snapshots[loadPointer].time:snapshots[loadPointer].settings.timeOfSnapshot;

                for (int p = 0; p<particleCount; p++) {
                    playgroundCache.birth[p] = PlaygroundC.globalTime+(playgroundCache.birth[p]-tos);
                    playgroundCache.death[p] = PlaygroundC.globalTime+(playgroundCache.death[p]-tos);
                    playgroundCache.size[p] = snapshots[loadPointer].settings.snapshotData.size[p];
                    particleCache[p].size = playgroundCache.size[p];
                }

                lifetime = snapshots[loadPointer].settings.lifetime;
                previousLifetimeValueMethod = lifetimeValueMethod;
                previousLifetime = lifetime;
                previousLifetimeMin = lifetimeMin;
                previousNearestNeighborOrigin = nearestNeighborOrigin;
                previousSorting = sorting;
                localDeltaTime = .001f;
            } else if (prevParticleCount!=particleCount) {
                SetLifetime(thisInstance, sorting, lifetime);
                yield return null;
                while (isSettingLifetime) {
                    yield return null;
                }
            }
            initNearestNeighborSeq = 6;
            hasActiveParticles = true;
            threadHadNoActiveParticles = false;
            lastTimeUpdated = PlaygroundC.globalTime;
            cameFromNonCalculatedFrame = false;
            cameFromNonEmissionFrame = false;
            loopExceeded = false;
            loopExceededOnParticle = -1;
            isLoading = false;
            isDoneThread = true;
            transitionAvailable = true;
        }