using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using ETModel; namespace ETHotfix { [ObjectSystem] public class ActorLocationSenderAwakeSystem : AwakeSystem { public override void Awake(ActorLocationSender self, long id) { self.LastSendTime = TimeHelper.Now(); self.Id = id; self.Tcs = null; self.FailTimes = 0; self.ActorId = 0; } } [ObjectSystem] public class ActorLocationSenderStartSystem : StartSystem { public override async void Start(ActorLocationSender self) { self.ActorId = await Game.Scene.GetComponent().Get(self.Id); self.Address = StartConfigComponent.Instance .Get(IdGenerater.GetAppIdFromId(self.ActorId)) .GetComponent().IPEndPoint; self.UpdateAsync(); } } [ObjectSystem] public class ActorLocationSenderDestroySystem : DestroySystem { public override void Destroy(ActorLocationSender self) { self.RunError(ErrorCode.ERR_ActorRemove); self.Id = 0; self.LastSendTime = 0; self.Address = null; self.ActorId = 0; self.FailTimes = 0; self.Tcs = null; } } public static class ActorLocationSenderHelper { private static void Add(this ActorLocationSender self, ActorTask task) { if (self.IsDisposed) { throw new Exception("ActorLocationSender Disposed! dont hold ActorMessageSender"); } self.WaitingTasks.Enqueue(task); // failtimes > 0表示正在重试,这时候不能加到正在发送队列 if (self.FailTimes == 0) { self.AllowGet(); } } public static void RunError(this ActorLocationSender self, int errorCode) { while (self.WaitingTasks.Count > 0) { ActorTask actorTask = self.WaitingTasks.Dequeue(); actorTask.Tcs?.SetException(new RpcException(errorCode, "")); } self.WaitingTasks.Clear(); } private static void AllowGet(this ActorLocationSender 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 ActorLocationSender 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 ActorLocationSender self) { try { long instanceId = self.InstanceId; while (true) { if (self.InstanceId != instanceId) { return; } ActorTask actorTask = await self.GetAsync(); if (self.InstanceId != instanceId) { return; } if (actorTask.ActorRequest == null) { return; } await self.RunTask(actorTask); } } catch (Exception e) { Log.Error(e); } } private static async Task RunTask(this ActorLocationSender self, ActorTask task) { ActorMessageSender actorMessageSender = Game.Scene.GetComponent().Get(self.ActorId); IActorResponse response = await actorMessageSender.Call(task.ActorRequest); // 发送成功 switch (response.Error) { case ErrorCode.ERR_NotFoundActor: // 如果没找到Actor,重试 ++self.FailTimes; // 失败MaxFailTimes次则清空actor发送队列,返回失败 if (self.FailTimes > ActorLocationSender.MaxFailTimes) { // 失败直接删除actorproxy Log.Info($"actor send message fail, actorid: {self.Id}"); self.RunError(response.Error); self.GetParent().Remove(self.Id); return; } // 等待0.5s再发送 await Game.Scene.GetComponent().WaitAsync(500); self.ActorId = await Game.Scene.GetComponent().Get(self.Id); self.Address = StartConfigComponent.Instance .Get(IdGenerater.GetAppIdFromId(self.ActorId)) .GetComponent().IPEndPoint; self.AllowGet(); return; case ErrorCode.ERR_ActorNoMailBoxComponent: self.RunError(response.Error); self.GetParent().Remove(self.Id); return; default: self.LastSendTime = TimeHelper.Now(); self.FailTimes = 0; self.WaitingTasks.Dequeue(); task.Tcs?.SetResult(response); return; } } public static void Send(this ActorLocationSender self, IActorLocationMessage request) { if (request == null) { throw new Exception($"actor send message is null"); } ActorTask task = new ActorTask(request); self.Add(task); } public static Task Call(this ActorLocationSender self, IActorLocationRequest request) { if (request == null) { throw new Exception($"actor call message is null"); } TaskCompletionSource tcs = new TaskCompletionSource(); ActorTask task = new ActorTask(request, tcs); self.Add(task); return task.Tcs.Task; } } }