第八章:L2JMobius学习 – 游戏服务GameServer讲解

news2024/11/13 8:57:16

本章节我们来讲解GameServer服务,首先来查看它的文件结构

ai:游戏角色自动化处理,比如说,自动攻击。
cache:数据缓存,里面就一个HtmCache.java类,缓存HTML文件内容。
communitybbs:bbs的管理。
data:对游戏数据的管理,涉及文件和数据库的操作。
enums:枚举类型,都是与游戏数据相关的,例如职业枚举数据。
geoengine:地图数据管理,例如三维场景下高度数据的获取。
handler:处理器,例如使用技能的效果处理。
instancemanager:各种类实例化管理,比如游戏对象实例化。
model:游戏业务模型,比如各种游戏对象类的实现。
network:网络数据通信,继承commons\network下的接口或父类
script:游戏脚本的管理
scripting:游戏脚本的管理
taskmanager:定时任务的管理
ui:图形界面目录,我们一般不使用它。
util:工具栏,一些辅助性功能的实现。
GameServer.java:GameServer服务启动入口,我们之前就是其他的它。
LoginServerThread.java:与LoginServer保持通信的线程
Shutdown.java:关闭GameServer服务

接下来,我们还是先研究network网络数据通信部分。

clientpackets:玩家客户端发送过来的数据包(继承ClientPacket接口)。
serverpackets:发送给玩家客户端的数据包(继承ServerPacket,继承WritablePacket)。

ClientPackets.java:客户端数据包数据枚举(根据ID实例化clientpackets数据包)。
ExClientPackets.java:客户端数据包数据枚举(解决ID数值超出byte范围问题)
ServerPackets.java:服务器数据包枚举(用来标记serverpackets的ID)
SystemMessageId.java:发送给客户端的消息ID

PacketLogger.java:数据包日志类。
PacketHandler.java:数据包处理器,继承PacketHandlerInterface接口。

BlowFishKeygen.java:秘钥生成(加密和解密数据包)
Encryption.java:加密解密类,继承EncryptionInterface接口。
GameClient.java:玩家客户端类,继承NetClient类。

ClientString.java:一个自定义的注解
ConnectionState.java:玩家客户端连接状态枚举。

loginserverpackets:发送给LoginServer服务的数据包(不讲解)。

接下来,我们介绍GameServer与玩家客户端之间的通信。当我们启动GameServer服务的时候,他会启动一个NetServer服务类,这个类我们之前已经讲过了。它里面有一个ServerSocketChannel,用来监听本机的7777端口。当有玩家客户端连接到GameServer的时候,我们就创建一个GameClient类,它代表了玩家客户端,继承自NetClient类。这个类非常重要,它会持有加密和解密的Encryption类,当然我们依然可以通过他的sendPacket方法向玩家客户端发送数据包。NetServer收到客户端发送的数据包之后,就会调用PacketHandler的handle方法来进行处理,这个类继承自PacketHandlerInterface接口。处理的方式就是,读取数据包的第一个字节,它就代表了数据包的ID。每一个数据包都有一个唯一标识ID,根据这个ID我们就能与真正的“游戏业务数据包”对应上了。这个对应关系是在ClientPackets和ServerPackets两个枚举类里面实现的。

这里,我们简单列举几个clientpackets游戏业务数据包

ProtocolVersion.java:客户端请求密钥,ID为0x00
AuthLogin.java:登录游戏服务器,返回玩家的角色列表,ID为0x08
NewCharacter.java:进入创建角色界面,发送角色模板数据,ID为0x0E(14)
CharacterCreate.java:创建并保存新角色,ID为0x0B (11)
CharacterSelected.java:选择角色,ID为0x0D (13)
EnterWorld.java:进入游戏世界,ID为0x03
Logout.java:退出游戏,ID为0x09

我们再来看一些serverpackets游戏业务数据包吧。

KeyPacket.java:向客户端发送密钥,ID为0x00
CharSelectInfo.java:返回玩家的角色列表,ID为0x13(19)
---------------------------------------------------------------------------
CharTemplates.java:角色模板,用于新建角色,ID为0x17(23)
CharCreateOk.java:创建角色成功,ID为0x19(25)
CharCreateFail.java:创建角色失败,ID为0x1A(26)
---------------------------------------------------------------------------
CharSelected.java:返回选中的角色信息,准备进入游戏世界,ID为0x15(21)
UserInfo.java:进入游戏世界,发送角色主要信息,ID为0x04
LeaveWorld.java:退出游戏世界,ID为0x7E(126)

