木须柄的时光工坊

探索技术与游戏乐趣的奇妙之旅

目录
关于爆发服务器公告栏信息的研究
/        

关于爆发服务器公告栏信息的研究

maxresdefault.jpg

3月份在尝试修改爆发服务器的公告内容,以下是一些研究记录。

一、爆发1

1. 东西区切换页面的信息

东西区的切换页面下面,有一个三行的信息栏。这个文本的内容在/var/www/enterareas.html 文件中,以 HTML 嵌入的形式保存。只要修改相应的文件即可。由于客户端内的默认字符编码为 SHIFT_JIS,所以页面文件需要保存为 SHIFT_JIS 格式,同时页面端的编码格式也要显式声明为 SHIFT_JIS 编码。

如果想要正确显示中文汉字,也需要转换对应编码。这里附带一个在线编码转换网站,可以辅助确认哪些简体中文无法正确转换,适当利用繁体字做替代即可。SHIFT_JIS 编码转换网站:

image-20240302235107015.png

enterareas.html 文件内容修改:

 1<html>
 2<head>
 3<!--CRS-lbs-info-get-->
 4<META HTTP-EQUIV=Content-Type CONTENT=text/html;CHARSET=Shift_JIS>
 5</head>
 6<!-- Results -->
 7<!-- LBS domain name + port number -->
 8<!-- connection number -->
 9<!-- Maximum number of connections -->
10<!-- Additional Information 1 -->
11<!-- Additional Information 2 -->
12<!-- Additional Information 3 -->
13<!-- LBS domain name + port number -->
14<!-- connection number -->
15<!-- Maximum number of connections -->
16<!-- Additional Information 1 -->
17<!-- Additional Information 2 -->
18<!-- Additional Information 3 -->
19<!--
20<CSV>
21"OK",
22"www01.kddi-mmbb.jp:8300",
23"0",
24"999",
25"0ad601082008,WEST TOWN,2",
26"<BODY><SIZE=4>Free Area<BR><BODY>Create your own games<BR><BODY>https://ob.alexpad.cn<END>",
27"<BODY><SIZE=4>自由模式<BR><BODY>創建自訂游戲<BR><BODY>[線上頁面] https://ob.alexpad.cn<END>",
28"www01.kddi-mmbb.jp:8300",
29"0",
30"999",
31"0ad601082008,EAST TOWN,1",
32"<BODY><SIZE=4>劇情模式<BR><BODY>在大廳等待2分鐘后開始游戲<BR><BODY>Phoenix, Miaocat and Alexpad<END>",
33"www01.kddi-mmbb.jp:8300",
34"0",
35"999",
36"0ad601082008,EAST TOWN,1",
37"<BODY><SIZE=4>Scenario Mode<BR><BODY>Wait 2 minutes in Lobby<END>",
38"<BODY><SIZE=4>Phoe-nix, Miaocat901 and Alexpad308<BR><BODY><END>",
39</CSV>
40-->
41</html>

注:西区的文本对齐方式比较奇怪,前三行内容无法正常显示,需要特别缩进一下。

修改后的实际效果如下:

image-20240302235732075.png

image-20240302235751827.png

2. 登陆公告栏

登陆公告栏的信息存储在 MySQL 数据库的motd 表中,具体的公告信息以 HTML 文本内容的形式,存储在id=2message 字段中。由于初始的 motd 表是空的,我们需要重建相关的数据。

首先进入 MySQL 数据库,选择爆发1的数据库bioserver,查看 motd 表:

 1# 选择爆发1数据库
 2MariaDB [bioserver]> USE bioserver;
 3Database changed
 4
 5# 查看 motd 表的字段信息
 6MariaDB [bioserver]> SHOW FULL COLUMNS FROM motd;
 7+---------+---------------+-------------------+------+-----+---------+----------------+---------------------------------+---------+
 8| Field   | Type          | Collation         | Null | Key | Default | Extra          | Privileges                      | Comment |
 9+---------+---------------+-------------------+------+-----+---------+----------------+---------------------------------+---------+
10| id      | int(11)       | NULL              | NO   | PRI | NULL    | auto_increment | select,insert,update,references |         |
11| message | varchar(2000) | latin1_swedish_ci | YES  |     | NULL    |                | select,insert,update,references |         |
12| active  | int(11)       | NULL              | NO   |     | 0       |                | select,insert,update,references |         |
13+---------+---------------+-------------------+------+-----+---------+----------------+---------------------------------+---------+
143 rows in set (0.023 sec)
15
16# 如果原数据库中有残留数据,可以清空 motd 表
17MariaDB [bioserver]> TRUNCATE TABLE motd;
18Query OK, 0 rows affected (0.171 sec)

