using System; using System.Collections.Generic; using System.Linq; using UnityEngine; using Valve.VR.InteractionSystem; namespace SicknessReduction.Visual.Vignetting { public interface IRestrectionSuggestor { float Suggestion { get; } } public abstract class RestrictionSuggestor : IRestrectionSuggestor { protected readonly float threshold; protected readonly float minRestriction; protected readonly float maxRestriction; protected readonly float maxValue; protected RestrictionSuggestor(float threshold, float minRestriction, float maxRestriction, float maxValue) { this.threshold = threshold; this.minRestriction = minRestriction; this.maxRestriction = maxRestriction; this.maxValue = maxValue; } protected float LerpedSuggestion(float value) => Mathf.Lerp(minRestriction, maxRestriction, (value - threshold) / (maxValue - threshold)); public abstract float Suggestion { get; } } public class ValueBasedRestrictionSuggestor : RestrictionSuggestor { public override float Suggestion { get { var abs = Mathf.Abs(Value); return abs < threshold ? 0f : LerpedSuggestion(abs); } } public float Value { set; get; } = 0f; public ValueBasedRestrictionSuggestor(float threshold, float minRestriction, float maxRestriction, float maxValue) : base(threshold, minRestriction, maxRestriction, maxValue) { } } public class ValueAndTimeBasedRestrictionSuggestor : RestrictionSuggestor { private readonly float tolerance; private readonly float timespan; private readonly Dictionary values = new Dictionary(); private float value; public ValueAndTimeBasedRestrictionSuggestor(float threshold, float minRestriction, float maxRestriction, float maxValue, float tolerance, float timespan) : base(threshold, minRestriction, maxRestriction, maxValue) { this.tolerance = tolerance; this.timespan = timespan; } public override float Suggestion { get { var abs = Mathf.Abs(value); var stable = !values.Values.Any(v => Mathf.Abs(v - value) > tolerance); return abs < threshold || stable ? 0f : LerpedSuggestion(abs); } } public void UpdateValue(float v) { value = v; var t = Time.time; values[t] = v; var keys = values.Keys.Where(k => t - k > timespan).ToList(); keys.ForEach(k => values.Remove(k)); } } public abstract class QueueBasedRestrictionSuggestor : RestrictionSuggestor { protected Queue> values; protected int bufferSize; public QueueBasedRestrictionSuggestor(float threshold, float minRestriction, float maxRestriction, float maxValue, int bufferSize = 10) : base(threshold, minRestriction, maxRestriction, maxValue) { this.bufferSize = bufferSize; values = new Queue>(bufferSize); } public void AddValue(T value) { if (values.Count >= bufferSize) { values.Dequeue(); } values.Enqueue(new Tuple(Time.time, value)); } } public class QueueBasedRestrictionSuggestorFloat : QueueBasedRestrictionSuggestor { public QueueBasedRestrictionSuggestorFloat(float threshold, float minRestriction, float maxRestriction, float maxValue, int bufferSize = 10) : base(threshold, minRestriction, maxRestriction, maxValue, bufferSize) { } public override float Suggestion { get { var perSecond = new float[values.Count]; var index = 0; var previousValue = values.FirstOrDefault(); foreach (var value in values) { // ReSharper disable once PossibleNullReferenceException var timeDif = value.Item1 - previousValue.Item1; perSecond[index] = timeDif == 0 ? 0f : Mathf.Abs(value.Item2 - previousValue.Item2) / timeDif; previousValue = value; index++; } var avg = perSecond.Length == 0 ? 0f : perSecond.Average(); return avg < threshold ? 0f : LerpedSuggestion(avg); } } } public class QueueBasedRestrictionSuggestorVector3 : QueueBasedRestrictionSuggestor { public QueueBasedRestrictionSuggestorVector3(float threshold, float minRestriction, float maxRestriction, float maxValue, int bufferSize = 10) : base(threshold, minRestriction, maxRestriction, maxValue, bufferSize) { } public override float Suggestion { get { var perSecond = new Vector3[values.Count]; var index = 0; var previousValue = values.FirstOrDefault(); foreach (var value in values) { // ReSharper disable once PossibleNullReferenceException var timeDif = value.Item1 - previousValue.Item1; perSecond[index] = timeDif == 0 ? Vector3.zero : Helpers.Vector3Abs(value.Item2 - previousValue.Item2) / timeDif; previousValue = value; index++; } var avg = perSecond.Aggregate(Vector3.zero, (agg, v) => agg + v) / perSecond.Length; var max = Helpers.GetMaxComponent(avg); return max < threshold ? 0f : LerpedSuggestion(max); } } } }