using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Timers; using Cysharp.Threading.Tasks; using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif namespace BITKit { [Serializable] public class IntervalTick:ITicker { [SerializeField] private float interval; public ulong TickCount=>IntervalTickService.GetTickCount(interval); public void Add(Action action) { throw new NotImplementedException(); } public void Add(Action action) { IntervalTickService.Add(action, interval); } public void Remove(Action action) { IntervalTickService.Remove(action, interval); } public void ManualTick(float delta) { throw new NotImplementedException(); } } public class IntervalTickService { [RuntimeInitializeOnLoadMethod] private static void Reload() { foreach (var x in _Timers.Values) { x.Stop(); x.Dispose(); } _Timers.Clear(); _Actions.Clear(); _CreateTimes.Clear(); } private class DelegateWrapper { public event Action Tick; public float Interval { get; set; } public async void Invoke(object sender, ElapsedEventArgs args) { await UniTask.SwitchToMainThread(); #if UNITY_EDITOR if (EditorApplication.isPlaying is false || EditorApplication.isPaused) { return; } #endif try { Tick?.Invoke(Interval); } catch (Exception e) { BIT4Log.LogException(e); } } } public static void Add(Action action, float interval) { var timer = _Timers.GetOrAdd(interval, Create); var action1 = _Actions.GetOrAdd(interval, CreateAction); action1.Tick += action; } public static void Remove(Action action, float interval) { var timer = _Timers.GetOrAdd(interval, Create); var action1 = _Actions.GetOrAdd(interval, CreateAction); action1.Tick -= action; } public static ulong GetTickCount(float interval) { return GameTickService.TickCount - _CreateTimes[interval]; } private static readonly ConcurrentDictionary _Timers = new(); private static readonly ConcurrentDictionary _Actions = new(); private static readonly ConcurrentDictionary _CreateTimes = new(); private static Timer Create(float interval) { var totalMilliseconds = TimeSpan.FromSeconds(interval).TotalMilliseconds; var timer = new Timer() { Interval = totalMilliseconds, }; _CreateTimes.TryAdd(interval, GameTickService.TickCount); var action = _Actions.GetOrAdd(interval, CreateAction); timer.Elapsed += action.Invoke; timer.Start(); BIT4Log.Log($"已创建Tick,Interval[{totalMilliseconds}]"); return timer; } private static DelegateWrapper CreateAction(float interval)=>new() { Interval = interval, }; } }