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

国内MUD都是GBK编码,可以使用fluffos v2017驱动,对旧MUD需要改造对很少,主要只需修改如下关键点:

  1. 修改static变量为nosave变量
  2. 修改static函数为protected函数
  3. 删除#pragram 相关预处理指令(不删除可以运行,但是日志会有warning)

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

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

  1. 编码转换

    使用的是https://github.com/fluffos/gbk2utf8 ,类似以下指令:

    gbk2utf8 --from GB18030 --to UTF8 --src code --dst code-utf8 --pattern "*.c"
    gbk2utf8 --from GB18030 --to UTF8 --src code --dst code-utf8 --pattern "*.h"

    除了.c文件和.h头文件,还有帮助文件需要转换格式,请务必保证所有文件编码都转为 utf-8。

  2. 代码修改

    需要修改的主要有几个方面:

(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()返回值是一致的,都是7;另外GBK下字符串中取汉字为str[0..1]而新版驱动中英文都是str[0..0],这就是重点需要修改的问题,得根据自己的游戏代码处理。最傻瓜的解决方案是把所有 strlen() 都替换成 strwidth(),这能解决绝大多数转码后的问题(并不建议这样傻瓜替换),但是还有一些人的代码用sizeof()判断字符串宽度的,这个需要自己检查处理,而不是简单替换了。另外就是类似str[0..1]str[2..3]这种取字符串中的汉字的代码也需要修改为str[0..0]str[1..1],这个主要包括以下几个地方:存档判断玩家姓名或生成NPC名字的NAME_D、地图系统MAP_D、玩家武功技能查询指令cha、少林峨眉门派改名的相关代码。

(3) 更新LIB的驱动相关include文件,可直接复制驱动提供的 include 文件到LIB的include目录。

(4) 更新运行时配置文件,推荐参考 config.iniconfig.test

(5) 表情emoted.o等存档及玩家存档格式转换转换为utf-8,另外CRLF换行符需要转换为LF,但是,存档是特别格式,CR换行不得转为LF,否则存档出错。

(6) 中文字符样式处理,这个比较简单,批量替换为二个英文字符就好,比如——--替换,::替换,**替换……否则GBK下美美的排版在UTF-8下惨不忍睹。

(7) 其它BUG修复,一方面是未用变量问题,在fluffos下会报警告,另一方面是错误变量,如在侠客行一百中,有用关键字 newclass 做变量名的,在fluffos下会报错。推荐先用 loadall 指令批量载入所有代码看看有什么错误,对未用变量的警告再使用 chklog 指令自动注释处理,处理完成再次批量更新检查一下。

(8) 为了方便使用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指定输出编码即可。

(9) 最后,如果你的本来有旧的游戏数据,需要做数据存档转码处理,除些之外,还需要修改登录验证密码的代码,保证兼容旧加密密码。密码验证参考代码如下:

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供大家体验:

京ICP备13031296号-4