国内GBK编码MUDLIB升级UTF-8编码指南

前言

国内MUD都是GBK编码,对旧MUD需要很少的代码改造就可以使用fluffos v2017驱动,但要使用fluffos v2019驱动,需要进一步升级,这个改动就比较大了,相对麻烦很多。

把LIB从fluffos v2017升级到fluffos v2019比较麻烦,但从原mudos升级到fluffos v2017还是非常简单的,如果你不想升级到2019,请至少保证升级到2017,一方面性能优化,另一方面64位的数据支持至少不会让你MUD因为数据过大而崩溃。

下面介绍原来mudos驱动的lib升级到fluffos v2019的流程,推荐操作是先升级到flufos v2017驱动,运行测试没有BUG后再升级到fluffos v2019驱动。

升级至 fluffos v2017 驱动

升级方案一

让LIB适配驱动,主要只需修改你的代码如下关键点:

  1. 修改static变量为nosave变量
  2. 修改static函数为protected函数
  3. 删除#pragma save_binary预处理指令(不删除可以运行,但是对不再支持的#pragma日志会有warning)

以上几点是需要在你的整个LIB中修改,推荐使用VS Code直接查找整个LIB然后判断是变量或函数后针对性替换。或使用以下perl脚本:

#!/usr/bin/perl -pi

