using System; using System.Collections.Generic; using Cysharp.Threading.Tasks; using UnityEngine; using Debug = UnityEngine.Debug; namespace DanieleMarotta.RiversongCodeShowcase { public abstract class GameSystemGroup : IGameSystem, IInitializable, IUpdatable, IDisposable { private List _initializables = new(); private List _updatables = new(); private List _disposables = new(); public virtual string Name => GetType().Name; public List Systems { get; } = new(); public IUpdateFilter UpdateFilter { get; set; } public void Add(IGameSystem system) { Systems.Add(system); if (system is IInitializable initializable) _initializables.Add(initializable); if (system is IUpdatable updatable) _updatables.Add(updatable); if (system is IDisposable disposable) _disposables.Add(disposable); } public virtual async UniTask InitializeAsync() { SystemSorter.InitializableSorter.Sort(_initializables); SystemSorter.UpdatableSorter.Sort(_updatables); SystemSorter.DisposableSorter.Sort(_disposables); var batches = SystemSorter.InitializableSorter.CreateExecutionBatches(_initializables); foreach (var batch in batches) { var tasks = new UniTask[batch.Count]; for (var i = 0; i < batch.Count; i++) tasks[i] = InitializeAndLogAsync(batch[i]); await UniTask.WhenAll(tasks); } } private static async UniTask InitializeAndLogAsync(IInitializable initializable) { var startTime = Time.unscaledTime; await initializable.InitializeAsync(); LogInitializationTime(initializable, startTime); } private static void LogInitializationTime(IInitializable initializable, float startTime) { if (initializable is GameSystemGroup) return; var elapsed = Time.unscaledTime - startTime; var log = $"Initialized {((IGameSystem)initializable).Name} in {(int)(elapsed * 1000)} ms"; if (elapsed > 0.3f) log = $"{log}"; Debug.Log(log); } public virtual void Update() { foreach (var updatable in _updatables) { if (UpdateFilter != null && !UpdateFilter.CanUpdate(updatable)) continue; updatable.Update(); } } public virtual void Dispose() { foreach (var disposable in _disposables) disposable.Dispose(); } } }