using CommonLang; using System; using System.IO; using System.Collections.Generic; using CommonAI.Zone.ZoneEditor; using CommonLang.Log; using CommonAI.Zone.Attributes; using CommonAI; using CommonAI.ZoneClient; using System.Threading; namespace Pomelo.DotNetClient.NetClient { public interface INetClient { EditorTemplates DataRoot { get; } void SendBattleMessage(CommonAI.Zone.Action action); } public abstract class BaseNetClient : IDisposable, INetClient where GATE : PomeloClient where GAME : PomeloClient where BATTLE : BaseBattleClient { public GATE GateSocket { get; private set; } public GAME GameSocket { get; private set; } public BATTLE BattleClient { get; protected set; } public CommonAI.ZoneClient.ZoneActor BattleActor { get { if (BattleClient != null) { return BattleClient.Actor; } return null; } } public abstract EditorTemplates DataRoot { get; } protected readonly Logger log; protected readonly List mUnhandledList = new List(); protected BATTLE NextBattleClient; protected SynchronizedBattleCodec mBattleCodec; //协同类任务列表// private readonly SyncMessageQueue mTasks = new SyncMessageQueue(); public BaseNetClient(GATE gate, GAME game) { this.log = LoggerFactory.GetLogger(GetType().Name); this.GateSocket = gate; this.GameSocket = game; this.GameSocket.NetWorkHandlePushImmediately += notify_OnBattleMessageReceivedImmediately; //this.QueueTask(InitCodec); InitCodec(); } public void InitCodec() { if (this.DataRoot != null && this.DataRoot.Templates != null) { this.mBattleCodec = new SynchronizedBattleCodec(this.DataRoot.Templates); } } //------------------------------------------------------------------------------------------------- #region _主动调用_ /// /// 提交一个任务让主线程处理,协同程序 /// /// public void QueueTask(Action action) { mTasks.Enqueue(action); } public void UpdateSocket(float delTime) { mTasks.ProcessMessages((act) => { act.Invoke(); }); this.GateSocket.update(delTime); this.GameSocket.update(delTime); } public void DoUpdateSend() { this.GateSocket.DoSendUpdate(); this.GameSocket.DoSendUpdate(); } public void UpdateBattleClient(int intervalMS) { if (BattleClient != null) { BattleClient.BeginUpdate(intervalMS); BattleClient.Update(); } } public void CreateNextBattleClient() { this.NextBattleClient = CreateBattle(); } public void Disconnect() { log.Debug("====socket ==BaseNetClient== Disconnect"); try { ClearBattle(); } catch (Exception err) { log.Error(err.Message, err); } if (this.GateSocket.IsConnected) { try { this.GateSocket.disconnect(); } catch (Exception err) { log.Error(err.Message, err); } } if (this.GameSocket.IsConnected) { try { this.GameSocket.disconnect(); } catch (Exception err) { log.Error(err.Message, err); } } } public void Dispose() { this.mOnBeginEnterScene = null; this.mOnEnterScene = null; this.mOnLeaveScene = null; this.mOnBattlePlayerReady = null; this.Disconnect(); try { this.GateSocket.Dispose(); } catch (Exception err) { log.Error(err.Message, err); } try { this.GameSocket.Dispose(); } catch (Exception err) { log.Error(err.Message, err); } } #endregion //------------------------------------------------------------------------------------------------- #region _Events_ private Action mOnBeginEnterScene; private Action mOnEnterScene; private Action mOnLeaveScene; private Action mOnBattlePlayerReady; [EventTriggerDescAttribute("BattleClient已创建,一般用于开始加载场景操作,场景加载完毕,调用GameSocket.Invoke_ChangeScene")] public event Action OnBeginEnterScene { add { mOnBeginEnterScene += value; } remove { mOnBeginEnterScene -= value; } } [EventTriggerDescAttribute("当单位已经进入场景时触发【角色已经进入战斗服】")] public event Action OnEnterScene { add { mOnEnterScene += value; } remove { mOnEnterScene -= value; } } [EventTriggerDescAttribute("当单离开场景时触发【收到PlayerLeaveScene】")] public event Action OnLeaveScene { add { mOnLeaveScene += value; } remove { mOnLeaveScene -= value; } } [EventTriggerDescAttribute("玩家单位已准备完毕【确保战斗服和游戏服可操作】")] public event Action OnBattlePlayerReady { add { mOnBattlePlayerReady += value; } remove { mOnBattlePlayerReady -= value; } } #endregion //------------------------------------------------------------------------------------------------- #region _Request Http_ /// /// HTTP同步请求. /// /// /// /// public string RequestHttpPost(string url, Dictionary args) { string requestUrl = url + '?'; foreach (KeyValuePair arg in args) { requestUrl += arg.Key + '=' + arg.Value + '&'; } requestUrl = requestUrl.Remove(requestUrl.Length - 1); System.Uri uri = new System.Uri(requestUrl); string result = CommonNetwork.Http.WebClient.Post(uri); return result; } /// /// HTTP异步请求. /// /// /// /// public void RequestHttpPostAsync(string url, Dictionary args, CommonNetwork.Http.HttpPostHandler handler) { string requestUrl = url + '?'; foreach (KeyValuePair arg in args) { requestUrl += arg.Key + '=' + arg.Value + '&'; } requestUrl = requestUrl.Remove(requestUrl.Length - 1); System.Uri uri = new System.Uri(requestUrl); CommonNetwork.Http.WebClient.PostAsync(uri, System.Text.Encoding.UTF8, (string result) => { if (handler != null) { QueueTask(() => { handler.Invoke(result); }); } }); } #endregion //------------------------------------------------------------------------------------------------- #region _BattleClient_ public abstract BATTLE CreateBattle(); public virtual void ClearBattle() { if (this.NextBattleClient != null) { this.NextBattleClient.Dispose(); this.NextBattleClient = null; } mUnhandledList.Clear(); } public abstract void SendBattleMessage(CommonAI.Zone.Action action); /// /// ChangeAreaPush 或 BindPlayer 后回调 /// 进入战斗场景开始. /// public void BattleClientInitBegin() { if (this.BattleClient != null) { this.BattleClient.Dispose(); this.BattleClient = null; } if (NextBattleClient == null) { BattleClient = this.CreateBattle(); } else { BattleClient = NextBattleClient; } NextBattleClient = null; if (mUnhandledList.Count > 0) { foreach (var msg in mUnhandledList) { this.BattleClient.OnReceivedBattleMessage(msg as CommonLang.Protocol.IMessage); } mUnhandledList.Clear(); } if (mOnBeginEnterScene != null) { mOnBeginEnterScene.Invoke(BattleClient); } } /// /// Request_EnterScene 回调 /// 进入战斗场景完成.(客户端加载完成) /// public void BattleClientInitFinish() { if (BattleClient != null) { if (mOnEnterScene != null) { mOnEnterScene.Invoke(BattleClient); } BattleClient.QueueTask(BattlePlayerReady); } } private void BattlePlayerReady(CommonAIClient.Client.AbstractBattle battle) { if (!battle.Layer.IsDesposed) { if (battle.Actor != null) { if (mOnBattlePlayerReady != null) { mOnBattlePlayerReady.Invoke(battle.Layer, battle.Actor); } } else { BattleClient.QueueTask(BattlePlayerReady); } } } /// /// 战斗协议回调.(直接从网络线程回调) /// /// protected virtual bool notify_OnBattleMessageReceivedImmediately(string route, Stream msg) { //log.Debug("socket ===== notify_OnBattleMessageReceivedImmediately ThreadID: " + Thread.CurrentThread.ManagedThreadId); if (route == "area.playerPush.battleClearPush") { this.NextBattleClient = this.CreateBattle(); if (mOnLeaveScene != null) { mOnLeaveScene.Invoke(BattleClient); } return true; } else if (route == "area.playerPush.battleEventPush") { object data; try { if (mBattleCodec == null) { log.Error("decode err: mBattleCodec is null"); return false; } if (msg == null) { log.Error("decode err: msg is null!"); return false; } if (mBattleCodec.doDecode(msg, out data)) { if (data is PlayerLeaveScene) { //this.NextBattleClient = this.CreateBattle(); //this.QueueTask(() => { if (mOnLeaveScene != null) { mOnLeaveScene.Invoke(BattleClient); } }); } else { if (NextBattleClient != null || this.BattleClient == null) { mUnhandledList.Add(data); } else { this.BattleClient.OnReceivedBattleMessage(data as CommonLang.Protocol.IMessage); } } } else { log.Error("[doDecodeBin] error:" + msg.ToString()); } } catch (Exception err) { log.Error("[doDecodeBin] error:" + err.Message, err); } return true; } return false; } #endregion } }