using System; using System.Collections.Generic; using Fantasy.Async; using NBC; using Fantasy.Entitas; using Fantasy.Entitas.Interface; namespace NBF.Fishing2 { public static class WaitTypeError { public const int Success = 0; public const int Destroy = 1; public const int Cancel = 2; public const int Timeout = 3; } public interface IWaitType { int Error { get; set; } } public class ObjectWait : Entity { public Dictionary> tcsDict = new(); } public static class ObjectWaitSystem { public class ObjectWaitAwakeSystem : AwakeSystem { protected override void Awake(ObjectWait self) { self.tcsDict.Clear(); } } public class ObjectWaitDestroySystem : DestroySystem { protected override void Destroy(ObjectWait self) { foreach (var p in self.tcsDict) { foreach (object v in p.Value) { ((IDestroyRun)v).SetResult(); } } self.tcsDict.Clear(); } } private interface IDestroyRun { void SetResult(); } private class ResultCallback : IDestroyRun where K : struct, IWaitType { private FTask tcs; public ResultCallback() { this.tcs = FTask.Create(true); } public bool IsDisposed { get { return this.tcs == null; } } public FTask Task => this.tcs; public void SetResult(K k) { var t = tcs; this.tcs = null; t.SetResult(k); } public void SetResult() { var t = tcs; this.tcs = null; t.SetResult(new K() { Error = WaitTypeError.Destroy }); } } public static async FTask Wait(this ObjectWait self) where T : struct, IWaitType { ResultCallback tcs = new ResultCallback(); FCancellationToken cancellationToken = FCancellationToken.ToKen; self.Add(typeof(T), tcs); T ret; try { cancellationToken?.Add(CancelAction); ret = await tcs.Task; } finally { cancellationToken?.Remove(CancelAction); } return ret; void CancelAction() { self.Notify(new T() { Error = WaitTypeError.Cancel }); } } public static void Notify(this ObjectWait self, T obj) where T : struct, IWaitType { Type type = typeof(T); if (!self.tcsDict.TryGetValue(type, out var tcsList) || tcsList.Count == 0) { return; } foreach (var tcs in tcsList) { ((ResultCallback)tcs).SetResult(obj); } tcsList.Clear(); } private static void Add(this ObjectWait self, Type type, object obj) { if (self.tcsDict.TryGetValue(type, out var list)) { list.Add(obj); } else { self.tcsDict.Add(type, new List { obj }); } } } }