Sui Yuan Xi Jian Lu (Sword Washed by Fate)

✅ 可玩

随缘洗剑录

syxjl

🔑 fluffos / Mud@2026 更新 f98208d 2026-09-04 源码 下载 ZIP

▶ 开始游玩 · Play Now

自称 【随缘洗剑录】,是"ES II"引擎家族的一员(与本项目中的神州、火影、武汉站等同宗),由 Annihilator 等人在原始 ES II 基础上多次改写而成,是一款有较长运营历史的老牌武侠 MUD。玩家从扬州"随缘客栈"起步,古龙笔下的浪子李寻欢会热情引导新手熟悉基本指令;玩法延续经典武侠养成路线——属性天赋抽取、门派拜师、武功修炼、江湖闯荡,风格朴实,没有花哨的额外系统。扬州广场常驻一个不算常见的彩蛋 NPC"圣诞老人"(随缘节日大使),全年送上节日祝福;死亡则有完整的鬼门关体验,由"白无常"接引,落脚在扬州武庙复活,鬼魂状态下无法移动,只能原地等待复活完成。

English

Self-titled "Sui Yuan Xi Jian Lu" (roughly, "the chronicle of washing one's sword as fate wills"), a member of the ES II engine family — kin to this archive's Shenzhou, Huoying, and Wuhan-station titles — repeatedly rewritten from the original ES II base by Annihilator and others, and a long-running, well-established wuxia MUD in its own right. New players start at the Chance Inn (随缘客栈) in Yangzhou, where Li Xunhuan — a wandering-swordsman character borrowed from Gu Long's novels — greets arrivals and walks them through the basics; play otherwise follows a classic, unadorned wuxia arc of stat rolling, sect apprenticeship, martial-arts training, and roaming the jianghu. Yangzhou's main square carries an unusual, permanent easter egg: a "Santa Claus" NPC (随缘节日大使) who hands out holiday greetings year-round. Death sends a character through a full ghost/afterlife sequence, escorted by the White Guard of Impermanence to the War God Temple (武庙) for revival, with the character unable to move until the process completes.

README

内容亮点

深度功能测试新发现的 bug(详见 NOTES.md)

adm/daemons/logind.lpc 有一处 §7.34 调试用 printf("%O\n", ob) 残留和一处 §8.9 食物/饮水初始化误判对象的 bug——已修复。死亡系统的 d/death/npc/wgargoyle.lpc(白无常,实际生效)有 AGENTS.md §7.68 归档的复活软锁死 bug,已修复并现场完整验证。同一系统里的 bgargoyle.lpc(黑无常)发现了一个更严重的变体:death_stage() 函数整个被注释掉,导致 init() 排程的 call_out 永远静默调用一个不 存在的函数,任何走到黑无常面前的人(正常玩法里鬼魂无法移动,实际 不可达)会被永久晾在原地——已恢复函数体并按标准修法修复。另外发 现并修复了两个和死亡系统无关的独立 bug:防刷屏踢人逻辑在 command("quit") 销毁玩家物件后仍继续执行,每次踢人都在 debug.log 留下一条运行时错误;广场彩蛋 NPC"圣诞老人"引用的一件 存档里从未存在过的物品文件,导致每次这个 NPC 被克隆都报错。以及一 个和姊妹会话(yhyxs/yanhuangwuhun)同类的 extensionless GBK 文 本残留:真正的 137 项姓名黑名单(adm/etc/banned_name)从未被转 码,运行时的自我播种逻辑悄悄用一份只有 6 项的弱化兜底列表顶替了原 本的内容审核名单——已转码恢复原始的完整名单。

在线试玩

https://mudlibs.fluffos.info/syxjl/

管理员账号 / Admin account

警告:对外公开架设前请务必修改此密码。

本地运行

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

游戏端口:40088

NOTES · 移植与修复记录

随缘洗剑录 (syxjl) — NOTES

Archive #96: archives/随缘洗剑录.rar ("Record of Sword-Washing by Fate").

What this lib is

An ES II-lineage MudOS v22 wuxia mudlib. Confirmed via adm/obj/master.c's own header comment: // for ES II mudlib, // original from Lil, // rewritten by Annihilator (11/07/94), plus a later 98-10-23 upgrade credit to ken@XAJH and a securityd.c credit to aeolus 12/25/2000. This is the same lineage family as many previously-done libs in this project (yueyingqiyuan, wuhanzhan, huoying, shenzhou, yanhuangwuhun, etc.) — same adm/daemons/securityd.c ACL-table shape, same feature/dbase.c real local set/query/delete implementation (i.e. NOT the nitan-family bare-simul_efun dbase architecture bug, §15 — this lib inherits F_TREEMAP and has genuine per-object storage, confirmed safe).

The raw archive's mudlib root is syxjl/world/ (syxjl/config.cfg points mudlib directory : ../mud/world, master file : /adm/obj/master). The directory shape (adm/, clone/, cmds/, d/, feature/, inherit/, kungfu/, maxim/, obj/, quest/, task/, u/) and content (kungfu/ skill-class directories, 客栈/李寻欢 starting NPC, 明教/武当/嵩山/衡山 etc. zone names) are standard wuxia-genre ES II content — nothing suggesting a closer match to any more specific already-done sibling lib than "generic ES II family", so no forced lineage claim beyond that.

Archive also bundled a prebuilt Windows driver (mudos.exe/mudos.dll, May 1998) and an addr_server binary — both left untouched/ignored per the pipeline (we use our own FluffOS build).

Port

40088 (per TODO.md's reservation for archive #96 in the #92-96 batch).

Fixes applied (with why)

1. §15ao — switch(port){ default: ... } with no real case in master.lpc's connect(). Hard parse error on this driver (a switch needs at least one real case label). There was no actual branching on port in the original code anyway (default: was the only clause) — rewrote as a plain unconditional block, preserving the catch(new(LOGIN_OB)) body verbatim. This is adm/obj/master.lpc, the file the config actually points at (a sibling copy at adm/single/master.lpc has the same pattern but isn't used by our config — left alone, noted here in case a future agent points a config at it).

