亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

一步一步開發Game服務器(四)地圖線程

2019-11-14 14:00:49
字體:
來源:轉載
供稿:網友

時隔這么久 才再一次的回歸正題繼續講解游戲服務器開發。

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

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

 

為什么會有區別呢?一個地圖肯定有執行線程,但是每一個地圖都有不同的時間任務。
比如檢測玩家身上的buffer,檢測玩家的狀態值。這種情況下如何處理呢?很明顯就需要定時器線程。

 我的處理方式是創建一個線程的時候根據需求創建對應的 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         /// 已分配的自定義線程靜態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">線程數量</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         /// 任務隊列 76         /// </summary> 77         protected List<TaskModel> taskQueue = new List<TaskModel>(); 78         /// <summary> 79         /// 任務隊列 80         /// </summary> 81         private List<TimerTask> timerTaskQueue = new List<TimerTask>(); 82  83         /// <summary> 84         /// 加入任務 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             //防止線程正在阻塞時添加進入了新任務 94             are.Set(); 95         } 96  97         /// <summary> 98         /// 加入任務 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         /// 通知一個或多個正在等待的線程已發生事件124         /// </summary>125         protected ManualResetEvent are = new ManualResetEvent(false);126 127         /// <summary>128         /// 通知一個或多個正在等待的線程已發生事件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                     /* 執行任務 */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 + " 執行任務:" + task.ToString() + " 遇到錯誤", 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 + " 完成了任務:" + task.ToString() + " 執行耗時:" + timeL1 + " 提交耗時:" + timeL2); }168                     else if (timeL1 <= 1000L) { Logger.Info(Thread.CurrentThread.Name + " 長時間執行 完成任務:" + task.ToString() + " “考慮”任務腳本邏輯 耗時:" + timeL1 + " 提交耗時:" + timeL2); }169                     else if (timeL1 <= 4000L) { Logger.Error(Thread.CurrentThread.Name + " 超長時間執行完成 任務:" + task.ToString() + " “檢查”任務腳本邏輯 耗時:" + timeL1 + " 提交耗時:" + timeL2); }170                     else171                     {172                         Logger.Error(Thread.CurrentThread.Name + " 超長時間執行完成 任務:" + task.ToString() + " “考慮是否應該刪除”任務腳本 耗時:" + timeL1 + " 提交耗時:" + timeL2);173                     }174                     task = null;175                 }176                 are.Reset();177                 //隊列為空等待200毫秒繼續178                 are.WaitOne(200);179             }180             Console.WriteLine(DateTime.Now.NowString() + " " + Thread.CurrentThread.Name + " Destroying");181         }182 183         /// <summary>184         /// 定時器線程處理器185         /// </summary>186         protected virtual void TimerRun()187         {188             ///無限循環執行函數器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 //是否滿足開始時間204                                 && (nowTime - timerEvent.GetSubmitTime() > timerEvent.IntervalTime)//提交以后是否滿足了間隔時間205                                 && (timerEvent.EndTime <= 0 || nowTime < timerEvent.EndTime) //判斷結束時間206                                 && (nowTime - lastTime >= timerEvent.IntervalTime))//判斷上次執行到目前是否滿足間隔時間207                         {208                             //提交執行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                     //隊列為空等待200毫秒繼續230                     timerAre.WaitOne(200);231                 }232             }233             Console.WriteLine(DateTime.Now.NowString() + "Thread:<" + Thread.CurrentThread.Name + "> Destroying");234         }235     }236 }
View Code

當我線程里面第一次添加定時器任務的時候加觸發定時器線程的初始化。

先看看效果

 

地圖運作方式怎么樣的呢?

來一張圖片看看

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

封裝地圖信息類

  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.49028c.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         /// 為跨服設計的服務器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 + " 結束"); 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);

 



這樣就創建了一張地圖。我們創建的新手村有兩條線。也就是兩個線程

