Skip to content

Commit e2b2455

Browse files
author
magiclu550
committed
[commit] #1071 add comments in Server
1 parent 82a4870 commit e2b2455

1 file changed

Lines changed: 220 additions & 2 deletions

File tree

JPLS/src/main/java/cn/jsmod2/core/Server.java

Lines changed: 220 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,228 @@
4747
import static cn.jsmod2.core.utils.Utils.*;
4848

4949
/**
50-
* jsmod2 cn.jsmod2.server class
50+
* JSMod2是一款基于协议(JSmod2协议)开发的一款使得java插件可以开发SCPSL:SCP基金会秘密实验室
51+
* 插件的一个框架,这个框架主要由两部分组成
52+
* JPLS和JSmod2组成,JPLS的全称叫做Java Plugin Loading System,JSmod2称为Java Server Mod
53+
* Java Server Mod提供了开发插件的接口和工具类,JPLS则是驱动插件生效的核心,同时C#服务端必须装配
54+
* ProxyHandler(协议代理插件)才能使得java插件真正生效于指定的客户端
55+
* JSMod2同时提供了
56+
* JSMod2Manager:基于python开发的管理控制平台
57+
* JSMod2DevelopmentKit:JSMod2开发工具包,结合在JSmod2中
58+
* JSMod2 Repo:JSMod2的maven控制平台
59+
* http://repo.noyark.net/nexus
60+
* 同时JSMod2的源代码在github开放,并作为主要的版本控制平台
61+
* https://www.github.com/jsmod2-java-c
62+
* JSMod2的官方网站:
63+
* http://jsmod2.cn
64+
* 以上就是JSMod2的执行体系,即JSmod2的结构
65+
* | 这一部分都是JSmod2的组件 |
66+
* JSmod2->插件->JPLS->ProxyHandler->ServerMod->MultiAdmin/LocalAdmin->Game
5167
*
52-
* @author magiclu550 #(code)jsmod2
68+
* 首先上一届课讲解了开发一款JavaServerMod插件的流程,JSMod2已经提供了方便的插件加载框架
69+
* 并且提供了web网站开发的支持
70+
* <code>
5371
*
72+
* @Controller
73+
* public class Test{
74+
*
75+
* @RequestMapping("/jsmod2")
76+
* public String hello(){
77+
* return "index.html";
78+
* }
79+
* }
80+
* </code>
81+
* 您完全可以在代码中使用这种形式进行开发网站,访问网站使用ip:jsmod2的默认web服务器端口/jsmod2即可
82+
*
83+
* 1.JSmod2的心脏: Server类和DefaultServer类
84+
* 这两个类是JSMod2的核心部分,一切能够让java和ServerMod交互,其实都是依靠了这个类/对象为基础,Server类
85+
* 和ServerMod的Server是不一样的
86+
*
87+
* - Server为基类,实现了IServer接口,IServer继承了Start和Closeable,Reloadable接口
88+
* - Start主要包含了start方法(startWatch方法其实和start的作用几乎差不多),Closeable包含close方法,Reloadable包含reload方法
89+
* - 分析Server的作用
90+
* - Server的第一个作用,就是存储了这个服务端运行时的一切基本信息
91+
* - 语言属性 lang
92+
* - jar包的所在目录 serverfolder
93+
* - 启动和成功的时间 startTime和startSuccessTime 启动时间就是(startSuccessTime-startTime)ms
94+
* - 指令的基本信息
95+
* - 一系列最常用的常量(在项目中使用频率最高)
96+
* - 记录管理员信息的对象OpsFile
97+
* - 使用的是udp还是tcp
98+
* - 是否和游戏已经对接
99+
* - Server的第二个作用,提供了这个服务端运行的基本对象
100+
* - LineReader 命令行对象
101+
* - RuntimeServer 正在运行的服务器对象
102+
* - Logger 打印日志信息的对象
103+
* - plugins 服务器的插件对象
104+
* - PluginManager 服务器的插件管理对象
105+
* - RegisterTemplate 注册机对象:就是管理一些字典信息的对象,用于运行过程根据情况获取,从而使得数据严谨整齐分区安放,比较易于管理
106+
* - 第三个作用,运行监听线程:start和startWatch
107+
* - 根据情况启动ListenerThread(TCP或者UDP)
108+
* - ListenerThread UDP
109+
* - ListenerThreadTCP TCP
110+
* - ListenerThread的作用是监听来自ProxyHandler的信息
111+
* - ProxyHandler由c#编写,后期将ProxyHandler会讲解
112+
* - ProxyHandler会在事件发生的时候发送数据包(EventPacket),JSmod2的
113+
* 监听线程会根据数据包id从Register中的registerEvents()中找到对应的class对象
114+
* 例如 -> 0x01 -> 找到AdminQueryEvent.class 之后调用newInstance()产生事件对象
115+
* 之后通过callEvent(传入一个Event对象)调用之前注册的监听器方法
116+
* - ListenerThread启动后,会将来自ProxyHandler的base64字符串解析成jsmod2协议的字符串(实际上是一个json字符串)
117+
* 之后将json字符串拆分注入
118+
*
119+
* 完整的事件jsmod2协议长这个样子:0x01-{}|||playerName:UUID序列|||admin-playerName:UUID序列
120+
* 这里会把AdminQueryEvent中的playerName字段注入UUID序列(这个序列是为了从Server Mod中找到它所对应的对象)
121+
* 然后从AdminQueryEvent中找到admin字段,是Player类型,然后Player类型中也有playerName字段,因此就把admin中的
122+
* playerName字段注入进去这个UUID序列(而且playerName和admin-playerName对应的uuid序列都是不同的)这样每个复杂对象
123+
* 都有一个uuid对应,在proxyHandler中,uuid将会和一个对象绑定在一起
124+
*
125+
* 此时ProxyHandler中的apiMapping就是这样的(在事件触发时就会把这两个信息放了进去,这里省略其他复杂对象)
126+
* {
127+
* "UUID1":"AdminQueryEvent对象1",
128+
* "UUID2":"admin对象1"
129+
* ...
130+
* }
131+
*
132+
* 当在jsmod2中,使用这个admin
133+
* <code>
134+
* public void onAdmin(IAdminQueryEvent e){
135+
* e.getAdmin().getName();
136+
* }
137+
* </code>
138+
* 此时getName发出了这个包
139+
* {
140+
* "id":"xxx"//具体id暂时不用知道
141+
* "field":"Name"
142+
* "playerName":"UUID2"
143+
* }
144+
* 之后传输到ProxyHandler
145+
* ProxyHandler会先读取playerName找到UUID2
146+
* 然后在通过UUID2,从apiMapping中找到admin对象1
147+
* 之后admin对象1.Name获取返回值
148+
* 然后通过JsonSetting对象把数据封装起来
149+
* 之后返回
150+
* 然后Socket此时进行write读取,然后通过BinaryStream的decode方法解码
151+
* 得到Name的返回值
152+
* 之后获取Name成功
153+
* 这是事件触发和调用方法获取属性的运行流程,也是jsmod2的基本流程
154+
* 游戏触发事件Event->之后把Event和它的复杂对象(如Player,TeamRole等等)放到apiMapping表里,并生成一个
155+
* UUID Key对应着他们,然后发出协议,把uuid注入到jsmod2的对象进去,之后对象在执行方法时候,会发出数据包,里面包含
156+
* 了该对象的uuid,ProxyHandler接受到后,通过这个uuid找到游戏里的这个对象,从而实现对应的操作
157+
*
158+
* 另外这些操作是jsmod2真正的核心部分,也是实现了jsmod2核心功能的地方
159+
*
160+
* 实现这些解码的核心组件是BinaryStream,也就是协议的翻译器
161+
*
162+
* 2.JSMod2的大脑: BinaryStream
163+
* - BinaryStream在JavaServerMod中是思考的角色,对一切传来的协议进行解析,再对一切发出的协议组合
164+
* - Server运行过程中,PacketManager是协议管理器,协议管理器只是充当了控制者和决策者角色,就是我该根据什么情况去调用什么地方
165+
* - 如调用事件和调用指令
166+
* - 根据id去判别
167+
* - Manager接口提供了已经实现的通过ID和数据包信息调用事件和指令的接口
168+
* - PacketManager事实上代码很简单
169+
* - 然后再就是callEventByPacket,
170+
* - 就是定义一个EventStream(BinaryStream的子类)
171+
* - 从events找到class对象
172+
* - 之后直接通过callEvent执行(callEvent如何执行的会在Plugin中讲解)
173+
* - 之后事件调用结束
174+
* - 如果不存在这个id
175+
* - 那么就是关心命令调用
176+
* - 命令调用两种方式,c#控制台调用和玩家调用
177+
* - 这个是ProxyHandler发的id信息来判断的
178+
* - 最终从数据包中获取这个VO对象(Value Object),其实就是把数据包信息拆解,组成的对象
179+
* - 最终获得到VO对象,就根据情况来执行,如果是控制台命令,那么就直接runConsoleCommand
180+
* - 如果不是,就获得到Player对象,然后传进去
181+
* - 最后socket会返回一个信息0xFF&1,对对方说明已经结束了指令和事件,游戏可以继续进行下去(在事件没有结束前,ProxyHandler是将
182+
* 事件给阻塞掉的)
183+
* - Server的sendDataPacket 是对象调用时,如Player对象,就会使用这个方法(发出数据包),核心实现还是由BinaryStream实现
184+
* - DataPacket是BinaryStream的子类
185+
* - DataPacket分为 GetPacket和SetPacket(ControlPacket)和DoPacket以及SimplePacket(DoMethodPacket DoStream...)
186+
* - DataPacket的介绍在Jsmod2-protocol[参见(1)]里说明了
187+
* - JSmod2前期采用一个Packet对应一个Handler,但是作者突发奇想,写出了SimpleHandler,即通用Handler,通过"反射"机制实现的Handler
188+
* 可以动态的设置和获取数值,这个解析器可以10行代码顶n行
189+
* - 对应SimpleHandler就是SimplePacket(Packet的定义在cn.jsmod2.network.protocol下)
190+
* 这些大概就是BinaryStream的作用
191+
*
192+
* 3.附带的组件
193+
* - MultiAdminCommand 基于ProxyHandler的CommandHandler实现的,可以直接调用smod2上的命令
194+
* multi HELP 查看smod2命令 multi 命令 参数1 参数2 调用smod2的命令
195+
* - Config Framework 基于yaml json properties的Config框架,可以通过ConfigQueryer来定义对象(这样使用了对象池,节省内存开销)
196+
*
197+
* - Oaml Config 这是为jsmod2定制的配置文件格式,位于oaml包下,可以从https://github.com/noyark-system/noyark_oaml_java来获得使用
198+
* 方法
199+
*
200+
* - Plugin Loading Framework 是为JSmod2定制的基于URLClassLoader的插件加载框架,可以实现自动定义和自动注册的插件框架
201+
* - 这个框架分为PluginClassLoader和PluginManager
202+
* - PluginClassLoader首先读取jar包,通过URLClassloader读取所有类对象,然后进行查找,如果找到配置文件则从plugin.yml读取信息,加载主类
203+
* 如果没有配置文件,则找@Main注解,然后找到Main注解后开始加载Plugin对象,加载onLoad onEnable,在服务器停止前调用onDisable(强制停止则不会)
204+
* - 找到@Main后,会再尝试查找EnableRegister注解,如果没找到,则不进行自动注册,如果找到,则扫描全部实现Listener接口和继承Command对象的类,并
205+
* 注册进去
206+
* - 注册Command只是将Plugin注入进去,然后放在commands映射表(PluginClassLoader中),如果是Listener,则将类进行拆分,整理出带@EventManager
207+
* 的方法,之后下一步根据优先级整理成一个个列表,然后放在一个映射表中(首先根据方法的参数类型划分成一个个列表,再根据优先级对列表排序),之后发生事件时,
208+
* 通过callEvent调用,callEvent则是先得到事件类型,然后把有和这个事件类型相同参数类型(或者子类的类型)的方法找到,然后根据优先级依次执行这些方法
209+
* <code>
210+
* public void onPlayerJoin(IPlayerJoinEvent e){
211+
*
212+
* }
213+
* //发送callEvent
214+
* Event e = PlayerJoinEvent.class.newInstance();//动态生成的事件对象
215+
* callEvent(e);//则会找到onPlayerJoin这个方法,之后执行
216+
* 因此您可以通过这个特性来自定义事件
217+
* </code>
218+
* - Emerald脚本语言
219+
* - 基于java写的脚本语言,但是这个语言目前有点挫,但是可以结合命令行使用
220+
*
221+
*
222+
*
223+
* 参见(1)
224+
* Jsmod2协议分为5种请求方式:Get,Set,IDSend,CommandRegister,CommandSender
225+
* 一种响应: Future响应
226+
* Jsmod2端会发送Get和Set和CommandRegister
227+
* Get请求发送后,会有一个具体的返回值,Get请求基本不会修改对方端的具体参数,它的目的仅仅为了返回值
228+
* Set请求发送后,不会有返回值,Set请求一定会修改对方端的具体参数,它的目的仅仅为了修改值
229+
* CommandRegister请求,用于注册命令,没有返回值
230+
* C#端会发送
231+
* IDSend是发送Event请求,当发送Event对象时,将全部对象添加到请求链,并附带一个id账号
232+
* CommandSender请求,用于执行jsmod2注册的命令
233+
*
234+
* Future响应是一个二进制的响应串,Jsmod2的Response对象已经封装了它,进行了响应编译
235+
*
236+
* Get和Set请求已经封装在了数据包中,直接使用send即可发包
237+
*
238+
* 一个Get请求
239+
* 111-{
240+
* "id":"111",
241+
* "type":"item",
242+
* "field":"xxx",
243+
* "player":"ADE4-FL09-ADGB-Y9E6“
244+
* }
245+
* 一个Set请求
246+
* 111-{
247+
* "id":"111",
248+
* "type":"item",
249+
* "do":"remove",
250+
* "player":"ADE4-FL09-ADGB-Y9E6“
251+
* }
252+
* 111-{
253+
* "id":"111",
254+
* "type":"item",
255+
* "kinematic":"true",
256+
* "player":"ADE4-FL09-ADGB-Y9E6“
257+
* }
258+
* IDSend请求
259+
* {
260+
* #省略,对象信息
261+
* }|||"admin-playerName":"ADE4-FL09-ADGB-Y9E6"
262+
*
263+
*
264+
* Future响应
265+
* {
266+
* #省略,对象信息
267+
* }|||"admin-item":"ADE4-FL09-ADGB-Y9E6"@!{
268+
* #省略,对象信息
269+
* }|||"admin-item":"ADE4-FL09-ADGB-Y9E7"
270+
*
271+
* @author magiclu550
54272
*/
55273

56274
public abstract class Server implements IServer {

0 commit comments

Comments
 (0)