using DeepCore; using DeepCore.GameData.Zone; using DeepCore.Log; using DeepCrystal.RPC; using DeepMMO.Protocol; using DeepMMO.Server.AreaManager; using DeepMMO.Server.Connect; using DeepMMO.Server.SystemMessage; using DeepCore.IO; using DeepMMO.Server.GameEvent; using System; using System.Collections.Generic; using System.Threading.Tasks; using DeepCore.GameEvent; using DeepCore.GameEvent.Message; using DeepCore.Game3D.Host.Instance; using System.Collections.Concurrent; using System.IO; using DeepCore.GameData; namespace DeepMMO.Server.Area { public class AreaService : IService { public Random random { get; private set; } = new Random(); public IDisposable sync_state_timer { get; private set; } public IRemoteService area_manager; private TypeCodec session_battle_codec; public BattleCodec BattleClientCodec { get; } public string ServerGroupId; public AreaService(ServiceStartInfo start) : base(start) { ServerGroupId = start.Config["groupID"]; this.BattleClientCodec = new BattleCodec(RPGServerBattleManager.Templates); this.session_battle_codec = base.ServerCodec.Factory.GetCodec(typeof(SessionBattleAction)); } protected override void OnDisposed() { } protected override async Task OnStartAsync() { this.area_manager = await ServerNames.GetOrCreateAreaManagerServiceAsync(this, ServerGroupId); this.sync_state_timer = this.Provider.CreateTimer(timer_SyncState, this, TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(TimerConfig.timer_sec_AreaStateNotify)); await area_manager.CallAsync(new RegistAreaRequest() { areaName = SelfAddress.ServiceName, areaNode = SelfAddress.ServiceNode, }); } protected override async Task OnStopAsync(ServiceStopInfo reason) { this.sync_state_timer.Dispose(); foreach (var item in zoneNodes) { await item.Value.DoStopAsync(); } } public override bool GetState(TextWriter sb) { ForEachZones(node => { sb.WriteLine(CUtils.SequenceChar('-', 100)); node.GetStatus(sb); sb.WriteLine(CUtils.SequenceChar('-', 100)); }); return true; } protected virtual void timer_SyncState(object obj) { this.area_manager.Invoke(new AreaStateNotify() { areaName = SelfAddress.ServiceName, areaNode = SelfAddress.ServiceNode, roleCount = this.PlayerCount, zoneCount = this.ZoneNodeCount, cpuPercent = 1, // TODO memoryMB = 1, // TODO }); this.LogState(); } //[RpcHandler(typeof(SystemStaticServicesStartedNotify))] //public virtual void rpc_HandleSystem(SystemStaticServicesStartedNotify shutdown) //{ // area_manager.CallAsync(new RegistAreaRequest() // { // areaName = SelfAddress.ServiceName, // areaNode = SelfAddress.ServiceNode, // }); //} //----------------------------------------------------------------------------------------------------------------------------- [RpcHandler(typeof(ServerGameEventNotify))] public virtual void rpc_event_notify(ServerGameEventNotify ntf) { var emsg = EventMessage.FromBytes(ntf.EventMessageData); if (ntf.Broadcast) { foreach (var node in zoneNodes) { node.Value.EventMgr?.OnReceiveMessage(emsg); } } else { var mgr = EventManagerFactory.Instance.GetEventManager(ntf.To); mgr?.OnReceiveMessage(emsg); } } //----------------------------------------------------------------------------------------------------------------------------- #region __CreateObject__ //-------------------------------------------------------------------------------------------------------------------------------- protected virtual AreaZonePlayer CreateZonePlayer(AreaZoneNode node, RoleEnterZoneRequest enter) { return new AreaZonePlayer(this, node, enter); } protected virtual AreaZoneNode CreateZoneNode(CreateZoneNodeRequest create, MapTemplateData map) { return new AreaZoneNode(this, create, map); } public virtual UnitInfo GetDefaultUnitTemplate() { return RPGServerBattleManager.DataRoot.Templates.GetUnit(95559); } public virtual AreaZoneNode GetDefaultZoneNode() { return random.GetRandomInArray(this.ZoneNodes); } #endregion //----------------------------------------------------------------------------------------------------------------------------- #region __ClientToArea__ //-------------------------------------------------------------------------------------------------------------------------------- /// /// Client -> Session -> Area /// [RpcHandler(typeof(SessionBattleAction), true)] public virtual void client_rpc_Handle(BinaryMessage action) { try { using (var buffer = MemoryStreamObjectPool.AllocAutoRelease(action.DataSegment)) using (var input = IOStreamObjectPool.AllocInputAutoRelease(base.ServerCodec.Factory, buffer)) { var roleID = input.GetUTF(); var player = GetPlayer(roleID); if (player == null) { return; } //drop 4 for bytes size// buffer.Position += 4; player.client_rpc_Handle(buffer); } } catch (Exception e) { log.Error(e.Message, e); } } public override void OnWormholeTransported(RemoteAddress from, object message) { if (message is BinaryMessage bin) { client_rpc_Handle(bin); } else if (message is SessionBattleAction ser) { var player = GetPlayer(ser.roleID); if (player == null) { player.client_rpc_Handle(ser.clientBattleAction); } } } #endregion //----------------------------------------------------------------------------------------------------------------------------- #region __LogicToArea__ //-------------------------------------------------------------------------------------------------------------------------------- /// /// 创建副本 /// /// /// [RpcHandler(typeof(CreateZoneNodeRequest), typeof(CreateZoneNodeResponse), ServerNames.AreaManagerType)] public async Task area_manager_rpc_CreateZone(CreateZoneNodeRequest create) { try { var maptemp = RPGServerTemplateManager.Instance.GetMapTemplate(create.mapTemplateID); if (maptemp == null) throw new Exception("No MapTemplate : " + create.mapTemplateID); var zoneUUID = create.managerZoneUUID; if (zoneNodes.ContainsKey(zoneUUID)) { throw new Exception(string.Format("node instance id ({0}) already exist!", zoneUUID)); } AreaZoneNode node = this.CreateZoneNode(create, maptemp); zoneNodes.TryAdd(zoneUUID, node); var z = await node.DoStartAsync(); // log.InfoFormat("Scene Started : {0} : {1}", z.UUID, z.Data); return (new CreateZoneNodeResponse() { areaName = SelfAddress.ServiceName, areaNode = SelfAddress.ServiceNode, zoneUUID = zoneUUID, TemplateID = maptemp.zone_template_id, }); } catch (Exception e) { log.Error("CreateZone failed, error: " + e.Message, e); return (new CreateZoneNodeResponse() { s2c_code = CreateZoneNodeResponse.CODE_ERROR, s2c_msg = e.Message, }); } } /// /// 销毁副本 /// /// /// [RpcHandler(typeof(DestoryZoneNodeRequest), typeof(DestoryZoneNodeResponse), ServerNames.AreaManagerType)] public async Task area_manager_rpc_DestroyZone(DestoryZoneNodeRequest stop) { try { if (this.zoneNodes.TryRemove(stop.zoneUUID, out var node)) { //删除场景实例的所有玩家 node.ZoneNode.ForEachPlayers((p) => { try { using (var player = p.Client as AreaZonePlayer) { log.Error("DestoryZoneNode Have Player : " + player.RoleUUID); players.TryRemove(player.RoleUUID, out var pp); } } catch (Exception err) { log.Error(err.Message, err); } }); await node.DoStopAsync(); return (new DestoryZoneNodeResponse() { s2c_msg = "done" }); } else { return (new DestoryZoneNodeResponse() { s2c_msg = "done" }); } } catch (Exception e) { log.Error("DestroyZone failed, error: " + e.Message, e); return (new DestoryZoneNodeResponse() { s2c_code = Response.CODE_ERROR, s2c_msg = e.Message }); } } /// /// 玩家进入副本 /// /// /// [RpcHandler(typeof(RoleEnterZoneRequest), typeof(RoleEnterZoneResponse), ServerNames.AreaManagerType)] public async Task area_manager_rpc_PlayerEnter(RoleEnterZoneRequest enter) { try { var node = this.FindZoneNode(enter); if (node == null) { //TODO 分配一个默认场景 node = this.GetDefaultZoneNode(); } //场景不存在// if (node == null) { return new RoleEnterZoneResponse() { s2c_code = RoleEnterZoneResponse.CODE_ZONE_NOT_EXIST, s2c_msg = $"PlayerEnter: ZoneNotExistException: roleID={enter.roleUUID} zone={enter.expectZoneUUID}" }; } if (this.players.TryGetOrCreate(enter.roleUUID, out var player, (uuid) => this.CreateZonePlayer(node, enter))) { if (player.ZoneNode == node) { var replace = await node.DoPlayerEnterReplace(player, enter); if (replace.IsSuccess) { return replace; } this.players.TryGetOrCreate(enter.roleUUID, out player, (uuid) => this.CreateZonePlayer(node, enter)); return await node.DoPlayerEnterAsync(player, enter); } else { return new RoleEnterZoneResponse() { s2c_code = RoleEnterZoneResponse.CODE_ZONE_NOT_EXIST, s2c_msg = $"PlayerEnter: ZoneNotExistException: roleID={enter.roleUUID} zone={enter.expectZoneUUID}" }; } } else { return await node.DoPlayerEnterAsync(player, enter); } } catch (Exception e) { log.Error(e.Message, e); return new RoleEnterZoneResponse() { s2c_code = Response.CODE_ERROR, s2c_msg = e.Message }; } } /// /// 玩家离开副本 /// /// /// [RpcHandler(typeof(RoleLeaveZoneRequest), typeof(RoleLeaveZoneResponse), ServerNames.AreaManagerType)] public async Task area_manager_rpc_PlayerLeave(RoleLeaveZoneRequest leave) { try { if (this.players.TryRemove(leave.roleID, out var player)) { using (player) { AreaZoneNode node = player.ZoneNode; if (node == null) { return (new RoleLeaveZoneResponse() { s2c_code = RoleLeaveZoneResponse.CODE_ROLE_NOT_EXIST, s2c_msg = $"PlayerLeave: ZoneNotExistException: roleID={leave.roleID} zone={player.ZoneUUID}" }); } return await node.DoPlayerLeaveAsync(player, leave); } } else { return (new RoleLeaveZoneResponse() { s2c_code = RoleLeaveZoneResponse.CODE_ROLE_NOT_EXIST, s2c_msg = $"PlayerLeave: PlayerNotExistException: roleID=roleID={leave.roleID} zone={leave.zoneUUID}" }); } } catch (Exception e) { log.Error(e.Message, e); return (new RoleLeaveZoneResponse() { s2c_code = Response.CODE_ERROR, s2c_msg = e.Message }); } } [RpcHandler(typeof(GetRolePositionRequest), typeof(GetRolePositionResponse), ServerNames.AreaManagerType)] public async Task area_manager_rpc_GetRolePosition(GetRolePositionRequest req) { var resp = new GetRolePositionResponse(); if (players.TryGetValue(req.roleUUID, out var role)) { return await role.ZoneNode.DoGetPlayerPosition(role, req); } else { resp.s2c_code = GetRolePositionResponse.CODE_ROLE_NOT_EXIST; return resp; } } //----------------------------------------------------------------------------------------------------------------------------- /// /// 玩家数据改变 /// /// [RpcHandler(typeof(RoleDataChangedNotify))] public void logic_rpc_PlayerNetStateChanged(RoleDataChangedNotify changed) { AreaZonePlayer player; AreaZoneNode node; try { if (TryGetPlayer(changed.roleID, out player, out node)) { player.logic_rpc_Handle(changed.roleData); } } catch (Exception e) { log.Error(e.Message, e); } } /// /// 玩家断开连接 /// /// [RpcHandler(typeof(SessionDisconnectNotify))] public void logic_rpc_Handle(SessionDisconnectNotify disconnect) { AreaZonePlayer player; AreaZoneNode node; try { if (TryGetPlayer(disconnect.roleID, out player, out node)) { node.DoPlayerDisconnect(player); } } catch (Exception e) { log.Error(e.Message, e); } } /// /// 玩家重新连接 /// /// [RpcHandler(typeof(SessionReconnectNotify))] public void logic_rpc_Handle(SessionReconnectNotify reconnect) { AreaZonePlayer player; AreaZoneNode node; try { if (TryGetPlayer(reconnect.roleID, out player, out node)) { node.DoPlayerReconnect(player); } } catch (Exception e) { log.Error(e.Message, e); } } [RpcHandler(typeof(SessionBeginLeaveRequest), typeof(SessionBeginLeaveResponse))] public async Task logic_rpc_Handle(SessionBeginLeaveRequest leave) { try { if (this.players.TryGetValue(leave.roleID, out var player)) { var node = player.ZoneNode; if (node != null) { await node.DoPlayerBeginLeaveAsync(player); return (new SessionBeginLeaveResponse() { s2c_code = Response.CODE_OK }); } } return (new SessionBeginLeaveResponse() { s2c_code = Response.CODE_ERROR }); } catch (Exception e) { log.Warn(e.Message, e); return (new SessionBeginLeaveResponse() { s2c_code = Response.CODE_ERROR, s2c_msg = e.Message }); } } #endregion //----------------------------------------------------------------------------------------------------------------------------- #region __ZoneAndPlayer__ //-------------------------------------------------------------------------------------------------------------------------------- private ConcurrentDictionary zoneNodes = new ConcurrentDictionary(); private ConcurrentDictionary players = new ConcurrentDictionary(); public int PlayerCount { get { { return players.Count; } } } public int ZoneNodeCount { get { { return zoneNodes.Count; } } } public List ZoneNodes { get { { return new List(zoneNodes.Values); } } } public List ZonePlayers { get { { return new List(players.Values); } } } public void ForEachPlayers(Action action) { using (var list = CollectionObjectPool.AllocList()) { { list.AddRange(players.Values); } foreach (var p in list) { action(p); } } } public void ForEachZones(Action action) { using (var list = CollectionObjectPool.AllocList()) { { list.AddRange(zoneNodes.Values); } foreach (var z in list) { action(z); } } } public AreaZoneNode GetZoneNode(string zoneUUID) { if (zoneNodes.TryGetValue(zoneUUID, out var ret)) { return ret; } return null; } public AreaZoneNode FindZoneNode(RoleEnterZoneRequest enter) { { if (enter.expectZoneUUID != null && zoneNodes.TryGetValue(enter.expectZoneUUID, out var node)) { return node; } if (enter.expectMapTemplateID != 0) { foreach (var e in zoneNodes.Values) { if (e.MapTemplateID == enter.expectMapTemplateID) { return e; } } } } return null; } public AreaZonePlayer GetPlayer(string roleID) { if (roleID != null && players.TryGetValue(roleID, out var ret)) { return ret; } return null; } public bool TryGetPlayer(string roleID, out AreaZonePlayer player, out AreaZoneNode node) { if (roleID != null && players.TryGetValue(roleID, out player)) { node = player.ZoneNode; // if (node == null) // { // throw new Exception("PlayerLeave: InstanceNotExistException: " + player.ZoneUUID); // } return true; } player = null; node = null; // else // { // //throw new Exception("PlayerLeave: PlayerNotExistException roleID: " + roleID); // } return false; } /// /// 异步执行战斗场景内交互代码 /// /// /// /// /// public Task QueueZoneTaskAsync(string zoneUUID, Func func) { if (zoneNodes.TryGetValue(zoneUUID, out var node)) { return node.ZoneNode.QueueSceneTaskAsync(func); } return Task.FromResult(func(null)); } /// /// 异步执行战斗场景内交互代码 /// /// /// /// /// public Task QueuePlayerTaskAsync(string roleUUID, Func func) { if (roleUUID != null && players.TryGetValue(roleUUID, out var player)) { var node = player.ZoneNode; return node.ZoneNode.QueuePlayerTaskAsync(roleUUID, func); } return Task.FromResult(func(null)); } /// /// 异步执行战斗场景内交互代码 /// /// /// /// /// public Task QueueZoneTaskAsync(string zoneUUID, Func func) { if (zoneNodes.TryGetValue(zoneUUID, out var node)) { return node.ZoneNode.QueueSceneTaskAsync(z => func(node, z)); } return Task.FromResult(func(null, null)); } /// /// 异步执行战斗场景内交互代码 /// /// /// /// /// public Task QueuePlayerTaskAsync(string roleUUID, Func func) { if (roleUUID != null && players.TryGetValue(roleUUID, out var player)) { var node = player.ZoneNode; return node.ZoneNode.QueuePlayerTaskAsync(roleUUID, p => func(player, p)); } return Task.FromResult(func(null, null)); } #endregion //----------------------------------------------------------------------------------------------------------------------------- } }