這樣只是創建地圖容器和地圖線程而已。

如何添加各個定時器呢?

  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.49028c.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秒執行一次 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("我是地圖心跳檢查器 執行線程:" + System.Threading.Thread.CurrentThread.Name); 47             Logger.Debug("我是地圖心跳檢查器 檢查玩家是否需要復活,回血,狀態"); 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.49028c.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秒執行一次 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("怪物心跳檢查器 執行線程:" + System.Threading.Thread.CurrentThread.Name);107             Logger.Debug("怪物心跳檢查器 檢查怪物是否需要復活,需要回血,是否回跑");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.49028c.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秒執行一次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("怪物移動定時器任務 執行線程:" + System.Threading.Thread.CurrentThread.Name);163             Logger.Debug("怪物移動定時器任務 怪物隨機移動和回跑");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

 

就在初始化地圖線程的時候加入定時器任務

 

 

 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                 //添加地圖心跳檢測器12                 lineInfo.MapServer.AddTimerTask(new MapHeartTimer(ServerID, i, MapID, MapModelID));13                 //添加怪物移動定時器14                 lineInfo.MapServer.AddTimerTask(new MonsterRunTimer(ServerID, i, MapID, MapModelID));15                 //添加怪物心跳檢測器16                 lineInfo.MapServer.AddTimerTask(new MonsterHeartTimer(ServerID, i, MapID, MapModelID));17 18                 mapLineInfos[i] = lineInfo;19             }20             Logger.Debug("初始化地圖: " + name + " 地圖ID:" + MapID + " 結束");21         }
其實所有的任務定時器處理都是交給了timer線程,timer線程只負責查看該定時當前是否需要執行。
而具體的任務執行移交到線程執行器。線程執行器是按照隊列方式執行。保證了timer線程只是一個簡單的循環處理而不至于卡死
同樣也保證了在同一張地圖里面各個單元參數的線程安全性。

來看看效果。

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

這樣就完成了各個定時器在規定時間內處理自己的事情。

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

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

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

這一章我只是簡單的闡述了地圖運行和任務等劃分和構成已經任務處理流程。