我们上面已经说明了,每一个数据包的第一个字节代表了该数据包的唯一标识ID(上展示的ID都是十六进制)。当然,还有很多很多的数据包。我们获取这个ID之后,就能知道他对应的是哪个“游戏业务数据包”。这个是根据ClientPackets.java,ExClientPackets.java和ServerPackets.java枚举类型来定义对应关系的。这里需要单独说明一下ClientPackets.java和ExClientPackets.java的关系,他们两个都是clientpackets游戏业务数据包的ID。只不过后者是为了解决ID数值超出Byte字节大小的问题。因为我们的clientpackets非常的多,以至于它必然会超出byte自己的大小范围。于是,我们就规定当ID = 0xD0的时候,我们就继续读取数据包中下一个ID的数值,使用它来继续确定是哪个clientpackets游戏业务数据包。那么这个第二个ID数值中个对应的数据包就由ExClientPackets.java枚举来确定了。

接下来,我们继续研究PacketHandler的handle方法,如何处理clientpackets游戏业务数据包。首先是读取数据包中的第一个字节数据

final int packetId;
packetId = packet.readByte();

根据ID找到枚举类型,也就是对应的clientpackets游戏业务数据包

final ClientPackets packetEnum = ClientPackets.PACKET_ARRAY[packetId];

然后就可以实例化了

final ClientPackets packetEnum = ClientPackets.PACKET_ARRAY[packetId];

虽然声明的是ClientPacket接口类型,但是实际上就是clientpackets游戏业务数据包。接下来,我们就使用线程池技术来执行ClientPacket里面的read和run方法。这两个方法,前者是进行Byte数组数据转化类属性变量的,后者则是执行具体的游戏业务代码。如果需要向客户端发送数据包的话,也是在这个run方法中执行的。

ThreadPool.execute(new ExecuteTask(client, packet, newPacket, packetId));

我们可以查看一下ExecuteTask任务内容

_newPacket.read(_packet);
_newPacket.run(_client);

就是依次执行了read方法和run方法。当ID值为0xD0的时候,我们就会实例化ExPacket这个数据包。它不是一个游戏业务数据包。我们查看它的read方法

final int exPacketId = packet.readShort() & 0xFFFF;
_packetEnum = ExClientPackets.PACKET_ARRAY[exPacketId];
_newPacket = _packetEnum.newPacket();
_newPacket.read(packet);

看到了吧,它实际是继续读取下一个ID数值,在根据这个ID数值去ExClientPackets.java枚举中找真正的游戏业务数据包。找到之后,就实例化newPacket,然后执行实例化后newPacket的read方法。然后在run方法中,也是同样执行实例化后newPacket的run方法。也就是说,我们对应游戏的处理,就重点查看clientpackets游戏业务数据包中的run方法就行了。如果需要向客户端返回serverpackets游戏业务数据包,也是在这里执行的。这里需要注意的是,serverpackets中的数据包是直接实例化的,而它的ID则是由ServerPackets.java枚举来提供的。这一点大家要明白。

接下来,我们就来根据数据包来大致介绍一下GameServer与玩家客户端的数据通信。首先,我们仍然是先对GameClient进行实例化,这个没有太多的业务代码。然后,玩家客户端会请求ProtocolVersion数据包,该数据包中包含了客户端的版本号,然后我们在run方法中向客户端返回KeyPacket数据包,这个数据包里面包含的就是加密和解密的秘钥。有了秘钥,客户端和服务器端才能进行数据通信。

client.setProtocolVersion(_version);
client.sendPacket(new KeyPacket(client.enableCrypt(), 1));

这个KeyPacket数据包还是比较简单的,首先是他的构造方法

public KeyPacket(byte[] key, int result)
{
    _key = key;
    _result = result;
}

就是将传递过来的数据,赋值给自己类的属性变量上面。接下来就是write方法。

ServerPackets.KEY_PACKET.writeId(this);
writeByte(_result); 
for (int i = 0; i < 8; i++)
{
    writeByte(_key[i]);
}
writeInt(Config.PACKET_ENCRYPTION);
writeInt(Config.SERVER_ID);
writeByte(1);

我们不用过多的理解返回客户端的Byte数据中的所有详细内容。因为这些数据是让客户端程序来解读的。我们看到的第一句代码,就是从ServerPackets.java枚举中获取ID。

