using CommonAI.Zone; using CommonAI.Zone.ZoneEditor; using CommonLang; using CommonLang.Log; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace CommonTickBattle.Battle { public class Battle : InstanceZoneListener, IDisposable { protected readonly Logger log = LoggerFactory.GetLogger("ZoneNode"); private readonly EditorTemplates mDataRoot; private readonly TemplateManager mTemplates; private readonly TBConfig mConfig; private readonly uint mUpdateInterval; private readonly uint mRequestLagging; private readonly uint mRequestLaggingTick; private readonly uint mResponseLagging; private readonly uint mResponseLaggingTick; //------------------------------------------------------------------------------------------------------------ // 内部主线程命令 // private SceneData mSceneData; private EditorScene mZone; private SyncMessageQueue mTasks = new SyncMessageQueue(); private ActionQueue mQueueActions = new ActionQueue(); private bool mShutDown = false; private bool mStarted = false; private bool mRunning = false; //------------------------------------------------------------------------------------------------------------ public Battle(EditorTemplates data_root, TBConfig cfg) { this.mDataRoot = data_root; this.mTemplates = data_root.Templates; this.mConfig = cfg; this.mUpdateInterval = cfg.GAME_FIXED_UPDATE_INTERVAL_MS; this.mRequestLagging = cfg.GAME_REQUEST_LAGGING_MS; this.mRequestLaggingTick = mRequestLagging / mUpdateInterval; this.mResponseLagging = cfg.GAME_RESPONSE_LAGGING_MS; this.mResponseLaggingTick = mResponseLagging / mUpdateInterval; } //------------------------------------------------------------------------------------------------------------ public string Name { get { return (mSceneData != null) ? mSceneData.ToString() : "null"; } } public SceneData SceneData { get { return mSceneData; } } public EditorTemplates DataRoot { get { return mDataRoot; } } public TemplateManager Templates { get { return mTemplates; } } public int SceneID { get { return mSceneData.ID; } } public EditorScene Zone { get { return mZone; } } //------------------------------------------------------------------------------------------------------------ /// /// 总共跑了多少帧 /// public ulong CurrentTick { get { return mZone.Tick; } } /// /// 每帧多少毫秒 /// public uint UpdateIntervalMS { get { return mUpdateInterval; } } /// /// Local->Host 超时时间(毫秒) /// public uint RequestLaggingMS { get { return mRequestLagging; } } /// /// Host->Local 超时时间(毫秒) /// public uint ResponseLaggingMS { get { return mResponseLagging; } } /// /// Local->Host 超时时间(帧) /// public uint RequestLaggingTick { get { return mRequestLaggingTick; } } /// /// Host->Local 超时时间(帧) /// public uint ResponseLaggingTick { get { return mResponseLaggingTick; } } //------------------------------------------------------------------------------------------------------------ public override string ToString() { if (mSceneData != null) { return mSceneData.Name + "(" + mSceneData.ID + ")"; } return "Unable to load scene"; } //------------------------------------------------------------------------------------------------------------ /// /// 房间初始化 /// public void Start(SceneData data) { lock (this) { if (mStarted) { return; } this.mStarted = true; // 解析游戏服创建房间信息 // this.mSceneData = data; { // 构造战斗场景 // this.mZone = TemplateManager.Factory.CreateEditorScene(this.Templates, this, mSceneData); // 非全屏同步,每个Client负责维护自己需要的队列 // this.mZone.SyncPos = false; this.mZone.IsSyncZ = false; // 半同步,场景不能大于255 // this.mZone.IsHalfSync = true; } this.mRunning = true; // 创建游戏主循环Timer // this.QueueTask(() => { OnStarted(); if (event_OnZoneStart != null) { event_OnZoneStart.Invoke(this); } }); } } /// /// 开始异步关闭房间 /// public void Stop() { lock (this) { mShutDown = true; } } public void Dispose() { lock (this) { if (mRunning) { throw new Exception("Battle is running"); } this.OnDispose(); this.DisposeEvents(); if (mZone != null) { this.mZone.Dispose(); } } } //------------------------------------------------------------------------------------------------------------ /// /// 战斗场景主逻辑更新// /// public virtual void Update() { lock (this) { if (mRunning) { int intervalMS = (int)mUpdateInterval; mTasks.ProcessMessages(do_task); ProcessAction(); OnBeginUpdate(); try { if (intervalMS > 0) { mZone.Update(intervalMS); this.OnZoneUpdate(); } } catch (Exception err) { log.Error(err.Message, err); OnError(err); } OnEndUpdate(); if (mShutDown) { mRunning = false; OnStopped(); if (event_OnZoneStop != null) { event_OnZoneStop.Invoke(this); } } } } } void InstanceZoneListener.onEventHandler(Event e) { this.OnZoneEventHandler(e); } //------------------------------------------------------------------------------------------------------------ #region FutureAction /// /// 想在未来某个时间点执行一个动作 /// /// /// 未来某个时间点 /// protected virtual bool PushAction(CommonAI.Zone.Action action, ulong tick) { lock (this) { if (tick > CurrentTick) { mQueueActions.Push(new FutureAction(action, tick)); return true; } else { log.ErrorFormat("指令已过期 : AT={0} : {1}", tick, action); } return false; } } private void ProcessAction() { while (mQueueActions.Count > 0) { var req = mQueueActions.Pop(Zone.Tick); if (req != null) { Zone.pushAction(req.action); } else { break; } } } private class FutureAction { public readonly CommonAI.Zone.Action action; public readonly ulong action_tick; public FutureAction(CommonAI.Zone.Action action, ulong tick) { this.action = action; this.action_tick = tick; } } private class ActionQueue : IComparer { private List queue = new List(); public int Count { get { return queue.Count; } } public void Push(FutureAction req) { queue.Add(req); queue.Sort(this); } public FutureAction Pop(ulong tick) { if (queue.Count > 0) { var req = queue[0]; if (req.action_tick == tick) { queue.RemoveAt(0); return req; } } return null; } public int Compare(FutureAction x, FutureAction y) { return (int)x.action_tick - (int)y.action_tick; } } #endregion //--------------------------------------------------------------------------------------- protected internal delegate void Task(); /// /// 保证在Task内部执行的代码线程安全 /// /// protected internal void QueueTask(Task task) { mTasks.Enqueue(task); } private void do_task(Task task) { task.Invoke(); } //--------------------------------------------------------------------------------------------------- protected virtual void OnStarted() { } protected virtual void OnStopped() { } protected virtual void OnZoneUpdate() { } protected virtual void OnBeginUpdate() { } protected virtual void OnEndUpdate() { } protected virtual void OnZoneEventHandler(Event e) { } protected virtual void OnError(Exception err) { } protected virtual void OnDispose() { } //------------------------------------------------------------------------------------------------------------ protected virtual void DisposeEvents() { this.event_OnZoneStart = null; this.event_OnZoneStop = null; } private Action event_OnZoneStart; private Action event_OnZoneStop; public event Action OnBattleStart { add { event_OnZoneStart += value; } remove { event_OnZoneStart -= value; } } public event Action OnBattleStop { add { event_OnZoneStop += value; } remove { event_OnZoneStop -= value; } } //--------------------------------------------------------------------------------------------------- } }