Code/ParticleEffectsManager.cs
using System.Collections.Generic;
using System.Linq;
using Sandbox;

[Title( "Particle Effects Manager" )]
[Category( "Particle" )]
[Description(
	"This component let's you manage the TimeScale , the pause and restart of every particle effect component present in the childrens of this component gameobject so it is easier to preview the whole system" )]
public sealed class ParticleEffectsManager : Component, Component.ExecuteInEditor
{
	[Property] List<ParticleEffect> ParticleEffects { get; set; }
	
	[Property] List<ParticleEmitter> ParticleEmitters { get; set; }


	[Property, Group( "Parameters" ), Range( -1f, 1f, 0.1f )]
	float TimeScale { get; set; } = 1f;

	[Property, Group( "Parameters" )] bool IsPaused { get; set; }
	[Property, Group( "Parameters" )] bool IsRestart { get; set; }

	[Property, Range( 0f, 1f, 0.001f )] private float PlayBack { get; set; }

	[Property] private bool IsPlayBack { get; set; }
	
	[Property, Range(0,10,0.001f)] public float DelayEffect { get; set; }

	protected override void OnEnabled()
	{
		ParticleEffects = GameObject.GetComponentsInChildren<ParticleEffect>().ToList();
		ParticleEmitters = GameObject.GetComponentsInChildren<ParticleEmitter>().ToList();

		if ( Scene.IsEditor ) return;
		foreach ( var particleEmitter in ParticleEmitters )
		{
			particleEmitter.Delay +=  DelayEffect;
		}
	}

	protected override void OnUpdate()
	{
		if ( !Scene.IsEditor ) return;
		
		if ( IsRestart ) Restart();
		
		foreach ( var particleEffect in ParticleEffects )
		{
			if ( IsPlayBack )
			{
				PlayBacking( particleEffect );
			}
			else
			{
				TimeScaling( particleEffect );
			}
		}
	}
	

	private void TimeScaling( ParticleEffect particleEffect )
	{
		particleEffect.TimeScale = TimeScale;
		var particleEmitter = particleEffect.Components.Get<ParticleEmitter>();
		if ( TimeScale < 0 && particleEmitter.time <= 0 && !IsPaused )
		{
			var timing = particleEmitter.Duration - 0.01f;
			SetParticulesTiming( particleEffect, timing );
			particleEmitter.time = timing;
		}
		else
		{
			particleEffect.Paused = IsPaused;
		}
	}

	private void PlayBacking( ParticleEffect particleEffect )
	{
		particleEffect.TimeScale = 0;
		var particleEmitter = particleEffect.Components.Get<ParticleEmitter>();
		var remappedTiming = PlayBack.Remap( 0, 1f, 0, particleEmitter.Duration);
		particleEmitter.time = remappedTiming;
		SetParticulesTiming( particleEffect , remappedTiming );
	}

	private void Restart()
	{
		IsPaused = false;
		IsRestart = false;
		foreach ( var particleEffect in ParticleEffects )
		{
			particleEffect.Clear();
			particleEffect.ResetEmitters();
		}
	}

	private void SetParticulesTiming( ParticleEffect particleEffect, float timing )
	{
		var particleEmitter = particleEffect.Components.Get<ParticleEmitter>();
		particleEmitter.time = timing;
		foreach ( var particule in particleEffect.Particles )
		{
			particule.Age = timing;
		}
	}
}