可以看出,当前message 字段的字符编码是 latin1_swedish_ci, 如果要支持中文字符,同样需要修改为 SHIFT_JIS 编码。由于数据库版本不同,可以首先查看一下当前数据库所支持的编码格式类型。

 1# 查看当前数据库所支持的编码格式类型
 2MariaDB [bioserver]> SELECT * FROM information_schema.CHARACTER_SETS;
 3+--------------------+----------------------+-----------------------------+--------+
 4| CHARACTER_SET_NAME | DEFAULT_COLLATE_NAME | DESCRIPTION                 | MAXLEN |
 5+--------------------+----------------------+-----------------------------+--------+
 6| big5               | big5_chinese_ci      | Big5 Traditional Chinese    |      2 |
 7| dec8               | dec8_swedish_ci      | DEC West European           |      1 |
 8| cp850              | cp850_general_ci     | DOS West European           |      1 |
 9| hp8                | hp8_english_ci       | HP West European            |      1 |
10| koi8r              | koi8r_general_ci     | KOI8-R Relcom Russian       |      1 |
11| latin1             | latin1_swedish_ci    | cp1252 West European        |      1 |
12| latin2             | latin2_general_ci    | ISO 8859-2 Central European |      1 |
13| swe7               | swe7_swedish_ci      | 7bit Swedish                |      1 |
14| ascii              | ascii_general_ci     | US ASCII                    |      1 |
15| ujis               | ujis_japanese_ci     | EUC-JP Japanese             |      3 |
16| sjis               | sjis_japanese_ci     | Shift-JIS Japanese          |      2 |
17| hebrew             | hebrew_general_ci    | ISO 8859-8 Hebrew           |      1 |
18| tis620             | tis620_thai_ci       | TIS620 Thai                 |      1 |
19| euckr              | euckr_korean_ci      | EUC-KR Korean               |      2 |
20| koi8u              | koi8u_general_ci     | KOI8-U Ukrainian            |      1 |
21| gb2312             | gb2312_chinese_ci    | GB2312 Simplified Chinese   |      2 |
22| greek              | greek_general_ci     | ISO 8859-7 Greek            |      1 |
23| cp1250             | cp1250_general_ci    | Windows Central European    |      1 |
24| gbk                | gbk_chinese_ci       | GBK Simplified Chinese      |      2 |
25| latin5             | latin5_turkish_ci    | ISO 8859-9 Turkish          |      1 |
26| armscii8           | armscii8_general_ci  | ARMSCII-8 Armenian          |      1 |
27| utf8mb3            | utf8mb3_general_ci   | UTF-8 Unicode               |      3 |
28| ucs2               | ucs2_general_ci      | UCS-2 Unicode               |      2 |
29| cp866              | cp866_general_ci     | DOS Russian                 |      1 |
30| keybcs2            | keybcs2_general_ci   | DOS Kamenicky Czech-Slovak  |      1 |
31| macce              | macce_general_ci     | Mac Central European        |      1 |
32| macroman           | macroman_general_ci  | Mac West European           |      1 |
33| cp852              | cp852_general_ci     | DOS Central European        |      1 |
34| latin7             | latin7_general_ci    | ISO 8859-13 Baltic          |      1 |
35| utf8mb4            | utf8mb4_general_ci   | UTF-8 Unicode               |      4 |
36| cp1251             | cp1251_general_ci    | Windows Cyrillic            |      1 |
37| utf16              | utf16_general_ci     | UTF-16 Unicode              |      4 |
38| utf16le            | utf16le_general_ci   | UTF-16LE Unicode            |      4 |
39| cp1256             | cp1256_general_ci    | Windows Arabic              |      1 |
40| cp1257             | cp1257_general_ci    | Windows Baltic              |      1 |
41| utf32              | utf32_general_ci     | UTF-32 Unicode              |      4 |
42| binary             | binary               | Binary pseudo charset       |      1 |
43| geostd8            | geostd8_general_ci   | GEOSTD8 Georgian            |      1 |
44| cp932              | cp932_japanese_ci    | SJIS for Windows Japanese   |      2 |
45| eucjpms            | eucjpms_japanese_ci  | UJIS for Windows Japanese   |      3 |
46+--------------------+----------------------+-----------------------------+--------+
4740 rows in set (0.016 sec)

这样,我们就把message 字段的字符编码修改为 SHIFT_JIS 编码。

 1# 修改 motd 表中 message 字段的编码类型为 SHIFT_JIS,以兼容中文字符
 2MariaDB [bioserver]> ALTER TABLE motd MODIFY COLUMN message VARCHAR(2000) CHARACTER SET sjis;
 3Query OK, 2 rows affected (0.429 sec)          
 4Records: 2  Duplicates: 0  Warnings: 0
 5
 6# 查看 motd 表的字段信息
 7SHOW FULL COLUMNS FROM motd;
 8+---------+---------------+------------------+------+-----+---------+----------------+---------------------------------+---------+
 9| Field   | Type          | Collation        | Null | Key | Default | Extra          | Privileges                      | Comment |
