// ReSharper disable MemberCanBePrivate.Global using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using RGB.NET.Core.Exceptions; namespace RGB.NET.Core { /// /// Represents an generic effect-target. /// /// public abstract class AbstractEffectTarget : IEffectTarget where T : IEffectTarget { #region Properties & Fields /// /// Gets a list of storing the attached effects. /// protected IList EffectTimes { get; } = new List(); /// /// Gets all attached to this . /// protected IList> InternalEffects => EffectTimes.Select(x => x.Effect).Cast>().ToList(); /// public IEnumerable> Effects => new ReadOnlyCollection>(InternalEffects); /// /// Gets the strongly-typed target used for the . /// protected abstract T EffectTarget { get; } #endregion #region Methods /// /// Updates all added to this . /// public virtual void UpdateEffects() { lock (InternalEffects) { for (int i = EffectTimes.Count - 1; i >= 0; i--) { long currentTicks = DateTime.Now.Ticks; EffectTimeContainer effectTime = EffectTimes[i]; if (!effectTime.Effect.IsEnabled) { effectTime.TicksAtLastUpdate = currentTicks; continue; } double deltaTime; if (effectTime.TicksAtLastUpdate < 0) { effectTime.TicksAtLastUpdate = currentTicks; deltaTime = 0; } else deltaTime = (currentTicks - effectTime.TicksAtLastUpdate) / 10000000.0; effectTime.TicksAtLastUpdate = currentTicks; effectTime.Effect.Update(deltaTime); if (effectTime.Effect.IsDone) EffectTimes.RemoveAt(i); } } } /// /// Adds an . /// /// The to add. public virtual void AddEffect(IEffect effect) { if (EffectTimes.Any(x => x.Effect == effect)) return; if (!effect.CanBeAppliedTo(EffectTarget)) throw new EffectException($"Failed to add effect.\r\n" + $"The effect of type '{effect.GetType()}' can't be applied to the target of type '{EffectTarget.GetType()}'."); effect.OnAttach(EffectTarget); EffectTimes.Add(new EffectTimeContainer(effect, -1)); } /// /// Removes an . /// /// The to remove. public virtual void RemoveEffect(IEffect effect) { EffectTimeContainer effectTimeToRemove = EffectTimes.FirstOrDefault(x => x.Effect == effect); if (effectTimeToRemove == null) return; effect.OnDetach(EffectTarget); EffectTimes.Remove(effectTimeToRemove); } /// public bool HasEffect(IEffect effect) { return InternalEffects.Contains(effect); } /// public bool HasEffect() where TEffect : IEffect { return InternalEffects.Any(x => x.GetType() == typeof(TEffect)); } #endregion } }