Bi Xue Jiang Hu — Tianya Edition

✅ 可玩

天涯之碧血江湖

tybxjh

🔑 fluffos / AdminPass123 更新 cceaeb2 2026-09-04 源码 下载 ZIP

▶ 开始游玩 · Play Now

天涯泥潭(Tianya MUD Wizard Group)自 2002 年建站运营至今的老牌武侠 MUD"碧血江湖",是本项目收录的整个"天涯"系列的真正原始根代码——`wlhd`(武林浩荡/金庸梦II)、`xhcii`(笑红尘Ⅱ)、`zxty`(再现天涯)、`ffxymud`(非凡夕阳MUD/时空游侠录)、`jhfy2`(江湖风云2)、`xysylmhb`(夕阳三-炎龙美化版)、`xyzxiiylzymh`(夕阳再现II-炎龙专用美化客户端)、`yzxiiizylfy`(夕阳再现III之炎龙封印)等档案的 `master.lpc`/`securityd.lpc`/`logind.lpc` 核心系统都与本档案几乎完全一致,只是各自独立改写了地图内容(其中 `xysylmhb`/`xyzxiiylzymh`/`yzxiiizylfy` 标题虽带"夕阳再现",血统其实属于这个"天涯"家族——真正的"夕阳再现"血统是 `xyzx`/`jhfy3`/`xajh4gkb`/`xyzxyl201412` 那完全不同的另一支代码)。地图几乎覆盖金庸小说的全部门派与地理版图:华山、武当、峨嵋、丐帮、明教、逍遥、星宿、天龙寺、少林、昆仑、桃花岛等门派场景一应俱全,城池跨越长安、荆州、襄阳、大理、西夏、泉州等地;`quest/japan/` 是一整条"抗日"主题任务线,把日本侵华的历史背景编织进传统武侠世界观,这在同类泥潭里并不常见;`quest/guojob` 则提供团队向的"国家任务",配合按银两数量分级的悬赏榜(赏金从 3000 到 200 万不等),是比单人打怪更结构化的经济/协作玩法;注册流程采用管理密码与登录密码分离的双密码设计,并有 150 秒的整体超时限制,是这份档案自己独有的登录设计。

English

The Tianya MUD Wizard Group's "Bi Xue Jiang Hu" (Jianghu of Sworn Blood) archive, a long-running wuxia MUD that has operated since 2002 and is the original root codebase for the wider "Tianya" lineage in this collection (wlhd, xhcii, and several others share near-identical master/securityd/logind core systems despite each independently customizing its own map). The map covers most of Jin Yong's classic sect and geographic universe — Huashan, Wudang, Emei, the Beggars' Sect, Ming Cult, Carefree School, Xingxiu, Tianlong Temple, Shaolin, Kunlun, Peach Blossom Island — spanning cities from Chang'an and Jingzhou to Xiangyang, Dali, Western Xia, and Quanzhou. Unusually for the genre, one full quest line (quest/japan) explicitly weaves a WWII-era anti-Japanese-invasion storyline into the wuxia setting, and a team-oriented "national tasks" system (quest/guojob) pairs with a tiered bounty board (rewards from 3,000 up to 2,000,000 in-game currency) for a more structured, cooperative alternative to solo grinding. Registration uses a distinctive dual-password design (separate admin and login passwords) with a genuine 150-second overall timeout.

README

本次处理内容

WASM 修复阶段没有发现需要修复的程序 bug。唯一做的事情是在 /adm/etc/wizlist 里加入管理员账号(SECURITY_D 正确指向 /adm/daemons/securitydu/zjb/securityd.lpc 是没有被实际引用的 分身档案)。

顺带一提,securityd.lpcget_status() 对四个特定账号 (daniel/zjb/kjh/jiji)写死返回最高的 (boss) 权限,不受 wizlist 内容影响——这是站方创始人账号的既有设计,不是 bug,也不 影响 fluffos 账号的权限。

深度功能测试(§10.7)发现这个"无需修复"的结论过于乐观——这份档案是 wlhd(武林浩荡)等一批同源档案的原始代码库,wlhd 自己已经确认 的 2 处 printf 调试残留、§8.9 食物/饮水年龄检查错对象、 exert_function() 类型错误在这里全部命中(后者甚至有 4 处,比 wlhd 的 1 处更多,分别废掉了升级师/两份医疗 NPC/转世僧人);另外 发现一个从未被记录过的严重安全问题:注册时设置的管理密码和普通 密码明文被 logind.lpc 额外写进 /doc/help/neima2/neima3——而 /doc/help/ 正是标准 help 指令对任何玩家开放搜索的路径,任何人 打 help neima2 就能看到建站以来每个账号的明文密码(已写入 AGENTS.md §7.84);还有一个进度条渲染 bug,几乎让 score 指令的食 物/饮水/气血条无论真实数值都显示"满格",掩盖了 §8.9 的真实影响(新 增 AGENTS.md §7.85)。详见 NOTES.md。