10+---------+---------------+------------------+------+-----+---------+----------------+---------------------------------+---------+
11| id      | int(11)       | NULL             | NO   | PRI | NULL    | auto_increment | select,insert,update,references |         |
12| message | varchar(2000) | sjis_japanese_ci | YES  |     | NULL    |                | select,insert,update,references |         |
13| active  | int(11)       | NULL             | NO   |     | 0       |                | select,insert,update,references |         |
14+---------+---------------+------------------+------+-----+---------+----------------+---------------------------------+---------+
153 rows in set (0.001 sec)

接下来插入数据,第一段字符没有发现什么实际用处,可以随意插入;第二段开始则是公告栏信息。

 1# 插入数据
 2MariaDB [bioserver]> INSERT INTO motd (id, message) VALUES (1, 'Board Information');
 3Query OK, 1 row affected (0.030 sec)
 4
 5MariaDB [bioserver]> INSERT INTO motd (id, message) VALUES (2, '<BODY><BR><C=6>Board Information</END>');
 6Query OK, 1 row affected (0.031 sec)
 7
 8# 激活公告栏信息
 9MariaDB [bioserver]> UPDATE motd SET active = 1 WHERE id = 2;
10Query OK, 1 row affected (0.042 sec)
11Rows matched: 1  Changed: 1  Warnings: 0
12
13# 查看测试数据记录
14MariaDB [bioserver]> SELECT * FROM motd;
15+----+----------------------------------------+--------+
16| id | message                                | active |
17+----+----------------------------------------+--------+
18|  1 | Board Information                      |      0 |
19|  2 | <BODY><BR><C=6>Board Information</END> |      1 |
20+----+----------------------------------------+--------+
212 rows in set (0.000 sec)

测试信息的效果如下:

image-20240303012134933.png

公告栏的内容,实际上是 HTML 页面的一部分,以<BODY>...</END> 标签包围。其中一些标签并非标准 HTML 格式,经过研究,部分标签含义如下:

 1# 标签C代表颜色(页面默认是黑色底)
 2<C=1> 3<C=2>	绿
 4<C=3> 5<C=4> 6<C=5> 7<C=6> 8<C=7> 9<C=8>10<C=9>	绿
11<C=10>12
13# 标签LF代表行距,<LF=1>等于<BR>

明确了内容,接下来更新公告栏数据,具体内容如下:

 1# 更新公告栏信息,注意汉字必须兼容 SJIS 编码
 2# 英文、数字、字符尽量使用全角符号
 3# 最后的   空格字符用于填充尾部,否则客户端显示不全
 4
 5MariaDB [bioserver]> UPDATE motd SET message ='
 6    <BODY><BR>
 7    <BODY><C=2>歡迎来到<C=6>生化危机:爆發<C=2>中文服務器!<BR><BR>
 8    <BODY><C=3>[NEWS!] 東区等待2分鐘即可開始游戲<BR><BR>
 9    <BODY><C=1>為了大家的游玩体驗<BR>請不要開啓模擬器加速功能!<BR><BR>
10    <BODY><C=4>[在線列表] https://ob.alexpad.cn<BR>
11    <BODY><C=4>[連机QQ群] 725374419<BR>
12    <BODY><C=4>     <BR>
13    </END>' where id = 2 ; 
14Query OK, 1 row affected (0.024 sec)
15Rows matched: 1  Changed: 1  Warnings: 0

一通操作猛如虎,结果公告栏输出成这个样子……

image-20240303021444735.png

利用之前介绍的编码解码网站,可以推断出字符还是以 UTF-8 编码存储的,而解析画面则是固定为 SJIS 编码。

image-20240303021657513.png

这里下方是以 UTF-8 编码的生化危机:爆發 中文服務器,即\xe7949f\xe58c96\xe58db1\xe69cba\xefbc9a\xe78886\xe799bc\x20\xe4b8ad\xe69687\xe69c8d\xe58b99\xe599a8,上方则是错误解码成 SJIS 编码的样子 逕溷喧蜊ア譛コ・夂・逋シ 荳ュ譁・恪蜍吝勣

顺着motd 这张数据库表的线索,回溯 Java 后端代码。找到 Databases.java 中的 getMOTD() 方法。这个就是后台读取公告内容的方法。

image-20240303030116754.png

顺着调用链继续找,找到PacketHandler.javasendMotheday() 方法,这个方法应该就是将公告信息编码打包,传输给客户端。我们顺着找到 MessageOfTheDay.java

image-20240303030149483.png

MessageOfTheDay.javagetPacket() 方法中,则详细展示了将文本文档转化为编码的方法。

image-20240303030502735.png

