using DeepCore;
using DeepCore.FuckPomeloClient;
using DeepCore.IO;
using DeepCore.Log;
using DeepMMO.Data;
using DeepMMO.Protocol;
using DeepMMO.Protocol.Client;
using System;
using System.Collections.Generic;
using DeepCore.GameData.Helper;
using DeepCore.GameEvent;
namespace DeepMMO.Client
{
public partial class RPGClient : Disposable
{
protected readonly Logger log;
protected readonly IExternalizableFactory codec;
protected readonly ClientInfo clientInfo;
protected readonly PomeloClient gate_client;
protected readonly PomeloClient game_client;
public IExternalizableFactory NetCodec { get { return codec; } }
public PomeloClient GateClient { get { return gate_client; } }
public PomeloClient GameClient { get { return game_client; } }
public int CurrentPing { get; private set; }
public bool IsAutoUpdateBattle { get; set; }
public int ConnectTimeOut { get; set; }
///
/// 曾经链接到游戏后掉线
///
public bool IsGameDisconnected
{
get { return (this.GameClient.IsConnected == false && this.last_EnterGameResponse != null); }
}
public RPGClient(IExternalizableFactory codec, ClientInfo client)
{
this.CurrentPing = 0;
this.IsAutoUpdateBattle = false;
this.ConnectTimeOut = 15000;
this.log = LoggerFactory.GetLogger(GetType().Name);
this.codec = codec;
this.clientInfo = client;
this.gate_client = new PomeloClient(codec);
this.game_client = new PomeloClient(codec);
this.game_client.NetHandleResponseImmediately += Game_client_AsyncHandleResponseImmediately;
this.game_client.NetHandleBodyImmediately += Game_client_AsyncHandleBodyImmediately;
this.game_client.OnRequestEnd += Game_client_OnRequestEnd1;
this.game_client.NetError += Game_client_AsyncError;
this.gate_client.NetError += Gate_client_AsyncError;
this.ping_codec = codec.GetCodec(typeof(ClientPing));
this.pong_codec = codec.GetCodec(typeof(ClientPong));
this.Gate_Init();
this.Connect_Init();
this.Area_Init();
this.OnCreateModules();
}
protected virtual void OnCreateModules()
{
AddModule(new EventModule(this));
}
public void Disconnect()
{
this.gate_client.Disconnect();
this.game_client.Disconnect();
}
//----------------------------------------------------------------------------------------------------------
private readonly TypeCodec pong_codec;
private readonly TypeCodec ping_codec;
private void Game_client_AsyncHandleResponseImmediately(DeepCore.FuckPomelo.IRecvMessage protocol)
{
if (protocol.MsgRoute == pong_codec.MessageID)
{
var pong = protocol.ReadBody() as ClientPong;
this.CurrentPing = (int)(DateTime.Now - pong.time).TotalMilliseconds;
}
}
private void Game_client_AsyncHandleBodyImmediately(object message)
{
// if (message is Response response)
// {
// response.EndRead();
// }
}
private void Game_client_OnRequestEnd1(string route, PomeloException error, ISerializable response, object option)
{
if (response is Response rsp)
{
rsp.EndRead();
}
}
//----------------------------------------------------------------------------------------------------------
#region Modules
private HashSet mModules = new HashSet();
public void AddModule(RPGClientModule module)
{
mModules.Add(module);
}
public void RemoveModule(RPGClientModule module)
{
mModules.Remove(module);
module.Dispose();
}
public T GetModel(Predicate predicate = null) where T : RPGClientModule
{
foreach (var m in mModules)
{
if (m is T model && (predicate == null || predicate.Invoke(model)))
{
return model;
}
}
return null;
}
protected virtual void OnGameClientConnected(object arg1, ISerializable arg2)
{
}
protected virtual void OnGameClientEntered(ClientEnterGameResponse enter)
{
foreach (var module in mModules)
{
module.OnStart();
}
}
protected virtual void OnGameClientDisconnected(object arg1, string arg2)
{
foreach (var module in mModules)
{
module.OnStop();
}
}
protected override void Disposing()
{
this.gate_client.Disconnect();
this.game_client.Disconnect();
this.tasks.Clear();
this.timer_tasks.Dispose();
this.Area_Disposing();
this.Connect_Disposing();
this.Gate_Disposing();
event_OnError = null;
foreach (IDisposable module in mModules)
{
module.Dispose();
}
mModules.Clear();
}
#endregion
//----------------------------------------------------------------------------------------------------------
#region Update
private readonly SyncMessageQueue tasks = new SyncMessageQueue(new SingleThreadCollectionPool());
private readonly TimeTaskQueue timer_tasks = new TimeTaskQueue(new SingleThreadCollectionPool());
public virtual void QueueTask(Action action)
{
tasks.Enqueue(action);
}
///
/// 【线程安全】增加时间任务
///
///
///
///
///
public TimeTaskMS AddTimeTask(int intervalMS, int delayMS, int repeat, TickHandler handler)
{
return timer_tasks.AddTimeTask(intervalMS, delayMS, repeat, handler);
}
///
/// 【线程安全】增加延时回调方法
///
///
///
public TimeTaskMS AddTimeDelayMS(int delayMS, TickHandler handler)
{
return timer_tasks.AddTimeDelayMS(delayMS, handler);
}
///
/// 【线程安全】增加定时回调方法
///
///
///
public TimeTaskMS AddTimePeriodicMS(int intervalMS, TickHandler handler)
{
return timer_tasks.AddTimePeriodicMS(intervalMS, handler);
}
public virtual void Update(int intervalMS)
{
if (IsAutoUpdateBattle && current_battle != null)
{
current_battle.BeginUpdate(intervalMS);
}
tasks.ProcessMessages((act) =>
{
try { act.Invoke(); } catch (Exception err) { DoError(err); }
});
timer_tasks.Update(intervalMS);
if (gate_client != null)
{
gate_client.Update();
}
if (game_client != null)
{
game_client.Update();
}
if (IsAutoUpdateBattle && current_battle != null)
{
current_battle.Update();
}
foreach (var module in mModules)
{
module.Update(intervalMS);
}
}
private void Game_client_AsyncError(Exception obj)
{
QueueTask(() => { DoError(obj); });
}
private void Gate_client_AsyncError(Exception obj)
{
QueueTask(() => { DoError(obj); });
}
protected virtual void DoError(Exception err)
{
log.Error(err.Message, err);
if (event_OnError != null) event_OnError(err);
}
#endregion
//----------------------------------------------------------------------------------------------------------
#region Events
private Action event_OnError;
public event Action OnError { add { event_OnError += value; } remove { event_OnError -= value; } }
#endregion
//----------------------------------------------------------------------------------------------------------
}
}