管理员账号 / Admin account

修正(round-two 深度测试发现):feature/dbase.lpcset() 有 一条防劫持保护,会把"这个 id 已经在 wizlist 里登记为 (admin)"错误 地当成"已有一个受保护的旧密码",导致 fluffos 这类"提前播种 wizlist、再走正常注册"的账号在第一次设置密码时就被自己的保护 机制拦截,密码从未真正写入存档——修复前虽然注册流程能顺利走完、 (admin) 权限显示正常,但用刚设置的密码重新连线会被三次拒绝踢下 线。已修复该逻辑缺陷(只在密码已存在时才触发保护),并用真实的 "设置密码→重新连线"往返验证过。详见 NOTES.md。

警告:这是一个公开的默认密码,仅供本地/浏览器试玩。正式对外开服前
请务必修改此密码。

测试注意事项

这份档案有一个真实存在、非测试artifact的 150 秒注册超时clone/user/login.lpctime_out()LOGIN_TIMEOUT 定义在 include/login.h,从连线那一刻就开始计时,不是每个提示符重置)。 get_email()/get_gender() 阶段会触发 /inherit/char/char 极其 庞大的一次性编译警告洪流,如果测试脚本用较长的 --idle(比如 6-15 秒)等待这些警告刷完,反而会撞上这个 150 秒的整体超时被系统 踢下线(显示"您花在连线进入手续的时间太久了")。用较短的 --idle 2 反而能够顺利在超时窗口内完成整个注册流程。

本地运行

cd libs/tybxjh
~/src/fluffos/build-debug/src/driver config.fluffos

游戏端口:40158

NOTES · 移植与修复记录

WASM 修复摘要(迁移自 meta.json 的 group_note)

天涯之碧血江湖(TIANYA.ZB 版),天涯泥潭巫师组,自 2002 年运营至今。在 WASM 下完全干净地启动运行——没有编译错误,没有运行时错误,整个代码库不需要任何修复。唯一采取的行动是把 fluffos (admin) 播种进 adm/etc/wizlist(SECURITY_D 正确指向 /adm/daemons/securityd,已通过 globals.h 确认;u/zjb/securityd.lpc 下有一份诱饵副本但没有被接上)。备注:securityd.lpc 的 get_status() 硬编码了 4 个具名 euid(daniel/zjb/kjh/jiji),不管 wizlist 内容如何都一律回传最高的 (boss) 等级——这是有意的创始人账号逻辑,不是 bug,也不影响 fluffos 账号。注册流程在一次连续的 WASM 客户端会话里完整验证过:英文 id→y/n 创建确认→中文名字→管理密码+确认→普通密码(必须不同)+确认→天赋数值选择(0 为随机,y 接受)→电子邮件(需要 id@address 格式)→性别→带着完整角色属性表进入游戏世界,全程没有任何意外错误。管理员权限已直接通过登录后的横幅"您目前权限:(admin)"确认。测试备注:这份档案强制执行一个真实存在的 150 秒 LOGIN_TIMEOUT(从连线那一刻用 call_out 计时,不是每个提示符重置),会把太慢的注册断线并提示"您花在连线进入手续的时间太久了"——这是真实、有意的 mudlib 行为(不是 WASM/测试artifact),已通过读取 clone/user/login.lpc 的 time_out()/LOGIN_TIMEOUT(150 秒,include/login.h)确认。早期测试用较长的 --idle(6-15 秒)来躲避编译警告刷屏的计时竞态,反而正好撞上了这个超时,因为 get_email()/get_gender() 会触发 /inherit/char/char 及其 feature 档案的一次沉重的一次性编译;改用较快的 --idle 2 能在窗口内顺利完成注册,这是这份档案特有的正确做法。LPC 格式化工具对全部 9398 个档案运行(写入 9303 个,61 个因为杂乱的历史代码报错,包括一处确认的转档前 token 不匹配跳过,34 个未改动);还原了 1 个档案(d/city/sj.lpc)确认有转档之前就存在(作者一方,早于本轮)的缺引号损坏被格式化工具进一步重新加了空格。没有 :: 父类呼叫拆分命中。没有找到 case 标签带尾随注释的候选。逐一比对了全部 4 个 map.lpc 档案——3 个只是大括号排版(K&R 合并);cmds/std/map.lpc 的 diff 一开始看起来更大,是因为一个很长的 sprintf() 呼叫被重新换行成多行,但去空白的全档案比对确认内容逐字节相同(2032 个字符,完全一致)。格式化后用同样的完整注册流程重新验证过——干净,管理员权限依然是 (admin)。

