Wu Lin Hao Dang (Jin Yong's Dream II)

✅ 可玩

武林浩荡

wlhd

🔑 fluffos / AdminPass123 更新 6140114 2026-09-01 源码 下载 ZIP

▶ 开始游玩 · Play Now

游戏内品牌为《金庸梦II》/《武林浩荡》,和这套合集里的 `tybxjh`(天涯之碧血江湖)共享同一套金庸门派/地图世界观——华山、武当、峨嵋、丐帮、明教、逍遥派、天龙寺一应俱全,城池覆盖长安、荆州、大理、西夏,`master.lpc`/`securityd.lpc`/`logind.lpc` 结构与注册提示文字也几乎一致,同属这套合集里的"天涯"代码家族(还包括 `xhcii` 笑红尘Ⅱ、`zxty` 再现天涯、`ffxymud` 非凡夕阳MUD、`jhfy2` 江湖风云2、`xysylmhb`、`xyzxiiylzymh` 等分支);`yxjh`(浴血江湖)的地图与本档案逐字节相同,用的正是本档案独立改写过的"jump"版跳崖场景(`d/city/sj.lpc`,指令改成 `jump` 并加了 `valid_leave()`),而非 `tybxjh` 的原始版本。权限阶梯比常见的 `(admin)` 更进一步,顶层是 `(ceo)`,档案里预置了三个 `(ceo)` 级创始人账号(`rock`/`jerry`/`kjh`),各有专属场景目录,配合 `job`/`working` 打工赚钱与结构化的悬赏/团队任务目录,构成一套完整的经济玩法。

English

Branded in-game as Jin Yong's Dream II / Wu Lin Hao Dang, a wuxia MUD sharing the same Jin Yong sect map and setting as this collection's tybxjh (Bi Xue Jiang Hu) — Shaolin, Wudang, Emei, the Beggars' Sect, the Ming Cult, the free-spirited Wandering School, and Tianlong Temple all present, with cities spanning Chang'an, Jingzhou, Dali, and Western Xia. Its wizard hierarchy goes one rank higher than the usual (admin) ceiling, topping out at (ceo), with three pre-seeded founder accounts (rock/jerry/kjh) each holding their own private scene directories; a job/working system plus a structured bounty/team-quest directory round out the economy. Both this rank structure and the underlying master/security/login daemons trace to the same "Tianya" code family as this collection's xhcii, zxty, ffxymud, and jhfy2. It independently rewrote the shared "Peak of the World" cliff-jump scene with its own custom "jump" command — a variant later reused verbatim by this collection's yxjh, with which it also shares a byte-identical map.

README

内容亮点

本次处理内容

WASM 修复阶段没有发现需要修复的程序 bug——在 WASM 下编译、注册、 进入游戏全程干净无错误。唯一做的事情是在 /adm/etc/wizlist 里加入 管理员账号(已有 rock/jerry/kjh 三个 (ceo) 级创始人账号, SECURITY_D 正确指向 /adm/daemons/securityd)。

深度功能测试(§10.7)发现这个结论过于乐观:和逐字节共享地图的手足 档案 yxjh 各自独立犯下了同样的 3 个 bug(两处 printf("%O") 调试 残留、§8.9 食物/饮水年龄检查错对象),照搬 yxjh 已验证的修法逐一 修复;另外发现一个 yxjh 自己没记录的独立新问题:d/jerry/ saveme.lpcexert_function(10) 类型错误彻底压垮了武庙(巫师起 始房间之一)里的 NPC "江湖医生";以及两处 d/death/npc/{b,w} gargoyle.lpc 的 §7.68 复活软锁。详见 NOTES.md。

管理员账号 / Admin account

修正(round-two 深度测试发现):上面这段此前的记录不准确—— feature/dbase.lpcset() 有一条防劫持保护,会把"这个 id 已经 在 wizlist 里登记为 (admin)"错误地当成"已有一个受保护的旧密码",导 致 fluffos第一次设置密码时就被自己的保护机制拦截,密码从 未真正写入存档(此前提交的存档打开后确认 dbase 映射里根本没有 "password"/"ad_password" 这两个键)——虽然登录横幅正常显示 "(admin)",但用刚设置的密码根本无法重新登录。已修复该逻辑缺陷(同 姊妹档案 tybxjh 的修法),删除旧的坏存档重新注册,并用真实的 "设置密码→重新连线"往返验证过。详见 NOTES.md。

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

本地运行

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

游戏端口:40121

NOTES · 移植与修复记录

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

武林浩荡,游戏内品牌为《金庸梦II》/《武林浩荡》。和 tybxjh(天涯之碧血江湖)同一血统/代码库——master.lpc/securityd.lpc/logind.lpc 字节相似,注册提示文字完全相同,wiz_levels 阶梯同样到 (ceo) 为止,globals.h 里同一条注释掉的 '// #define SECURITY_D "/adm/daemons/securd"' 诱饵档案提醒也一样。在 WASM 下启动并完整完成注册,没有任何编译或运行时错误——没有发现任何 LPC bug。唯一的改动:把 fluffos (admin) 播种进 adm/etc/wizlist(已有三个 (ceo) 级创始人账号——rock/jerry/kjh;SECURITY_D 正确指向 /adm/daemons/securityd)。注册流程在一次连续的 WASM 客户端会话里完整验证过:英文 id→y/n 创建确认→中文名字→管理密码+确认→普通密码(必须不同)+确认→天赋数值选择(0 为随机,y 接受)→电子邮件(需要 id@address 格式)→性别→带着完整角色属性表进入游戏世界,全程没有任何意外错误。管理员权限已直接通过登录后的横幅"您目前权限:(admin)"确认。LPC 格式化工具对全部 11160 个档案运行(写入 10179 个,945 个报错——大多是杂乱的 kungfu/quest 内容无法幂等往返触发的 TOKEN MISMATCH 安全门跳过,加上一处确认的未结束字符串词法失败,全都安全地保持原样未动,36 个未改动)。没有 :: 父类呼叫拆分命中,没有 CJK 重新加空格命中,没有 case 标签带尾随注释的候选。全部 4 个 map.lpc 档案确认内容完全相同(只是空白差异)。格式化后用同样的完整注册流程重新验证过——干净,管理员权限依然是 (admin)。

§10.7 深度功能测试(本次新增)

此前只做过一次浅层的注册流程验证,声称"没有发现需要修复的程序 bug"。 本次实际深入游玩后发现这个结论过于乐观——本档案和逐字节共享地图的 手足档案 yxjh(浴血江湖)用了完全独立的两份 logind.lpcyxjh 自己 §10.7 pass 里发现的三类 bug,直接在 wlhd 的源码里逐一核对后 确认全部命中,属于两个独立代码库各自平行犯下同样错误(不是复制 粘贴),照搬已验证过的修法后逐一实测确认。

修复 1、2:logind.lpc 里两处 printf("%O") 调试残留

分布在两条并行的取名流程上——接受系统随机生成的中文名 (get_resp(),第 693 行) 和自己手动输入中文名 (get_name(),第 740 行)——都紧挨在"请设置你的管理密码"提示之前,会把登录连线对象 的内部路径(如 /clone/user/login#0)直接打印在新玩家屏幕上。和 yxjh/hc 那次发现的形状完全一样(同一行调试代码被复制到两条并 行流程里)。两处都已删除,实测确认新流程里不再出现。

修复 3:§8.9 同款 bug(yxjh 的精简写法)

logind.lpcuser->setup() 之后:if (ob->query("age") == 14) { user->set("food", ...); user->set("water", ...); }——ob 是登录连 线对象,从未被赋过 age,条件永久为假,食物/饮水满血初始化从未真正 生效过。已改为 user->query("age")

修复 4(本次独立新发现,未见于 yxjh 自己的记录):d/jerry/saveme.lpc 的 exert_function() 类型错误彻底压垮了新手起始房间的 NPC

d/jerry/saveme.lpccreate() 里有一行 exert_function(10);——exert_function()(定义在 inherit/char/npc.lpc)需要的是一个技能名字符串,不是整数,导致这 个 NPC("江湖医生")完全编译不过:*error: Bad type for argument 1 of exert_function ( string vs int )。这份档案恰好被放置在 d/city/wumiao(武庙)——也就是本档案巫师角色的起始房间——第 一次注册管理员账号、进入武庙查看房间内容时,"江湖医生"这个 NPC 完 全没有出现在房间物品列表里,直接验证了这个编译失败确实会静默抹掉一 个本该存在的 NPC。这个具体的死代码调用(exert_function(10))此前 已经在手足档案 yxjh 的 WASM 修复阶段被发现并删除过,但那是两份 完全独立的档案(各自的原始压缩包各自打包了一份这个死代码文件), yxjh 那次的修复没有、也不可能自动带到 wlhd 这边——本次是在这份 档案自己的 WASM 修复阶段之后、第一次真正深度游玩时才被发现。已比照 yxjh 的处理方式(原始意图已经无法还原)直接删除这一行调用。

检查、确认不适用的已知 bug 类别

实战验证

用管理员角色在南大街对"小贩"(combat_exp 10000,attitude peaceful,正确的调用别名是 fan——xiaofan 整体不是有效别名)发起 攻击,完整交手至将其击杀,战斗叙述、伤害递进、"倒地不省人事"到"死 了"的完整流程均正常。受限于本次会话时间,未能找到足够强的对手来触 发管理员自己的死亡/复活测试(管理员默认属性异常高:攻击力 240000/ 躲闪 160000),bgargoyle.lpc/wgargoyle.lpc 的 §7.68 修复只做到 编译层面确认。

本次会话的一次工具使用事故(已在提交前完全修复,无遗留影响)

为了让 fluffos 账号能重新走一次干净的注册流程,误执行了 rm -rf work/data/login/f work/data/user/f——这份档案在这两个目录 下除了 fluffos.o 之外,还存有几十个真实存在的历史玩家存档(凡是 英文 id 以字母 f 开头的玩家都归在同一个目录桶里,不是按账号单独存 放)。在 git status 里发现大量意外的 D(删除)之后,立即用 git checkout -- 完整还原了这些档案,确认恢复后的档案数量 (login/f 63 个、user/f 100 个)和还原前一致,本次提交只包含 真正想要的源码改动和新增的 fluffos.o

更正(2026-08-05):§7.68 复活软锁"修复"已撤销

上面提到的"鬼魂离开/不在场时被永久放弃复活流程"曾被当作 AGENTS.md §7.68 记录的一类 bug 修复(把单次判定改成每 5 秒重试)。经用户指出并 重新审视:这更可能是有意的游戏设计,不是 bug——大多数这类档案里 鬼魂根本无法自行移动,所以"不在场"要么从未真正发生,要么是"离开去 在阴间游荡,想回来时再走回这个房间、流程会通过 init() 重新从头开始" 这种有意为之的宽松机制,而不是需要强制追上玩家的错误。强行重试还可能 引入新问题:如果鬼魂之后又走回这个房间,旧的重试和 init() 重新触发的 新一轮流程可能同时运行,导致对话重叠错乱。已把这处改动撤销,恢复成 原始的 if (!ob || !present(ob)) return; 单次判定写法(bmxkx2001 除外——那份档案里这确实是一个真实存在、经过实际复现验证的 bug:鬼魂 本身完全无法移动,是另一个不相关的 NPC 强行把鬼魂拖走导致的)。详见 AGENTS.md §7.68 顶部的撤销说明。

§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 驱动文本回退)。这份档案和 tybxjh(天涯之碧血江湖)是同一套"天 涯"引擎的姊妹档案(master.lpc/securityd.lpc/logind.lpc/ feature/dbase.lpc 逐字节相似),本轮三个 bug 全部命中,和 tybxjh 完全同一形状,修法也完全相同。

发现并修复的 PROGRAMMING bug

1. log_error()adm/obj/master.lpc,CRLF 行尾档案)完全没有严 重度检查:和 tybxjh 完全同一形状,同一修法 (strsrch(message, "arning:") == -1)。 2. log_file()adm/simul_efun/file.lpc)完全没有 assure_file() 保护:和 tybxjh 完全同一形状(login/newid.logget_gender() 注册最后一步调用),同一修法。这份档案的 assure_file() 也定义在 log_file() 后面,同样需要前向声明 (这次没有漏加)。 3. feature/dbase.lpcset() 密码防劫持保护错误拦截了自己第 一次的密码设置——这份档案不仅命中了和 tybxjh 完全相同的这个 新发现 bug 类别,而且是活生生的现场证据**:此前提交的 data/{login,user}/f/fluffos.o 存档("WASM 修复摘要"一节声称 "登录横幅直接显示确认生效")打开一看,dbase 映射里根本没有 "password"/"ad_password" 这两个键——和 tybxjh 修复前的现 场复现结果一模一样,证实这个旧存档从一开始就是坏的,账号从未真 正能够登录。已应用和 tybxjh 完全相同的修法(只在 dbase[prop] 已存在时才触发保护)。删除旧的坏存档,重新走完整 注册流程,新存档的 dbase 映射正确包含两个密码哈希;用刚设置 的普通密码断线重连,"重新连线完毕"确认真正登录成功。

