using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using ETModel; namespace ETHotfix { [ObjectSystem] public class ActorMessageSenderAwakeSystem : AwakeSystem { public override void Awake(ActorMessageSender self) { self.LastSendTime = TimeHelper.Now(); self.Tcs = null; self.FailTimes = 0; self.MaxFailTimes = 5; self.ActorId = 0; self.Error = 0; } } [ObjectSystem] public class ActorMessageSenderAwake2System : AwakeSystem { public override void Awake(ActorMessageSender self, long actorId) { self.LastSendTime = TimeHelper.Now(); self.Tcs = null; self.FailTimes = 0; self.MaxFailTimes = 0; self.ActorId = actorId; self.Error = 0; } } [ObjectSystem] public class ActorMessageSenderStartSystem : StartSystem { public override async void Start(ActorMessageSender self) { if (self.ActorId == 0) { self.ActorId = await Game.Scene.GetComponent().Get(self.Id); } self.Address = Game.Scene.GetComponent() .Get(IdGenerater.GetAppIdFromId(self.ActorId)) .GetComponent().IPEndPoint; self.UpdateAsync(); } } [ObjectSystem] public class ActorMessageSenderDestroySystem : DestroySystem { public override void Destroy(ActorMessageSender self) { while (self.WaitingTasks.Count > 0) { ActorTask actorTask = self.WaitingTasks.Dequeue(); actorTask.Tcs?.SetException(new RpcException(self.Error, "")); } self.LastSendTime = 0; self.Address = null; self.ActorId = 0; self.FailTimes = 0; var t = self.Tcs; self.Tcs = null; t?.SetResult(new ActorTask()); } } public static class ActorMessageSenderEx { private static void Add(this ActorMessageSender self, ActorTask task) { if (self.IsDisposed) { throw new Exception("ActorProxy Disposed! dont hold actorproxy"); } self.WaitingTasks.Enqueue(task); // failtimes > 0表示正在重试,这时候不能加到正在发送队列 if (self.FailTimes == 0) { self.AllowGet(); } } private static void AllowGet(this ActorMessageSender self) { if (self.Tcs == null || self.WaitingTasks.Count <= 0) { return; } ActorTask task = self.WaitingTasks.Peek(); var t = self.Tcs; self.Tcs = null; t.SetResult(task); } private static Task GetAsync(this ActorMessageSender self) { if (self.WaitingTasks.Count > 0) { ActorTask task = self.WaitingTasks.Peek(); return Task.FromResult(task); } self.Tcs = new TaskCompletionSource(); return self.Tcs.Task; } public static async void UpdateAsync(this ActorMessageSender self) { try { while (true) { ActorTask actorTask = await self.GetAsync(); if (self.IsDisposed) { return; } await self.RunTask(actorTask); } } catch (Exception e) { Log.Error(e); } } private static async Task RunTask(this ActorMessageSender self, ActorTask task) { Session session = Game.Scene.GetComponent().Get(self.Address); task.ActorMessage.ActorId = self.ActorId; IResponse response = await session.Call(task.ActorMessage); // 发送成功 switch (response.Error) { case ErrorCode.ERR_Success: self.LastSendTime = TimeHelper.Now(); self.FailTimes = 0; self.WaitingTasks.Dequeue(); task.Tcs?.SetResult(response); return; case ErrorCode.ERR_NotFoundActor: // 如果没找到Actor,重试 ++self.FailTimes; // 失败MaxFailTimes次则清空actor发送队列,返回失败 if (self.FailTimes > self.MaxFailTimes) { // 失败直接删除actorproxy Log.Info($"actor send message fail, actorid: {self.Id}"); self.Error = response.Error; self.GetParent().Remove(self.Id); return; } // 等待1s再发送 await Game.Scene.GetComponent().WaitAsync(1000); self.ActorId = await Game.Scene.GetComponent().Get(self.Id); self.Address = Game.Scene.GetComponent() .Get(IdGenerater.GetAppIdFromId(self.ActorId)) .GetComponent().IPEndPoint; self.AllowGet(); return; default: // 其它错误 self.Error = response.Error; self.GetParent().Remove(self.Id); return; } } public static void Send(this ActorMessageSender self, IActorMessage message) { ActorTask task = new ActorTask(message); self.Add(task); } public static Task Call(this ActorMessageSender self, IActorRequest request) { TaskCompletionSource tcs = new TaskCompletionSource(); ActorTask task = new ActorTask(request, tcs); self.Add(task); return task.Tcs.Task; } public static string DebugQueue(this ActorMessageSender self, Queue tasks) { string s = ""; foreach (ActorTask task in tasks) { s += $" {task.ActorMessage.GetType().Name}"; } return s; } } }