if (/,/ || /=/) {
    s/static/nosave/;
}
elsif (/\([^{[:]/) {
    s/static/protected/;
}
elsif (/;/) {
    s/static/nosave/;
}
else {
    s/static/protected/;
}

示例:保存这个脚本到你的LIB根目录中,文件名"fixstatic.pl",然后在你的LIB目录中执行以下指令:

find . -name "*.c" -print | xargs fixstatic.pl

提示:windows系统的用户,请安装git后直接在你的LIB目录中右键菜单Git Bash here打开后运行以上指令。

建议:使用git管理你的LIB,执行以上指令后,再用git diff查看改了什么,检查一下有没有问题。

diff --git a/adm/daemons/backupd.c b/adm/daemons/backupd.c
index fd71712..b454fd5 100755
--- a/adm/daemons/backupd.c
+++ b/adm/daemons/backupd.c
@@ -8,7 +8,7 @@ inherit F_DBASE;

 #define BACKUP_DATE     7               // the oldest's backup (days)

-static int state;
+nosave int state;

 #define SLEEPING        0
 #define GET_READY       1
@@ -18,8 +18,8 @@ static int state;
 #define CMD_RM          "/cmds/wiz/rm"
 #define CMD_CP          "/cmds/wiz/cp"

-static int *tlist = ({ 0, 550, 559, 600 });
-static int *hlist = ({ 45, 1, 1, 1 });
+nosave int *tlist = ({ 0, 550, 559, 600 });
+nosave int *hlist = ({ 45, 1, 1, 1 });

注意:这个脚本不能保证100%解决所有问题,但至少可以处理90%的代码,剩下的手动处理也没多少工作量了。

升级方案二

让驱动兼容LIB,不对LIB做不做任何修改,而是在编译fluffos v2017前修改配置文件 src/local_options,把 #define SENSIBLE_MODIFIERS 改为 #undef SENSIBLE_MODIFIERS,这样编译的驱动直接支持MUDOS驱动的LIB。

提示:这里不推荐第二种解决方案,最好还是把 static 修改掉,根据经验来说,修改变量和函数问题不会超过30分钟,而且有更好的兼容性。


使用fluffos v2017驱动升级后的MUD应该会在log日志中有大量的代码警告,这是因为fluffos在代码检查上更严格,如果你定义了一个变量但又没有去使用这个变量,就会有类似以下的Warning: Unused local variable警告:

/cmds/skill/jifa.c line 131: Warning: Unused local variable 'types' before the end of line

推荐修复方案为把未用变量清除掉,可以使用胖大神写的指令自动处理:

  1. 使用指令 loadall 编译所有文件
  2. 使用指令chklog自动清理未用变量

还有比较常见的重复定义宏的警告,类似如下:

/include/ansi.h line 68: Warning: redefinition of #define BLK before #define RED

这是代码中重复引用了头文件,可以通过条件编译判断修复,参考教程:https://bbs.mud.ren/threads/35

因为警告问题不是致命错误,如果你很懒,不想修复Warning相关的问题,也可以掩耳盗铃的方式处理,你看不见它就当它不存在了🤣,具体为修改MASTER_OB中的void log_error(string file, string message)方法,不记录Warning类型的日志。

void log_error(string file, string message)
{
    if (strsrch(message, "Warning") == -1)
    {
        // 记录错误日志
        efun::write_file(LOG_DIR + "log_error", message);
    }
    else
    {
        // 记录警告日志(注释掉这里就不再记录警告日志,但控制抬和debug.log还会显示)
        efun::write_file(LOG_DIR + "log", message);
    }
}

而其它因为不规范写代码造成的警告问题和错误需要自己手动修理了,如在侠客行一百中,有用关键字 newclass 做变量名的,在fluffos下会报错。修复完成后,推荐使用 updateall 指令更新一下,看看你的LIB能不能正常通过编译。

另外需要注意的是localtime() 问题处理,因为数据处理方式问题,在fluffos中如果给的时间戳超过上限localtime()返回0,这就可能造成了游戏时间系统相关功能报错。

mudos下localtime时间上限是2038年1月19日11时14分7秒,时间戳最大值是2147483647(2**31-1),超上限后溢出重新从1970年1月1月0时0分0秒开始(北京时间是8时)

fluffos v2017 时间上限是2147483647年12月31日23时59分59秒,正常游戏开发基本不回溢出

fluffos v2019下windows系统时间上限是3001年1月1日15时59分59秒,时间戳最大值是32535244799,超上限后返回0

还有就是加密算法的改变,fluffos中加crypt密码算法是SHA-512,MUDOS中的加密函数crypt在fluffos中被改为oldcrypt,为保证老玩家正常登录,需要对密码验证做兼容处理,参考方法见本文下方登录验证兼容处理相关内容。

升级至 fluffos v2019 驱动

如果要使用fluffos v2019最新版,除了以上根据方案一升级到fluffos v2017的修改还得转换LIB为UTF-8编码并修改部分代码,这是大工程,要搞事情,不要问我为什么要升级,喜欢旧版不升级也可以的,见仁见智而已。

根据炎黄群侠传的升级分享经验如下,也方便大家结合自己的MUD修改,具体步骤如下:

1. 编码转换

使用的是https://github.com/fluffos/gbk2utf8 ,类似以下指令:
# 转换.c文件
gbk2utf8 --from GB18030 --to UTF8 --src code --dst code-utf8
# 转换.h文件
gbk2utf8 --from GB18030 --to UTF8 --src code --dst code-utf8 --pattern "*.h"
# 以下方式转换所有文件(慎用)
gbk2utf8 --from GB18030 --to UTF8 --src code --dst code-utf8 --pattern "*"

软件用法:

    $ gbk2utf8 --help
    gbk2utf8(version v1.0.3)

    Usage:
      gbk2utf8 [flags]

    Flags:
      -c, --config FILENAME   config FILENAME, default to `config.yaml` or `config.json`
          --version           just print version number only
      -h, --help              show this message
          --gen-yaml          generate config.yaml
          --gen-json          generate config.json
      -f, --from string       将要转换的文件的编码,可选值: GB2312/GBK/GB18030/BIG5/UTF8 (default "GB18030")
      -t, --to string         想要转换成的目的文件编码,可选值: GB2312/GBK/GB18030/BIG5/UTF8 (default "UTF8")
      -s, --src string        想要转换的文件或者目录。如果是目录,则将会转换此目录下所有的文件,包含子目录
      -d, --dst string        转换完的目标文件名或目录名。注意目标路径下的内容会被清空
      -p, --pattern string    想要转换的文件名的模式。只有文件名符合模式的文件才会被转换 (default "*.c")
除了.c文件和.h头文件,还有帮助文件需要转换格式,请务必保证所有文件编码都转为 utf-8。

升级最最花时间的地方就在这里,虽然有工具批量转码,根本MUD代码的复杂度,从转码到检查处理完所有可能的错误,还是得不少时间。

2. 代码修改

需要修改的主要有几个方面,请务必全面检查,否则就BUG了~
(1) is_chinese() sefun修改

utf-8下判断中文使用prce正则表达式即可:

  int is_chinese(string str)
  {
      if (!str)
          return 0;

      return pcre_match(str, "^\\p{Han}+$");
  }
(2) 字符串相关问题修改

旧驱动gbk下中文占2个字节,strlen()strwidth()函数返回的都是字符宽度,而新驱动strlen()返回的是字符个数,strwidth()是字符宽度。如strlen("文字MUD")在旧版返回7,新版返回5,而strwidth("文字MUD")返回值是一致的,都是7;另外GBK下字符串中取汉字为str[0..1]而新版驱动中英文都是str[0..0],这就是重点需要修改的问题,得根据自己的游戏代码处理。

最傻瓜的解决方案是把所有 strlen() 都替换成 strwidth(),这能解决绝大多数转码后的问题(并不建议这样傻瓜替换),但是还有一些代码用sizeof()判断字符串宽度的,这个需要自己检查处理,而不是简单替换了。另外就是类似str[0..1]str[2..3]这种取字符串中的汉字的代码修改为str[0..0]str[1..1]

因为不同LIB差异较大,这里列出共性存在的几个需要修改的地方:

  • 模拟外部函数sort_string
  • 存档判断玩家姓名或生成NPC名字的NAME_D
  • 地图系统MAP_D
  • 玩家武功技能查询指令cha
  • 少林峨眉等门派改名的相关代码
(3) 更新LIB的驱动相关include文件

可直接复制驱动提供的 include 文件到LIB的include目录。

(4) 更新运行时配置文件

推荐参考 config.iniconfig.test

(5) 表情emoted.o等存档及玩家存档格式转换

存档是特别格式,CR换行不得转为LF,否则存档出错。推荐使用类似以下指令转码:

gbk2utf8 -s GBK/data/ -d UTF8/data/ -p "*"
(6) 中文字符样式处理

这个比较简单,批量替换中文符号为二个英文字符就好,比如——--替换,::替换,**替换……如果不替换在GBK下美美的排版在UTF-8下惨不忍睹,因为这些宽度为2的字符在UTF-8下也变成了1,造成排版错位。

(7) 增加GBK端口

为了方便使用zMud的玩家,最好增加游戏的GBK编码支持,最简单的方式为固定一个端口为GBK输出,代码只需对 MASTER_OB 中的connect方法做类似如下修改,即可固定5555端口为GBK编码输出。


object connect(int port)
{
    object login_ob;
    mixed err;
    if (port == 5555)
    {
        set_encoding("GBK");
    }
    err = catch(login_ob = new(LOGIN_OB));

    if (err) {
        write("现在有人正在修改使用者连线部份的程式,请待会再来。\n");
        write(err);
        destruct(this_object());
    }
    return login_ob;
}

当然,也可以在LOGIN_D 文件中修改让玩家选择输出编码,只要使用set_encoding EFUN指定输出编码即可。

(8) 登录验证兼容处理

如果你的游戏本来有旧的玩家数据,除了需要做数据存档转码处理,还需要修改登录验证密码的代码,保证兼容旧加密密码。

密码验证参考代码如下:

nomask int matches_password(string str, string password)
{
    if (password[0..2] == "$6$")
        return crypt(str, password) == password;
    else
        return oldcrypt(str, password) == password || crypt(str, password) == password;
}

提供一些转码完成的LIB供大家体验:

更多fluffos版lib请看这里:MUDLIB fluffos v2017版及v2019版下载汇总

京ICP备13031296号-4