Proactive checks(无需改动)

实测过程

登录流程和 tybxjh 完全一致(英文 id → y/n 确认 → 中文名字 → 管理 密码+确认 → 普通密码+确认 → 天赋 0 随机+接受 → 邮箱 → 性别)。 log/debug.log 里全是 *Too long evaluation/*Can't catch eval cost too big error,追查后确认全部发生在全新驱动进程首次预载/注 册触发的冷编译级联期间(AGENTS.md §7.90/§10.8 已归档类别),断线 重连后未再出现,确认已自愈,非持久性 bug。驱动最终按精确 PID kill,ps -p 确认已退出。

已清理

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" from include/globals.h). Deleted 2,384 live standalone replace_program(ROOM); lines under work/ via fix_710_room.py, plus hand-fixed both room-building tool copies' string-builder template (work/clone/misc/roommaker.lpc, work/u/tyui/obj/roommaker.lpc). Checked 98 real .lpc files under work/data/{area,room,proom,...} for the known data/-exclusion false-negative — none had the bug pattern. All remaining replace_program(ROOM) matches after the fix are pre-existing //-commented lines only.

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/west/score/ quit all worked cleanly.

Extra caution note per this lib's standing player-save-damage history: the live login run left several incidental data/ diffs — routine heart_beat() background saves on unrelated player accounts (ccc.o, cscb.o, seven.o, area/*.o), the fluffos account picking up starting equipment from normal gameplay, AND (more notably) a deletion of data/login/f/fluffos.o (the credential/ password-hash file) observed after quit, even though that same file was used successfully to log in during this very session. Root cause not investigated (out of scope for this sweep — not related to the replace_program fix), but ALL data/ drift including this deletion was reverted via git checkout HEAD -- work/data before committing, so the credential file and all other player saves are untouched in the committed diff. Flagging for whoever next touches this lib's fluffos account or investigates login/logout save behavior.

§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.

§10.7 deep functional test, round three (2026-08-24): closing the four gaps flagged by NOTES.md audit

Prior passes never actually exercised death/revival, shop buy, sect apprenticeship, or a message-board post/read round trip. This pass closed all four, live, against a freshly-rebuilt fluffos driver (build-debug/src/driver, src/fluffos checkout at 1e74a758).

Found and fixed: securityd.lpc valid_read() self-recursive infinite loop — hits EVERY non-rock/jerry login

adm/daemons/securityd.lpc's valid_read(file, user, func) has a trusted-caller bypass list (sscanf(base_name(user), "/adm/daemons/%*s") || ".../adm/etc/%*s" || ".../feature/%*s" || ".../inherit/%*s" || ".../include/%*s" || ".../cmds/%*s") that lets system code read anything. It was missing /adm/obj/ — the directory holding master.lpc and, critically, the special object the driver attributes every simul_efun call to (base_name(user) prints as /adm/obj/simul_efun for any call made from inside a simul_efun body).

The deny branch a few lines below (for any non-rock/jerry player reading a path under /log/, /u/rock/, /u/jerry/, or /u/kjh/) calls log_file("file/bug_read", ...) to record the violation. log_file() (adm/simul_efun/file.lpc) calls assure_file(), which calls file_size() on that *same* "/log/file/bug_read" target path before writing it — and that file_size() call re-enters valid_read() with user = the simul_efun wrapper object. Because /adm/obj/ wasn't in the trusted-caller list, that nested call takes the *same* deny branch again, logging the violation again, forever — a textbook self-recursive cycle, not just an incidentally-deep call chain — until the driver's call-depth limit aborts with Too deep recursion. This fires on every single login by any account that isn't rock/jerry (including the seeded admin, fluffos), because clone/user/logind.lpc's own enter_world() unconditionally probes file_size("/log/login/notice") right before the "身份消息" banner — that first denied read starts the cycle. It's non-fatal (the driver's per-call catch absorbs it and login continues) but wastes real cycles on every login and floods the player's screen with ~35 repeated "警告:你不能操作这些目录下的文件。" lines before the "身份消息" banner appears — confirmed 100% reproducible across repeated fresh admin logins before the fix, and gone (clean login, zero Too deep recursion in debug.log) after adding sscanf(base_name(user), "/adm/obj/%*s") to the bypass list, on both the admin account and a fresh non-admin registration.

1. Death/revival: clean, full cycle verified

admin call <id>->die() shortcut used per this project's established pattern (registered a fresh non-admin test character, wlhdtest/ 测试武林, since the seeded admin's 240000/174000/218400 attack/dodge/ defense make it unkillable via normal combat — and per AGENTS.md §10.7's item 6a, an admin/wizardp() account can also be silently excluded from the ghost-NPC flow by design, so a non-admin target is the correct choice regardless). call wlhdtest->die() triggered the real death sequence: "你大叫一声倒在地上,挣扎了几下,死了!" → moved to 鬼门关 (d/death/npc/wgargoyle.lpc's room) → all 5 death_msg stages fired automatically via call_out over ~25s (no player input required, despite the flavor text reading like a question) → reincarnate() → moved to REVIVE_ROOM (d/city/wumiao). score afterward showed "你共死亡:1 次" and reduced <精>/<气> (expected death penalty), no debug.log errors. Confirms the §7.68 fix from an earlier pass (bgargoyle/wgargoyle's retry-guard, later reverted per the 2026-08-05 correction — see above) never actually needed the revert's concern to trigger: this is a clean single-pass init()/call_out() flow, no reentrancy hazard exercised.

2. Shop buy: clean, correct change/inventory math

小贩 NPC (d/village/npc/seller.lpc, feature/dealer.lpc's do_buy()) in d/village/ehouse1. Gave the test character 500 coin (admin cloned a /clone/money/coin, set_amount(500), give'd it — note give requires wizardp() to bypass no_give, and requires the target to be genuinely interactive(), i.e. actually connected, not a stale disconnected body left in the room from a prior test connection). buy stick ("手杖", value 100) succeeded: "你向小贩买下一根手杖。", the item appeared in inventory, and the money correctly decremented by exactly 100 (500 coin → auto-consolidated display as "四两银子", i.e. 400 remaining at the coin/silver conversion rate). No bug.

3. Sect apprenticeship (拜师): clean, score reflects new sect

bai/apprentice (cmds/skill/apprentice.lpc) against 欧阳不空 (d/tongchi/npc/ouyang.lpc, 通吃帮 second-generation elder, whose attempt_apprentice() auto-accepts any non-无性-gender applicant via command("recruit " + ...)) — reached via admin goto/summon since the test character has no wizard-level travel shortcuts. Checked this lib's apprentice.lpc/feature/apprentice.lpc against the §7.117 "betrayal check missing a first-timer guard" pattern flagged for this session: not present here — every family-name comparison is correctly guarded by mapp(me->query("family"))/mapp(ob->query("family")) before dereferencing, both in apprentice.lpc (line ~40) and feature/apprentice.lpc's recruit_apprentice()/is_apprentice_of(). bai ouyang completed cleanly: "你跪了下来向欧阳不空恭恭敬敬地磕了四个 响头,叫道:「师父!」恭喜您成为通吃帮的第三代弟子。" — score afterward showed 称谓 "通吃帮第三代弟子" and 师傅 "欧阳不空". No bug.

Note, first attempt used the seeded admin account and silently failed (no error, no message, bai ouyang just printed "你想要拜欧阳 不空为师。" and nothing further) — root-caused via temporary debug_message() instrumentation (removed before finishing) to clone/user/user.lpc's id(): if (this_player() && !this_player()->visible(this_object())) return 0; — an ordinary NPC (this_player() during the NPC's own command("recruit ...")) cannot present()-match an admin whose env/invisibility is set (which logind.lpc sets by default for every wizardp() login), so recruit.lpc's present(arg, environment(me)) never finds the admin at all. This is the same documented class as AGENTS.md §10.7 item 6a (admin accounts are deliberately invisible to ordinary NPC-driven interactions) — not a bug, just another reason to always keep a non-admin test character on hand.

4. Message board post/read: clean round trip

post <title> → line editor (. to save) → read <num> at 意见簿 (d/city/wumiao's board, inherit/misc/bboard.lpc). Full round trip (title + body, correct author/timestamp, board's unread/total counts incrementing) confirmed clean via a fresh raw Python socket connection. Test posts deleted afterward (delete <num>, works because the poster owns their own post) to leave the board exactly as before (11 posts).

Two test-tooling false alarms hit and resolved along the way (not mudlib bugs): (1) scripts/tmux_mud.sh's multi-line send into the board's line editor tripped the local telnet client's own escape handling, dropping the session into a dead telnet> prompt — recovered by switching to a raw Python socket for this specific interaction (matches this session's guidance to cross-check tmux_mud.sh mojibake/ corruption against a fresh raw socket, generalized here to a different tmux/telnet client-side artifact, same remedy). (2) The first raw-socket attempt used the wrong wire encoding (GBK) and produced mojibake ("锟斤拷...") in the posted title/body — this lib's actual wire encoding is UTF-8 (confirmed by decoding the login banner correctly only under UTF-8); redone with the correct encoding and the round trip was clean.

Cleanup

Test character wlhdtest/测试武林 was not committed (its save files were deleted before finishing, per the driver's own built-in "logged in under 30 minutes → save deleted on quit" resource-saving rule — see below — plus a manual rm of the residual file after the final driver shutdown autosave). All incidental data/ drift from this session (fluffos's equipment/gold from normal play, ccc/cscb/ seven/area/* background heart_beat() saves, the board's pure resave-reordering diff) was reverted via git checkout before committing — only the securityd.lpc fix is in the diff.

Observation (not a bug, documented for whoever next investigates fluffos account save/quit behavior)

This session finally explains the "mysterious fluffos.o deletion after quit" flagged as unexplained in the 2026-08-19 §7.100 entry above: cmds/usr/quit.lpc has an explicit, intentional resource-saving rule — any account that has been logged in less than 30 minutes (me->query("mud_age") < 1800) gets both its login/ and user/ save files rm()'d on quit, with a player-facing warning message ("注意:由于您这个ID登陆不到30分钟,系统为了节省资源不给予存档!") printed at the exact same time. This is deliberate design, not a bug — confirmed by the matching warning text and reproduced consistently every time a short session quits. Not previously connected to the 2026-08-19 observation because that pass didn't have a quit message correlated with the deletion in the same session.