LocationComponent.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading.Tasks;
  4. using MongoDB.Bson.Serialization.Attributes;
  5. namespace ETModel
  6. {
  7. public abstract class LocationTask: Component
  8. {
  9. [BsonIgnore]
  10. public Scene Scene { get; set; }
  11. public abstract void Run();
  12. }
  13. public sealed class LocationLockTask : LocationTask
  14. {
  15. private readonly long key;
  16. private readonly int lockAppId;
  17. private readonly int time;
  18. private readonly TaskCompletionSource<bool> tcs;
  19. public LocationLockTask(long key, int lockAppId, int time)
  20. {
  21. this.key = key;
  22. this.lockAppId = lockAppId;
  23. this.time = time;
  24. this.tcs = new TaskCompletionSource<bool>();
  25. }
  26. public Task<bool> Task
  27. {
  28. get
  29. {
  30. return this.tcs.Task;
  31. }
  32. }
  33. public override void Run()
  34. {
  35. try
  36. {
  37. Scene.GetComponent<LocationComponent>().Lock(this.key, this.lockAppId, this.time);
  38. this.tcs.SetResult(true);
  39. }
  40. catch (Exception e)
  41. {
  42. this.tcs.SetException(e);
  43. }
  44. }
  45. }
  46. public sealed class LocationQueryTask : LocationTask
  47. {
  48. private readonly long key;
  49. private readonly TaskCompletionSource<int> tcs;
  50. public LocationQueryTask(long key)
  51. {
  52. this.key = key;
  53. this.tcs = new TaskCompletionSource<int>();
  54. }
  55. public Task<int> Task
  56. {
  57. get
  58. {
  59. return this.tcs.Task;
  60. }
  61. }
  62. public override void Run()
  63. {
  64. try
  65. {
  66. int location = Scene.GetComponent<LocationComponent>().Get(key);
  67. this.tcs.SetResult(location);
  68. }
  69. catch (Exception e)
  70. {
  71. this.tcs.SetException(e);
  72. }
  73. }
  74. }
  75. public class LocationComponent : Component
  76. {
  77. private readonly Dictionary<long, int> locations = new Dictionary<long, int>();
  78. private readonly Dictionary<long, int> lockDict = new Dictionary<long, int>();
  79. private readonly Dictionary<long, Queue<LocationTask>> taskQueues = new Dictionary<long, Queue<LocationTask>>();
  80. public void Add(long key, int appId)
  81. {
  82. this.locations[key] = appId;
  83. Log.Info($"location add key: {key} appid: {appId}");
  84. // 更新db
  85. //await Game.Scene.GetComponent<DBProxyComponent>().Save(new Location(key, address));
  86. }
  87. public void Remove(long key)
  88. {
  89. Log.Info($"location remove key: {key}");
  90. this.locations.Remove(key);
  91. }
  92. public int Get(long key)
  93. {
  94. this.locations.TryGetValue(key, out int location);
  95. return location;
  96. }
  97. public async void Lock(long key, int lockAppId, int time = 0)
  98. {
  99. if (this.lockDict.ContainsKey(key))
  100. {
  101. Log.Error($"不可能同时存在两次lock, key: {key} lockAppId: {lockAppId}");
  102. return;
  103. }
  104. Log.Info($"location lock key: {key} lockAppId: {lockAppId}");
  105. this.lockDict.Add(key, lockAppId);
  106. // 超时则解锁
  107. if (time > 0)
  108. {
  109. await Game.Scene.GetComponent<TimerComponent>().WaitAsync(time);
  110. int saveAppId = 0;
  111. if (!this.lockDict.TryGetValue(key, out saveAppId))
  112. {
  113. return;
  114. }
  115. if (saveAppId != lockAppId)
  116. {
  117. Log.Error($"timeout unlock appid is different {saveAppId} {lockAppId}");
  118. return;
  119. }
  120. Log.Info($"location timeout unlock key: {key} time: {time}");
  121. this.UnLock(key);
  122. }
  123. }
  124. public void UpdateAndUnLock(long key, int unLockAppId, int value)
  125. {
  126. int lockAppId = 0;
  127. this.lockDict.TryGetValue(key, out lockAppId);
  128. if (lockAppId != unLockAppId)
  129. {
  130. Log.Error($"unlock appid is different {lockAppId} {unLockAppId}" );
  131. }
  132. Log.Info($"location unlock key: {key} unLockAppId: {unLockAppId} new: {value}");
  133. this.locations[key] = value;
  134. this.UnLock(key);
  135. }
  136. private void UnLock(long key)
  137. {
  138. this.lockDict.Remove(key);
  139. if (!this.taskQueues.TryGetValue(key, out Queue<LocationTask> tasks))
  140. {
  141. return;
  142. }
  143. while (true)
  144. {
  145. if (tasks.Count <= 0)
  146. {
  147. this.taskQueues.Remove(key);
  148. return;
  149. }
  150. if (this.lockDict.ContainsKey(key))
  151. {
  152. return;
  153. }
  154. LocationTask task = tasks.Dequeue();
  155. task.Run();
  156. }
  157. }
  158. public Task<bool> LockAsync(long key, int appId, int time)
  159. {
  160. if (!this.lockDict.ContainsKey(key))
  161. {
  162. this.Lock(key, appId, time);
  163. return Task.FromResult(true);
  164. }
  165. LocationLockTask task = new LocationLockTask(key, appId, time);
  166. this.AddTask(key, task);
  167. return task.Task;
  168. }
  169. public Task<int> GetAsync(long key)
  170. {
  171. if (!this.lockDict.ContainsKey(key))
  172. {
  173. this.locations.TryGetValue(key, out int location);
  174. Log.Info($"location get key: {key} {location}");
  175. return Task.FromResult(location);
  176. }
  177. LocationQueryTask task = new LocationQueryTask(key);
  178. this.AddTask(key, task);
  179. return task.Task;
  180. }
  181. public void AddTask(long key, LocationTask task)
  182. {
  183. if (!this.taskQueues.TryGetValue(key, out Queue<LocationTask> tasks))
  184. {
  185. tasks = new Queue<LocationTask>();
  186. this.taskQueues[key] = tasks;
  187. }
  188. task.Scene = this.GetParent<Scene>();
  189. tasks.Enqueue(task);
  190. }
  191. public override void Dispose()
  192. {
  193. if (this.IsDisposed)
  194. {
  195. return;
  196. }
  197. base.Dispose();
  198. }
  199. }
  200. }