国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

一步一步開發(fā)Game服務(wù)器(四)地圖線程

2019-11-14 14:00:49
字體:
供稿:網(wǎng)友

時(shí)隔這么久 才再一次的回歸正題繼續(xù)講解游戲服務(wù)器開發(fā)。

開始講解前有一個(gè)問題需要修正。之前講的線程和定時(shí)器線程的時(shí)候是分開的。

但是真正地圖線程與之前的線程模型是有區(qū)別的。

 

為什么會(huì)有區(qū)別呢?一個(gè)地圖肯定有執(zhí)行線程,但是每一個(gè)地圖都有不同的時(shí)間任務(wù)。
比如檢測(cè)玩家身上的buffer,檢測(cè)玩家的狀態(tài)值。這種情況下如何處理呢?很明顯就需要定時(shí)器線程。

 我的處理方式是創(chuàng)建一個(gè)線程的時(shí)候根據(jù)需求創(chuàng)建對(duì)應(yīng)的 timerthread

直接上代碼其他不BB

  1 using System;  2 using System.Collections.Generic;  3 using System.Linq;  4 using System.Text;  5 using System.Threading;  6 using System.Threading.Tasks;  7   8 namespace Sz.ThreadPool  9 { 10     /// <summary> 11     /// 線程模型 12     /// </summary>     13     public class ThreadModel 14     { 15         /// <summary> 16         ///  17         /// </summary> 18         public bool IsStop = false; 19         /// <summary> 20         /// ID 21         /// </summary> 22         public int ID { get; PRivate set; } 23         /// <summary> 24         /// 已分配的自定義線程靜態(tài)ID 25         /// </summary> 26         public static int StaticID { get; private set; } 27  28         string Name; 29  30         /// <summary> 31         /// 初始化線程模型, 32         /// </summary> 33         /// <param name="name"></param> 34         public ThreadModel(String name) 35             : this(name, 1) 36         { 37  38         } 39  40         /// <summary> 41         /// 初始化線程模型 42         /// </summary> 43         /// <param name="name">線程名稱</param> 44         /// <param name="count">線程數(shù)量</param> 45         public ThreadModel(String name, Int32 count) 46         { 47             lock (typeof(ThreadModel)) 48             { 49                 StaticID++; 50                 ID = StaticID; 51             } 52             this.Name = name; 53             if (count == 1) 54             { 55                 System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(Run)); 56                 thread.Name = "< " + name + "線程 >";                 57                 thread.Start(); 58                 Logger.Info("初始化 " + thread.Name); 59             } 60             else 61             { 62                 for (int i = 0; i < count; i++) 63                 { 64                     System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(Run)); 65                     thread.Name = "< " + name + "_" + (i + 1) + "線程 >";                     66                     thread.Start(); 67                     Logger.Info("初始化 " + thread.Name); 68                 } 69             } 70         } 71  72         System.Threading.Thread threadTimer = null; 73  74         /// <summary> 75         /// 任務(wù)隊(duì)列 76         /// </summary> 77         protected List<TaskModel> taskQueue = new List<TaskModel>(); 78         /// <summary> 79         /// 任務(wù)隊(duì)列 80         /// </summary> 81         private List<TimerTask> timerTaskQueue = new List<TimerTask>(); 82  83         /// <summary> 84         /// 加入任務(wù) 85         /// </summary> 86         /// <param name="t"></param> 87         public virtual void AddTask(TaskModel t) 88         { 89             lock (taskQueue) 90             { 91                 taskQueue.Add(t); 92             } 93             //防止線程正在阻塞時(shí)添加進(jìn)入了新任務(wù) 94             are.Set(); 95         } 96  97         /// <summary> 98         /// 加入任務(wù) 99         /// </summary>100         /// <param name="t"></param>101         public void AddTimerTask(TimerTask t)102         {103             t.RunAttribute["lastactiontime"] = SzExtensions.CurrentTimeMillis();104             if (t.IsStartAction)105             {106                 AddTask(t);107             }108             lock (timerTaskQueue)109             {110                 if (threadTimer == null)111                 {112                     threadTimer = new System.Threading.Thread(new System.Threading.ThreadStart(TimerRun));113                     threadTimer.Name = "< " + this.Name + " - Timer線程 >";                    114                     threadTimer.Start();115                     Logger.Info("初始化 " + threadTimer.Name);116                 }117                 timerTaskQueue.Add(t);118             }119             timerAre.Set();120         }121 122         /// <summary>123         /// 通知一個(gè)或多個(gè)正在等待的線程已發(fā)生事件124         /// </summary>125         protected ManualResetEvent are = new ManualResetEvent(false);126 127         /// <summary>128         /// 通知一個(gè)或多個(gè)正在等待的線程已發(fā)生事件129         /// </summary>130         protected ManualResetEvent timerAre = new ManualResetEvent(true);131 132         /// <summary>133         /// 線程處理器134         /// </summary>135         protected virtual void Run()136         {137             while (!this.IsStop)138             {139                 while ((taskQueue.Count > 0))140                 {141                     TaskModel task = null;142                     lock (taskQueue)143                     {144                         if (taskQueue.Count > 0)145                         {146                             task = taskQueue[0];147                             taskQueue.RemoveAt(0);148                         }149                         else { break; }150                     }151 152                     /* 執(zhí)行任務(wù) */153                     //r.setSubmitTimeL();154                     long submitTime = SzExtensions.CurrentTimeMillis();155                     try156                     {157                         task.Run();158                     }159                     catch (Exception e)160                     {161                         Logger.Error(Thread.CurrentThread.Name + " 執(zhí)行任務(wù):" + task.ToString() + " 遇到錯(cuò)誤", e);162                         continue;163                     }164                     long timeL1 = SzExtensions.CurrentTimeMillis() - submitTime;165                     long timeL2 = SzExtensions.CurrentTimeMillis() - task.GetSubmitTime();166                     if (timeL1 < 100) { }167                     else if (timeL1 <= 200L) { Logger.Debug(Thread.CurrentThread.Name + " 完成了任務(wù):" + task.ToString() + " 執(zhí)行耗時(shí):" + timeL1 + " 提交耗時(shí):" + timeL2); }168                     else if (timeL1 <= 1000L) { Logger.Info(Thread.CurrentThread.Name + " 長時(shí)間執(zhí)行 完成任務(wù):" + task.ToString() + " “考慮”任務(wù)腳本邏輯 耗時(shí):" + timeL1 + " 提交耗時(shí):" + timeL2); }169                     else if (timeL1 <= 4000L) { Logger.Error(Thread.CurrentThread.Name + " 超長時(shí)間執(zhí)行完成 任務(wù):" + task.ToString() + " “檢查”任務(wù)腳本邏輯 耗時(shí):" + timeL1 + " 提交耗時(shí):" + timeL2); }170                     else171                     {172                         Logger.Error(Thread.CurrentThread.Name + " 超長時(shí)間執(zhí)行完成 任務(wù):" + task.ToString() + " “考慮是否應(yīng)該刪除”任務(wù)腳本 耗時(shí):" + timeL1 + " 提交耗時(shí):" + timeL2);173                     }174                     task = null;175                 }176                 are.Reset();177                 //隊(duì)列為空等待200毫秒繼續(xù)178                 are.WaitOne(200);179             }180             Console.WriteLine(DateTime.Now.NowString() + " " + Thread.CurrentThread.Name + " Destroying");181         }182 183         /// <summary>184         /// 定時(shí)器線程處理器185         /// </summary>186         protected virtual void TimerRun()187         {188             ///無限循環(huán)執(zhí)行函數(shù)器189             while (!this.IsStop)190             {191                 if (timerTaskQueue.Count > 0)192                 {193                     IEnumerable<TimerTask> collections = null;194                     lock (timerTaskQueue)195                     {196                         collections = new List<TimerTask>(timerTaskQueue);197                     }198                     foreach (TimerTask timerEvent in collections)199                     {200                         int execCount = timerEvent.RunAttribute.GetintValue("Execcount");201                         long lastTime = timerEvent.RunAttribute.GetlongValue("LastExecTime");202                         long nowTime = SzExtensions.CurrentTimeMillis();203                         if (nowTime > timerEvent.StartTime //是否滿足開始時(shí)間204                                 && (nowTime - timerEvent.GetSubmitTime() > timerEvent.IntervalTime)//提交以后是否滿足了間隔時(shí)間205                                 && (timerEvent.EndTime <= 0 || nowTime < timerEvent.EndTime) //判斷結(jié)束時(shí)間206                                 && (nowTime - lastTime >= timerEvent.IntervalTime))//判斷上次執(zhí)行到目前是否滿足間隔時(shí)間207                         {208                             //提交執(zhí)行209                             this.AddTask(timerEvent);210                             //記錄211                             execCount++;212                             timerEvent.RunAttribute["Execcount"] = execCount;213                             timerEvent.RunAttribute["LastExecTime"] = nowTime;214                         }215                         nowTime = SzExtensions.CurrentTimeMillis();216                         //判斷刪除條件217                         if ((timerEvent.EndTime > 0 && nowTime < timerEvent.EndTime)218                                 || (timerEvent.ActionCount > 0 && timerEvent.ActionCount <= execCount))219                         {220                             timerTaskQueue.Remove(timerEvent);221                         }222                     }223                     timerAre.Reset();224                     timerAre.WaitOne(5);225                 }226                 else227                 {228                     timerAre.Reset();229                     //隊(duì)列為空等待200毫秒繼續(xù)230                     timerAre.WaitOne(200);231                 }232             }233             Console.WriteLine(DateTime.Now.NowString() + "Thread:<" + Thread.CurrentThread.Name + "> Destroying");234         }235     }236 }
View Code

當(dāng)我線程里面第一次添加定時(shí)器任務(wù)的時(shí)候加觸發(fā)定時(shí)器線程的初始化。

先看看效果

 

地圖運(yùn)作方式怎么樣的呢?

來一張圖片看看

在正常情況下一個(gè)地圖需要這些事情。然后大部分事情是需要定時(shí)器任務(wù)處理的,只有客戶端交互通信是不需要定時(shí)器任務(wù)處理。

封裝地圖信息類

  1 using System;  2 using System.Collections.Generic;  3 using System.Linq;  4 using System.Text;  5 using System.Threading.Tasks;  6 using Sz.MMO.GameServer.IMapScripts;  7 using Sz.MMO.GameServer.TimerMap;  8 using Sz.MMO.GameServer.TimerMonster;  9  10  11 /** 12  *  13  * @author 失足程序員 14  * @Blog http://www.survivalescaperooms.com/ty408/ 15  * @mail 492794628@QQ.com 16  * @phone 13882122019 17  *  18  */ 19 namespace Sz.MMO.GameServer.Structs.Map 20 { 21     /// <summary> 22     ///  23     /// </summary> 24     public class MapInfo<TPlayer, TNpc, TMonster, TDropGoods> : IEnterMapMonsterScript, IEnterMapNpcScript, IEnterMapPlayerScript, IEnterMapDropGoodsScript 25     { 26         /// <summary> 27         /// 為跨服設(shè)計(jì)的服務(wù)器id 28         /// </summary> 29         public int ServerID { get; set; } 30         /// <summary> 31         /// 地圖模板id 32         /// </summary> 33         public int MapModelID { get; set; } 34         /// <summary> 35         /// 地圖id 36         /// </summary> 37         public long MapID { get; set; } 38  39         /// <summary> 40         /// 地圖分線處理 41         /// </summary> 42         Dictionary<int, MapLineInfo<TPlayer, TNpc, TMonster, TDropGoods>> mapLineInfos = new Dictionary<int, MapLineInfo<TPlayer, TNpc, TMonster, TDropGoods>>(); 43  44         public MapInfo(string name, int mapModelId, int lineCount = 1) 45         { 46  47             this.MapID = SzExtensions.GetId(); 48             this.MapModelID = mapModelId; 49             Logger.Debug("開始初始化地圖: " + name + " 地圖ID:" + MapID); 50  51             for (int i = 1; i <= lineCount; i++) 52             { 53                 MapLineInfo<TPlayer, TNpc, TMonster, TDropGoods> lineInfo = new MapLineInfo<TPlayer, TNpc, TMonster, TDropGoods>(name + "-" + i + ""); 54  55                 mapLineInfos[i] = lineInfo; 56             } 57             Logger.Debug("初始化地圖: " + name + " 地圖ID:" + MapID + " 結(jié)束"); 58         } 59  60     } 61  62     #region 地圖分線 class MapLineInfo<TPlayer, TNpc, TMonster, TDropGoods> : IEnterMapMonsterScript, IEnterMapNpcScript, IEnterMapPlayerScript, IEnterMapDropGoodsScript 63     /// <summary> 64     /// 地圖分線 65     /// </summary> 66     /// <typeparam name="TPlayer"></typeparam> 67     /// <typeparam name="TNpc"></typeparam> 68     /// <typeparam name="TMonster"></typeparam> 69     /// <typeparam name="TDropGoods"></typeparam> 70     class MapLineInfo<TPlayer, TNpc, TMonster, TDropGoods> : IEnterMapMonsterScript, IEnterMapNpcScript, IEnterMapPlayerScript, IEnterMapDropGoodsScript 71     { 72         public MapThread MapServer { get; set; } 73  74         public int ServerID { get; set; } 75  76         public int LineID { get; set; } 77  78         public int MapModelID { get; set; } 79  80         public long MapID { get; set; } 81  82         public MapLineInfo(string name) 83         { 84             Players = new List<TPlayer>(); 85             Monsters = new List<TMonster>(); 86             Npcs = new List<TNpc>(); 87             DropGoodss = new List<TDropGoods>(); 88             MapServer = new Structs.Map.MapThread(name); 89         } 90  91         /// <summary> 92         /// 地圖玩家 93         /// </summary> 94         public List<TPlayer> Players { get; set; } 95  96         /// <summary> 97         /// 地圖npc 98         /// </summary> 99         public List<TNpc> Npcs { get; set; }100 101         /// <summary>102         /// 地圖怪物103         /// </summary>104         public List<TMonster> Monsters { get; set; }105 106         /// <summary>107         /// 地圖掉落物108         /// </summary>109         public List<TDropGoods> DropGoodss { get; set; }110     }111     #endregion112 }
View Code
   Structs.Map.MapInfo<Player, Npc, Monster, Drop> map = new Structs.Map.MapInfo<Player, Npc, Monster, Drop>("新手村", 101, 2);

 



這樣就創(chuàng)建了一張地圖。我們創(chuàng)建的新手村有兩條線。也就是兩個(gè)線程

這樣只是創(chuàng)建地圖容器和地圖線程而已。

如何添加各個(gè)定時(shí)器呢?

  1 using System;  2 using System.Collections.Generic;  3 using System.Linq;  4 using System.Text;  5 using System.Threading.Tasks;  6 using Sz.MMO.GameServer.IMapScripts;  7   8   9 /** 10  *  11  * @author 失足程序員 12  * @Blog http://www.survivalescaperooms.com/ty408/ 13  * @mail 492794628@qq.com 14  * @phone 13882122019 15  *  16  */ 17 namespace Sz.MMO.GameServer.TimerMap 18 { 19     /// <summary> 20     ///  21     /// </summary> 22     public class MapHeartTimer : ThreadPool.TimerTask 23     { 24  25         int serverID, lineID, mapModelID; 26         long mapID; 27  28         /// <summary> 29         /// 指定1秒執(zhí)行一次 30         /// </summary> 31         public MapHeartTimer(int serverID, int lineID, long mapID, int mapModelID) 32             : base(1000 * 10) 33         { 34             this.serverID = serverID; 35             this.lineID = lineID; 36             this.mapID = mapID; 37             this.mapModelID = mapModelID; 38         } 39  40         /// <summary> 41         ///  42         /// </summary> 43         public override void Run() 44         { 45              46             Logger.Debug("我是地圖心跳檢查器 執(zhí)行線程:" + System.Threading.Thread.CurrentThread.Name); 47             Logger.Debug("我是地圖心跳檢查器 檢查玩家是否需要復(fù)活,回血,狀態(tài)"); 48             //var scripts = Sz.ScriptPool.ScriptManager.Instance.GetInstances<IMapHeartTimerScript>(); 49             //foreach (var item in scripts) 50             //{ 51             //    item.Run(serverID, lineID, mapID, mapModelID); 52             //} 53         } 54  55     } 56 } 57  58  59  60  61  62 using System; 63 using System.Collections.Generic; 64 using System.Linq; 65 using System.Text; 66 using System.Threading.Tasks; 67 using Sz.MMO.GameServer.IMonsterScripts; 68  69  70 /** 71  *  72  * @author 失足程序員 73  * @Blog http://www.survivalescaperooms.com/ty408/ 74  * @mail 492794628@qq.com 75  * @phone 13882122019 76  *  77  */ 78 namespace Sz.MMO.GameServer.TimerMonster 79 { 80     /// <summary> 81     ///  82     /// </summary> 83     public class MonsterHeartTimer: ThreadPool.TimerTask 84     { 85  86         int serverID, lineID, mapModelID; 87         long mapID; 88  89         /// <summary> 90         /// 指定1秒執(zhí)行一次 91         /// </summary> 92         public MonsterHeartTimer(int serverID, int lineID, long mapID, int mapModelID) 93             : base(1000 * 10) 94         { 95             this.serverID = serverID; 96             this.lineID = lineID; 97             this.mapID = mapID; 98             this.mapModelID = mapModelID; 99         }100 101         /// <summary>102         /// 103         /// </summary>104         public override void Run()105         {            106             Logger.Debug("怪物心跳檢查器 執(zhí)行線程:" + System.Threading.Thread.CurrentThread.Name);107             Logger.Debug("怪物心跳檢查器 檢查怪物是否需要復(fù)活,需要回血,是否回跑");108             //var scripts = Sz.ScriptPool.ScriptManager.Instance.GetInstances<IMonsterHeartTimerScript>();109             //foreach (var item in scripts)110             //{111             //    item.Run(serverID, lineID, mapID, mapModelID);112             //}113         }114     }115 }116 117 118 119 using System;120 using System.Collections.Generic;121 using System.Linq;122 using System.Text;123 using System.Threading.Tasks;124 125 126 /**127  * 128  * @author 失足程序員129  * @Blog http://www.survivalescaperooms.com/ty408/130  * @mail 492794628@qq.com131  * @phone 13882122019132  * 133  */134 namespace Sz.MMO.GameServer.TimerMonster135 {136     /// <summary>137     /// 138     /// </summary>139     public class MonsterRunTimer: ThreadPool.TimerTask140     {141 142         int serverID, lineID, mapModelID;143         long mapID;144 145         /// <summary>146         /// 指定1秒執(zhí)行一次147         /// </summary>148         public MonsterRunTimer(int serverID, int lineID, long mapID, int mapModelID)149             : base(1000 * 5)150         {151             this.serverID = serverID;152             this.lineID = lineID;153             this.mapID = mapID;154             this.mapModelID = mapModelID;155         }156 157         /// <summary>158         /// 159         /// </summary>160         public override void Run()161         {            162             Logger.Debug("怪物移動(dòng)定時(shí)器任務(wù) 執(zhí)行線程:" + System.Threading.Thread.CurrentThread.Name);163             Logger.Debug("怪物移動(dòng)定時(shí)器任務(wù) 怪物隨機(jī)移動(dòng)和回跑");164             //var scripts = Sz.ScriptPool.ScriptManager.Instance.GetInstances<IMonsterHeartTimerScript>();165             //foreach (var item in scripts)166             //{167             //    item.Run(serverID, lineID, mapID, mapModelID);168             //}169         }170     }171 }
View Code

 

就在初始化地圖線程的時(shí)候加入定時(shí)器任務(wù)

 

 

 1         public MapInfo(string name, int mapModelId, int lineCount = 1) 2         { 3  4             this.MapID = SzExtensions.GetId(); 5             this.MapModelID = mapModelId; 6             Logger.Debug("開始初始化地圖: " + name + " 地圖ID:" + MapID); 7  8             for (int i = 1; i <= lineCount; i++) 9             {10                 MapLineInfo<TPlayer, TNpc, TMonster, TDropGoods> lineInfo = new MapLineInfo<TPlayer, TNpc, TMonster, TDropGoods>(name + "-" + i + "");11                 //添加地圖心跳檢測(cè)器12                 lineInfo.MapServer.AddTimerTask(new MapHeartTimer(ServerID, i, MapID, MapModelID));13                 //添加怪物移動(dòng)定時(shí)器14                 lineInfo.MapServer.AddTimerTask(new MonsterRunTimer(ServerID, i, MapID, MapModelID));15                 //添加怪物心跳檢測(cè)器16                 lineInfo.MapServer.AddTimerTask(new MonsterHeartTimer(ServerID, i, MapID, MapModelID));17 18                 mapLineInfos[i] = lineInfo;19             }20             Logger.Debug("初始化地圖: " + name + " 地圖ID:" + MapID + " 結(jié)束");21         }
其實(shí)所有的任務(wù)定時(shí)器處理都是交給了timer線程,timer線程只負(fù)責(zé)查看該定時(shí)當(dāng)前是否需要執(zhí)行。
而具體的任務(wù)執(zhí)行移交到線程執(zhí)行器。線程執(zhí)行器是按照隊(duì)列方式執(zhí)行。保證了timer線程只是一個(gè)簡單的循環(huán)處理而不至于卡死
同樣也保證了在同一張地圖里面各個(gè)單元參數(shù)的線程安全性。

來看看效果。

為了方便我們看清楚一點(diǎn),我把地圖線程改為以一條線。

這樣就完成了各個(gè)定時(shí)器在規(guī)定時(shí)間內(nèi)處理自己的事情。

需要注意的是這里只是簡單的模擬的一個(gè)地圖處理各種事情,最終都是由一個(gè)線程處理的。那么肯定有人要問了。
你一個(gè)線程處理這些事情能忙得過來嘛?
有兩點(diǎn)需要注意
1,你的每一個(gè)任務(wù)處理處理耗時(shí)是多久,換句話說你可以理解為你一秒鐘能處理多少個(gè)任務(wù)。
2,你的地圖能容納多少怪物,多少玩家,多少掉落物?換句話說也就是你設(shè)計(jì)的復(fù)雜度間接限制了你的地圖有多少場(chǎng)景對(duì)象。

那么還有什么需要注意的呢?

其實(shí)地圖最大的消耗在于尋路。高性能的尋路算法和人性化尋路算法一直是大神研究的對(duì)象,我也只能是借鑒他們的了。

這一章我只是簡單的闡述了地圖運(yùn)行和任務(wù)等劃分和構(gòu)成已經(jīng)任務(wù)處理流程。

接下來我會(huì)繼續(xù)講解游戲服務(wù)器編程,一步一步的剖析。

文路不是很清晰。希望大家不要見怪。

 


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 南汇区| 梧州市| 托克逊县| 兴隆县| 浏阳市| 房产| 长海县| 柯坪县| 灵山县| 横山县| 若尔盖县| 阿巴嘎旗| 皮山县| 海城市| 广德县| 和政县| 衢州市| 罗源县| 东方市| 西藏| 札达县| 武山县| 宽城| 鄄城县| 长沙县| 定州市| 洛隆县| 定结县| 潮州市| 卢湾区| 柞水县| 新龙县| 海林市| 彭阳县| 遂昌县| 惠东县| 宣汉县| 南召县| 锡林郭勒盟| 玉门市| 喜德县|