2. §15h — is_chinese() GBK-byte-range check. adm/simul_efun/chinese.lpc had the classic strlen(str)>=2 && str[0] > 160 && str[0] < 255 byte-range check — always false against real UTF-8 codepoints on this driver. Fixed to a CJK Unicode range check (str[0] >= 0x4e00 && str[0] <= 0x9fff) with strlen(str)>=1 (a single Chinese character is a complete valid name-char now, not "half a GBK character").

3. §15h — check_legal_name()'s byte-length bounds and byte-stride loop, in adm/daemons/logind.lpc. strlen(name) < 2 || > 8 (meant "1 to 4 Chinese characters" per the message text, calibrated for 2 bytes/char) halved to < 1 || > 4. The sliding-window loop's i%2==0 && !is_chinese(name[i..<0]) (only checking even BYTE offsets, i.e. each GBK character's lead byte) had the i%2==0 && guard dropped entirely, since every UTF-8 index is already one full character now. Verified via full registration test with a 3-character Chinese name (秦风寒).

4. §15p / §15ai — network/dns_master preload exclusion, PLUS a live call-site guard. Removed /adm/daemons/network/dns_master from adm/etc/preload (standing policy — avoids a boot-time hang against an unreachable intermud "boot server"). Also, unlike some prior libs, adm/daemons/logind.lpc's encoding_to_mudlist() (the very first step of EVERY connection, right after the GB/Big5 prompt) called DNS_MASTER->query_muds()/->query_svc() unconditionally, with no find_object() guard — this would have silently lazy-loaded the excluded daemon back in on every single connection (defeating the preload exclusion entirely), and the subsequent keys(mud_list) would have thrown on a 0 mud_list if the daemon failed to load. Guarded the whole mud-list-fetch block behind find_object(DNS_MASTER), falling back to an empty ([]) mud list (the code already printed a "not connected to other muds" message in this case — just made sure it doesn't also crash). Confirmed via the debug.log's Undefined function/ Bad argument absence and a clean multi-run registration test that this never surfaces.

5. §15ar-adjacent — commandd.lpc's sscanf(cmds[i], "%s.c", cmds[i]). Checked proactively per policy. This one was already fixed by convert_lib.sh's own .c"-reference sed (the format string's .c sits immediately before the closing quote, exactly the pattern that sed already handles) — confirmed it now reads "%s.lpc" with no manual intervention needed. Documenting as confirmed NOT needed as a manual fix, since this exact bug class has bitten two previously-shipped libs (bxsj/bxsj1) that needed it fixed by hand.

6. §15ae — private nomask command-hook. Checked feature/command.lpc's command_hook() proactively. It's declared plain nomask (no private) and dispatch (add_action("command_hook", "", 1)) works correctly — confirmed NOT present, no fix needed. Verified end-to-end with real post-login look/score/i commands (see below).

7. §15n / §8c / §4 — custom securityd.lpc's valid_read/valid_write, and master.lpc's lazy SECURITY_D load. Checked proactively. This lib's valid_read/valid_write only apply their ACL restriction for a short allow-list of sensitive func values (read_file, file_size, stat, read_bytes, tail, ed_start for read; write_file, save_object special-cased, else the ACL for write) — anything else (including load_object/recompile_object/include) falls through to return 1; unconditionally. Confirmed NOT the §15n bug — compiling/ including code was never blocked here. master.lpc's own valid_read/valid_write already wrap load_object(SECURITY_D) in catch() (no reentrancy flag, but the catch() alone was sufficient — confirmed no stack-overflow/recursion crash on a clean boot) — confirmed the §4 pattern's dangerous shape (unguarded lazy load with no catch) is NOT present, no fix needed.

8. §7 — get_root_uid()/get_bb_uid(). Both already implemented in master.lpc, returning ROOT_UID/BACKBONE_UID. Confirmed present, no fix needed.

9. §15ag — ed_start/ed_cmd/query_ed_mode. Grepped the whole lib — zero hits. Confirmed not present, no fix needed.

10. §15l — master.lpc create() destructing SIMUL_EFUN_OB. create() is just write("master: loaded successfully.\n");confirmed not present, no fix needed.

11. §15r — check_config.lpc-style driver self-check. No such file anywhere in the archive. Confirmed not present.

