using System.Collections; using System.Collections.Generic; using UnityEngine; using Starpelly; namespace HeavenStudio.Games { public class CallAndResponseHandler { public struct CallAndResponseEventParam { public string propertyName; public dynamic value; public CallAndResponseEventParam(string propertyName, dynamic value) { this.propertyName = propertyName; this.value = value; } } public class CallAndResponseEvent { public double beat; public float length; public double relativeBeat; // this beat is relative to the intervalStartBeat public Dictionary DynamicData; //if you need more properties for your queued event public string tag; public CallAndResponseEvent(double beat, double relativeBeat, string tag, float length = 0) { this.beat = beat; this.length = length; this.relativeBeat = relativeBeat; DynamicData = new Dictionary(); this.tag = tag; this.length = length; } public void CreateProperty(string name, dynamic defaultValue) { if (!DynamicData.ContainsKey(name)) { DynamicData.Add(name, defaultValue); } } public dynamic this[string propertyName] { get { if (DynamicData.ContainsKey(propertyName)) { return DynamicData[propertyName]; } else { Debug.LogWarning("This property does not exist on this callAndResponse event."); return null; } } set { if (DynamicData.ContainsKey(propertyName)) { DynamicData[propertyName] = value; } else { Debug.LogError($"This callAndRespone event does not have a property named {propertyName}! Attempted to insert value of type {value.GetType()}"); } } } } public double intervalStartBeat = -1; // the first beat of the interval public float intervalLength = -1; // the duration of the interval in beats public List queuedEvents = new List(); /// /// Returns the normalized progress of the interval /// public float GetIntervalProgress(float lengthOffset = 0) { return Conductor.instance.GetPositionFromBeat(intervalStartBeat, intervalLength - lengthOffset); } public float GetIntervalProgressFromBeat(double beat, float lengthOffset = 0) { return (float)((beat - intervalStartBeat) / Mathf.Max(1, intervalLength - lengthOffset)); } /// /// Is the interval currently on-going? /// public bool IntervalIsActive() { float progress = GetIntervalProgress(); return progress >= 0 && progress <= 1; } /// /// Starts the interval. /// /// The interval start beat. /// The length of the interval. public void StartInterval(double beat, float length) { if (queuedEvents.Count > 0) queuedEvents.Clear(); intervalStartBeat = beat; intervalLength = length; } /// /// Adds an event to the queued events list. /// /// The current beat. /// The length of the event.> /// The tag of the event. /// Extra properties to add to the event. public void AddEvent(double beat, float length = 0, string tag = "", List crParams = null) { CallAndResponseEvent addedEvent = new(beat, beat - intervalStartBeat, tag, length); if (crParams != null && crParams.Count > 0) { foreach (var param in crParams) { addedEvent.CreateProperty(param.propertyName, param.value); } } queuedEvents.Add(addedEvent); } /// /// Check if an event exists at beat. /// /// The beat to check. public bool EventExistsAtBeat(double beat) { if (queuedEvents.Count == 0) { return false; } CallAndResponseEvent foundEvent = queuedEvents.Find(x => x.beat == beat); return foundEvent != null; } /// /// Check if an event exists at relativeBeat. /// /// The relativeBeat to check. public bool EventExistsAtRelativetBeat(double relativeBeat) { if (queuedEvents.Count == 0) { return false; } CallAndResponseEvent foundEvent = queuedEvents.Find(x => x.relativeBeat == relativeBeat); return foundEvent != null; } } }