深度功能测试(§10.7,2026-08-05)

之前的 WASM 修复阶段结论"完全无需修复"过于乐观——这是同源"天涯"家族 (wlhd/xhcii/zxty/ffxymud/jhfy2 等)的原始代码库,先检查了 wlhd 自己已经完成的 §10.7 记录(2x printf 调试残留、§8.9 食物/饮 水年龄检查错对象、一处 exert_function() 类型错误),逐项在 tybxjh 自己的源码里核实,而不是假设结论可以照搬——结果全部命中,而且比 wlhd 更严重:

§7.86 跨库扫描修复(留言板 post 崩溃)

深度功能测试(2026-08-13,round two,新驱动重测)

Re-tested against the freshly-rebuilt build-debug/src/driver(post 全库 quest_times/win_times %-operator 修复 + Warning/warning 驱动文本回退)。

发现并修复的 PROGRAMMING bug

1. log_error()adm/obj/master.lpc,CRLF 行尾档案)完全没有严 重度检查(AGENTS.md §7.34-class,本轮反复确认的形状)if (this_player(1)) efun::write(...)——不区分巫师/玩家,也不区 分警告/错误。修复:加上 strsrch(message, "arning:") == -1 判 断(用 Python 字节级正则替换保留 CRLF 行尾——第一次尝试直接用 贪婪正则捕获整行字符串字面量时越界匹配到了跨越 + message + "\n" 的部分,产生了重复代码,已发现并撤销重做, 改用精确匹配已知字面量的方式)。 2. log_file()adm/simul_efun/file.lpc)完全没有 assure_file() 保护(AGENTS.md §7.11-class 的又一确认实例)adm/daemons/ logind.lpcget_gender()(新角色注册流程的最后一步)紧跟 着调用 log_file("login/newid.log", ...)——和 ffxymud/hc/ jhfy/jhfy2 完全同一形状。已补上 assure_file(LOG_DIR + file);第一次尝试时漏加了前向声明assure_file() 定义在同文件后面),导致 /adm/obj/ simul_efun 编译失败、整个驱动无法启动("Undefined function assure_file")——立即发现(下一步就是启动驱动)并补上前向声明 重新编译,驱动恢复正常启动。

发现并修复的重大 PROGRAMMING bug:新注册的管理员账号永远无法真

正登录(密码从未被持久化)

3. feature/dbase.lpcset()password/ad_password 属 性有一条防劫持保护,但错误地把"这个 id 已经在 wizlist 里被列为 (admin)"当成了"这个账号已经有一个受保护的旧密码",导致这个 id 第一次注册、设置自己密码的那一刻就已经被自己的保护机制拦 截(新发现的 bug 类别): `` if ((prop == "password" || prop == "ad_password") && wizhood(this_object()->query("id")) == "(admin)" && this_player() && geteuid(this_player()) != this_object()->query("id")) return; ` wizhood() 只读取 /adm/etc/wizlist 这个纯文本文件,和这个 id 是否已经有一个真实存在的角色/密码完全无关。本项目标准做法是提 前把 fluffos (admin) 写进 wizlist,再让 fluffos 走正常注 册流程——但正是这个标准做法,让 fluffos它自己第一次设置 密码的那一刻,就已经满足 wizhood(id)=="(admin)" 这个条件; 同时因为此刻这个连线对象自己的 euid 还没被 seteuid(id) 提权 (提权发生在后面的 make_body()),第二个条件 geteuid(this_player()) != id 也成立——两个条件同时满足, set("password", ...) 直接 return从未真正写入 dbase["password"]**。现场复现确认:修复前完整走完注册流程、 score 也正常显示"(admin)"权限,但存档文件 data/login/f/ fluffos.odbase 映射根本没有 "password"/"ad_password" 这两个键;第二次用刚设置的密码重新连线,被要求输入密码时三次 都被拒绝,账号被踢下线。这不是这份档案独有的偶发问题,而是 set() 权限检查本身的逻辑缺陷:它把"保护一个已存在的密码不被 覆盖"错误地实现成了"任何 wizlist 里已登记为 admin 的 id,永远 不能通过正常流程设置自己的密码"——任何库如果也用了同一段 feature/dbase.lpc(或类似逻辑),都会在"提前播种 wizlist、再 走正常注册"这个本项目的标准 §1.5 流程下必然复现这个 bug。 修复:只在 dbase[prop] 已经存在(真的有一个旧密码需要保护) 时才触发这条保护,不影响原本"禁止非本人覆盖他人已有密码"的安 全意图: ` if ((prop == "password" || prop == "ad_password") && wizhood(this_object()->query("id")) == "(admin)" && this_player() && geteuid(this_player()) != this_object()->query("id") && mapp(dbase) && dbase[prop]) return; ` 已现场复现验证:修复后重新走一次完整注册流程,data/login/f/ fluffos.odbase 映射里 "password"/"ad_password"` 两个 键都有正确的 crypt 哈希值;用刚设置的普通密码重新连线, "重新连线完毕"确认真正登录成功(此前会被三振出局踢下线)。