接下来,客户端获取了秘钥之后,就会继续发送AuthLogin请求数据包,里面包含了会话SessionKey数据对象和账号信息。然后在run方法中,会与LoginServer进行通信,告诉有玩家登录游戏了。然后GameServer收到LoginServer的回复之后,会想客户端发送CharSelectInfo数据包。这个数据包就是从数据库中查询玩家的所有游戏角色,然后玩家选择其中一个角色,就可以进入游戏世界了。当然,由于我们是第一次运行程序,因此,我们是没有角色的。所以,我们需要创建游戏角色。因此,我们需要在游戏客户端里面点击“创建角色”的按钮,进入到创建角色的界面。此时,客户端会向服务端发送NewCharacter数据包,这个数据包会返回客户端CharTemplates数据包,这个数据包包含了游戏的基础职业信息(人类法师和战士,精灵法师和战士等等)。关于如何创建角色,我们下一个章节介绍。

本章节涉及的内容均已上传百度网盘:

https://pan.baidu.com/s/1XdlcCFPvXnzfwFoVK7Sn7Q?pwd=avd4

欢迎加企鹅交流裙:874700842(裙文件里面也可以下载所有内容)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/733848.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C语言】1-Visual C++ 2010 的简单使用和第一个 C 语言程序

1. Visual C++ 2010 的简单使用 1.1 面板介绍 1.2 新建C语言项目 打开 Visual C++ 2010,点击 New Project 根据下面的图示进行操作,其中需要注意 ③:这里输入的为项目名(建议和我的命名保持一致) ④:这里是项目存放的位置,可以自己选择,最好不要有中文路径(只要是使…

苹果用户要留意?女子FaceTime通话面临巨额骗局,损失高达160万

FaceTime通话是苹果提供的一项服务&#xff0c;可以让使用iOS、iPadOS设备或Mac电脑的用户进行视频或音频通话。只要知道对方的Apple ID&#xff0c;世界各地的苹果设备都可以通过该ID进行呼叫。 据报道&#xff0c;一名居住在上海金山的女性最近遭受了一种新型诈骗&#xff0c…

js逆向补环境-调试工具vscode与nodejs使用之无环境联调

目录 一、啊哈一、Nodejs安装1、nodejs最新版本的安装&#xff08;windows&#xff09;2、旧版nodejs更新成最新版本&#xff08;windows&#xff09;3、nodejs安装&#xff08;linux&#xff09; 二、vscode安装使用(windows)1、下载安装vscode2、vscode运行插件Code Runner安…

多元分类预测 | Matlab基于K近邻算法(KNN)的数据分类预测,多特征输入模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 基于K近邻算法(KNN)的数据分类预测,多特征输入模型 多特征输入单输出的二分类及多分类模型。程序内注释详细,直接替换数据就可以用。程序语言为matlab,程序可出分类效果图,迭代优化图,混淆矩阵图。 部分源码

MAYA粒子爆炸

创建粒子替代 中心归零 只有一种石头 particleShape1.shitourand(0,5); 设置石头大小 等比例变小 particleShape1.daxiao<<0.2,0.2,0.2>>; 使用变量代替 float $daxiaorand(0.2,0.5); particleShape1.daxiao<<$daxiao,$daxiao,$daxiao>>; 非等比例缩…

【国家标准】GB 7713-87 科学技术报告、学位论文和学术论文编写格式

目 录 1 引言 2 定义 2.1 科学技术报告 2.2 学位论文 2.3 学术论文 3 编写要求 4 编写格式 5 前置部分 5.1 封面 5.2 封二 5.3 题名页 5.4 变异本 5.5 题名 5.6 序或前言 5.7 摘要 5.8 关键词 5.9 目次页 6 主体部分 6.1 格式 6.2 序号 6.3 引言(或绪论)…

基于stm32单片机的智能家居环境监控系统

​一.硬件方案 智能家居环境监控系统的整体电路主要由stm32单片机最小系统&#xff0c;光MQ-2烟雾传感器电路&#xff0c;红外人体检测电路&#xff0c;DS18B20温度传感器&#xff0c;LCD1602显示电路&#xff0c;水泵驱动电路&#xff0c;风扇驱动电路&#xff0c;LED指示灯&…

传输方式的分类【图解TCP/IP(笔记五)】

文章目录 传输方式的分类面向有连接型和无连接型面向有连接型面向无连接型 电路交换与分组交换根据接收端数量分类单播&#xff08;Unicast&#xff09;广播&#xff08;Broadcast&#xff09;多播&#xff08;Multicast&#xff09;任播&#xff08;Anycast&#xff09; 传输方…

ModaHub魔搭社区:Zilliz Cloud快速开始教程(一)

目录 前提条件 创建 Collection 查看 Collection 插入数据 本教程涵盖以下 Zilliz Cloud 集群操作指南: 创建 Collection查看 Collection插入数据向量搜索、向量查询、通过 ID 获取 Entity删除 Entity删除 Collection 前提条件 在本文档中,我们将使用 Milvus 的 SDK。…

FL Studio21中文版DAW宿主软件

FL Studio21让你的计算机就像是全功能的录音室&#xff0c;漂亮的大混音盘&#xff0c;先进的创作工具&#xff0c;让你的音乐突破想象力的限制。你有着满腔的音乐才华&#xff0c;想要自己在家里发片吗&#xff1f;还是听 MOBY 的电子舞曲不过瘾&#xff0c;要再帮他做做 REMI…

Mybatis-plus——增删改查相关+id生成策略+多数据操作(删除)+逻辑删除+乐观锁+代码生成器

项目文件总览 Dao层中 domain层中 测试类中含有三个测试方法&#xff0c;分别对应&#xff0c;插入删除和修改 id生成策略 针对不同的场景使用不同的id,用到提供的一个注解TableId 在实体类中使用Tablefiled注解时可以看见有如下的多种策略 使用第一个AUTO策略 运行插入方法得…

Nuxt3 loyouts公共页面布局

1.目录结构 2.在app.vue入口处添加代码 注意&#xff1a;Header首字母我是大写的&#xff0c;然而页面并没有显示头部&#xff0c;只显示尾部 改为首字母小写才会有效

SWAT模型18项典型案例实践、EFDC模型建模方法

SWAT模型“十八般武艺”高阶研修 以18项典型的案例为主线&#xff0c;不仅能够从技术层系统掌握&#xff0c;还能更好的拓展与相关学科的融合创新应用&#xff0c;解决实际的问题&#xff0c;内容讲解具有技术深度与系统、普遍需求、热点创新、实际问题解决等特点&#xff0c;…

计算机组成原理课程论文: Intel 80386/80486 的体系架构调研

摘要 本文以Intel 80386/80486体系架构为研究对象&#xff0c;详细介绍了该体系架构的基本概念、特点和优势&#xff0c;分析了其在不同领域的应用情况&#xff0c;并对其未来的发展做出一定的展望和评价。 首先&#xff0c;我们介绍了研究背景和目的&#xff0c;阐述了Intel 8…

40. 同时在线最多的人数

文章目录 题目需求思路一实现一题目来源 题目需求 根据用户登录明细表&#xff08;user_login_detail&#xff09;&#xff0c;求出平台同时在线最多的人数。 期望结果如下&#xff08;截取部分&#xff09;&#xff1a; cn7 需要用到的表&#xff1a; 用户登录明细表&…

接口性能优化技巧

背景 我负责的系统在去年初就完成了功能上的建设&#xff0c;然后开始进入到推广阶段。随着推广的逐步深入&#xff0c;收到了很多好评的同时也收到了很多对性能的吐槽。 刚刚收到吐槽的时候&#xff0c;我们的心情是这样的&#xff1a; 当越来越多对性能的吐槽反馈到我们这里的…

阿里云服务器架构X86_GPU_裸金属_超级计算集群详解

阿里云服务器架构有什么区别&#xff1f;X86计算、ARM计算、GPU/FPGA/ASIC、弹性裸金属服务器、超级计算集群有什么区别&#xff1f;阿里云服务器网分享云服务器ECS架构详细说明&#xff1a; 目录 阿里云服务器ECS架构说明 X86计算 ARM计算 GPU/FPGA/ASIC 弹性裸金属服务…

基于simulink使用SAD方法进行运动检测(附源码)

一、前言 此示例演示如何使用绝对差分总和 &#xff08;SAD&#xff09; 方法来检测视频序列中的运动。此示例将 SAD 独立应用于视频序列的四个象限。如果在象限中检测到运动&#xff0c;则示例会以红色突出显示该象限。 二、模型 下图显示了移动侦测示例模型&#xff1a; 三…

一文搞懂Java线程池执行原理核心参数

文章目录 前言一、为什么要使用线程池创建线程&#xff1f;二、线程池的核心参数&#xff08;重点&#xff09;1.核心线程数2.最大线程数3.救急线程的存活时间4.救急线程的时间单位5.任务队列6.线程工厂7.任务拒绝策略 三、线程池的执行原理四、一个小案例总结 前言 最近面试过…

CEC2018动态多目标优化算法:基于自适应启动策略的混合交叉动态约束多目标优化算法(MC-DCMOEA)求解CEC2018

一、动态多目标优化问题 1.1问题定义 1.2 动态支配关系定义 二、 基于自适应启动策略的混合交叉动态多目标优化算法 基于自适应启动策略的混合交叉动态多目标优化算法&#xff08;Mixture Crossover Dynamic Constrained Multi-objective Evolutionary Algorithm Based on Se…