接下來我會繼續講解游戲服務器編程,一步一步的剖析。

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

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久伊人精品视频| 91在线观看免费| 亚洲午夜小视频| 日韩av手机在线观看| 国产精品电影网| 亚洲女人被黑人巨大进入al| 91爱视频在线| 久久精品99久久香蕉国产色戒| 韩曰欧美视频免费观看| 久久亚洲精品中文字幕冲田杏梨| 欧美与黑人午夜性猛交久久久| 国产精品久久久| 亚洲黄色av女优在线观看| 日韩av最新在线观看| 视频在线观看一区二区| 国自在线精品视频| 日韩黄色在线免费观看| 欧美亚洲视频在线看网址| 95av在线视频| 亚洲色图校园春色| 久久久久久久久久久久久久久久久久av| www.精品av.com| 亚洲精品www久久久| 亚洲一区二区三区乱码aⅴ蜜桃女| 日韩美女写真福利在线观看| 成人啪啪免费看| 青草热久免费精品视频| 国产91ⅴ在线精品免费观看| 91精品国产自产91精品| 亚洲男人av在线| 亚洲国产成人在线播放| 美女啪啪无遮挡免费久久网站| 国产精品网红福利| 国产亚洲精品美女久久久久| 欧美日韩国产精品一区二区不卡中文| 国产精品免费看久久久香蕉| 97免费中文视频在线观看| 国产成一区二区| 国内精品久久久| 国产一区二区三区在线播放免费观看| 久久婷婷国产麻豆91天堂| 日韩美女写真福利在线观看| 欧美日韩国产中文精品字幕自在自线| 日韩国产高清视频在线| 日本成熟性欧美| 国产丝袜精品视频| 日韩中文字在线| 26uuu亚洲国产精品| 欧美成人免费va影院高清| 91久久久久久久| 久久中文字幕在线| 中文国产亚洲喷潮| 国产亚洲精品日韩| 久久99精品久久久久久噜噜| 大胆欧美人体视频| 亚洲色图校园春色| 日韩精品极品毛片系列视频| 成人在线国产精品| 日韩欧美在线视频| 成人激情黄色网| 国语对白做受69| 国产精品久久二区| 精品av在线播放| 欧美精品免费看| 欧美—级a级欧美特级ar全黄| 欧美黑人xxxⅹ高潮交| 亚洲欧美999| 国产婷婷成人久久av免费高清| 伊人激情综合网| 91在线看www| 久久电影一区二区| 国产不卡精品视男人的天堂| 国内精品久久久久久久久| 美女性感视频久久久| 国语自产精品视频在线看抢先版图片| xxav国产精品美女主播| 亚洲精品资源在线| 成人字幕网zmw| 久久人人爽人人爽人人片亚洲| 亚洲福利视频专区| 最近免费中文字幕视频2019| 日韩动漫免费观看电视剧高清| 欧美激情亚洲一区| 亚洲黄色免费三级| 欧美在线视频免费观看| 成人看片人aa| 欧美精品videofree1080p| 欧美日韩精品在线观看| 国产欧美一区二区| 亚洲日本欧美中文幕| 亚洲视频在线观看视频| 日产精品99久久久久久| 精品成人69xx.xyz| 九九热精品在线| 精品国产乱码久久久久久天美| 精品爽片免费看久久| 日韩综合中文字幕| 亚洲国产精彩中文乱码av在线播放| 日本三级久久久| 国模吧一区二区| 亚洲国产成人精品女人久久久| 亚洲天堂av女优| 久久伊人免费视频| 久久精品国产欧美激情| 性欧美亚洲xxxx乳在线观看| 日本伊人精品一区二区三区介绍| 欧美日韩黄色大片| 久久久国产影院| 国产精品成人v| 欧美日韩一区二区在线播放| 日本中文字幕成人| 欧美最猛性xxxxx(亚洲精品)| 欧美日韩中文字幕在线| 亚洲国产精品va| 日本人成精品视频在线| 国产精品视频最多的网站| 欧美一级在线播放| 欧美野外猛男的大粗鳮| 奇米四色中文综合久久| 91高清在线免费观看| 亚洲女人被黑人巨大进入al| 欧美日韩亚洲成人| 国产精品久久久久国产a级| 久久精品成人欧美大片| 色妞色视频一区二区三区四区| 91精品国产精品| 欧美一区二粉嫩精品国产一线天| 亚洲一区制服诱惑| 亚洲综合色激情五月| 国产日韩专区在线| 成人久久18免费网站图片| 成人国产精品日本在线| www国产精品视频| 在线播放国产一区二区三区| 久久久女人电视剧免费播放下载| 日韩视频在线免费观看| 亚洲欧美www| 精品成人乱色一区二区| 亚洲国产欧美一区| 国产日韩欧美视频在线| 亚洲国产精品久久91精品| 日韩精品在线免费观看视频| 久久天天躁狠狠躁夜夜爽蜜月| 欧美成人精品在线播放| 91精品国产自产91精品| 亚洲国产一区二区三区在线观看| 亚洲最大的成人网| 国产精品久久婷婷六月丁香| 欧美日韩精品在线播放| 亚洲四色影视在线观看| 亚洲第一福利网| 精品国产91久久久久久老师| 欧美在线视频免费观看| 深夜精品寂寞黄网站在线观看| 欧美老少配视频| 日韩欧美精品网站| 欧美精品免费在线观看| 一区二区福利视频| 国产偷亚洲偷欧美偷精品| 亚洲激情国产精品| 4388成人网| 欧美激情中文字幕乱码免费| 亚洲欧美激情在线视频| 国产午夜精品理论片a级探花|