Proactive checks(无需改动)

发现但未修复:update 指令报"没有这个档案"

修复验证阶段尝试用 update /adm/simul_efun/file//adm/daemons/ logind//adm/obj/master 都报"没有这个档案。",但这些文件在磁盘上 确实存在(file_size() 检查失败的原因未查明——不是本轮改动引入的 回归,update.lpcresolve_path()/SECURITY_D->valid_write() 链路较复杂,值得未来单独排查,但不影响本轮已经验证过的核心结论: 密码持久化 bug 已用真实的"设置密码→重新连线"往返验证过,属于比 update 权限检查更直接、更关键的验证)。

发现但未修复:两条 debug.log 记录,均判定为已知的非 bug 类别

2026-08-13 更正并修复:emote 存档损坏,之前误判为"仅噪音"

上一轮记录把 *restore_object(): Illegal mapping format while restoring emote./adm/daemons/emoted 开机 preload 阶段)当成和 jqxz2008e2c_dict.o 一样的"数据损坏但已被 catch() 安全吞掉、 不影响运行",未展开修复。本轮重新深挖,结论有一半不成立:损坏本 身确认属实(data/emoted.o 291724 字节,[/]/(/) 括号计数 不平衡:[ 455 次 vs ] 454 次,( 461 次 vs ) 462 次,是真实 的存档级结构损坏,不是格式化工具误判),master.lpcpreload() 确实用 catch(call_other(file, "??")) 拦住了这个错误 让开机不中断——但错误往上抛穿了 emoted.ccreate()

void create() {
  if (!restore() && !mapp(emote))
    emote = ([]);
}

restore() 内部的 restore_object() 抛出的是一个可以被 catch() 拦截、但不是"返回 0"的错误,会中断 create() 的执行,导致 emote = ([]) 这个兜底赋值根本没机会跑到——emote 全局变量最终 停留在从未初始化的 int 0,不是一个空 mapping。用临时 write_file() 埋点在真实驱动里验证过:preload()catch(call_other(file, "??")) 捕获到的 err 正是这行错误文本; 紧接着调用 EMOTE_D->query_all_emote()(内部是 keys(emote))会 再抛出 *Bad argument 1 to keys(): Expected mapping Got: 0——而 cmds/imm/edemote.lpc/cmds/adm/udemote.lpc(巫师/管理员编辑预 设动作表的指令)第一步就调用 EMOTE_D->query_all_emote(),也就是 说这两个巫师指令在修复前会直接崩溃,不只是开机日志噪音。

修复:git rm work/data/emoted.o。删除后 restore() 正常返回 0 (文件不存在),emote = ([]) 按设计兜底执行,query_all_emote()/ query_emote() 恢复正常(返回空表而不是报错)。do_emote()emote <动作词> 里带参数匹配预设动作模式的那条路径)修复前后行为其实一致 ——它自己用 !mapp(emote) || ... 短路判断,mapp(0) 返回假不会报 错,所以预设动作在修复前后都是"匹配不到"(数据本来就已经不可用), 不构成回归,只是 edemote/udemote 的硬崩溃被消除了。

验证:新驱动进程干净启动 5 次,boot_verify.log/debug.log 均不再 出现 Illegal mapping 或任何 emote 相关报错;用临时埋点直接调用 EMOTE_D->query_all_emote() 确认不再抛错、返回空 array。完整走了 两次全新注册流程(英文 id→中文名→双密码→天赋→email→性别→进入游戏 世界),均正常到达 (player) 权限、正常显示房间描述,没有任何 emote 相关报错。另外用已提交的管理员 fluffos 账号(data/login/ data/user 下的存档早于本次改动,来自更早的会话)做了一次真实的 "全新连线→用已存普通密码登录→look 看到正确房间描述"的重连验证。