这里我们将getByte() 显示指定为 SJIS 编码,并添加异常处理。

 1public byte[] getPacket() {
 2        byte[] retval = new byte[3 + message.length()];
 3        retval[0] = number;
 4        if (message.length() == 0) retval[0] = 0;
 5        retval[1] = (byte) (message.length() >> 8);
 6        retval[2] = (byte) (message.length() & 0xFF);
 7
 8        try {
 9            System.arraycopy(message.getBytes("SJIS"), 0, retval, 3, message.length());
10        } catch (UnsupportedEncodingException ex) {
11            System.arraycopy(message.getBytes(), 0, retval, 3, message.length());
12        }
13
14        return (retval);
15    }

重启 Java 后端服务,再次登陆客户端,显示一切正常!

image-20240303050023677.png

二、爆发2

1. 修改二代区域描述信息

基本原理与前面相同,这里就不再赘述。

Areas.java

image-20240303050943556.png

修改为:

 1private void initializeAreas(byte secretAreaStatus) {
 2        areas.add(new Area(1, "Free Area", "<BODY><SIZE=3>自由標准模式<BR><BODY><C=3><END>", Area.STATUS_ACTIVE));
 3        areas.add(new Area(2, "Nightmare", "<BODY><SIZE=3>默設開啓悪梦模式<BR><BODY><C=3><END>", Area.STATUS_ACTIVE));
 4        areas.add(new Area(3, "Survival", "<BODY><SIZE=3>默認開啓友傷<BR><BODY><C=3><END>", Area.STATUS_ACTIVE));
 5        areas.add(new Area(4, "Panic", "<BODY><SIZE=3>默認開啓悪梦和友傷<BR><BODY><C=3><END>", Area.STATUS_ACTIVE));
 6        areas.add(new Area(5, "Infinity", "<BODY><SIZE=3>默認開啓无限子彈,可開啓悪梦和友傷<BR><BODY><C=3><END>", Area.STATUS_ACTIVE));
 7        areas.add(new Area(6, "SP Hunt", "<BODY><SIZE=3>默認開啓SP道具閃光<END>", Area.STATUS_ACTIVE));
 8        areas.add(new Area(7, "TESTING", "<BODY><SIZE=3>測試用<BR><BODY><END>", Area.STATUS_ACTIVE));
 9        areas.add(new Area(8, "Elimination", "<BODY><SIZE=3>僅限殲滅1-3<BR><BODY><C=3>在給定的時間内与隊友一起打敗敵人<END>", Area.STATUS_ACTIVE));
10        areas.add(new Area(9, "Showdown", "<BODY><SIZE=3>僅限對峙1-3<BR><BODY><C=3>聯合起来打敗BOSS!<END>", Area.STATUS_ACTIVE));
11        areas.add(new Area(10, "SECRET Area", "<BODY><SIZE=3>可開啓悪梦和初始感染<BR><BODY><C=3><END>", Area.STATUS_ACTIVE));
12    }

PacketHandler.java

image-20240303050713149.png

修改为:

 1void sendAreaDescript(ServerThread server, SocketChannel socket, Packet ps) {
 2        int nr = ps.getNumber();
 3        String areadesc = areas.getDescription(nr);
 4        byte[] retval = new byte[areadesc.length() + 4];
 5        retval[0] = (byte) ((nr >> 8) & 0xff);
 6        retval[1] = (byte) (nr & 0xff);
 7        retval[2] = (byte) ((areadesc.length() >> 8) & 0xff);
 8        retval[3] = (byte) (areadesc.length() & 0xff);
 9
10        try {
11            System.arraycopy(areadesc.getBytes("SJIS"), 0, retval, 4, areadesc.length());
12        } catch (UnsupportedEncodingException ex) {
13            System.arraycopy(areadesc.getBytes(), 0, retval, 4, areadesc.length());
14        }
15    
16        Packet p = new Packet(Commands.AREADESCRIPT, Commands.TELL, Commands.SERVER, ps.getPacketID(), retval);
17        this.addOutPacket(server, socket, p);
18    }

2. 登陆公告栏

同理,修改数据库内容:

1UPDATE motd SET message ='
2    <BODY><BR>
3    <BODY><C=2>歡迎来到<C=6>生化危机:爆發2<C=2>中文服務器!<BR><BR>
4    <BODY><C=3>[NEWS!] 祝大家新年快樂,龍年大吉!<BR><BR>
5    <BODY><C=1>為了大家的游玩体驗<BR>請不要開啓模擬器加速功能!<BR><BR>
6    <BODY><C=4>[在線列表] https://ob.alexpad.cn<BR>
7    <BODY><C=4>[連机QQ群] 725374419<BR>
8    <BODY><C=4>     <BR>
9    </END>' where id = 2 ;
评论
取消