Xiao Ao Jiang Hu: Return to the Jianghu

✅ 可玩

笑傲江湖之重出江湖

xajhzcjh

🔑 fluffos / Mud@2026 更新 919c138 2026-09-01 源码 下载 ZIP

▶ 开始游玩 · Play Now

笑傲江湖之重出江湖由作者 AKAI 打造,脱胎自"夕阳再现-江湖风云2-风云再起"引擎(属于"夕阳再现/XYZX"系列衍生分支,与本项目收录的多部同系列作品——如《侠客风云》《西阳再现疯狂版》等——师出同门,但游戏内容各自独立开发),是经典金庸《笑傲江湖》题材的江湖世界:新角色从南大街的客店起步,围绕"武庙""铁枪庙"等地展开门派与个人历练;除膂力、悟性、根骨、身法四项常规武侠属性外,还设有福缘、容貌两项隐藏天赋,会悄悄影响解谜结果与NPC对玩家的印象;连线时有一道隐藏的客户端版本号校验(必须先输入 `2060`),并设有"普通密码"与"管理密码"两套独立密码——archive 名称中的"服务端+客户端"其实指的是同一套游戏支持两种连线协议(普通 telnet 客户端和 TOMUD 菜单客户端),并不是额外附带了一个独立的客户端程序。

English

By author AKAI, this Smiling-Proud-Wanderer game grew out of the "Sunset Reappears — Jianghu Fengyun 2 — Storm Rising Again" engine lineage, a branch of the broader Sunset Reappears/XYZX family shared with several other archives in this collection, though its content was developed independently. New characters start at an inn on South Street and build their jianghu reputation around locations like the Wu Temple and Iron Spear Temple. Beyond the four familiar wuxia attributes, it tracks two hidden talents — fate and appearance — that quietly influence puzzle outcomes and how NPCs regard the player. Connecting requires a hidden client-version handshake (players must type "2060" first), and the game runs an unusual dual-password scheme: a normal login password plus a separate management PIN. The archive name's "server + client" actually refers to support for two connection protocols on the same game — plain telnet and a TOMUD menu client — not a bundled standalone client program.

README

内容亮点

在线试玩

https://mudlibs.fluffos.info/xajhzcjh/

管理员账号 / Admin account

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

本地运行

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

游戏端口:40070

NOTES · 移植与修复记录

