Legend of Mir(传奇)官方源码学习3服务端程序初始化过程
Posted シ゛甜虾
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Legend of Mir(传奇)官方源码学习3服务端程序初始化过程相关的知识,希望对你有一定的参考价值。
一、窗体事件
整个服务端界面只有2个事件,一个SMain_Load一个SMain_FormClosing,一个负责初始化,一个负责程序关闭保存
SMain_Load事件
private void SMain_Load(object sender, EventArgs e)
EditEnvir.LoadDB();
Envir.Start();
AutoResize();
这里要讲一下比较有趣的变量(用到了=> 运算符(C# 参考))
public static Envir Envir => Envir.Main;
public static Envir EditEnvir => Envir.Edit;
有的人可能看不懂了,lambda运算符:所有的lambda表达式都是用新的lambda运算符 " => ",可以叫他,“转到”或者 “成为”。运算符将表达式分为两部分,左边指定输入参数,右边是lambda的主体,这里的实际效果与下面代码效果相同。
public static Envir Envir = Envir.Main;
public static Envir EditEnvir = Envir.Edit;
一个Envir.Main,和一个Envir.Edit,创建的竟然是同一个类,看来这个类里面有不少公共的东西在里面,要不然也不会放到一起不拆分开来。
public static Envir Main get; = new Envir();
public static Envir Edit get; = new Envir();
一个负责加载游戏资源,一个负责执行游戏逻辑,可能是方便多人开发的这么写的具体为啥这么写不知道,总感觉怪怪的,继续往下看,可能就知道了
EditEnvir.LoadDB(); //也就是Envir Edit
Envir.Start(); //也就是Envir Main
整个代码还是比较清晰的,Envir类一共2个锁
public static object AccountLock = new object(); //账户锁
public static object LoadLock = new object(); //Load锁
3个路径配置
public static readonly string DatabasePath = Path.Combine(".", "Server.MirDB"); //主数据库路径
public static readonly string AccountPath = Path.Combine(".", "Server.MirADB"); //账户数据库路径
public static readonly string BackUpPath = Path.Combine(".", "Back Up"); //客户端升级文件列表?
LoadDB(),加载地图NPC等等数据,如果文件不存在就创建DB文件,并把默认设置写进去
//Server DB
public int MapIndex, ItemIndex, MonsterIndex, NPCIndex, QuestIndex, GameshopIndex, ConquestIndex, RespawnIndex;
public List<MapInfo> MapInfoList = new List<MapInfo>();
public List<ItemInfo> ItemInfoList = new List<ItemInfo>();
public List<MonsterInfo> MonsterInfoList = new List<MonsterInfo>();
public List<MagicInfo> MagicInfoList = new List<MagicInfo>();
public List<NPCInfo> NPCInfoList = new List<NPCInfo>();
public DragonInfo DragonInfo = new DragonInfo();
public List<QuestInfo> QuestInfoList = new List<QuestInfo>();
public List<GameShopItem> GameShopList = new List<GameShopItem>();
public List<RecipeInfo> RecipeInfoList = new List<RecipeInfo>();
public Dictionary<int, int> GameshopLog = new Dictionary<int, int>();
这个DB文件呢,就很简单,单纯的二进制存储
简单有直接写DB如下
public void SaveDB()
using (var stream = File.Create(DatabasePath))
using (var writer = new BinaryWriter(stream))
writer.Write(Version);
writer.Write(CustomVersion);
writer.Write(MapIndex);
writer.Write(ItemIndex);
writer.Write(MonsterIndex);
writer.Write(NPCIndex);
writer.Write(QuestIndex);
writer.Write(GameshopIndex);
writer.Write(ConquestIndex);
writer.Write(RespawnIndex);
writer.Write(MapInfoList.Count);
for (var i = 0; i < MapInfoList.Count; i++)
MapInfoList[i].Save(writer);
writer.Write(ItemInfoList.Count);
for (var i = 0; i < ItemInfoList.Count; i++)
ItemInfoList[i].Save(writer);
writer.Write(MonsterInfoList.Count);
for (var i = 0; i < MonsterInfoList.Count; i++)
MonsterInfoList[i].Save(writer);
writer.Write(NPCInfoList.Count);
for (var i = 0; i < NPCInfoList.Count; i++)
NPCInfoList[i].Save(writer);
writer.Write(QuestInfoList.Count);
for (var i = 0; i < QuestInfoList.Count; i++)
QuestInfoList[i].Save(writer);
DragonInfo.Save(writer);
writer.Write(MagicInfoList.Count);
for (var i = 0; i < MagicInfoList.Count; i++)
MagicInfoList[i].Save(writer);
writer.Write(GameShopList.Count);
for (var i = 0; i < GameShopList.Count; i++)
GameShopList[i].Save(writer);
writer.Write(ConquestInfos.Count);
for (var i = 0; i < ConquestInfos.Count; i++)
ConquestInfos[i].Save(writer);
RespawnTick.Save(writer);
Envir.Start(); 加载完数据,就准备开始游戏,这里再次加载DB数据,这么看前期加载只是个测试
public void Start()
if (Running || _thread != null) return;
Running = true;
_thread = new Thread(WorkLoop) IsBackground = true;
_thread.Start();
这里启动了一个新的线程,开始加载地图和NPC等资源
StartEnvir(); //加载地图和NPC等资源
var canstartserver = CanStartEnvir(); //效验BOOS怪物是否加载
效验BOOS怪物是否加载,如果BOOS没有顺利加载停止服务器运行
这个代码就比较有意思,多少个线程就弄多少个链表
if (Settings.Multithreaded)
for (var j = 0; j < MobThreads.Length; j++)
MobThreads[j] = new MobThread();
MobThreads[j].Id = j;
每个链表传递给一个工作线程,如果Settings.Multithreaded==0,那么就只有主线程WorkLoop在工作,看样子,MobThread里面有的Envir里面也有,果不其然
if (Settings.Multithreaded)
for (var j = 0; j < MobThreads.Length; j++)
var Info = MobThreads[j];
if (j <= 0) continue;
MobThreading[j] = new Thread(() => ThreadLoop(Info)) IsBackground = true;
MobThreading[j].Start();
ThreadLoop代码
private void ThreadLoop(MobThread Info)
Info.Stop = false;
var starttime = Time;
try
var stopping = false;
if (Info._current == null)
Info._current = Info.ObjectsList.First;
stopping = Info._current == null;
//while (stopping == false)
while (Running)
if (Info._current == null)
Info._current = Info.ObjectsList.First;
else
var next = Info._current.Next;
//if we reach the end of our list > go back to the top (since we are running threaded, we dont want the system to sit there for xxms doing nothing)
if (Info._current == Info.ObjectsList.Last)
next = Info.ObjectsList.First;
Info.LastRunTime = (Info.LastRunTime + (Time - Info.StartTime)) / 2;
//Info.LastRunTime = (Time - Info.StartTime) /*> 0 ? (Time - Info.StartTime) : Info.LastRunTime */;
Info.StartTime = Time;
if (Time > Info._current.Value.OperateTime)
if (Info._current.Value.Master == null)//since we are running multithreaded, dont allow pets to be processed (unless you constantly move pets into their map appropriate thead)
Info._current.Value.Process();
Info._current.Value.SetOperateTime();
Info._current = next;
//if it's the main thread > make it loop till the subthreads are done, else make it stop after 'endtime'
if (Info.Id == 0)
stopping = true;
for (var x = 1; x < MobThreads.Length; x++)
if (MobThreads[x].Stop == false)
stopping = false;
if (!stopping) continue;
Info.Stop = stopping;
return;
if (Stopwatch.ElapsedMilliseconds <= Info.EndTime || !Running) continue;
Info.Stop = true;
lock (_locker)
while (Info.Stop) Monitor.Wait(_locker);
catch (Exception ex)
if (ex is ThreadInterruptedException) return;
MessageQueue.Enqueue(ex);
File.AppendAllText(Path.Combine(Settings.ErrorPath, "Error.txt"),
$"[Now] exEnvironment.NewLine");
//Info.Stop = true;
开启网络,HTTPService默认是不开启的
StartNetwork(); //开启网络,加载
if (Settings.StartHTTPService)
http = new HttpServer();
http.Start();
从这里开始,就可以登录了,下面就是一些游戏逻辑
玩家逻辑,里面有走,技能,交易等,下一篇文章详细讲解
AdjustLights();//时间切换,黑天,白天等
lock (Connections)
for (var i = Connections.Count - 1; i >= 0; i--)
//玩家执行一步
Connections[i].Process();
其他
//地图执行一步
for (var i = 0; i < MapList.Count; i++)
MapList[i].Process();
DragonSystem?.Process();
Process();//执行一步
if (Time >= saveTime)
//数据保存,默认5分钟存储一次
saveTime = Time + Settings.SaveDelay * Settings.Minute;
BeginSaveAccounts();
SaveGuilds();
SaveGoods();
SaveConquests();
if (Time >= userTime)
//5分钟给所有玩家发送一下在线玩家数量
userTime = Time + Settings.Minute * 5;
Broadcast(new S.Chat
Message = string.Format(GameLanguage.OnlinePlayers, Players.Count),
Type = ChatType.Hint
);
以上是关于Legend of Mir(传奇)官方源码学习3服务端程序初始化过程的主要内容,如果未能解决你的问题,请参考以下文章