| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585 |
- using DeepCore.GameData.Zone.ZoneEditor;
- using DeepCore.GameEvent;
- using DeepCore.IO;
- using DeepCore.Log;
- using DeepCrystal.RPC;
- using DeepMMO.Server.AreaManager;
- using System;
- using System.Threading.Tasks;
- using DeepCore.Game3D.Host.Instance;
- using DeepCore.Game3D.Host.ZoneEditor;
- using DeepCore.Game3D.Host.ZoneServer;
- using DeepCore.Game3D.Host.ZoneServer.Interface;
- using DeepCore.Geometry;
- using DeepMMO.Data;
- using DeepCore;
- using System.Text;
- using System.IO;
- namespace DeepMMO.Server.Area
- {
- public class AreaZoneNode : IZoneNodeServer
- {
- private readonly static TypeAllocRecorder Alloc = new TypeAllocRecorder(typeof(AreaZoneNode));
- protected readonly Logger log;
- protected readonly AreaService service;
- protected readonly CreateZoneNodeRequest create;
- protected readonly MapTemplateData map_temp;
- protected readonly string uuid;
- protected readonly ZoneNode node;
- public string ZoneUUID { get { return uuid; } }
- public int MapTemplateID { get { return create.mapTemplateID; } }
- public int ZoneTemplateID { get { return map_temp.zone_template_id; } }
- public string GuildUUID => create.guildUUID;
- public string RoomKey => create.roomKey;
- /// <summary>
- /// 场景保留时间,将超时时间从TLAreaZoneNode同步到AreaZoneNode,为了ZoneBaseEvent调用
- /// </summary>
- public DateTime KeepSceneExpireTime;
- //public string ServerID => create.serverID;
- public string ServerGroupID => create.serverGroupID;
- public ZoneNode ZoneNode { get { return node; } }
- public AreaZoneNode(AreaService svc, CreateZoneNodeRequest create, MapTemplateData map_temp)
- {
- Alloc.RecordConstructor(GetType().ToVisibleName() + ":" + map_temp.id);
- this.log = LoggerFactory.GetLogger(string.Format("{0}-{1}", GetType().Name, create.managerZoneUUID));
- this.service = svc;
- this.create = create;
- this.map_temp = map_temp;
- this.uuid = create.managerZoneUUID;
- this.node = CreateZoneNode(create);
- }
- #if DEBUG
- ~AreaZoneNode()
- {
- Alloc.RecordDestructor(GetType().ToVisibleName() + ":" + map_temp.id);
- }
- #endif
- public virtual void rpc_Handle(ISerializable msg, OnRpcReturn<ISerializable> cb)
- {
- zone_rpc_call_handler?.Invoke(msg, (rsp, err) => { cb(rsp as ISerializable, err); });
- }
- public virtual void rpc_Handle(ISerializable msg)
- {
- zone_rpc_invoke_handler?.Invoke(msg);
- }
- public virtual void rpc_Call(ISerializable msg, OnRpcReturn<ISerializable> cb)
- {
- }
- public virtual void rpc_Invoke(ISerializable msg)
- {
- }
- //--------------------------------------------------------------------------------------------------------------------------------
- #region 主动调用
- //--------------------------------------------------------------------------------------------------------------------------------
- public virtual async Task<EditorScene> DoStartAsync()
- {
- var sd = LoadSceneData(create);
- var zone = await this.node.StartAsync(sd) as EditorScene;
- zone.UUID = ZoneUUID;
- OnNodeStarted(zone as EditorScene);
- return zone;
- }
- public virtual Task<EditorScene> DoStopAsync()
- {
- Alloc.RecordDispose(GetType().ToVisibleName() + ":" + map_temp.id);
- node.OnZoneStop += (z) =>
- {
- OnNodeStopped(z as EditorScene);
- };
- return node.StopAsync().ContinueWith(t => t.Result as EditorScene);
- }
- public virtual async Task<RoleEnterZoneResponse> DoPlayerEnterAsync(AreaZonePlayer player, RoleEnterZoneRequest enter)
- {
- if (await player.OnEnterAsync() == false)
- {
- log.Error("Can Not Find Session Or Logic : " + enter.roleSessionName + " : " + enter.roleUUID);
- }
- try
- {
- player.SessionReconnect();
- var tcs = new System.Threading.Tasks.TaskCompletionSource<RoleEnterZoneResponse>();
- this.node.PlayerEnter(player, ToAddUnit(enter), client =>
- {
- if (HasAddPlayer == false)
- {
- HasAddPlayer = true;
- }
- client.Actor.SetAttribute(nameof(AreaZonePlayer.RoleSessionName), player.RoleSessionName);
- tcs.TrySetResult(new RoleEnterZoneResponse()
- {
- s2c_code = RoleEnterZoneResponse.CODE_OK,
- mapTemplateID = this.MapTemplateID,
- zoneUUID = this.ZoneUUID,
- zoneTemplateID = this.ZoneTemplateID,
- roleBattleData = enter.roleData,
- roleDisplayName = enter.roleDisplayName,
- roleUnitTemplateID = enter.roleUnitTemplateID,
- roleScenePos = new ZonePosition()
- {
- x = client.Actor.X,
- y = client.Actor.Y,
- z = client.Actor.Z
- },
- areaName = service.SelfAddress.ServiceName,
- areaNode = service.SelfAddress.ServiceNode,
- guildUUID = enter.guildUUID,
- });
- }, err =>
- {
- tcs.TrySetResult(new RoleEnterZoneResponse()
- {
- s2c_code = RoleEnterZoneResponse.CODE_ERROR,
- s2c_msg = err.Message,
- });
- });
- return await tcs.Task;
- }
- catch (Exception err)
- {
- log.Error(err);
- return (new RoleEnterZoneResponse()
- {
- s2c_code = RoleEnterZoneResponse.CODE_ERROR,
- s2c_msg = err.Message,
- });
- }
- }
- public virtual Task<RoleLeaveZoneResponse> DoPlayerLeaveAsync(AreaZonePlayer player, RoleLeaveZoneRequest leave)
- {
- var tcs = new System.Threading.Tasks.TaskCompletionSource<RoleLeaveZoneResponse>();
- this.node.PlayerLeave(player,
- (c) =>
- {
- tcs.TrySetResult(new RoleLeaveZoneResponse()
- {
- lastScenePos = new Data.ZonePosition()
- {
- x = c.Actor.X,
- y = c.Actor.Y,
- z = c.Actor.Z,
- },
- curHP = c.Actor.CurrentHP,
- curMP = c.Actor.CurrentMP,
- LeaveZoneSaveData = c.LastZoneSaveData,
- });
- },
- (e) =>
- {
- tcs.TrySetResult(new RoleLeaveZoneResponse()
- {
- s2c_code = RoleLeaveZoneResponse.CODE_ERROR,
- s2c_msg = e.Message,
- });
- });
- return tcs.Task;
- }
- public Task<GetRolePositionResponse> DoGetPlayerPosition(AreaZonePlayer player, GetRolePositionRequest req)
- {
- return node.QueuePlayerTaskAsync<GetRolePositionResponse>(player.RoleUUID, (instancePlayer) =>
- {
- return (new GetRolePositionResponse()
- {
- x = instancePlayer.X,
- y = instancePlayer.Y,
- z = instancePlayer.Z,
- s2c_code = GetRolePositionResponse.CODE_OK
- });
- });
- }
- public virtual void DoPlayerDisconnect(AreaZonePlayer player)
- {
- player.SessionDisconnect();
- this.node.PlayerDisconnect(player, (client) => { }, (err) => { });
- }
- public virtual void DoPlayerReconnect(AreaZonePlayer player)
- {
- player.SessionReconnect();
- this.node.PlayerReconnect(player, (client) => { }, (err) => { });
- }
- public virtual Task DoPlayerBeginLeaveAsync(AreaZonePlayer player)
- {
- player.SessionBeginLeave();
- return this.node.QueueSceneTaskAsync(z => { return 1; });
- }
- public virtual Task<RoleEnterZoneResponse> DoPlayerEnterReplace(AreaZonePlayer player, RoleEnterZoneRequest enter)
- {
- return node.QueuePlayerTaskAsync<RoleEnterZoneResponse>(player.RoleUUID, (instancePlayer) =>
- {
- if (instancePlayer == null)
- {
- return new RoleEnterZoneResponse() { s2c_code = RoleEnterZoneResponse.CODE_ERROR };
- }
- return (new RoleEnterZoneResponse()
- {
- mapTemplateID = this.MapTemplateID,
- zoneUUID = this.ZoneUUID,
- zoneTemplateID = this.ZoneTemplateID,
- roleBattleData = enter.roleData,
- roleDisplayName = enter.roleDisplayName,
- roleUnitTemplateID = enter.roleUnitTemplateID,
- roleScenePos = new ZonePosition()
- {
- x = instancePlayer.X,
- y = instancePlayer.Y,
- z = instancePlayer.Z
- },
- areaName = service.SelfAddress.ServiceName,
- areaNode = service.SelfAddress.ServiceNode,
- guildUUID = enter.guildUUID,
- s2c_code = RoleEnterZoneResponse.CODE_OK_REPLACE
- });
- });
- // var client = this.node.GetPlayerClient(player.RoleUUID);
- /*
- float px = 0, py = 0, pz = 0;
- if (client != null)
- {
- px = client.Actor.X;
- py = client.Actor.Y;
- pz = client.Actor.Z;
- }
- return (new RoleEnterZoneResponse()
- {
- mapTemplateID = this.MapTemplateID,
- zoneUUID = this.ZoneUUID,
- zoneTemplateID = this.ZoneTemplateID,
- roleBattleData = enter.roleData,
- roleDisplayName = enter.roleDisplayName,
- roleUnitTemplateID = enter.roleUnitTemplateID,
- roleScenePos = new ZonePosition() { x = px, y = py, z = pz},
- areaName = service.SelfAddress.ServiceName,
- areaNode = service.SelfAddress.ServiceNode,
- guildUUID = enter.guildUUID,
- s2c_code = RoleEnterZoneResponse.CODE_OK_REPLACE;
- });
- */
- }
- #endregion
- //--------------------------------------------------------------------------------------------------------------------------------
- #region 构造对象
- //--------------------------------------------------------------------------------------------------------------------------------
- protected virtual AddUnit ToAddUnit(RoleEnterZoneRequest enter)
- {
- var unitInfo = RPGServerBattleManager.DataRoot.Templates.GetUnit(enter.roleUnitTemplateID);
- if (unitInfo == null)
- {
- unitInfo = service.GetDefaultUnitTemplate();
- }
- DeepCore.Vector.Vector3 pos = null;
- if (enter.roleScenePos != null)
- {
- if (enter.roleScenePos.HasFlag)
- {
- var sceneObj = node.FindSceneObjData(enter.roleScenePos.flagName);
- if (sceneObj != null)
- {
- pos = new DeepCore.Vector.Vector3(sceneObj.X, sceneObj.Y, sceneObj.Z);
- }
- }
- else if (enter.roleScenePos.HasPos)
- {
- if (enter.roleScenePos.x == enter.roleScenePos.y && enter.roleScenePos.x == -1)
- {
- var map = node.SceneData.GetStartRegions();
- var ret = map.Get(2);
- if (ret != null)
- pos = new DeepCore.Vector.Vector3(ret.X, ret.Y, ret.Z);
- else
- pos = new DeepCore.Vector.Vector3(enter.roleScenePos.x, enter.roleScenePos.y, enter.roleScenePos.z);
- }
- else
- pos = new DeepCore.Vector.Vector3(enter.roleScenePos.x, enter.roleScenePos.y, enter.roleScenePos.z);
- }
- }
- var add = new AddUnit()
- {
- info = unitInfo,
- player_uuid = enter.roleUUID,
- pos = pos,
- arg = enter,
- //中立单位0,怪物1,玩家2.
- force = enter.roleForce > 0 ? (byte)enter.roleForce : (byte)2,
- editor_name = enter.roleDisplayName,
- last_zone_save_data = enter.LastZoneSaveData,
- };
- return add;
- }
- protected virtual SceneData LoadSceneData(CreateZoneNodeRequest input)
- {
- return RPGServerBattleManager.Instance.GetSceneAsCache(this.ZoneTemplateID);
- }
- protected virtual ZoneNode CreateZoneNode(CreateZoneNodeRequest input)
- {
- return RPGServerBattleManager.ZoneFactory.CreateServerZoneNode(this, RPGServerBattleManager.DataRoot, RPGServerBattleManager.NodeConfig);
- }
- #endregion
- //--------------------------------------------------------------------------------------------------------------------------------
- #region 回调事件
- //--------------------------------------------------------------------------------------------------------------------------------
- public EventManager EventMgr { get; private set; }
- protected virtual void OnNodeStarted(EditorScene z)
- {
- z.OnUnitDead += Z_OnUnitDead;
- z.OnUnitGotInstanceItem += Z_OnUnitGotInstanceItem;
- z.OnGameOver += Z_OnGameOver;
- //z.OnCurrentSecretPlacePlayTypeUpdateAction += Z_OnCurrentSecretPlacePlayTypeUpdate;
- if (TimerConfig.timer_sec_ZoneKeepPlayerTimeout > 0)//场景无人后清理时间.程序控制.
- {
- keepPlayerExpire = TimeSpan.FromSeconds(TimerConfig.timer_sec_ZoneKeepPlayerTimeout);
- z.AddTimePeriodicMS((int)(keepPlayerExpire.TotalMilliseconds / 2), (t) =>
- {
- CheckZoneDispose(z, t);
- });
- }
- this.EventMgr = EventManagerFactory.Instance.CreateEventManager("Zone", z.UUID);
- if (this.EventMgr != null)
- {
- this.EventMgr.PutObject("Zone", z);
- this.EventMgr.PutObject("Service", this.service);
- this.EventMgr.PutObject("Node", this);
- this.EventMgr.Start();
- node.OnZoneBeginUpdate += zone =>
- {
- this.EventMgr.EnterUpdate();
- };
- node.OnZoneEndUpdate += zone =>
- {
- this.EventMgr.Update();
- };
- }
- }
- protected virtual void OnNodeStopped(EditorScene z)
- {
- this.zone_rpc_call_handler = null;
- this.zone_rpc_invoke_handler = null;
- z.OnUnitDead -= Z_OnUnitDead;
- z.OnUnitGotInstanceItem -= Z_OnUnitGotInstanceItem;
- z.OnGameOver -= Z_OnGameOver;
- //z.OnCurrentSecretPlacePlayTypeUpdateAction -= Z_OnCurrentSecretPlacePlayTypeUpdate;
- this.EventMgr?.Dispose();
- this.EventMgr = null;
- }
- //--------------------------------------------------------------------------------------------------------------------------------
- public virtual void GetStatus(TextWriter sb)
- {
- sb.WriteLine(" UUID = " + this.uuid);
- sb.WriteLine(" SceneData = " + this.node.SceneData);
- sb.WriteLine(" PlayerCount = " + this.node.PlayerCount);
- //sb.WriteLine(" ExpireTime = " + this.mExpireTimeUTC.ToLocalTime());
- sb.WriteLine(" IsGameOver = " + zoneGameOver);
- sb.WriteLine(" HasAddPlayer = " + HasAddPlayer);
- sb.WriteLine(" PassTime = " + node.ZonePassTime);
- }
- private DateTime keepPlayerLastTick = DateTime.Now;
- private TimeSpan keepPlayerExpire;
- private bool zoneGameOver = false;
- //private DateTime mExpireTimeUTC = DateTime.UtcNow;
- private bool HasAddPlayer = false;// player already in zone
- // public void SetSceneExpireTime(DateTime time)
- // {
- // mExpireTimeUTC = time.ToUniversalTime();
- // }
- // private bool IsExpire()
- // {
- // return (DateTime.UtcNow - mExpireTimeUTC).TotalSeconds > 0;
- // }
- /// <summary>
- /// 检测是否需要维持场景,否则,则销毁场景
- /// </summary>
- /// <returns></returns>
- protected virtual bool CheckNeedKeepPlayer(EditorScene z)
- {
- if (node.PlayerCount > 0) return true;
- if (zoneGameOver) return false;
- if (HasAddPlayer == false) return true;
- // if (!IsExpire()) return true;
- return false;
- }
- protected virtual void CheckZoneDispose(EditorScene z, TimeTaskMS t)
- {
- if (CheckNeedKeepPlayer(z))
- {
- zoneGameOver = false;
- keepPlayerLastTick = DateTime.Now;
- }
- else if ((DateTime.Now - keepPlayerLastTick) > keepPlayerExpire)
- {
- if (!zoneGameOver)
- {
- zoneGameOver = true;
- //notify areamanager close zone.
- service.area_manager.Invoke(new AreaZoneGameOverNotify()
- {
- zoneUUID = this.ZoneUUID,
- reason = "KeepPlayerTimeOver",
- });
- }
- t.Dispose();
- //start delay desotry.
- var delayDestoryTime = TimeSpan.FromSeconds(TimerConfig.timer_sec_DelayDestoryTime);
- // if (delayDestoryTime > TimeSpan.Zero)
- {
- //log.Info("ZoneNode Start Delay Destory : " + delayDestoryTime + " " + this.ZoneUUID);
- var evt = new DeepCore.GameData.Zone.GameOverEvent() { WinForce = 0, message = "KeepPlayerTimeOver" };
- service.Provider.Delay((st) =>
- {
- if (node.IsDisposed) { return; }
- //log.Info("ZoneNode Send AreaZoneDestoryNotify ZoneUUID : " + this.ZoneUUID);
- NotifyAllLogicsGameOver(evt);
- service.area_manager.Invoke(new AreaZoneDestoryNotify()
- {
- zoneUUID = this.ZoneUUID,
- reason = evt.message,
- });
- }, create, delayDestoryTime);
- }
- }
- }
- //--------------------------------------------------------------------------------------------------------------------------------
- protected virtual void Z_OnUnitDead(InstanceZone zone, InstanceUnit obj, InstanceUnit attacker)
- {
- if (attacker != null && obj != null)
- {
- if (obj.Info.UType == DeepCore.GameData.Zone.UnitInfo.UnitType.TYPE_MONSTER && attacker is InstancePlayer)
- {
- //玩家.
- var player = attacker as InstancePlayer;
- //生成奖励信息.
- var notify = GetRoleBattleAward(zone, obj, player);
- if (notify != null)
- {
- //通知游戏服.
- NotifyLogicRoleAward(player.PlayerUUID, notify);
- }
- }
- }
- }
- protected virtual void Z_OnCurrentSecretPlacePlayTypeUpdate(int updateType,int playID)
- {
- service.area_manager.Invoke(new CurrentSecretPlacePlayTypeUpdateNotify()
- {
- update = updateType,
- zoneUUID = this.ZoneUUID,
- playID = playID
- }); ;
- }
- //交给子类去实现
- protected virtual void Z_OnUnitGotInstanceItem(InstanceZone zone, InstanceUnit unit, InstanceItem item)
- {
- //TODO
- }
- protected virtual void Z_OnGameOver(InstanceZone zone, DeepCore.GameData.Zone.GameOverEvent evt)
- {
- zoneGameOver = true;
- //log.Info("ZoneNode GameOver : " + evt.message + " " + this.ZoneUUID);
- //notify logic.
- NotifyAllLogicsGameOver(evt);
- //notify areamanager close zone.
- service.area_manager.Invoke(new AreaZoneGameOverNotify()
- {
- zoneUUID = this.ZoneUUID,
- reason = evt.message,
- });
- }
- /// <summary>
- /// 通知逻辑服,场景结束
- /// </summary>
- /// <param name="evt"></param>
- protected virtual void NotifyAllLogicsGameOver(DeepCore.GameData.Zone.GameOverEvent evt)
- {
- node.ForEachPlayers((p) =>
- {
- var player = p.Client as AreaZonePlayer;
- player.DoGameOver(evt);
- });
- }
- /// <summary>
- /// 通知客户端,场景即将结束
- /// </summary>
- protected virtual void NotifyAllSessionsGameOver(TimeSpan delayTime)
- {
- //TODO 客户端显示倒计时
- //node.ForEachPlayers((p) =>
- //{
- // var player = p.Client as AreaZonePlayer;
- // player.SendToSession(null);
- //});
- }
- /// <summary>
- /// 向游戏服logic发送奖励信息.
- /// </summary>
- /// <param name="uuid"></param>
- /// <param name="notify"></param>
- protected virtual void NotifyLogicRoleAward(string uuid, RoleBattleAwardNotify notify)
- {
- var logic = service.GetPlayer(uuid);
- if (logic != null)
- {
- logic.logic_rpc_Invoke(notify);
- }
- }
- /// <summary>
- /// 生成奖励.
- /// </summary>
- /// <param name="zone"></param>
- /// <param name="obj"></param>
- /// <param name="attacker"></param>
- /// <returns></returns>
- protected virtual RoleBattleAwardNotify GetRoleBattleAward(InstanceZone zone, InstanceUnit obj, InstancePlayer attacker)
- {
- RoleBattleAwardNotify ret = new RoleBattleAwardNotify();
- ret.MonsterID = obj.Info.ID;
- ret.RoleID = attacker.PlayerUUID;
- return ret;
- }
- #endregion
- //--------------------------------------------------------------------------------------------------------------------------------
- #region IServer
- private Action<object, Action<object, Exception>> zone_rpc_call_handler;
- private Action<object> zone_rpc_invoke_handler;
- void IZoneNodeServer.GameServerRpcInvoke(object msg)
- {
- this.rpc_Invoke(msg as ISerializable);
- }
- void IZoneNodeServer.GameServerRpcCall(object msg, Action<object, Exception> callback)
- {
- this.rpc_Call(msg as ISerializable, (rsp, err) => { callback(rsp, err); });
- }
- void IZoneNodeServer.ListenGameServerRpcInvoke(Action<object> handler)
- {
- this.zone_rpc_invoke_handler = handler;
- }
- void IZoneNodeServer.ListenGameServerRpcCall(Action<object, Action<object, Exception>> handler)
- {
- this.zone_rpc_call_handler = handler;
- }
- #endregion
- }
- }
|