顺带发现但明确排除在本次修复范围之外、留给未来处理的两个不相关 pre-existing bug(用同一个 fluffos 账号反复重连测试时命中,用 "先还原 emoted.o、同样步骤复现" 的对照实验确认这两个和本次的 emote 修复无关,删除/不删除损坏档案都一样会触发): 1. Too deep recursion. program: /adm/daemons/securityd.lpc:263—— 在管理密码登录改密码、以及"踢掉重复连线"两条路径上都能稳定复 现,不是一次性冷启动效应(同一新号连续两次注册都命中同一行)。 2. cmds/usr/quit.lpc 第 38 行 environment(me)->query("fight_room")environment(me) 为 0 时 call_other() 直接报错——命中一次, 与前一条同一次会话里的 fluffos 账号状态有关,未确认是否对全 新注册角色同样可复现。 两者均已如实记录,不属于本轮任务范围(emote 存档),未做任何改动。

已清理

AGENTS.md §7.100 fix (2026-08-19): redundant replace_program(ROOM) landmine

Same corpus-wide bug as the batch-1-6 sweep (ROOM macro "/inherit/room/room", same tybxjh/wlhd sibling lineage as include/globals.h confirms). Deleted 2,376 live standalone replace_program(ROOM); lines under work/ via fix_710_room.py, plus hand-fixed the room-building tool's string-builder template (work/clone/misc/roommaker.lpc). work/data/ only had 2 real .lpc files, neither with the bug pattern — no false negative. Remaining matches after the fix are all pre-existing //-commented.

Verified: clean build-debug boot (zero new compile errors, zero "cannot replace"/"cannot bind" in debug.log), live admin login (fluffos/LoginPass456) into the game world, look/score/quit all worked cleanly. Same sibling-lineage quirk as wlhd: quit deleted data/login/f/fluffos.o (credential file) even though it had just been used to log in successfully — reverted via git checkout HEAD -- work/data before committing, unrelated to this fix and out of scope.

§7.30 uninitialized-mapping accessor sweep (2026-08-20)

Corpus-wide mechanical sweep of the feature/skill.lpc shared-lineage bug (confirmed independently on xiakexing2017/jqxz2015/haiyang2 via round-four testing): 4 accessor(s) in this file returned a raw never-initialized mapping instance variable (defaults to int 0, not ([]), until first assigned), crashing any unguarded keys()/sizeof()/indexing caller for a fresh/untrained character. Fixed at the accessor level (mapp(x) ? x : ([])) per the documented remedy. Verified via lpcc --batch static compile check only (not a live boot) as part of a large mechanical sweep; not individually functionally re-tested live on this lib.

深度功能测试(2026-09-03,round three,shop + 拜师)

新角度:醉仙楼购物 + 丐帮左全拜师,并核对存盘后门派是否还在。 2026-08-13 那一轮没测这两步。

实测过程

管理员 fluffos / 普通密码 LoginPass456(2026-08-13 注册时设的, 本次未走管理密码)。落地 /d/city/wumiaogoto /d/city/zuixianloulist 价目为铜钱尺度(烤鸡腿八十文钱)。clone /clone/money/goldbuy jitui 成功(找零九十九两银子 + 二十个铜板)。F_DEALER 没有丐帮「穷叫化」拒绝。没有 join 名门正派 门。

goto /d/gaibang/inholeapprentice zuo:左全收徒,score 称谓 「丐帮第二十代弟子」、师傅左全。显式 save 成功,user.o 立刻带上 family。断线重连 score 仍是丐帮第二十代弟子 / 师傅左全,银子还在。 没有 wzd_log 验证码。

quit.lpcmud_age < 1800 会删档(真正 rm 没有 wizardp())。 既有政策,未改,本轮不 quit

发现并修复的 PROGRAMMING bug

1. cmds/usr/save.lpc 把真正的 link_ob->save() / me->save() 注释掉了,只打印「档案储存完毕」。 和 yxjh/zxty 同一形状。已 恢复成真正调用两个 save()

2. securityd.lpc valid_read() 里对 /log/ 的拒绝会 log_file("file/bug_read") 再入。zjb/daniel 的巫师 (包括 fluffos)登陆会 Too deep recursion。加了 in_valid_read 重入保护。修复后登陆两行警告,clone 一行警告 加黄金复制成功,本 boot 零 recursion。