Article29 Apr 2026

变量名全是中文

回郑州

2019年,妻子怀孕,我们一起离开了北京,回家待产。

那段时间没上班,时间宽裕,却不知道往哪里放。有一天无意中点开了抖音上的一条广告——是传奇的手游版,我小时候玩过的那个传奇。

我最喜欢用法师。法师的好处是不需要跟妖怪贴身肉搏,可以保持距离,灵活走位,一点点把妖怪磨死。我喜欢这种风格。


工会

后来加入了一个工会。里边大多数是跟我差不多的中年人,各自情况不一样,相同的是小时候都玩过传奇。我们一起做任务、跑地图、攻打沙巴克。那段时间挺开心的。

游戏里金币总是不够用。所有活动、任务都需要消耗金币,大家普遍短缺,只能去找金币商人购买。与此同时,游戏里有大量繁琐的跑图任务——二十四节气每个都有对应的任务,要跑到特定地图打特定妖怪,捡特定的道具,提交之后才换来金币和装备。反反复复,很耗时间。

于是外挂应运而生。很多大号也在用,挂机跑任务,解放双手。我买了两种,一种是按键精灵手机版写的,粗糙,但反应快。另一种是Lua写的,运行在root过的旧iPhone上,要价300元一份。


SSH进去看一看

买回来之后,我做了一件对我来说很自然的事:SSH登录进手机,把外挂的所有文件翻了一遍。

这是我的习惯。遇到一个陌生的系统,第一反应就是看它的文件结构,看看它是怎么运作的。

外挂启动时是一个加载器,验证Key之后,所有资源从阿里云服务器动态加载。通信是明文HTTP,没有加密。我在网关做了代理,把流量截下来看,逻辑很清晰。

真正让我起了兴趣的是它的功能程序文件。用Hex Editor打开,里面的字符串很奇怪。我盯着看了一会儿,发现规律:把字符串反转,前面加上"LuaQ"几个字符,得到的就是 lua 字节码。找了一个Java写的Lua反编译工具,跑了一遍。

源码出来了。变量名全是中文。


中文变量名

看到中文变量名的那一刻,我知道做对了。如果看到其他的,我还不能确定是不是真正的源码。但中文,那绝对没错。

我第一反应是有点鄙视——就像看到用拼音命名变量的代码一样,觉得不专业。

但是当我逐渐读完整个框架,态度变了。

对中文母语者来说,中文命名本身就是注释。"回城中"、"找极品怪"——不需要任何额外说明,一眼就知道这段代码在干什么。模块切割得很清楚,基础功能单独封装——寻路、识别、点击各自独立。游戏出了新活动,只需要调用现有的函数组合一下,不需要大改。

这个代码写得真的漂亮。我不知道写这套系统的人是谁,但我开始敬佩他。

Codelua
function 盟重快速出售()
  if 比色(主界面.主界面) then
    click(主界面点击.回城按钮)
    toast("准备快速出售物品,请等待...")
    mSleep(1500)
    飞盟重主城()
    for i = 1, 23 do
      mSleep(1000)
      界面处理()
      找老兵(NPC.盟重小贩, NPC.点击盟重小贩, NPC.盟重小贩偏移X, NPC.盟重小贩偏移Y, 1000)
      if 比色(主界面.推送商城) then
        click(主界面点击.关闭图鉴, 500)
        回城中()
        找老兵(NPC.盟重小贩, NPC.点击盟重小贩, NPC.盟重小贩偏移X, NPC.盟重小贩偏移Y, 1000)
      end
      if 比色(主界面.NPC对话界面) then
        快速出售物品()
        mSleep(500)
        if 比色(回城购买物品.成功出售) then
          沃玛ZB卖金币()
          click(主界面点击.NPC对话界面, 500)
          break
        end
      else
        处理找不到NPC()
        回城中()
      end
    end
    捆存太阳水()
    存疗伤药()
    存万年雪霜()
    装备材料存放()
  end
end

在上面建自己的东西

既然源码有了,我就开始改。

首先做了一个代理层:本地运行的是我修改过的程序,不再直接连外挂服务器,而是连接到我本地的Python代理,由它统一用Key向服务器请求资源并缓存。这样多台手机共用一个Key也没有问题。

然后做了热补丁系统。外挂原版有时候更新不及时,或者识别有bug。我的补丁会在加载时自动覆盖对应的函数,不需要等官方修复。

又做了一个Web配置界面。原版是Lua写的配置界面,在手机上操作很麻烦。我做了一个完全兼容的Web版,配置保存到Redis,客户端定期检查版本号,发现更新就自动热加载。

为了识别游戏地图名称和坐标,我训练了Tesseract的字库,做了OCR识别模块。

最高峰的时候,我买了20个旧iPhone,加上一个多口USB供电设备,一排插着充电,同时运行。


金猪

游戏里有一个活动,每天中午,金猪会随机出现在几个固定地图的随机坐标上。打死金猪会掉落金砖,每块金砖可以换大量金币。

我做了一套自动打金猪的系统。

活动开始前五分钟,程序自动回城,清理背包,买好随机传送券。我收集了历史上金猪出现的坐标数据,做了一个简单的预测模型,找出最可能出现的位置,提前把手机传送过去等待。活动开始后,用OCR识别系统公告里金猪出现的地图名称和坐标,如果很远就一直用随机券变换坐标,如果近就打开小地图换算坐标,自动点击寻路,走到金猪附近开启自动攻击,打死之后自动捡金砖。

运气最好的时候,预测的坐标几乎就在金猪刷新的位置旁边,程序还没走几步就开始打了。

二十台手机同时跑这个程序。有一段时间,一个服务器里的金猪,几乎都被我包圆了。

每次程序打到金猪,我会跑到卧室,用很轻的声音告诉妻子:我的程序又打到金猪了。她怀孕,经常卧床休息。如果没睡着,她就能听到。如果睡着了,我就不打扰,自己回去继续看日志。

炫耀

有一天,我忍不住跟那个卖给我外挂的人说了这件事——我已经把他的程序完全破解了,还加了他们没有的功能。

他天天来找我,想要合作,一起把改进版的外挂卖出去。

我拒绝了。风险太大,而且我也没缺钱到那个地步。

但我更在意的是,他完全没有理解我跟他说的是什么。我骄傲的不是能用这套系统赚钱,而是把一个封闭的系统从头拆开、读懂、然后在上面建出了更好的东西。这件事本身就是目的,不需要变现。


关服

后来孩子出生了,事情多了,我也找到了新工作。手机一台一台关掉,程序就这样停了。

这类传奇手游有自己的生命周期。运营商不断推出新服务器,刚开始大家站在同一起跑线,慢慢地氪金的人和不氪金的人差距越来越大,最后不氪金的玩不下去,氪金的也没得玩,服务器就死了。大家转移到下一个服务器,或者下一个游戏。

About this article

Author
Lerry
Published
2026-04-29