0x0. 北斗服务端启动过程

graph LR
    A(ServerApplication.main) --> B[ServerManager.run] --> C[Server.init]

ServerApplication.main

读取 application.yml 取得mysql的链接地址和账户密码。通过 url 路径得到数据库名称。组合sql判断数据库是否存在。如果不存在调用sql创建并初始化。

Server.init

  1. 加载WZ
  2. 重置登录状态和雇佣商店状态
  3. 清空失效的现金物品
  4. 重载倍率卡
  5. 接受未完成的改名
  6. 接受转区
  7. 加载玩家排名
  8. 加载自动封禁配置
  9. 主动清理每日零点需要清理的数据
  10. world初始化后需要加载的
  11. initLoginServer 初始化登录端口
  12. loadCommandsExecutor 加载GM执行命令
  13. 所有频道加载事件脚本
  14. 修改变量服务端启动

加载WZ

创建了虚拟线程负责同时加载4个WZ对应回调。future.get(); 保证所有wz都加载完毕后才会继续往下走init后续逻辑.

  1. 技能.SkillFactory::loadAllSkills,
  2. 商店.CashItemFactory::loadAllCashItems,
  3. 任务.Quest::loadAllQuests,
  4. 技能书.SkillbookInformationProvider::loadAllSkillbookInformati

world 的初始化

game_config.world 中取出创建世界的最大值。Server.initWorld 负责创建并初始化。从 game_config 中读取 经验倍率.exp_rate, meso_rate, 掉落倍率.drop_rate, BOOS掉落倍率.boss_drop_rate, 任务倍率.quest_rate, 旅行倍率.travel_rate, 钓鱼倍率.fishing_rate, flag 初始化必要的字段。

注册定时器

注册世界后台定时器,需要持续定时执行的任务。

变量 作用 回调 重复周期 首次延迟
petsSchedule 宠物饥饿处理 PetFullnessTask 1分钟 1分钟
srvMessagesSchedule 处理服务器消息显示状态,注释里说是为 Boss HP 条存在时临时禁用 server message。 ServerMessageTask 10秒 10秒
mountsSchedule 坐骑疲劳处理 MountTirednessTask 1分钟 1分钟
merchantSchedule 雇佣商店相关定时处理 HiredMerchantTask 10分钟 10分钟
timedMapObjectsSchedule 地图中的定时对象处理 TimedMapObjectTask 1分钟 1分钟
charactersSchedule 自动保存在线角色到数据库,并保存 HpMpAlert 数据 CharacterAutosaverTask 1小时 1小时
marriagesSchedule 遍历 world 下所有 channel,检查并启动教堂/礼堂婚礼预约。 WeddingReservationTask 分钟.game_config.wedding_reservation_interval 分钟.game_config.wedding_reservation_interval
mapOwnershipSchedule 地图归属系统检查 MapOwnershipTask 20秒 20秒
fishingSchedule 钓鱼系统检查 FishingTask 10秒 10秒
partySearchSchedule 组队搜索信息刷新 PartySearchTask 10秒 10秒
timeoutSchedule :扫描在线角色,如果当前时间减去 lastPacket 大于 timeout_duration,就自动断开连接。 TimeoutTask 10秒 10秒
hpDecSchedule 地图环境持续掉血处理 CharacterHpDecreaseTask game_config.map_damage_overtime_interval game_config.map_damage_overtime_interval
use_family_system 家族系统 FamilyDailyResetTask 1分钟 24小时之后就

频道的初始化

每个世界能创建多少个频道都是从 game_config.channel_size 中取出频道。频道的类是 Channel。频道的IP和端口从 application.yml.wan-host 中读出,端口默认从 7575 开始。

initServer 频道网络的初始化

initServer(频道端口, 世界ID, 频道ID) 函数接受三个参数。通过 ChannelServer.nettyChannel 来创建TCP网络。new ChannelServerInitializer 这个类继承了 class ChannelServerInitializer extends ServerChannelInitializer 所以当有TCP进入绑定的频道端口时,会自动触发连接到 ChannelServerInitializer.initChannel() 回调中。

Channel.eventSM 暂且不谈,这个是脚本事件的初始化。
Channel.services 暂且不谈,还不知道这个具体内容

最终频道初始化完毕后存储在 World.addChannel().channels.list 中。每个新建的世界最终存储在 Server.worlds.list 中。所有频道信息都存储在 Server.channels

客户端启动连接的TCP端口的初始化

initLoginServer() 启动端口的初始化和频道网络的初始化过程一致,只是回调是 LoginServerInitializer 当客户端启动时TCP连接触发 LoginServerInitializer.initChannel 回调

NPC信息加载

世界初始化后 loadPlayerNpcMapStepFromDb() 函数负责从数据库表 playernpcs_field 中加载出所有NPC信息。然后根据 playernpcs_field.world 找到对应的世界调用 world.setPlayerNpcMapData()。不过这个表中字段是空的????

初始化收发包协议

OpcodeConstants.generateOpcodeNames(); 中判断当前版本是否是083,如果是则对其 OpcodeConstants.sendOpcodeNames = SendOpcode; OpcodeConstants.recvOpcodeNames = RecvOpcode;

初始化GM命令

CommandsExecutor.getInstance().loadCommandsExecutor(); 通过从数据库表 command_info 中读取所有GM命令存储在 CommandsExecutor.registeredCommands 和 CommandsExecutor.commandsNameDesc

加载事件脚本

EventScriptManager 脚本引擎管理器。ch.reloadEventScriptManager() 逻辑为

  1. 从路径 scripts\event 目录下读取所有脚本文件,并且在 initializeEventEntry 中加载到系统中
  2. 把脚本接口, Channel, 脚本名称通过 EventManager 绑定在一起。
  3. 最后通过 EventEntry 把脚本接口和 EventManager 包装一起存储在 EventScriptManager.events

结束

至此服务端初始化完毕。

评论*

* 为必填