| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635 |
- using DeepCore;
- using DeepCore.GameEvent;
- using DeepCore.GameEvent.Message;
- using DeepCore.IO;
- using DeepCore.Log;
- using DeepCore.Statistics;
- using DeepCore.Threading;
- using DeepCrystal.ORM;
- using DeepCrystal.RPC;
- using DeepCrystal.Sql;
- using DeepMMO.Protocol;
- using DeepMMO.Protocol.Client;
- using DeepMMO.Server.Area;
- using DeepMMO.Server.Connect;
- using DeepMMO.Server.GameEvent;
- using DeepMMO.Server.Logic.Model;
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Threading.Tasks;
- namespace DeepMMO.Server.Logic
- {
- public partial class LogicService : IService
- {
- public static int SAVE_EXPECT_TIME_LIMIT = 200;
- public static int LOAD_EXPECT_TIME_LIMIT = 200;
- public static TimeStatisticsRecoder Statistics { get; private set; } =
- new TimeStatisticsRecoder("LogicStatistics");
- /// <summary>
- /// 账号ID.
- /// </summary>
- public string accountID { get; private set; }
- /// <summary>
- /// 服务器ID.
- /// </summary>
- public string serverID { get; private set; }
- public string serverGroupID { get; private set; }
- public string sessionName { get; private set; }
- public string sessionNode { get; private set; }
- public string roleID { get; private set; }
- public string roleDigitID { get => roleModule.GetRoleData().digitID; }
- public ClientInfo clientInfo { get; private set; }
- public IRemoteService session { get; private set; }
- public LanguageManager Language { get => roleModule.Language; }
- public EventManager EventMgr { get; private set; }
- public IMappingAdapter DBAdapter { get; private set; }
- public event Action OnSessionReconnect;
- public event Action OnBeforeSaveData;
- public event Action OnClientEntered;
- private IDisposable mEventTimer;
- private IDisposable mSaveDataTimer;
- public bool IsClientEntered { get; private set; }
- public override ServiceProperties Properties
- {
- get
- {
- var ret = base.Properties;
- ret.IsConcurrent = false;
- return ret;
- }
- }
- public LogicService(ServiceStartInfo start) : base(start)
- {
- this.sessionName = start.Config["sessionName"].ToString();
- this.sessionNode = start.Config["sessionNode"].ToString();
- this.accountID = start.Config["accountID"].ToString();
- this.serverID = start.Config["serverID"].ToString();
- this.roleID = start.Config["roleID"].ToString();
- this.serverGroupID = start.Config["serverGroupID"].ToString();
- this.clientInfo = new ClientInfo(start.Config);
- this.DBAdapter = ORMFactory.Instance.DefaultAdapter;
- }
- protected override async Task OnStartAsync()
- {
- var stopwatch = Stopwatch.StartNew();
- try
- {
- this.session = await base.Provider.GetAsync(new RemoteAddress(sessionName, sessionNode));
- this.OnCreateModules();
- await this.OnModulesStartAsync();
- await this.OnModulesStartedAsync();
- this.EventMgr = EventManagerFactory.Instance.CreateEventManager("Player", roleID);
- if (EventMgr != null)
- {
- EventMgr.PutObject("Service", this);
- EventMgr.Start();
- mEventTimer = Provider.CreateTimer(OnEventManagerTick, this,
- TimeSpan.FromSeconds(0),
- TimeSpan.FromSeconds(TimerConfig.timer_sec_EventUpdateTime));
- }
- {
- //定期存数据.
- int interval = TimerConfig.timer_minute_SaveDataTimer;
- interval = Math.Max(5, interval);
- this.mSaveDataTimer = Provider.CreateTimer(
- OnFlushDataTickAsync,
- this,
- TimeSpan.FromMinutes(interval));
- }
- if (stopwatch.ElapsedMilliseconds > LOAD_EXPECT_TIME_LIMIT)
- {
- log.Warn("LogicService : OnStartAsync Use Time = " + stopwatch.Elapsed);
- }
- }
- catch (Exception hzdsb)
- {
- hzdsb.PrintStackTrace();
- }
- finally
- {
- stopwatch.Stop();
- }
- }
- private void OnEventManagerTick(object state)
- {
- EventMgr?.Update();
- }
- private Task OnFlushDataTickAsync(object state)
- {
- return this.OnModulesSaveDataAsync();
- }
- protected override async Task OnStopAsync(ServiceStopInfo reason)
- {
- IsClientEntered = false;
- mSaveDataTimer?.Dispose();
- await OnModulesStopAsync();
- EventMgr?.Dispose();
- if (reason.Event != ServiceStopInfo.ShutdownEvent.START_ERROR)
- {
- await OnModulesSaveDataAsync();
- }
- await OnModulesStopedAsync();
- }
- protected override void OnDisposed()
- {
- this.OnModulesDispose();
- OnSessionReconnect = null;
- OnBeforeSaveData = null;
- OnClientEntered = null;
- mEventTimer?.Dispose();
- EventMgr = null;
- }
- //---------------------------------------------------------------------------------------------------
- #region Modules
- public RoleModule roleModule { get; protected set; }
- public AreaModule areaModule { get; protected set; }
- private List<ILogicModule> modules = new List<ILogicModule>();
- protected virtual void OnCreateModules()
- {
- this.roleModule = RegistModule(new RoleModule(this));
- this.areaModule = RegistModule(new AreaModule(this));
- }
- protected T RegistModule<T>(T module) where T : ILogicModule
- {
- modules.Add(module);
- return module;
- }
- private async Task OnModulesStartAsync()
- {
- using (var list = CollectionObjectPool<ILogicModule>.AllocList(modules))
- {
- foreach (var module in list)
- {
- try
- {
- await module.OnStartAsync();
- }
- catch (Exception err)
- {
- log.Error(ErrorBaseInfo() + err.Message, err);
- throw;
- }
- }
- }
- }
- private async Task OnModulesStartedAsync()
- {
- using (var list = CollectionObjectPool<ILogicModule>.AllocList(modules))
- {
- foreach (var module in list)
- {
- try
- {
- await module.OnStartedAsync();
- }
- catch (Exception err)
- {
- log.Error(err.Message, err);
- }
- }
- }
- }
- private async Task OnModulesSaveDataAsync()
- {
- var stopwatch = Stopwatch.StartNew();
- try
- {
- OnBeforeSaveData?.Invoke();
- if (ORMFactory.IsTest)
- {
- var watch_exe = CUtils.TickTimeMS;
- //var exe = new SyncTaskExecutor();
- var trans = DBAdapter.CreateExecutableObjectTransaction(this);
- using (var list = CollectionObjectPool<ILogicModule>.AllocList(modules))
- {
- foreach (var module in list)
- {
- var watch = CUtils.TickTimeMS;
- try
- {
- module.OnSaveData(trans);
- }
- catch (Exception err)
- {
- log.Error(err.Message, err);
- }
- finally
- {
- Statistics.LogTime($"{module.GetType().Name} : OnSaveData", CUtils.TickTimeMS - watch);
- }
- }
- }
- var test = new TestTransaction(CFiles.CurrentSubDir("/test_orm/"), this.roleID, trans, ORMFactory.Instance.DefaultAdapter, this);
- await trans.ExecuteAsync().ContinueWith(t =>
- {
- Statistics.LogTime($"{GetType().Name} : OnModulesSaveDataAsync", CUtils.TickTimeMS - watch_exe);
- });
- await test.CheckAsync(false);
- }
- else
- {
- var watch_exe = CUtils.TickTimeMS;
- var trans = DBAdapter.CreateExecutableObjectTransaction(this);
- using (var list = CollectionObjectPool<ILogicModule>.AllocList(modules))
- {
- foreach (var module in list)
- {
- var watch = CUtils.TickTimeMS;
- try
- {
- module.OnSaveData(trans);
- }
- catch (Exception err)
- {
- log.Error(err.Message, err);
- }
- finally
- {
- Statistics.LogTime($"{module.GetType().Name} : OnSaveData", CUtils.TickTimeMS - watch);
- }
- }
- }
- await trans.ExecuteAsync().ContinueWith(t =>
- {
- Statistics.LogTime($"{GetType().Name} : OnModulesSaveDataAsync", CUtils.TickTimeMS - watch_exe);
- });
- }
- }
- finally
- {
- stopwatch.Stop();
- //if (DeepCore.Log.Logger.SHOW_LOG)
- {
- if (stopwatch.ElapsedMilliseconds > SAVE_EXPECT_TIME_LIMIT)
- {
- log.Warn(" Warn LogicService : OnModulesSaveDataAsync Flush Time = " + stopwatch.Elapsed);
- }
- else
- {
- log.Debug("Debug LogicService : OnModulesSaveDataAsync Flush Time = " + stopwatch.Elapsed);
- }
- }
- }
- }
- private async Task OnModulesStopAsync()
- {
- using (var list = CollectionObjectPool<ILogicModule>.AllocList(modules))
- {
- list.Reverse();
- foreach (var module in list)
- {
- try
- {
- await module.OnStopAsync();
- }
- catch (Exception err)
- {
- log.Error(err.Message, err);
- }
- }
- }
- }
- private async Task OnModulesStopedAsync()
- {
- using (var list = CollectionObjectPool<ILogicModule>.AllocList(modules))
- {
- list.Reverse();
- foreach (var module in list)
- {
- try
- {
- await module.OnStopedAsync();
- }
- catch (Exception err)
- {
- log.Error(err.Message, err);
- }
- }
- }
- }
- private async Task NotifyModulesClientEnterGameAsync()
- {
- IsClientEntered = true;
- OnClientEntered?.Invoke();
- using (var list = CollectionObjectPool<ILogicModule>.AllocList(modules))
- {
- foreach (var module in list)
- {
- try
- {
- await module.OnClientEnterGameAsync();
- }
- catch (Exception err)
- {
- log.Error(err.Message, err);
- }
- }
- }
- }
- private void OnModulesDispose()
- {
- using (var list = CollectionObjectPool<ILogicModule>.AllocList(modules))
- {
- list.Reverse();
- foreach (var module in list)
- {
- try
- {
- module.Dispose();
- }
- catch (Exception err)
- {
- log.Error(err.Message, err);
- }
- }
- }
- modules.Clear();
- }
- private void OnModulesSessionReconnect()
- {
- using (var list = CollectionObjectPool<ILogicModule>.AllocList(modules))
- {
- foreach (var module in list)
- {
- try
- {
- module.OnSessionReconnect();
- }
- catch (Exception err)
- {
- log.Error(err.Message, err);
- }
- }
- }
- }
- private void OnModulesSessionDisconnect()
- {
- using (var list = CollectionObjectPool<ILogicModule>.AllocList(modules))
- {
- foreach (var module in list)
- {
- try
- {
- module.OnSessionDisconnect();
- }
- catch (Exception err)
- {
- log.Error(err.Message, err);
- }
- }
- }
- }
- private string ErrorBaseInfo()
- {
- return string.Format("ServerID:{0}|AccountID:{1}|RoleID:{2} ", serverID, accountID, roleID);
- }
- #endregion
- //---------------------------------------------------------------------------------------------------
- #region Area
- /// <summary>
- /// Area通知逻辑需要传送操作,一般是踩到场景传送点
- /// </summary>
- /// <param name="tp"></param>
- [RpcHandler(typeof(RoleNeedTransportNotify), ServerNames.AreaServiceType)]
- public void area_rpc_Handle(RoleNeedTransportNotify tp)
- {
- var task = areaModule.RequestTransportAsync(tp);
- }
- /// <summary>
- /// Area通知逻辑服无缝切场景
- /// </summary>
- /// <param name="tp"></param>
- [RpcHandler(typeof(RoleCrossMapNotify), ServerNames.AreaServiceType)]
- public void area_rpc_Handle(RoleCrossMapNotify notify)
- {
- areaModule.RequestCrossMapAsync(notify).NoWait();
- }
- [RpcHandler(typeof(AreaGameOverNotify), ServerNames.AreaServiceType)]
- public void area_rpc_Handle(AreaGameOverNotify notify)
- {
- areaModule.DoAreaGameOverNotify(notify);
- }
- #endregion
- //---------------------------------------------------------------------------------------------------
- #region Session
- /// <summary>
- /// 玩家断开连接
- /// </summary>
- /// <param name="disconnect"></param>
- [RpcHandler(typeof(SessionDisconnectNotify), ServerNames.SessionServiceType)]
- public virtual void session_rpc_Handle(SessionDisconnectNotify disconnect)
- {
- var area = areaModule.currentArea;
- if (area != null)
- {
- disconnect.roleID = this.roleID;
- area.Invoke(disconnect);
- }
- this.OnModulesSessionDisconnect();;
- }
- /// <summary>
- /// 玩家重新连接
- /// </summary>
- /// <param name="disconnect"></param>
- [RpcHandler(typeof(SessionReconnectNotify), ServerNames.SessionServiceType)]
- public virtual void session_rpc_Handle(SessionReconnectNotify reconnect)
- {
- this.clientInfo = new ClientInfo(reconnect.config);
- var area = areaModule.currentArea;
- if (area != null)
- {
- reconnect.roleID = this.roleID;
- area.Invoke(reconnect);
- }
- this.OnModulesSessionReconnect();
- OnSessionReconnect?.Invoke();
- }
-
- [RpcHandler(typeof(SessionBeginLeaveRequest), typeof(SessionBeginLeaveResponse), ServerNames.SessionServiceType)]
- public virtual void session_rpc_Handle(SessionBeginLeaveRequest disconnect, OnRpcReturn<SessionBeginLeaveResponse> cb)
- {
- var area = areaModule.currentArea;
- if (area != null)
- {
- area.Call(disconnect, cb);
- }
- else
- {
- cb(new SessionBeginLeaveResponse() { s2c_code = Response.CODE_ERROR });
- }
- }
- [RpcHandler(typeof(ClientEnterGameRequest), typeof(ClientEnterGameResponse), ServerNames.SessionServiceType)]
- public void client_rpc_Handle(ClientEnterGameRequest enter, OnRpcReturn<ClientEnterGameResponse> cb)
- {
- cb(new ClientEnterGameResponse() { s2c_role = this.roleModule.ToClientRoleData() });
- Provider.Execute(NotifyModulesClientEnterGameAsync);
- }
- /// <summary>
- /// 测试客户端Ping,Pong
- /// </summary>
- [RpcHandler(typeof(ClientPing), typeof(ClientPong))]
- public virtual void client_rpc_Handle(ClientPing ping, OnRpcReturn<ClientPong> cb)
- {
- #if TEST
- session.Invoke(new LogicTimeNotify() { index = 0, time = ping.time });
- session.Invoke(new LogicTimeNotify() { index = 1, time = ping.time });
- cb(new ClientPong()
- {
- s2c_code = (ping.time.Millisecond % 2 == 0) ? Response.CODE_OK : Response.CODE_ERROR,
- s2c_msg = DateTime.Now.ToString(),
- time = ping.time
- });
- session.Invoke(new LogicTimeNotify() { index = 2, time = ping.time });
- session.Invoke(new LogicTimeNotify() { index = 3, time = ping.time });
- #else
- cb(new ClientPong() { s2c_code = Response.CODE_OK, time = ping.time });
- #endif
- }
- [RpcHandler(typeof(ServerGameEventNotify))]
- public virtual void rpc_event_notify(ServerGameEventNotify ntf)
- {
- if (EventMgr != null && (string.IsNullOrEmpty(ntf.ServerGroupID) || ntf.ServerGroupID == serverGroupID))
- {
- EventMgr.OnReceiveMessage(EventMessage.FromBytes(ntf.EventMessageData));
- }
- }
- [RpcHandler(typeof(ClientGameEventNotify))]
- public virtual void client_rpc_notify(ClientGameEventNotify ntf)
- {
- var msg = EventMessage.FromBytes(ntf.EventMessageData);
- if (msg is NamedEventMessage nameMsg)
- {
- nameMsg.From = EventMgr?.Address;
- }
- var address = EventManagerAddress.Parse(msg.From);
- address = new EventManagerAddress("Client", address.UUID);
- msg.From = address.Address;
- EventManager.MessageBroker.Publish(ntf.To, EventMgr, msg);
- }
- [RpcHandler(typeof(ClientGetZoneInfoSnapRequest), typeof(ClientGetZoneInfoSnapResponse))]
- public virtual Task<ClientGetZoneInfoSnapResponse> client_rpc_Handle(ClientGetZoneInfoSnapRequest req)
- {
- return areaModule.DoClientGetZoneInfoSnapRequest(req);
- }
- [RpcHandler(typeof(ClientChangeZoneLineRequest), typeof(ClientChangeZoneLineResponse))]
- public virtual Task<ClientChangeZoneLineResponse> client_rpc_Handle(ClientChangeZoneLineRequest req)
- {
- return areaModule.DoClientChangeZoneLineRequest(req);
- }
- #endregion
- public class ClientInfo
- {
- public string Os { get; private set; }
- public string Network { get; private set; }
- public string AppVersion { get; private set; }
- public string AppVersionCode { get; private set; }
- public string OsVersion { get; private set; }
- public string SdkVersion { get; private set; }
- public string DeviceBrand { get; private set; }
- public string DeviceModel { get; private set; }
- public string DeviceScreen { get; private set; }
- public string Mac { get; private set; }
- public string Imei { get; private set; }
- public string Uuid { get; private set; }
- public string PackageName { get; private set; }
- public string BuildNumber { get; private set; }
- public string Carrier { get; private set; }
- public string Iccid { get; private set; }
- public string Imsi { get; private set; }
- public string Idfa { get; private set; }
- public string ClientIp { get; private set; }
- public string DeviceID { get; private set; }
- public string Channel { get; private set; }
- public string SDKName { get; private set; }
- public string PlatformAccount { get; private set; }
- public ClientInfo(HashMap<string, string> config)
- {
- this.Os = config["deviceType"]?.ToString();
- this.Os = SQLFactory.CurrentFactory.EscapeString(Os);
- this.Network = config["network"]?.ToString();
- this.Network = SQLFactory.CurrentFactory.EscapeString(Network);
- this.AppVersion = config["clientVersion"]?.ToString();
- this.AppVersion = SQLFactory.CurrentFactory.EscapeString(AppVersion);
- this.AppVersionCode = null;
- this.OsVersion = null;
- this.SdkVersion = config["sdkVersion"]?.ToString();
- this.SdkVersion = SQLFactory.CurrentFactory.EscapeString(SdkVersion);
- this.DeviceBrand = null;
- this.DeviceModel = config["deviceModel"]?.ToString();
- this.DeviceModel = SQLFactory.CurrentFactory.EscapeString(DeviceModel);
- this.DeviceScreen = null;
- this.Mac = config["deviceId"]?.ToString();
- this.Mac = SQLFactory.CurrentFactory.EscapeString(Mac);
- this.Imei = null;
- this.Uuid = config["roleID"]?.ToString();
- this.Uuid = SQLFactory.CurrentFactory.EscapeString(Uuid);
- this.PackageName = null;
- this.BuildNumber = null;
- this.Carrier = null;
- this.Iccid = null;
- this.Imsi = null;
- this.Idfa = config["deviceId"]?.ToString();
- this.Idfa = SQLFactory.CurrentFactory.EscapeString(Idfa);
- this.ClientIp = config["clientIp"]?.ToString();
- this.ClientIp = SQLFactory.CurrentFactory.EscapeString(ClientIp);
- this.DeviceID = config["deviceId"]?.ToString();
- this.DeviceID = SQLFactory.CurrentFactory.EscapeString(DeviceID);
- this.Channel = config["channel"]?.ToString();
- this.Channel = SQLFactory.CurrentFactory.EscapeString(Channel);
- if (string.IsNullOrEmpty(Channel))
- this.Channel = "0";
- this.SDKName = config["sdkName"]?.ToString();
- this.SDKName = SQLFactory.CurrentFactory.EscapeString(SDKName);
- this.PlatformAccount = config["platformAccount"]?.ToString();
- }
- }
- //---------------------------------------------------------------------------------------------------
- }
- }
|