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}] {ex}{Environment.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
        });
}
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花开花落的个人博客

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值