xajhzcjh — 「笑傲江湖」之「重出江湖」 (archive #76)

Archive: 笑傲江湖服务端+客户端.rar ("Laughing in the Wind, server + client bundle"). Port: 40070. Status: done (boots clean, full registration flow verified twice end-to-end including real post-login commands look and score).

Triage: client-vs-mudlib determination

Despite the archive's name suggesting a bundled player client (following the precedent of archive #24, TOMud_VC源代码.rar, which really was client-only), this archive is genuine LPC mudlib source, no separate client bundled at all:

Conclusion: proceeded with the full standard conversion pipeline.

Lineage

Not related to any of the three existing "Laughing in the Wind" libs (explicitly checked per task instructions, via md5sum/diff against raw archives and directory-layout comparison):

This archive IS a member of the 夕阳再现 (Xiyangzaixian)/"XYZX" lineage already established across archives #46 (xyzxfk), #47 (xyzxfy2), #48 (xyzx3), #55 (wmkj), #59 (jhfy), #68 (ylfyxa3), and #71 (bixiecanyang) — confirmed via the bundled readme (碧血残阳说明.txt, titled "关于笑傲江湖-重出江湖的说明", explicitly self-identifying its base as "夕阳再现-江湖风云2-风云再起", credited to author "AKAI", same author credited in bixiecanyang's own readme) and via md5sum:

This archive's own in-game identity is 「笑傲江湖」之「重出江湖」 ("Laughing in the Wind" — "Return to Jianghu"), a *different*, independent game-content fork within the same shared 夕阳再现 engine family — not a duplicate of any processed archive (12378 raw files here vs bixiecanyang's ~13580, ylfyxa3's ~17380, etc; distinct master.lpc/ logind.lpc/securityd.lpc content in every case).

Fixes applied

Ported/cross-checked against the 夕阳再现-family playbook (bixiecanyang/#71, xyzxfy2/#47) where lineage matches, plus fresh findings from this archive's own content:

1. AGENTS.md §15h (adm/simul_efun/chinese.lpc's is_chinese()): GBK lead-byte range check (strlen(str)>=2 && str[0] > 160 && str[0] < 255) → CJK Unicode codepoint range check (strlen(str)>=1 && str[0] >= 0x4e00 && str[0] <= 0x9fff). 2. AGENTS.md §15h (adm/daemons/logind.lpc's check_legal_name()): byte-count bound strlen(name) < 2 || > 10 → character-count bound < 1 || > 5 (matches the message's own stated "1 到 5 个中文字"); the sliding-window gate i%2==0 && !is_chinese(name[i..<0]) had its i%2==0 && dropped so every character position is checked (same reasoning as bixiecanyang: is_chinese() only inspects index 0 of whatever's passed, so a full-length suffix slice is functionally a single-character check either way). 3. AGENTS.md §15z (3 files: include/globals.h, adm/obj/master.lpc, adm/obj/simul_efun.lpc): each carried an #ifndef __SENSIBLE_MODIFIERS__ / #define nosave static / #define protected static compatibility shim, and convert_lib.sh's blanket staticnosave sed rewrote the shim's own lines to #define nosave nosave / #define protected nosave (silently aliasing protected to nosave). Neutralized the whole shim (replaced with a one-line comment) in all 3 files. New nuance for the catalog: this driver build's own predefine table (dumped at boot) DOES include #define __SENSIBLE_MODIFIERS__ — meaning the #ifndef guard is actually false here and the buggy branch is dead code at compile time regardless. The textual sed-collision still happened (the sed doesn't know about #ifdef state), so the fix was still applied as free, harmless insurance, but it may not have been live either way on this particular driver build/config. Worth checking __SENSIBLE_ MODIFIERS__'s presence in the predefine dump on future libs before assuming §15z is *always* a live bug versus just a latent one. 4. AGENTS.md §3 counterexample (7 files): the same blanket sed hit log_file("static/XXX", ...) string literals (a real on-disk log subdirectory name), rewriting them to "nosave/XXX". Reverted all occurrences back to "static/XXX" in: clone/misc/dan.lpc, adm/simul_efun/override.lpc (×5), adm/daemons/securityd.lpc, adm/obj/master.lpc (×5), cmds/std/give.lpc, cmds/std/suicide.lpc, and adm/daemons/复件 securityd.lpc (see item 10 below). 5. AGENTS.md §14 (adm/obj/master.lpc's valid_override): upgraded from the 2-arg signature to the documented 3-arg (file, name, main_file) form, checking main_file == SIMUL_EFUN_OB || main_file == MASTER_OB in addition to the original file check — simul_efun.lpc is a pure #include composer (pulls in object.lpc, message.lpc, etc, several with efun:: overrides), so file alone never equals SIMUL_EFUN_OB for those fragments. No live boot/registration failure observed without this fix (consistent with the catalog's note this may never surface on a real boot) but applied as free insurance. 6. AGENTS.md §15s (adm/simul_efun/message.lpc's tell_room()): the dominant 2-arg call form (275+ of 332 call sites in this archive) leaves varargs object *exclude at its default int 0, which then flows straight into message("tell_room", str, ob, exclude) — this driver's message() rejects a raw int 0 for its 4th (void|object|object*) argument. Fixed at the shared root: exclude || ({}). Also found and fixed the same shape in shout() (a variant not previously seen written exactly this way): message( "shout", str, users(), this_player())this_player() can itself be 0 outside a genuine player context, hitting the identical rejection; fixed by wrapping in me ? ({ me }) : ({}). 7. New §15b-style gap (adm/simul_efun/message.lpc): two functions called throughout the lib but never defined anywhere — message_combatd(msg, me, you) (called from adm/daemons/itemd.lpc and 2 kungfu/skill/ files) and message_sort(msg, me, you) (called 4× from adm/daemons/itemd.lpc). Both aliased to the already-defined message_vision() (identical 3-arg shape), added right after it in the same file (safe ordering, no §15aa risk since message_vision is textually first). 8. §15ac-style bare macro (3 files: d/quanzhou/npc/tang3.lpc, d/taishan/tang3.lpc, adm/daemons/network/netmail.lpc): bare SAVE_EXTENSION (never defined anywhere in this lib) → this driver's real autogenerated __SAVE_EXTENSION__ constant. 9. AGENTS.md §15ab (clone/user/login.lpc's receive_message()): the pre-login connection object's copy was missing the !stringp(str) guard that the post-login player body's copy (feature/message.lpc) already has — added proactively as insurance (no live crash observed here since the two files this pattern usually trips on, motd/ welcome, both exist with real content in this archive, but the gap is real and cheap to close). 10. Orphaned backup file (adm/daemons/复件 securityd.lpc, Chinese for "copy of securityd.c" — a stray backup with a different, older, and genuinely broken shape than the real securityd.lpc, not referenced by anything in the tree): renamed to 复件securityd.orphaned-backup so it can't be mistaken for a live compilable object (same treatment as AGENTS.md §12's precedent). 11. AGENTS.md §15w (adm/obj/master.lpc's log_error()): broadcast to the connected player was unconditional (if (this_player(1)) efun::write(...)) even for ordinary compile *warnings*, not just real errors. Gated the broadcast on the message NOT containing "warning:" (log-file write is unchanged/unconditional). 12. New content-gap fix, single shared root (d/city/obj/cloth.lpc, file did not exist at all in the raw archive — d/city/obj/ only shipped box/gourou/jitui/table/zhubang.lpc): 47 different NPC files spread across at least a dozen different zones (city2, wudujiao, tangmen, guanwai, village, mingjiao, quanzhou, lingshedao, gumu, kungfu/class/{gumu,npc}, migong, etc.) all hardcode the literal carry_object("/d/city/obj/cloth")->wear(); as their standard starting-garment call (clearly one shared boilerplate template copy-pasted verbatim into dozens of zone-specific NPC files, never updated to each zone's own local obj/cloth.lpc the way most other zones' NPCs correctly do), and since the target never existed, carry_object(...) returned 0 and ->wear() on it crashed silently during each NPC's own create() (the crash is swallowed with no printed diagnostic — same silent-nested-compile-failure shape as AGENTS.md §15d, just triggered by a genuinely-missing file instead of an ACL denial). This was the single highest-impact lpcc-sweep fix: restoring ONE file (copied verbatim from the byte-for-byte-identical sibling template at d/city/npc/obj/cloth.lpc/d/village/npc/obj/ cloth.lpc/d/tangmen/obj/cloth.lpc — all three are the same "basic starting cloth" boilerplate, confirmed by direct comparison before reconstructing, not fabricated content) dropped the lpcc sweep's failure count from 336 to 285 in one shot (see "lpcc sweep" below for the exact before/after numbers). 13. 3 small genuine pre-existing typos found via the lpcc sweep: - d/baituo/obj/bowl.lpc and d/baituo/npc/obj/bowl.lpc: set_name("海口大碗", "bowl") — second arg is a bare string where set_name() expects string* (the alias-list idiom used everywhere else in this lib, e.g. set_name("布衣", ({ "cloth" }))). Fixed to ({ "bowl" }). - clone/book/lbook5.lpc and clone/book/pixie_book.lpc: each had a literal duplicate int query_autoload() { return 1; } declaration (copy-paste artifact) causing "Redeclaration of function". Removed the redundant second copy in both. - d/npc/m_weapon/weapon/m_bian.lpc: two void create() definitions — the first is the complete, correct item setup (name/weight/ wield-messages/init_whip); the second is a short, clearly incomplete leftover fragment (unit/no_get/no_drop/setup() only). Removed the second (dead/incomplete) one, keeping the first. 14. 5-file iconv-eaten-newline fix (matches the documented Encoding gotcha: iconv -c's invalid-byte recovery can eat the adjacent REAL newline too, merging a @LONG...LONG text block's closing tag onto the preceding text line): d/heimuya/tang.lpc, d/heimuya/npc/ tang.lpc, d/heimuya/shenggu.lpc, d/quanzhen_old/manglin1.lpc, d/quanzhen_old/manglin2.lpc — all 5 showed error: End of file in text block from a merged ...文本.LONG ); (or CRLF 。LONG\r\n) line. Confirmed against the raw pre-conversion bytes in each case (an invalid/truncated GBK byte immediately followed by a literal newline) before inserting the newline back in at the exact point indicated by the raw byte layout — not a guess. All 5 verified compiling clean afterward via standalone lpcc.

Confirmed NOT needed (verified by reading source)

Registration flow (read from logind.lpc's actual input_to chain)

logon()get_version (unconditional; the prompt reads "请输入您 的英文名字:" — textually indistinguishable from a normal id prompt, but the real check is arg[0..3] != "2060"; sending anything else prints an "警告!本游戏必须使用TOMUD客户端..." alert and disconnects — a live instance of AGENTS.md §15q) → English id (get_id; "new" branches to registration) → GetNewId (english id, must not be "new"/"quit", must be unused) → confirm_id (y/n) → get_name (Chinese name, 1-5 characters; typing a name directly skips the get_resp y/n loop entirely — that loop only fires for the empty-inputrandom_name() path) → new_wizpwd (an "admin password", ≥5 chars) → confirm_ wizpwdnew_password (the real login password, ≥5 chars, must differ from the admin password) → confirm_passwordselect_gift (attribute roll, 0-4; 0 = system-random via get_gift's y/n accept loop) → get_email ([email protected] format required) → get_gender (m/f) → enter_world().

banned_name list: 你/你的/我/我的/自己/屁/他/他的/她/她的/它/它的/鬼王/ 风云/流氓/爸/妈/祖先/祖宗/爷/奶/毛泽东/邓小平/江泽民/【/】/马克思/恩格斯/ 列宁/抄/手淫/老百姓 — checked before testing; neither "秦风" nor "林风" match any entry.

Interactive test #1 — full registration + post-login commands, real name "秦风"

Single continuous mudclient.py session, in order:

Zero real error:/"Read access denied"/"Bad argument"/"Too deep recursion" lines anywhere in debug.log for this session — only the same benign Unknown #pragma, ignored / Unused local variable compile *warnings* seen throughout every other lib in this family.

Interactive test #2 (after ALL fixes above, fresh driver restart) — real name "林风", female, incl. score

Per AGENTS.md's own diagnosis-technique note ("LPC objects don't recompile just because their source file changed on disk; you must restart the driver process"), the driver was killed and rebooted fresh after every fix in this NOTES.md was applied (several touched adm/simul_efun/message.lpc, a file every room/NPC's heartbeat/emote path depends on) before this second, independent verification run:

Zero real error:/"denied"/"crash"/"undefined"/"bad argument" lines in debug.log for this second, post-fix session either (grepped explicitly, excluding the harmless config-table dump lines that happen to contain the word "error"/"crash" in key names like mudlib error handler/trap crashes).

lpcc sweep

Ran 3 times (before content-gap fix / after the d/city/obj/cloth.lpc content-gap fix / after all remaining typo fixes), memory monitored throughout (well within budget — 11413 files, never dropped below ~17GB free on this 23GB host, nowhere near the §6b mega-lib danger zone):

| Pass | Pass | Fail | Total | Pass rate | |---|---|---|---|---| | 1 (pre-fix) | 11076 | 336 | 11412 | 97.06% | | 2 (after cloth.lpc fix) | 11128 | 285 | 11413 | 97.50% | | 3 (final, after typo fixes) | 11138 | 275 | 11413 | 97.59% |

Triage of the failures (per AGENTS.md §6b's "categorize before fixing" guidance):

Re-verification pass (2026-07-23)

Clean re-boot confirmed (zero fatal errors, empty etc/preload boots in well under 5 seconds). Ran the full registration + look/score/quit flow once more in a single continuous connection (id qinchuan, real Chinese name 秦川, male): 2060 client-version gate → new → id → y confirm → Chinese name accepted → admin password (2x) → real password (2x) → gift roll 0/y → email → gender m → entered the world at 客店/"the inn", saw real NPC (店小二/innkeeper) and board content, look re-rendered the room correctly, score produced the full character sheet, quit disconnected cleanly ("欢迎下次再来!"). Zero runtime errors in debug.log. No code changes needed — clean re-confirmation of the original pass's findings.

Config notes

config.fluffos adapted from the raw config.cfg (name "夕阳再现", the generic engine name — the live banner shows the game's real identity, 「笑傲江湖」之「重出江湖」). Dropped obsolete keys per driver warnings: address server ip, address server port, reserved size, binary directory, swap file. Port set to 40070; mudlib directory points at this lib's work/; log directory is the usual /log (sibling of config.fluffos, driver always launched via cd into this directory first, per AGENTS.md §6).

Encoding

convert_lib.sh reported 29 lossy conversions (invalid bytes dropped) out of 12378 files — all but 5 (see fix #14 above) turned out to be genuinely harmless (either non-code data/save files, or code positions where the dropped byte didn't touch anything load-bearing). No stragglers found by the standard post-conversion file -b sweep beyond one false positive (d/emei/shenshuige.lpc, a normal, fully-valid UTF-8 room file that file misclassifies as "data" for unrelated heuristic reasons — confirmed by a full Python UTF-8 decode, not a real encoding problem).

Driver rebuild / formatter / WASM pass (2026-07-23)

WASM-enablement pass (2026-07-24)

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

1. Loopback always allowedadm/daemons/band.lpc: added an is_local_site(site) helper (fail-closed, see retrofit note below) and short-circuited: - is_banned() (called from logind.lpc's logon() ban check) → local always returns 0 (not banned); - vaild_allow_address() (the account's own allow_ip allowlist check, logind.lpc) → local always returns 1 (allowed), regardless of whatever allow_ip list the account has configured. 2. Uptime startup gateadm/daemons/logind.lpc's logon() had if (uptime() < 10) { ...destruct(ob)... } (documented as a known, pre-existing, non-blocking-natively design gate in the "Driver rebuild / WASM pass" section above). Now only applies to non-loopback connections: if (!is_local && uptime() < 10) { ... }. 3. Anti-flood throttles exempt loopbacklogind.lpc's logon(): the per-IP concurrent-connection cap (ban_cnt > 8) now skips local connections; get_id()'s per-IP concurrent-player cap (ip_cnt > 8) is now also skipped for local connections (wiz_level(arg) < 2 && !BAN_D->is_local_site(...)). 4. Admin account seeded — id fluffos, pw Mud@2026, name 浮浮, registered via the real flow (2060 client-version gate → new → id → y confirm → Chinese name → admin/"management" password → confirm → real password → confirm → gift 0/y → email → gender m). Granted (admin) via adm/etc/wizlist (fluffos (admin)). - This lib's registration flow has an unusual double-password step: besides the real login password, it also asks for a wizpwd ("管理密码"/"management password") — despite the name, reading logind.lpc's get_passwd()/reset_wizpwd() confirms this is NOT related to wizard/admin status at all — it's a self-service password-reset PIN (typing it at the normal password prompt triggers "you typed the management password, please reset your normal password"). Set to FluffMgmt1 (≥5 chars, must differ from the real password) — document this as a secondary recovery PIN, distinct from the Mud@2026 login password, since a future agent re-seeding this account needs both. - Genuine pre-existing bug found while verifying admin access: include/command.h defines ADM_PATH/WIZ_PATH/IMM_PATH (and the other unused historical rank macros BOS_PATH/ARC_PATH/ ANG_PATH/APR_PATH/GEN_PATH) as ({}) — an EMPTY command search path — confirmed identical in the raw, unconverted archive (not a conversion artifact). feature/command.lpc's enable_player() calls set_path(ADM_PATH) for any account whose wizhood() is "(admin)", so promoting fluffos via wizlist (the documented, standard admin-grant mechanism) left the account with ZERO working commands — not just wizard commands, but ordinary ones too (look, quit, everything), since commandd.lpc's find_command() searches exactly the directories in path and an empty list matches nothing. No wizard-only command files exist anywhere in this lib to legitimately populate these macros with, so fixed by aliasing all of them to the same directories as PLR_PATH (/cmds/std/, /cmds/usr/, /cmds/skill/) — promoted accounts keep normal command access instead of being silently locked out of the game entirely. This is outside the standard four-item WASM-enablement scope but was necessary to satisfy §1.5's "verify a wizard command actually works" step at all.

Save files (untracked, NOT gitignored — orchestrator must git add):

Fail-closed loopback retrofit (2026-07-24)

Security correction, applied together with the initial patch above (this lib was patched fresh in this same pass, so it was written fail-closed from the start rather than needing a later retrofit):

int is_local_site(string site) {
  if (!stringp(site)) return 0;
  if (site == "127.0.0.1" || site == "::1") return 1;
  if (strlen(site) >= 4 && site[0..3] == "127.") return 1;
  return 0;
}

An unparseable/empty IP is treated as remote/untrusted, not loopback — deliberately, since the original code already rejected missing/malformed IPs outright and there is no longer a WASM driver bug to work around.

Retest (2026-07-24)

Both done against a fresh driver restart (to pick up the command.h fix, which is compile-time):

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

"夕阳再现"衍生引擎上的一款独立游戏。状态已从过时的 limited 修正——这份档案自己的 README 里从未记录过任何缺陷说明,本轮重新测试也没有发现:这个版本需要 Tomud 客户端版本握手(第一行字面回答"2060",和本项目其它地方已经记录过的家族共同模式一致)——实测确认:2060→id→密码→"★ 您目前权限:(admin)",quit 干净。

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

深度功能测试 / Deep functional test (AGENTS.md §10.7)

Status: done. One real programming bug found and fixed (registration- breaking, every single new character); everything else — combat, organic skill/sect acquisition, quit/reconnect persistence — verified live and clean.

Environment setup gap (not a code bug, noted for the record)

This session's fresh checkout had no log/ directory at all (gitignored, libs/*/log/ + libs/*/work/log/), so the FIRST boot attempt crashed before the connection handler ever printed a prompt: *Wrong permissions for opening file /log/debug.log for append. "No such file or directory", followed by Error in mudlib error handler (the driver's own error reporting couldn't even write *itself* because the directory was missing). Fixed by mkdir -p log work/log before booting — this project's two distinct log roots for this lib: the driver's own debug.log (log directory config key, resolves against the launch CWD == lib root, confirmed via ls libs/xajhzcjh/log/) vs. mudlib-level write_file()/ log_file() calls using the LPC-virtual /log/ path (resolves against work/, confirmed via libs/xajhzcjh/work/log/dbgtrace appearing there during live instrumentation) — two genuinely separate roots for two genuinely separate log mechanisms, not a typo. Both are the standard, already-documented (§7.44) "runtime dir doesn't exist in a fresh checkout" setup step, not something to fix in code.

Bug found and fixed: log_file() never calls assure_file() — breaks EVERY new registration (AGENTS.md §7.11, new confirmed sibling instance)

Symptom, 100% reproducible across 5+ independent registration attempts in this session: a brand-new character completes the ENTIRE registration ritual (client-version gate → id → Chinese name → wizpwd → password → gift → email → gender) with every prompt rendering correctly, then lands on a bare > prompt with zero world-entry banner (no MOTD, no "你连 线进入这个世界" line, no ★ 您目前权限), zero working commands (look/score/i all return the driver's generic default fail message, "什么?", because enable_player() never ran), and zero save file ever written to work/data/{login,user}/<letter>/<id>.o. No error appears anywhere — not on the player's screen, not in debug.log. This exactly matches AGENTS.md §7.11's already-documented xajhxo sibling-instance shape (same TMI-2/夕阳再现-adjacent family pattern, same get_gender() call site) — this is now a second confirmed instance in the same 夕阳再现/XYZX lineage (libs/xyzxfy2 and libs/ylfyxa3 were ALSO independently found and fixed with the identical shape in their own deep-test passes — adm/simul_efun/file.lpc's log_file()/assure_file() pair is a shared low-level utility copy-pasted across this whole family, so check it FIRST on any future 夕阳再现-lineage dive rather than rediscovering this from scratch).

Root cause: adm/daemons/logind.lpc's get_gender() — the LAST step of the registration input_to() chain, executed right after the gender prompt, immediately before init_new_player()/enter_world() — calls log_file("login/newid.log", sprintf(...)) to record the new account in a per-lib registration log. adm/simul_efun/file.lpc's log_file() was a bare write_file(LOG_DIR + file, text) with no directory-existence guard at all. On a fresh work/ tree, work/log/login/ has never been created (nothing in this archive's own boot path creates it), so this write_file() throws *Wrong permissions for opening file /log/login/newid.log for append. "No such file or directory" — and since nothing in get_gender() catches it, the uncaught error aborts the rest of that function, meaning CHANNEL_D->do_channel(...), init_new_player(user), and — critically — enter_world(ob, user) never run. enter_world() is where user->setup() (which calls enable_player(), wiring up every player command) and user->save()/ ob->save() live, so skipping it silently strands the new character with no commands, no save, and no visible sign anything went wrong.

Confirmed via live catch()-wrapped instrumentation (temporarily added then reverted, not part of the shipped fix) that this exact call is the one throwing: err=*Wrong permissions for opening file /log/login/newid.log for append. "No such file or directory", and that wrapping it (or fixing the shared root) lets enter_world() run to completion with the full banner, working commands, and a real save file.

Fix (adm/simul_efun/file.lpc, matching this lineage's established assure_file()-before-write_file() convention exactly, same shape as xyzxfy2/ylfyxa3's own fixes): added assure_file(LOG_DIR + file); as the first line of log_file(), plus a one-line forward declaration (void assure_file(string file); before log_file()'s own definition) since assure_file() is textually defined further down in the same file and this driver's compiler doesn't resolve forward references without an explicit prototype (same convention logind.lpc itself already uses elsewhere). This is the shared-root-cause fix (AGENTS.md §6.4): it covers every log_file() call site in the tree, not just get_gender()'s, including any future subdirectory nobody has thought to pre-seed yet.

Formatter: ran format-corpus.mjs on the touched file — 0 written (already idempotent with the fix applied), 0 errors. Checked the 3 §9 blind-spot greps on this file specifically: clean (no : : split, no \ n corruption).

Registration + state verification (multiple independent live sessions, post-fix)

Raw-socket Python test client (scripts/mudclient.py-equivalent, written ad hoc this session — tmux/telnet kept dying mid-session in this particular container for unrelated reasons, see below) driving one continuous connection each time:

- Reconnect after a real ~1-hour wall-clock gap (this session's own root-cause investigation + NOTES.md drafting time, not a sleep): logged back in with yangfei/playpass456landed back at the exact saved room (天山山路) → score confirmed full state persistence: title still 星宿派第三代弟子, "你的师父是狮吼子。" (master field persisted), all 4 attributes unchanged (19/22/18/21) → quit clean again. No quit-retention lockout or grace-period logic exists in cmds/usr/quit.lpc for new accounts (confirmed by reading it: unconditional me->save(); destruct(me);, no deletion path) — didn't need the "kill the raw connection instead" fallback.

log/debug.log grepped after every one of the above sessions for real error:/denied/crash/undefined/bad argument lines (excluding the benign Unknown #pragma/Unused local variable compile warnings and the literal string "mudlib error handler" in a config dump key): zero real errors in the entire final (post-fix) test corpus.

Combat mechanism (read from cmds/std/fight.lpc, then live-verified both branches)

fight <target> is this lib's dedicated safe-sparring command — its own help text says so explicitly ("这种形式的战斗纯粹是点到为止,因此只会 消耗体力,不会真的受伤"/"purely a courtesy bout, only costs stamina, no real injury"), distinct from kill (real, lethal) and hit. Critical nuance this lib's own source reveals, worth reading before picking a test target in ANY sibling of this lineage: fight.lpc's main() branches on obj->query("can_speak") — if the target can't speak, the "polite challenge" flow is skipped ENTIRELY and it falls straight into me->fight_ob(obj); obj->kill_ob(me);, i.e. a real, lethal fight, even though the player typed fight, not kill. can_speak is set to 1 only by adm/daemons/race/human.lpc's setup_human() — so it's effectively "is this NPC human" — every non-human race (beasts, etc.) is UNSAFE to fight despite the command's name and help text. Confirmed live on both sides: fight wuya (race 野兽/beast, no can_speak) → real kill_ob() combat, took actual damage. fight bayi (default race, human, can_speak set) → real accept_fight()-mediated safe spar, non-lethal flavor text only. Lesson for future dives in this lineage: "a clearly-safe humanoid NPC" isn't just stylistic advice here — picking an animal NPC for the "safe" combat test would have been actively unsafe on this exact codebase.

Default accept_fight() (inherit/char/npc.lpc) requires the target NOT be already fighting, above 90% jing/qi, and NOT have attitude: friendly (friendly NPCs always decline — matches the scavenger/维吾尔族妇女 rejections seen live). heroism/aggressive/killer/unset attitudes all accept by default. No dedicated "training dummy" NPC was actually reached live this pass (the d/*/npc/mu-ren.lpc "练功木人" with no_die: 1 seen during source review would have been an even stronger choice, but bayi already gave a clean, complete, accepted spar).

Skill/sect acquisition — organic path (live, succeeded) and admin shortcut (confirmed absent)

Organic path: apprentice <target> (aliased bai, cmds/skill/ apprentice.lpc) → for an NPC target with a working attempt_apprentice() override, an unconditional acceptor recruits immediately in one command (see 狮吼子/Shihou-zi run above — full success, title + master field both persisted through a reconnect). Most class-master NPCs (kungfu/class/<sect>/*.lpc) gate acceptance on stats/gender/karma (read several: kungfu/class/gaibang/hong.lpc wants str>=20 && con>=25, .../liang.lpc wants str>=25, .../zuo-qu.lpc wants male, etc.) — but a handful (kungfu/class/xingxiu/{azi,shihou,tianlang,zhaixing}.lpc, at least) accept unconditionally. Default attempt_apprentice() (inherit/char/npc.lpc) always politely declines for any NPC without an override (verified live: apprentice tuobo-seng/apprentice limochou against non-master NPCs both got the correct in-character decline/ not-found response, no crash).

Admin shortcut: confirmed absent. This lib ships no cmds/adm/ or cmds/wiz/ directory at all (ls cmds/ → only skill/, std/, usr/) — matches the already-documented include/command.h finding (§1.5 admin-seeding pass, this same NOTES.md above) that this archive never shipped any wizard-only command files. There is no in-game admin command anywhere in this lib to directly grant a skill or sect membership to a player — the organic apprentice/learn/study/ practice commands are the only path, for admins and players alike.

发现但判定为既有设计、未改动的现象 (observations, not bugs)

WASM 未验证说明

Not re-verified under WASM this pass (native-only, per this project's current WASM build blocker). Confirm via: curl -sS "$HTTPS_PROXY/__agentproxy/status" — emsdk's storage.googleapis.com dependency is denied by the proxy, unchanged from every other lib checked this session.

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

针对升级后的驱动(quest_times/win_times %-operator 修复 + Warning/ warning 大小写驱动兼容回退)做的第二轮 §10.7 重测。

环境笔记:build/src/driver 在本次会话的宿主 CPU 上崩溃(非本 lib 问题)

scripts//AGENTS.md 惯用的 /home/sunyc/src/fluffos/build/src/driver 本次会话启动即崩溃:Illegal instructionevthread_use_pthreads——反汇编确认该函数被编译成使用 AVX 指令 (vmovq/vpinsrq/vinsertf128),而本次会话实际落地的宿主 CPU 是 Intel(R) Xeon(R) CPU L5520(Nehalem,2009 年,/proc/cpuinfo flags 里最高只到 sse4_2,完全没有 AVX)——一个构建/宿主 CPU 不匹配 的环境问题,与 xajhzcjh 自身代码无关。改用同仓库另一份构建 /home/sunyc/src/fluffos/build-debug/src/driver(未启用相同的 AVX 代码生成路径)成功干净启动、监听 40070、完成本轮全部测试。记录此 坑供后续同一宿主上的 session 参考:如果 build/src/driver 启动即 "Illegal instruction",先试 build-debug/src/driver,不要误判为 lib 本身的问题。

发现并修复的 PROGRAMMING bug

1. adm/daemons/logind.lpc 里两处遗留的 printf("%O\n", ob); 调试 残留(AGENTS.md §7.34 的形状,与 xajh4gkb round two 独立确认的同一 位置形状一致):分别在确认中文名字后进入密码设置的两条并行分支 ——get_resp()(接受随机产生的名字)第 532 行、get_name()(手动 输入名字被接受)第 565 行——每次注册确认名字后都会把 obfile_name(如 /clone/user/login#0)原样打印给玩家。Live 实测 已复现:用测试号 testqqchen 走完整注册流程,屏幕上在"请设定您 的管理密码"提示前出现了裸的 /clone/user/login#0。两处均删除该行, 只保留紧邻的 ob->set("name", ...)。round one 的 NOTES 完全没有提 到这两行,是本轮新发现(round one 覆盖了这个文件的其它 bug 类,唯 独漏了这个)。修复后用第二个测试号 verqqchen(女性分支)重新走完 整注册流程确认:不再出现任何裸路径泄漏,正常进入游戏世界,男女分 支各自的起始服装(布衣 vs 粉红绸衫)都正确。

§7.34 log_error() / §7.11 log_file():round one 已修复,本轮确认仍在位

adm/obj/master.lpc's log_error() 仍有大小写不敏感的 strsrch(message, "arning:") == -1 判断;adm/simul_efun/file.lpc's log_file() 仍在 write_file() 前调用 assure_file(LOG_DIR + file) (含正确的前向声明)。两处均未见回归。

§5/dbase.lpc 密码守卫检查:不适用

feature/dbase.lpcset(prop, data) 是纯粹的无守卫赋值(读取整份 文件确认),没有任何 wizhood()/password 相关的特殊分支——跟 tybxjh/wlhd 那个 bug 形状完全不同,这个 lib 没有对应问题。

管理员播种验证:wizlist 条目确有对应存档,本轮做了真正的断线重连

adm/etc/wizlistfluffos (admin) 这条 round one 就已写入, data/login/f/fluffos.odata/user/f/fluffos.o 也确实存在(不像本 轮重测系列里其他几个 lib 那样"wizlist 里看起来对但从未真正注册过")。 本轮用 fluffos/Mud@2026 走了一次登陆(2060 → id → 密码),入世 后横幅确认 ★ 您目前权限:(admin)look/east/west/score 全部 正常。强制验证步骤quit 断线后用一个全新的 tmux 会话重新连接, 2060fluffosMud@2026 完成一次真正的断线-密码-重连,密码验 证通过,管理员权限保持 (admin),落回原来存档的房间(武庙)——不是 只看世界进入和权限横幅就下结论。存档文件的 last_on/combat_exp 字 段随之更新(score 命令触发的正常游玩状态变化),已随本次提交一并 纳入。

移动/驱动兼容性检查

eastwest 往返移动、score 多次未触发任何"Too long evaluation" 崩溃或其他异常,debug.log 全程(262 行,逐行读过)只有一贯的 Unknown #pragma/Unused local variable 编译期警告,与 round one 记 录的基线一致,零真实 error/denied/crash/undefined。

quest_times/win_times %-operator 修复:抽查确认在位

d/city2/npc/refereew.lpc 现有 to_int(query("win_times")) % 5,是 corpus-wide 2026-08-12 sweep(commit c571a53629f)已经打过补丁的写 法,无需额外改动。

未在本轮测试

拜师门派、商店购物、完整战斗到死亡/复活循环——round one 已用多个测试 号做过完整覆盖(安全切磋 vs 真实战斗的 can_speak 分支、组织化拜师 成功案例、跨重连状态持久化),本轮认为不需要重复;本轮重点是驱动升级 后的回归检查 + 正常游玩中顺手发现的 bug(本次即发现了新的 §7.34 实 例)。

AGENTS.md §7.100 修复(2026-08-19,批次三)

ROOM 基类冗余 replace_program(ROOM); 自崩溃地雷(详见 AGENTS.md §7.100):4239 处命中。自带建房工具 clone/misc/roommaker.lpc 的 字符串拼接模板同样修复。

git diff --stat:4238 files changed, 1 insertion(+), 4239 deletions(-), 与预期精确吻合。

验证:build-debug 驱动真实冷启动,端口 40070 正常监听。既有管理 员账号 fluffos/Mud@2026(经本 lib 要求的 "2060" 客户端版本握手) 登录,您目前权限:(admin) 确认,武庙→北大街→北门多房间走访无 误,quit 干净退出,全程无新增 "cannot replace"/"cannot bind" 日 志行。

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