12. §3 — staticnosave blanket sed, and its known string-literal counterexample. Ran the standard \bstatic\bnosave sed (89 files touched net of the revert below). Then found and fixed a real instance of the exact moniHuafu counterexample from AGENTS.md §3: this lib uses a log_file("static/CRASHES", ...)-style convention (a literal "static" path SEGMENT, not the keyword) in 22 files, PLUS a subtler variant the counterexample note doesn't explicitly cover — "/log/static/LASTCRASH"-shaped strings where static appears mid-path, not at the very start of the string (17 more occurrences across combatd(1).lpc, adm/single/master.lpc, cmds/.../{kill,fuhuo,shutdown,reboot,recover,bai,apprentice,uptime}.lpc). The word-boundary sed corrupted ALL of these to "nosave/..." / "/log/nosave/...". Found this because cmds/usr/uptime.lpc's write(read_file("/log/nosave/LASTCRASH")) (called from logind.lpc's login() on EVERY connection) then read a nonexistent file, got 0 back, and write(0) crashed with *Bad argument 1 to receive(): Expected string or buffer Got: 0 inside clone/user/login.lpc's receive_message()this derailed the entire registration flow on the FIRST test run: after that crash, the connection's input_to() chain never got (re-)armed, so every subsequent typed line just hit the default fail message ("What ?"), looking exactly like a totally broken/silent server. Fixed by reverting every "[/]nosave/... string back to "[/]static/... (verified against the raw pre-conversion archive that static — never nosave — was the ORIGINAL word in every one of these 39 total occurrences, so this is a pure revert, not a guess).

13. A same-named directory colliding with the .c.lpc rename (the xjcq2000/zitengzhan-shaped bug, but a fresh instance): kungfu/skill/chuixue-jian.c/ (a directory containing taiji-jian.c/ liehuo-jian.c) and u/duanfei/chuixue-jian.c/ (containing lian.c) both got renamed to ...chuixue-jian.lpc (a directory, not a file) by the blind rename pass, with their *inner* files left un-renamed (the parent directory rename raced ahead of find's listing). Confirmed via grep that NOTHING in the whole lib references either directory by that literal path (the live, working skill is a differently-named sibling, hantian-chuixue-jian) — these are orphaned/superseded duplicate-content folders, not live code. Renamed both directories to *.orphaned-dir (and their never-renamed inner .c files to .lpc for consistency) so nothing mistakes a directory for a compilable object. A third, genuinely-empty directory, kungfu/skill/cuixue-jian.c/ (note: different spelling, no h) hit the same rename bug but had zero children even in the raw archive — renamed to cuixue-jian.orphaned-empty-dir.

14. Uppercase .C files (the shenmo-shaped bug). 6 files: d/shashou/obj/{YINGXION,XUEYI}.C, d/quanzhen/obj/jia.C, d/shashou/npc/obj/{YINGXION,XUEYI}.C, d/quanzhen/npc/obj/bookshelf.C. convert_lib.sh's glob is case-sensitive and skipped these; one file (cangjingge2.lpc) references bookshelf via an extensionless __DIR__"obj/bookshelf" path that would have resolved fine on a case-insensitive filesystem but not here. Renamed all 6 directly to .lpc (their file-based encoding guess already correctly ran them through iconv during the original convert pass, confirmed valid UTF-8).

15. A genuinely corrupted/truncated raw source file: d/wudujiao/npc/cunfu.c failed BOTH strict and -c/lossy iconv (exit 1 either way — iconv: incomplete character or shift sequence at end of buffer), and convert_lib.sh's current fallback logic treats ANY nonzero exit from the -c attempt as total failure (discards the temp file, logs "FAILED to convert", leaves the original raw GBK bytes in work/ untouched) — this is a real gap in convert_lib.sh itself worth flagging for the main session to consider: iconv -c can still exit nonzero even after writing a perfectly good *partial* conversion to stdout (confirmed: piping the same command's stdout directly showed clean, correct UTF-8 text right up to where the raw bytes are genuinely garbage), so the current "discard on any nonzero exit" logic throws away recoverable partial output, not just failed output. Inspected the raw bytes directly (xxd): the file is a small, trivial random-NPC-name generator (cunfu.c — "村妇", a random village-woman NPC) whose content is cleanly valid right up through set("max_qi", 200);, then abruptly turns into non-text binary garbage for the rest of its ~340 remaining raw bytes (looks like unrelated corrupted/overwritten disk content, not anything resembling LPC or even valid GBK). Fixed by extracting only the valid leading ~500 bytes, converting those cleanly, and closing the create() function's brace immediately after the last valid statement — no fabricated content, matching the project's established "close gracefully, don't invent" convention for genuinely truncated files (same approach used for archive #91's one similarly-truncated file). This file is not preloaded/reachable from the standard registration/look/score path either way.

16. A one-shot, whole-mudlib-affecting header bug: kungfu/skill/eff_msg.h duplicated its ENTIRE body within itself (confirmed present byte-for-byte in the RAW pre-conversion archive too — not something our pipeline introduced): eff_status_msg() and damage_msg() were each fully defined TWICE in the same file (once around line 9, once again around line 150), each copy also trailed by a stray, non-matching #include "/kungfu/skill/eff_msg.h"; / int p; ... snippet (an unclosed second "usage example" left active instead of commented, unlike the identical-looking, correctly commented-out block at the very top of the file) — this crashed EVERY file that includes it (linboweibu, linboweibu1, taiji-quansd, taiji-quan/zhensd, huifeng-jian, yijin-jing, 6 kungfu-skill action files) with Redeclaration of function 'eff_status_msg'/ 'damage_msg'. The two copies' damage_msg() actually cover *different, non-overlapping* damage-type case labels (one has 擦伤/割伤/砸伤/default, the other has 瘀伤/内伤/震伤/抓伤/刺伤/default) — NOT simple duplicates, so a naive "just delete the dupe" fix would also silently drop real damage-flavor-text coverage either way. Kept the FIRST copy (immediately after the doc comment, the position every sibling working file's own eff_msg.h-alike would put the real definitions) and removed the second, to keep the fix conservative (no fabricated merge risking a duplicate-case compile error of its own). One of the 6 dependent files (huifeng-jian.lpc) had a SECOND, independent bug once this was fixed: #include "/kungfu/skill/eff_msg.h"; (which defines global variables) appeared textually BEFORE inherit SKILL; — illegal on this driver (§15t variant 3) — reordered so inherit comes first. All 6 files verified passing via direct lpcc afterward.

17. A recurring "pager status line pasted into the source" corruption (confirmed present in the raw archive, NOT a conversion artifact) — found in 3 unrelated places: d/xingxiu/obj/sheep.c and kungfu/skill/yijin-jing/heal.c each had a stray, standalone line reading == 未完继续 NN% == (ENTER 继续下一页,q 离开,b 前一页) (a Chinese more-style pager's "-- More --" status line) embedded mid-function — clearly captured by accident during some long-ago editing/screen-scraping session, not code. Deleted both lines outright (they're 100% non-code noise, confirmed by comparing against the surrounding statements' obvious intent). A related, nastier variant in u/linghu/ground2.lpc (a PK-arena feature in a personal wizard directory) had the SAME pager garbage spliced into two live statements rather than sitting on its own line: {(q 离开,b 前一页,其他继续下一页) (should just be {) and if (brief)== (q 离开,b 前一页,其他继续下一页) (should just be if (brief)), plus a case MO with no colon and no real constant name a few lines earlier (inferred, from this same switch's sibling cases elsewhere in the file using MODE_SINGLE_SD/MODE_SINGLE_LT/ MODE_TEAM_LT/MODE_TEAM_DZ/MODE_TEAM_XH in that exact order and this being the FIRST case in its switch, to be the truncated start of MODE_SINGLE_SD:). Fixed all three spots in ground2.lpc. Left un-fixed, documented as a known gap (see below): the SAME file's do_debug() function (much further down, ~250 lines) has extensive, unrelated pre-existing corruption (missing semicolons and closing parens across ~40+ lines) that also predates this project — a genuinely unfinished/never-tested wizard debug utility, not reached by any normal play, not worth the repair time this session.

18. Missing/dropped closing quotes in string literals (§10-shaped, confirmed pre-existing in the raw archive via byte-level diff against both strict and lossy iconv output) — found in 7 unrelated files: d/quanzhen/{hudi3,hudi4,hudi5,hudi6}.lpc (missing OPENING quote before a set("long", ...) multi-line text block — hudi5 was additionally missing its CLOSING quote too, a second independent instance in the same file), kungfu/skill/qingyi-jian.lpc ("skill_name" : "大悲式, missing the closing quote before the comma), kungfu/skill/yanxing-dao.lpc (same shape, ...刺去,), kungfu/skill/jueqing-chenfa.lpc (two independent instances in the same file: ...阴毒无\n塘, — note this one lost more than just the quote, an unrecoverable original-content truncation the raw bytes confirm predates us too, closed cleanly after the last legible word rather than fabricating the rest — and a second ...阴毒无 case further down, same fix). Each fixed by inserting the missing " at the exact point the content/context indicates.

19. A 4-file set("long", @LONG ... LONG) closing-tag-merged-onto-text bug (the exact tianxia/AGENTS.md-documented "iconv -c eats an adjacent real newline" shape) in d/quanzhen/{manglin1,manglin2}.lpc, d/chang'an/gulouerceng.lpc, d/wudang/xiaolu2.lpc — the closing LONG heredoc tag must start its own line, but was merged onto the end of the preceding Chinese text line in all 4. Diagnostic footnote for future agents: my first repair attempt used a careless manual iconv -f GB18030 -t UTF-8 ... 2>/dev/null (no -c, stderr discarded) to re-extract 2 of these 4 files from raw for inspection, which SILENTLY TRUNCATED both of them mid-file (strict iconv was failing partway through on an unrelated bad byte elsewhere in each file, and redirecting stderr to /dev/null hid the nonzero exit and the truncation both) — caught immediately by a sanity line-count/ content check before it was ever written back into work/, redone correctly with -c. This was purely a self-inflicted diagnostic mistake, not a flaw in convert_lib.sh itself (which already does the correct strict-then--c-fallback dance with proper exit-code checking) — noting it here only as a reminder to always re-derive a file from raw/ through the SAME strict→-c-fallback discipline the real pipeline uses, never a bare one-off iconv call.

20. A shared-header path mismatch, 21 files at once (§8g: one root cause, not 21 bugs): every file under u/think/gfjob/npc/*.lpc (~21 files) did #include "/quest/gfjob/npc/npc.h" — but /quest/gfjob/ doesn't exist anywhere in the archive; the real npc.h lives at /u/think/gfjob/npc/npc.h (same directory as the files including it — a personal-wizard quest-content area, clearly moved at some point without updating its own header's #include path in whichever template it was cloned from). Fixed the #include path in all 21 files in one sed pass to point at the real location. A related, unrelated-cause pair: u/bombju/wudang/{hutou,langmei}.lpc did #include "feng.h" (quoted, local-dir-first resolution) but neither file's own directory has a feng.h — the real one lives at /d/wudang/feng.h (these two files are near-verbatim clones of the d/wudang/taoyuan/tyroad*.lpc room family, sharing that header). Fixed both to the absolute path. d/wudang/taoyuan/{tyroad4,5,6,7}.lpc had a THIRD, distinct variant of the same underlying "which feng.h" confusion: #include __DIR_"feng.h" (note: single trailing underscore, not the real __DIR__ macro) — a typo that resolves to nothing at all (__DIR_ isn't a macro), and even a corrected __DIR__"feng.h" would have been wrong anyway since feng.h lives one directory up, not alongside these 4 files. Fixed all 4 to the same /d/wudang/feng.h absolute path.

21. new used as a bare variable name (7 files) — the exact bug class already retroactively found in jqxz2008/xiakexing3 (archive #91's report): d/quanzhou/npc/{tang,tang1,tang2,tang3}.lpc, d/taishan/{tang2,tang3,xingtang}.lpc all declared object *inv, new; then did new = new("/clone/npc/...")new is a reserved token (L_NEW) on this driver's lexer, not just a shadowable identifier, so the DECLARATION itself is a hard parse error. Renamed the variable to new_ob throughout all 7 files (declaration + both use sites each) via a scoped sed, verified each compiles clean afterward.

22. A duplicate inherit F_UNIQUE; line (3 files) — same shape as already found in the jqxz2008 pass: d/mingjiao/npc/{yinwufu,yinwulu,yinwushou}.lpc all had inherit F_UNIQUE; written TWICE (byte-identical files, likely all cloned from one template with the same authoring slip), producing Illegal to redefine 'nomask' function 'violate_unique' (the second inherit tries to re-bring-in a nomask function F_UNIQUE already installed by the first). Removed the duplicate line from all 3.

23. message_combatd — the exact simul_efun gap AGENTS.md's own §8b write-up is named after, recurring here: called from 4 kungfu combat-skill files (chousui-zhang/{sandu,throw}.lpc, force/transfer.lpc, one more commented-out call site) with the same (msg, me, target) 3-arg shape as message_vision(), but never defined anywhere in this lib's simul_efun. Restored as a thin alias to message_vision() in adm/simul_efun/message.lpc (added AFTER message_vision's own definition in the same file, per the §8b same-file-ordering rule), which already handles exactly this $N/$n attacker/target substitution shape. All 3 real call sites verified compiling clean afterward.

24. A same-file forward-declared function whose real body lives entirely inside a comment (3 files): d/jingzhou/npc/{dingdian,shiye, lingtuisi}.lpc each reference (: do_zhuibu :) in an inquiry mapping (an NPC "ask about work" hook), but do_zhuibu()'s actual body — along with a ~200-line quest implementation — is entirely inside a /* ... */ block (confirmed: even the function's OWN forward declaration a few lines above create() is itself commented out, //string do_zhuibu();, in all 3 files) — a deliberately disabled/unfinished feature, not something this project should resurrect (that would mean writing ~200 lines of new quest logic from scratch, well out of scope). Removed just the "工作" : (: do_zhuibu :), entry from each NPC's inquiry mapping (leaving an empty ([ ])), which is the minimal fix that stops referencing a genuinely absent function without fabricating the missing feature.

Directories created (raw archive didn't ship them, but code references

them)

static/, binaries/, adm/swap/, data/nosave/, log/nosave/, nosave/ (bare — cmds/adm/recover.lpc writes to /nosave/RECOVER), hate/ (PK-hatred-list feature, feature/attack.lpc/combatd(1).lpc/ cmds/usr/hatred.lpc), topten/ (referenced by TOPTEN_DIR in toptend.lpc). None of these being absent caused a HARD failure during registration/look/score (mostly write_file()/log_file() calls that either aren't on the critical path or degrade gracefully), but per §15ah precedent they're cheap, proactive insurance against a silent write failure derailing some other flow later.

Config (config.fluffos) adjustments

Registration flow + post-login command test (verified twice, full

transcripts)

Flow shape: GB/Big5 encoding choice → "Press Enter to Continue" (past an inline DNS-mud-list display, now empty since dns_master is excluded) → banner/stats/uptime → English id (check_legal_id: lowercase a-z only, 3-12 chars) → (existing-save-file check; new id → confirm y/n) → Chinese name (check_legal_name: 1-4 real Chinese characters after the §15h fix) → password (twice) → gift-stat selection (0 = random, or 1-5 to pick one stat to name a value for, then accept/reject the rolled set) → email → gender (m/f) → drops into the game world at 随缘客栈 (the starting inn), greeted by NPC 李寻欢.

Final verification run (mudclient.py 127.0.0.1 40088, one continuous session, --idle 1.0):

gb → "" → qinfengfinal → y → 秦风寒 → password123 → password123
→ 0 → y → [email protected] → m → look → score → i → quit

Result: registration completed cleanly, landed in 随缘客栈 with the correct room description, NPC greeting text, and exit list; look re-displayed the room correctly; score printed the full character sheet (中文姓名 秦风寒, 英文姓名 qinfengfinal, stats, all fields populated, no crash); i (inventory) listed the starting items correctly; quit cleanly dropped an item and printed the goodbye message. log/debug.log for this run has exactly one non-fatal runtime line (*/topten/source: lstat failed, harmless — topten/ directory was missing pre-existing content for whatever sub-path constructs "source" as a topten category key; didn't block anything, not chased further given time budget) and otherwise zero errors.

An earlier full run (before the final config/driver restart, id hantianli/name 秦风寒/gender f) is what originally caught bug #12 above (the uptime.lpc/LASTCRASH static→nosave corruption) — that run's look command hard-crashed the object (*No program in object '/cmds/std/look'!) before the fix (bug #18's look_msg.h dropped-quote issue, found in that same first pass) was applied; both are now confirmed fixed with a subsequent clean run.

lpcc_check.sh sweep results

97.3% pass: 7306/7508 (lpcc_fail.log in this directory has full detail). Started at 96.5% (263 failures) before this pass's fixes; every genuine driver-compat/typo bug found in the sweep that's described above was fixed and individually re-verified via direct lpcc before the final sweep. Memory stayed well within safe bounds throughout (peaked ~1.3GB RSS on the lpcc process, ~9-10GB free system-wide) — no need to back off per §6b, this lib (7508 files) isn't in the "mega-lib" risk tier.

Remaining ~200 failures, triaged into known-noise categories (not bugs to fix):

What was confirmed NOT needed (checked proactively, all negative)

Process hygiene

Driver launched via run_in_background/setsid nohup ... & disown (several times across the fix/re-verify cycle), always killed by exact recorded PID (never a broad pkill pattern) once done with each round of testing. Confirmed via ss -tlnp/ps after each kill that the port was actually freed and no stray process remained. Multiple other sibling agents' driver processes were observed running concurrently on this host throughout (archives #92-95) — none were touched.

Rebuilt-driver / formatter / WASM re-verification pass (2026-07-23)

1. LPC formatter applied across all 7,509 .lpc files in work/: {"total":7509,"written":7454,"wouldChange":0,"unchanged":6, "errors":49}. Verified post-format feature/command.lpc's command_hook is still plain nomask. Found and fixed the same formatter bug discovered across this pass's other libs (full writeup in tianxia/NOTES.md): a bare ::fn(...) call immediately after ( with no space is mis-lexed as a (: ... :) closure literal. Hit once, in adm/object/bm.lpc's short(): capitalize(::query("id")) got rewritten to the syntactically broken capitalize (: : query("id")\n)\n+ ")". Hand-fixed back to return ::name(1) + "(" + capitalize(::query("id")) + ")";. Re-verified via a full lpcc_check.sh sweep: 7,306/7,508 pass (202 fail, matching the pre-format baseline below), bm.lpc not in the failure log. 2. Native re-test against the rebuilt build-debug/src/driver: booted clean (zero fatal errors). Full registration verified end-to-end via mudclient.py (this lib prompts for a GB/Big5 encoding choice before the ID prompt, first send "g"): id syxfmte → confirm → real Chinese name 秦风廿八 → password ×2 → attribute roll (0/random) → accept → email [email protected] → gender m → entered the game world at 随缘客栈, look displayed the room (correctly re-shown), score showed a correctly-populated character card matching registration, quit dropped items and printed "欢迎下次再来!". debug.log: zero error in error handler/denied/undefined function/bad argument lines. No new fixes needed; the reformatted source is still fully sound. 3. WASM test: boots cleanly through Initializations complete (only the expected missing-sockets-package compile errors for ftpd/httpd/emaild). A real registration playthrough could not be driven through this specific harness, for a reason distinct from the documented query_ip_number() limitation: cmds/usr/uptime.lpc's main() does write(read_file("/log/static/LASTCRASH")) with no type-check on read_file()'s return, called from logind.lpc's login() on every new connection to print the "上次当机原因" banner line. scripts/wasm_client.js deliberately does not copy the *contents* of work/log/ into the wasm instance's in-memory FS (see the script's own comment — avoids wasting time/memory on runtime-churn log files), so /log/static/LASTCRASH — a legitimate small reference file, not actually churn — doesn't exist there, read_file() returns 0, and write(0) throws Bad argument 1 to receive() uncaught mid-login(). Because this happens before login() reaches the code that prints the ID prompt and registers input_to(), the connection is left with no input handler at all — every subsequent line sent just falls through to the ordinary (empty-environment) command parser ("What?") instead of being treated as an ID/name/password answer. Assessment: this is a wasm-harness/no-persistent-log-data interaction, not a mudlib bug in the sense of "broken on a real server" (the archive ships LASTCRASH, and the native session above is proof registration works perfectly there) — but it is a genuine latent fragility (write(read_file(x)) with no string-type guard) that would reproduce identically on ANY from-scratch deployment lacking pre-existing /log/static/LASTCRASH data (e.g. a real from-scratch browser/wasm deployment with no prior log history), so it's worth flagging even though it isn't the already-catalogued query_ip_number() limitation. Not patched, per the task's "note, don't force a fix for wasm-specific gaps" guidance.

WASM-enablement pass (2026-07-24)

Standard four-change pass (AGENTS.md §1.3b/§1.3e/§1.5):

1. Loopback-allow (empty/non-string/127.* IP treated as loopback): - adm/daemons/logind.lpc login()BAN_D->is_banned() gate and the ip_cnt >= 20 same-host cap both skipped for loopback. - adm/daemons/band.lpc is_banned() — loopback/localhost/malformed sites never banned. (The sited is_valid/is_multi calls in this lib were already commented out upstream.) 2. Uptime gate: none present. 3. cmds/usr/uptime.lpc LASTCRASH crash FIXED (was documented-only): write(read_file("/log/static/LASTCRASH")) now guarded with stringp() (§7.9 fresh-checkout bomb — log/ is gitignored, so every fresh checkout/WASM bundle lacked the file and write(0) killed the whole login chain before the ID prompt; this was the lib's documented WASM blocker). 4. Admin seeded: fluffos / Mud@2026 / 浮浮 → (admin) appended to /adm/etc/wizlist. Save files: work/data/login/f/fluffos.o, work/data/user/f/fluffos.o (data/ not gitignored). Verified: update /cmds/usr/uptime → 重新编译成功 (conveniently recompiling the patched file itself cleanly). 5. Retest: fresh registration (syqfc/秦风, deleted after test) into 随缘客栈 with look/score/quit OK. debug.log: the only runtime error was /topten/source: lstat failed (caught; §7.11 missing-runtime-dir class — work/topten/ is gitignored churn; created work/topten/source/ locally). Removed the runtime-regenerated adm/etc/banned_name (the lib rewrites it from its built-in list on demand — NOT the yueyingqiyuan shipped-content case; nothing was deleted from git). Flow gotcha documented for future scripting: after the GB/BIG5 answer there is a hidden "Press Enter to Continue..." input_to (easily lost in the mudlist banner) — the first line sent after gb is swallowed by it.

Retrofit: fail-closed loopback check (2026-07-24)

The loopback-allow gates above were originally written per the (now superseded) defensive instruction to also treat an empty/non-string/ malformed query_ip_number() result as loopback, since older WASM driver builds returned garbage. That driver bug is now fixed upstream (query_ip_number()/resolve() return real values under WASM too), so the "malformed IP = trust it" fallback was a fail-open bypass with no remaining justification. Tightened every gate listed above to the strict pattern: loopback is ONLY ip == "127.0.0.1", ip == "::1", or a leading "127." prefix — a non-string/empty/malformed IP is now treated as untrusted/remote and subject to the gate normally, not silently allowed through. Retested: fluffos login (127.0.0.1, real value under the current driver) still passes every gate; debug.log stayed clean of denied/undefined function/error in error handler.

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

状态已从过时的 limited 修正——这份档案自己的 README 里从未记录过任何缺陷说明,本轮重新测试也没有发现:管理员登录干净正常:GB/BIG5 选择→一个带自己"按 Enter 继续……"关卡的姊妹站泥潭列表画面→id+密码→"目前权限:(admin)"。

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

原生 driver(端口 40088)跑了一遍超出注册流程的完整游玩。这份档案 每次连线都要先选 GB/Big5 编码(发给 UTF-8 客户端时这一步已经是安 全的空操作,选哪个都行),紧接着还有一个泥潭列表画面自带的"按 Enter 继续……"关卡,测试脚本要多算一步空发送,容易漏掉。

主动检查命中 2 处,都在 adm/daemons/logind.lpc:单一姓名输入 路径(没有随机取名分支)紧挨在 ob->set("name", arg) 之前的 printf("%O\n", ob) 调试残留(§7.34);enter_world() 里食物/饮 水初始化用错对象的经典 §8.9 bug(ob->query("age") 应为 user->query("age"),紧跟在 user->setup() 之后)。两处都已修 复;注册后食物/饮水显示 280/280(满值),确认 §8.9 修复生效。 command_hook 有两份拷贝(feature/command.lpcF_COMMAND 宏 实际指向的活文件,u/ybl/command.lpc 是巫师私人目录下未被引用的 死拷贝),两份都是干净的 nomask,不是 bug。

注册与游玩:注册测试角色(秦水 / id qinshui),天赋可以自选 一项数值、其余系统随机(或全部 0=随机),落在"随缘客栈","李寻 欢"(古龙小说角色)作为新手向导 NPC 出场讲解基本指令,角色自带专 属邮箱。

发现并修复 §7.68 的又一实例,外加一个更严重的全新变体:这份档 案的死亡系统有 d/death/npc/{wgargoyle,bgargoyle}.lpc(活的, DEATH_ROOM 宏指向 d/death/gate.lpc,摆的是 npc/wgargoyle)——

1. wgargoyle.lpc(白无常,真正在游戏里生效)有标准的 if (!ob || !present(ob)) return; §7.68 守卫,已按已验证的修法 拆分修复。现场完整验证:被"欧阳克"(金庸小说反派,本轮是第 四个独立血统里发现的同一个反复出现的固定布景角色,之前已经在 jyqxc/yhyxs/yanhuangwuhun 里见过)一击致死,落到"鬼门关" 见到"白无常",没有主动打断复活序列,重连确认角色已复活、站在 "武庙",精神/气息 31/100(死亡惩罚,正在恢复中)、食物/饮水基 本无损、潜能减半——本轮系列测试第四次现场完整验证 undisturbed 路径正确性。另外确认死亡的鬼魂无法移动("你已经没有力气再 走路了,休息一下吧。"),这意味着 d/death/gateway.lpc (摆着 npc/bgargoyle)在正常玩法里实际上不可达——虽然技术上 被一个房间的 exit 引用着,鬼魂状态下走不过去。 2. 一个比 §7.68 更严重的全新变体,在 bgargoyle.lpc(黑无常)里 发现init() 正常调度了 call_out("death_stage", 5, previous_object(), 0),但 death_stage() 函数本体整个被 /* ... */ 注释掉了!这意味着这个 call_out 永远静默地调用一个 不存在的函数——没有任何报错,没有任何提示,任何走到黑无常面前 的对象都会被永久晾在原地,复活对话一句都不会说,reincarnate() 永远不会被呼叫。已把整段函数体取消注释并按标准修法拆分守卫,恢 复成和 wgargoyle.lpc 对等的可用状态。因为鬼魂物理上走不到黑无 常面前(见上),这个修复没能现场触发真实的复活对话,只验证了恢 复后的代码能正常编译、不再报错——诚实记录为未现场复现的修复。 d/death/wgargoyle.lpc(不带 npc/ 子目录的裸路径重复文件, 已确认无任何引用,是被 d/death/npc/wgargoyle.lpc 取代的旧 副本)里也有同样"整个 death_stage() 被注释掉"的写法,但因为这 份文件是双重死代码(既未被引用,函数体又被注释),修复它不会产 生任何实际效果,故未做改动,只记录在案。 3. d/shaolin/npc/yu-zu2.lpc(少林地牢"狱卒"关禁闭机制,和 jyqxc 发现的同名同形状 bug 一致)——确认是被 d/shaolin/npc/yu-zu.lpc(没有任何监狱机制的简化版)取代的死代 码,仍按已验证的修法拆分修复(成本很低)。

发现并修复两个全新的、和死亡系统无关的独立 bug

4. feature/alias.lpc 的防刷屏踢人逻辑(process_input()):连续 发送 30 次以上相同指令会触发 command("quit") 把玩家踢下线,但 quit 会销毁 this_object(),之后紧接着第 34 行还有一句 this_object()->query_temp("disable_inputs"),在已销毁的物件上 呼叫方法,每次踢人都会在 debug.log 里留下一条 Bad argument 1 to EFUN call_other() 运行时错误(物件显示为 0)。虽然玩家看到的踢出效果本身是对的,但这是一处真实的、每 次触发都会留痕的运行时错误。已在 command("quit") 后补上 return,修复后现场用连续 35 次 look 重新触发踢人验证, debug.log 干净,不再报错。 5. u/bsd/npc/christmas-man.lpc("圣诞老人",实际摆在"扬州广场", 不是纯粹的巫师私人测试内容)的 create()carry_object("/u/bsd/obj/silver-cloth")->wear() 没有做存在性 检查——/u/bsd/obj/silver-cloth.lpc 这个文件在整个归档里完全不 存在(包括 raw 原始压缩包,不是转码遗漏,是内容本身就缺失; u/bsd/obj/ 目录下只有另外三个不相关的物件),carry_object() 返回 int 0,对 0 呼叫 ->wear() 触发同样的 Bad argument 1 to EFUN call_other(),每次这个 NPC 被克隆(进 入"扬州广场"、地图重置时)都会报错一次。没有编造替代物品,改成 先判断 carry_object() 是否真的返回了物件再穿。修复过程中的 一个教训:第一次尝试用 if (object cloth = carry_object(...)) 这种内联声明写法,通过了 lpc-syntax 格式化工具的解析,但实际 driver 编译报语法错误("unexpected L_IDENTIFIER, expecting L_COLON_COLON or '('")——这个 driver 的 LPC 方言不支持 if 条件 内联变量声明,格式化工具的解析器比实际 driver 更宽松,不能只靠 它验证语法,必须重启 driver 实际编译才能确认。改成先单独声明变 量再赋值后编译通过,现场重连并走到"扬州广场"确认"圣诞老人"正 常出现、ask laoren about liwu 触发圣诞祝福对话,debug.log 干 净。

发现并修复一个和 yhyxs/yanhuangwuhun 会话完全同类的 extensionless GBK 文本残留 bug,但这次是配置数据而不是帮助文档adm/etc/ banned_name(禁止注册使用的姓名黑名单)在原始压缩包里是一份真正 的 137 行列表(包含大量特定历史时期的敏感政治词汇/职务名称——领导 人姓名、政府机关职务、"台独"相关词汇等,是这类 2000 年前后中文泥 巴常见的内容审核配置),但从未被转码进 work/(同样是无扩展名文 件,转码流程的已知盲区)。logind.lpccheck_legal_name() 有 一个"文件不存在就用硬编码的 6 个代词兜底,并把兜底列表写回磁盘" 的自我播种逻辑(第 979-986 行)——本轮测试连线时,这个自我播种逻辑 真的触发了,在 work/ 里创建了一个只有"自己/它/她/他/我/你"六项 的弱化版名单,掩盖了原本 137 项的真实内容审核名单从未存在这个事 实。用 iconv -f GB18030 -t UTF-8 转换 raw 归档里的原始文件(137 行全部转换成功,人工核对是通顺的中文),替换掉刚被自动生成的弱化 版,重启验证:banned_name 文件行数恢复到 137 行,用"你"注册仍 然正确触发"对不起,这种名字会造成其他人的困扰。"的拒绝提示,确 认文件被正确加载而不是被兜底逻辑覆盖。

quit 正常退出,driver 全程存活未崩溃。debug.log 全程没有真实 的 error:/denied/Too deep recursion 行(Bad argument 1 to EFUN call_other() 的两处已在本轮修复并现场确认消失)。formatter 检查(所有改动的 .lpc 文件均已是干净格式或首次接触触发全文件重 排版,语义改动已逐一核对)、git status --short libs/syxjl/ 复查 均确认改动范围干净——六处 .lpc 源码修改 + 一份新增的 banned_name 配置数据文件是跟踪变更,测试角色的新存档保持未跟踪、未提交。

更正(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 驱动文本回退)。log_error()adm/obj/master.lpc,CRLF 行尾档 案)已经在更早一轮(引用注释里的"AGENTS.md #15w")正确修复过,管 理员账号(fluffos/Mud@2026adm/etc/wizlist 已有 fluffos (admin) 且存档已提交,README 本身已经准确记录了 GB/BIG5 +"Press Enter to Continue"这两步登录细节)也已经全部正确,本轮只 发现并修复了 log_file() 一处。

发现并修复的 PROGRAMMING bug

1. log_file()adm/simul_efun/file.lpc,CRLF 行尾档案)完全没 有 assure_file() 保护(AGENTS.md §7.11-class 的又一确认实 例)cmds/std/{drop,give,put}.lpc/cmds/app/update.lpc 等 文件多处 log_file("static/...", ...) 调用依赖对应子目录存 在——其中 static/update 这一条每次巫师执行 update 指令都 会触发,本轮的 update 验证步骤本身就顺带验证了这个修复。注 册/登录本身只写 log_file("USAGE"/"loginnum", ...)(无子目 录,本来就存在),不受影响。已补上 assure_file(LOG_DIR + file);(含前向声明,用 Python 字节级替 换保留原 CRLF 行尾格式)。

Proactive checks(无需改动)

实测过程

用已提交的 fluffos/Mud@2026 登录(gb 选码 → "Press Enter to Continue" → 密码),score/update /adm/simul_efun/file(就是本 轮改过的文件,同时验证了上面提到的 static/update 日志路径)确认 可正常重新编译,零诊断刷屏。log/debug.log 时间戳全程未变化 (Jul 23,早于本次会话),确认无新增未捕获运行期错误。登录本身 产生的存档时间戳类微小 diff 已用 git checkout 撤销,不提交。驱 动最终按精确 PID kill,ps -p 确认已退出。

§7.100 房间基类 replace_program() 扫尾修复(2026-08-19)

ROOM 宏(/inherit/room/room)在本档案 2,073 处房间文件的 create() 里紧跟 inherit ROOM; 之后又多余调用了一次 replace_program(ROOM);——AGENTS.md §7.100 记录的同一个休眠 bug。 用 fix_710_room.py 扫过 work/,删除全部 2,073 处标准形状,与脚 本自报数字、git diff --stat 净删行数完全吻合。clone/misc/ roommaker.lpc(本档案的房间建造工具)确认从未含有这个 bug(两处 ROOM_CODE/字符串拼接模板都只有 setup();,没有多余的 replace_program),无需修复。修复后 work/ 下 0 处存活残留,剩 余 118 处均为转档之前已注释掉的 // 行,原样保留;work/data/ 下没有真实 .lpc 源码命中。

驱动干净启动(零新增编译错误、端口 40088 正常监听、debug.log 无任何"cannot replace"/"cannot bind"行)。管理员 fluffos/ Mud@2026(先选 gb 编码、"Press Enter to Continue")实机登录成 功,look/score/quit 均正常,全程 debug.log 保持干净。管理 员存档的时间戳漂移已用 git checkout HEAD -- 还原,未提交。驱动 按精确 PID 结束。

§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-04,round three,shop + 拜师)

新角度:醉仙楼购物 + 丽春院空空儿拜师。2026-08-13 第二轮只测了战斗/ 死亡和 log_file,没有买东西、也没有拜师。这是 ES II 随缘洗剑录 (混有金庸门派),端口 40088。第一输入是 GB/BIG5 选单,发 gb,然后 「Press Enter to Continue」发空行,再英文 id。密码 Mud@2026

实测过程

管理员 fluffos / Mud@2026(权限 (admin))。clone /clone/money/gold 可用。

goto /d/city/zuixianlou(醉仙楼,店小二源码 kungfu/class/npc/xiaoer.lpcF_VENDOR_SALE;现场显示名「独孤宝贝」 是摊位易主,不是缺 NPC)。list 烤鸡腿八十文铜板 / 包子五十文铜板。 cmds/std/buy.lpcis_vendor() 自动选中摊主,buy jitui 成功 (「你向独孤宝贝买下一根烤鸡腿」)。当场 i 是九十九两白银 + 二十文 铜板 + 一两黄金 + 烤鸡腿。F_DEALER 店铺对丐帮拒绝购买,必须先买再拜; 本轮买的是 F_VENDOR_SALE 摊,没有踩到那条门。随缘客栈自己的店小二只卖 灯笼/火把,不是食物摊。

goto /d/city/lichunyuan,空空儿(kungfu/class/gaibang/kongkong.lpc) 对 combat_exp < 2000 的局外人无门槛收徒。apprentice kong 一次成功: 恭喜成为丐帮第二十代弟子,score 称谓「丐帮一袋弟子」、师傅空空儿。 同室左全(/d/gaibang/inhole)只收已经是丐帮且袋数够的弟子,不要拿 他当新手拜师点。cmds/usr/save.lpc 真正写盘(「【存盘精灵】档案储存 成功」)。save 后杀驱动冷启动再登录,称谓/师傅/银子铜板/布袋都在。烤 鸡腿未进 autoload。

本轮没有新的 programming bug。