info.html · 介绍 · play.html · 游玩 · llms.txt · 下载与本地运行 · ZIP · GitHub
浴血重生登录横幅自称 "1.YXCS"/"浴血重生",是一款围绕"浴血重生"这一江湖恩怨、洗心革面主题展开的传统武侠 MUD,新角色要经历标准的门派拜师与完整的功夫技能体系,创角时还能选择"国际挑战者"式的比武活动;血统比较特殊:既有 ES II 引擎系列的痕迹(`chinesed.lpc` 等文件署名可追溯到 "ES"→"XKX" 一支),又混入了"Lonely"("nitan/NT" 系列的作者)后期改写的部分模块,属于一个 ES 系底子上被二次深度魔改的分支,不是纯血统的任何一支;地图上"世界之巅"跳崖场景与"天涯"家族(`xysylmhb`/`xyzxiiylzymh`/`yzxiiizylfy`/`xyzx3`/`tianxiawuxue`)逐字节相同,"Lonely"这条线索也和 `tianxiawuxue` 鸣谢名单里的同一位作者相呼应;另有一处防盗号保护,已在 wizlist 中登记为高权限的 ID 无法在注册流程中直接设置密码,需先从名单移除、注册完成后再加回去。
English
A traditional wuxia revenge story built around its "Reborn in Blood" premise — the login banner self-identifies as "1.YXCS" / "Reborn in Blood." New characters go through standard sect apprenticeship and a full kungfu/skill system, plus an "international challenger"-style tournament option at character creation; a wizlist-based anti-account-theft protection strips password-setting rights from any ID already registered as a high-privilege wizard until it's temporarily removed from the list. Its lineage is unusual: it carries traces of the ES II engine series (files like chinesed.lpc trace authorship back through the "ES"-to-"XKX" branch) mixed with modules later rewritten by "Lonely," the author behind the Nitan/NT series — making it a deeply modified hybrid rather than a pure descendant of any single lineage. Its map can be pinned down more precisely: the "Peak of the World" cliff-jump scene is byte-identical to the unrelated "Tianya" family shared by several other archives in this collection (xysylmhb/xyzxiiylzymh/yzxiiizylfy/xyzx3/tianxiawuxue).
README
内容亮点
- 整体内容比较完整、系统衔接也比较扎实,功夫技能与门派拜师流程之间 没有明显的断层或缺角。
- 血统混杂反而让内容更丰富:ES 系的武功框架之上叠加了"Lonely"改写的 模块,比单一血统的同类档案多出一些独特设计。
在线试玩
https://mudlibs.fluffos.info/yxcs/
管理员账号 / Admin account
- ID:
fluffos密码:Mud@2026中文名: 浮浮 - 权限:
(boss)(本 lib 巫师等级表的最高级"巫师协会懂事";通过adm/etc/wizlist授予)。
警告:这是一个公开的默认密码,仅供本地/浏览器试玩。正式对外开服前
请务必修改此密码。
本地运行
cd libs/yxcs
~/src/fluffos/build-debug/src/driver config.fluffos游戏端口:40056。
NOTES · 移植与修复记录
yxcs — 浴血重生 (archive #62)
Archive: archives/浴血重生MUD.rar. Port: 40056. Status: done
(boots clean, full registration flow verified end-to-end with real Chinese
names, reaching an actual game room; lpcc sweep at ~98%+ pass).
What this is
The mudlib's own config.cfg self-identifies name : 1.YXCS — "YXCS" is
the pinyin initialism of 浴血重生 ("Bathed in Blood, Reborn"), matching
the archive's own title exactly. The live in-game banner also prints
"浴血重生(2.YXCS)". No slug discrepancy worth noting.
Archive layout: the actual mudlib root is nested one level down at
raw/socket/yxcs/ — raw/socket/ also bundles several unrelated Windows
binaries alongside it (MudOS.exe, serv-u/ — a cracked FTP server
installer + keygen, superscan/ — a 2000s-era network port scanner). These
are contemporary "toolbox" bundling from whoever originally distributed
this archive, not part of the mudlib at all — ignored entirely, only
raw/socket/yxcs/ was copied into work/.
13,452 raw files / 11,995 .lpc after conversion — a normal-to-large-sized
lib, well below the "mega-lib" bracket (AGENTS.md §6b) that would call for
skipping the full lpcc sweep.
Lineage
A genuine hybrid of two lineages already seen elsewhere in this project, not a clean match to either:
adm/simul_efun/chinesed.c-equivalent (adm/daemons/chinesed.lpc) credits "by Annihilator@ES ... modified by Xiang@XKX ... modified by Securityd" — the ES/XKX ("ES II") lineage credit chain shared withes1_win/esI/xkx2001/rzrmud/xo/bmxkx2001/kxkj/yueyingqiyuan/wuhanzhan.feature/dbase.lpc,adm/daemons/named.lpc, andinclude/globals.h(// for 1.YXCS mudlib, by lonely) all credit "Lonely" — the same author as the "NT/nitan/Lonely" lineage (nitan170911/nitan6/nitan_ceshi/nitan_san). Confirms via authorship comments what the layout (adm/obj/{master,simul_efun},adm/daemons/,adm/simul_efun/) already suggested: this looks like an ES-derived base that "Lonely" (the nitan-family author) built this specific game on top of, independently of the later nitan/kernel-layout snapshots.- Confirmed the core §15 dbase architecture bug does NOT apply here:
feature/dbase.lpcalready has real, localset/query/delete/add/_tempvariants (not bare simul_efun calls) — this predates or never needed that bug, same conclusion asnitan_ceshi/nitan_san(both earlier/distinct snapshots). No MySQL backend requirement either.
Fixes applied, and why
1. NEW bug class: #define nosave static / #define protected static
guarded by an LPC macro this driver never predefines — silently
converts nearly every nosave function in the lib into static
function (a hard parse error, AGENTS.md §3)
include/globals.h (and identical copies in adm/obj/master.lpc,
adm/obj/simul_efun.lpc, and 4 files under a u/lonely/ backup tree) had:
#ifndef __SENSIBLE_MODIFIERS__
#define nosave static
#define protected static
#endif__SENSIBLE_MODIFIERS__ (double-underscore, LPC-visible) is never
predefined by this driver to LPC code (confirmed: only mentioned in
~/src/fluffos/src/local_options.README as a suggestion, never actually
#define'd anywhere reachable from LPC) — so this #ifndef branch always
fires. Since this driver DOES support nosave as a real (soft-warning-only)
function modifier and rejects static on functions with a hard parse error
(empirically verified: static int foo(){} → hard error, nosave void
foo(){} → soft "Illegal to declare nosave function" warning only), this
macro would have converted the vast majority of this lib's own nosave
function declarations into an immediate, near-universal boot-blocking
parse error.
Caught by luck, then fixed properly: convert_lib.sh's blanket
\bstatic\b → nosave sed (§3's standard fix) also fired on the word
"static" *inside this macro's own replacement text*, turning #define
nosave static into #define nosave nosave — a self-referential macro
that the C preprocessor's "blue paint" rule resolves as a no-op (leaves
nosave as itself), which accidentally neutralized exactly half the
problem. But it also turned #define protected static into #define
protected nosave, silently changing protected's semantics
(DECL_PROTECTED → DECL_NOSAVE) instead of leaving it alone. Verified
protected is a fully legal, real modifier on this driver on its own
(protected int foo(){} compiles clean, no warning) — so the correct fix
is to let BOTH pass through completely unchanged, not alias one to the
other. Rewrote all 7 files' macro block to:
#define nosave nosave
#define protected protectedSpot-checked afterward: grep -rn '\bstatic\b' across the whole work/
tree now only matches my own new comments, confirming no other lingering
static-as-function-modifier collateral.
2. §15h (is_chinese / check_legal_name GBK byte-range bugs)
adm/simul_efun/chinese.lpc'sis_chinese():strlen(str)>=2 && str[0]>160 && str[0]<255→strlen(str)>=1 && str[0]>=0x4e00 && str[0]<=0x9fff(CJK codepoint range, matches every other lib in this project).adm/daemons/logind.lpc'scheck_legal_name(): boundsstrlen(name) < 2 || > 10(byte-count, matching the message's real intent "1 到 5 个 中文字") halved to< 1 || > 5(character-count); dropped thei%2==0 &&guard on the per-characteris_chinese(name[i..<0])loop (was landing on alternating GBK lead-byte offsets, now every index is already one full character).adm/daemons/named.lpc(the classic nitan-familynamed.lpcshape, present here despite the different dbase architecture — genuinely dead code, see below):PATH(name)macro'sname[0..1]("first GBK char") →name[0..0];strlen(name) < 2→< 1(×3 call sites);strlen(name) < 4→< 2; sliding-windowname[i..i+3]/name[i..i+5](4-byte/6-byte = 2-char/3-char windows) →name[i..i+1]/name[i..i+2]; loop boundsi <= l - 4→i <= l - 2,i + 6 <= l→i + 3 <= l. Confirmed dead:NAME_Dmacro is defined inglobals.hbut grepping the entirework/tree finds zero call sites anywhere (NAME_D->...) — fixed anyway as cheap insurance per standing policy, consistent with the identical finding onwmkj(#55).
3. §14 (valid_override needs the 3-arg signature)
adm/obj/master.lpc's valid_override(file, name) upgraded to
valid_override(file, name, main_file), checking both file and
main_file against SIMUL_EFUN_OB/MASTER_OB.
4. §15w (log_error() conflates warnings with real errors)
adm/obj/master.lpc's log_error() unconditionally showed the scary
"编译时段错误:..." message to whatever player happened to be connected
for EVERY compile diagnostic reaching the apply, including harmless soft
warnings (e.g. this driver's own nosave-function warning, #pragma
warnings, unused-variable warnings — all very common in this lib). Gated
the player-facing write on strsrch(message, "warning:") == -1, matching
the wuhanzhan (#58) precedent. Everything still logged to the log file
regardless.
Confirmed NOT needed: error_handler() already unconditionally does
efun::write_file(LOG_DIR + "debug.log", standard_trace(...)) at the end
of its own body (no "falls through automatically" assumption relying on a
non-existent return-value path) — the §15w "add a permanent
RUNTIME_ERRORS insurance write" follow-up wasn't needed here.
5. NEW: #8e (tail) — fatal here since it's inside the composed
simul_efun compilation unit
adm/simul_efun/file.lpc's tail(string file) called efun::tail(file)
— never a real FluffOS efun. Reimplemented in plain LPC (read_file +
explode on \n + slice last 20 lines + write), same pattern as every
other lib. Also fixed an identical copy in u/lonely/sec/file.lpc (an
unused wizard-homedir backup copy, not on the live compile path, fixed for
consistency). Confirmed dead/rarely-used admin tooling — no live callers
found anywhere in the tree.
6. §15s (tell_room()'s bare message() 4th-arg bug)
adm/simul_efun/message.lpc's varargs void tell_room(mixed ob, string
str, object *exclude) { if(ob) message("tell_room", str, ob, exclude); }
— when called in the common 2-arg form, exclude defaults to bare int
0, which this driver's message() (4th arg typed void | object |
object *) can reject. Fixed to exclude || ({}).
7. §11-style copy-paste bug: clone/weapon/panguanbi.lpc
inherit PEN; / init_pen(25) — PEN was never a defined macro anywhere
(PIN exists, a *different* weapon type meaning "针"/needle) and
init_pen() was never a real function. The item's own content (id
"panguanbi", long description "这是一柄普通的精钢剑" — "an ordinary fine
steel sword") plus a working sibling copy at
/d/obj/weapon/sword/panguanbi.lpc (correctly inherit SWORD;
init_sword(20);) confirm this was a copy-paste-and-half-rename artifact.
Fixed to inherit SWORD; ... init_sword(25); (kept the original numeric
argument).
8. §8g-style missing #defines: SSERVER, F_NOCLONE
Two bare macros used by inherit SSERVER; (5 skill files) and inherit
F_NOCLONE; (4 boss-NPC files under kungfu/class/ultra/ — 南海神尼/黄裳/
独孤/葵花太监, all major named Jin Yong characters) were never #define'd
anywhere, a hard parse error (inherit <undefined identifier> parses as
"expecting L_STRING", not silently OK). Both had an obvious, already-
existing target to alias to rather than fabricate:
SSERVER→F_SSERVER(/feature/sserver.lpc), which already exists and has the exact sameoffensive_target()helper as the un-prefixed- macro's actual target file/inherit/sserver.lpc.F_NOCLONE→F_UNIQUE(/feature/unique.lpc) — confirmed via other sibling boss NPCs in the same lib (kungfu/class/mingjiao/yintianzheng .lpc,fanyao.lpc) using the IDENTICAL shape (inherit NPC; inherit F_MASTER; inherit F_UNIQUE;) for exactly the same "only one instance of this boss may exist" purpose that "NOCLONE" implies. Nonoclone.lpcfile exists anywhere in the archive to restore faithfully — aliasing to the already-proven-working sibling mechanism was the correct call per AGENTS.md §11's own guidance ("don't try to implement the missing base class from scratch").
Follow-on: the 4 F_NOCLONE boss files each call a bare check_clone()
explicitly from their OWN create() (which fully overrides
feature/unique.lpc's own automatic-on-create uniqueness check without
ever calling ::create()), so the automatic check never actually ran for
them. Added check_clone() to feature/unique.lpc itself (same body as
its own create()), which — since it's inherited via the new
F_NOCLONE→F_UNIQUE alias — became available to all 4 files at once.
9. §15b (never-defined-but-called globals): add_light, keep_heart_beat
add_light(object, int)— called from ~14 sites (mostlyd/temple/*roomcreate()s, plus one skill file) for a room/object lighting cosmetic effect that was never implemented anywhere in the archive (not even in a.bak). Restored as a no-op simul_efun stub (adm/simul_efun/ object.lpc) — a documented, safe compromise (same spirit as the project'sdb_affected()precedent), since there's no reference implementation to restore faithfully and none of the affected rooms are on the registration/critical path.keep_heart_beat()(bare, no args) — called from 3 NPC generator files (girl.lpc/killed.lpc/receiver.lpc, ×2 each incl.u/lonely/backup copies). Clearly an alias for the realset_heart_beat(1)call used identically elsewhere in this same lib (feature/attack.lpc,feature/damage.lpc,feature/action.lpc). Restored asvoid keep_heart_beat() { efun::set_heart_beat(1); }.
10. NEW: whole "competitor" (international-challenger event) subsystem
silently dropped from feature/attack.lpc
feature/attack.lpc had a .bak sibling (feature/attack.bak, 555 lines
vs the live file's 342) — diffing them showed the ENTIRE competitor
variable + query_competitor()/set_competitor()/competition_with()/
win()/lost() subsystem existed in the backup but had been completely
removed from the live file, while 9+ other files (kungfu/class/generate/
challenger|indian|european|japanese|japanese1.lpc + u/lonely/ copies,
adm/daemons/story/challenge.lpc, inherit/char/challenger.lpc,
u/lonely/obj/user/quit.lpc) still call it — a real, wide-reaching
"only ever called, never defined" gap (§15b), not a typo. Restored
verbatim from attack.bak (not a guess) into feature/attack.lpc:
the competitor variable + query_competitor()/set_competitor() near
the top (no forward-call issue), and competition_with()/win()/lost()
moved to just AFTER fight_ob()'s own definition later in the file — per
§8b, these three call fight_ob()/run_override() and calling a
same-file function before its definition fails to resolve on this driver;
the backup's original ordering (which put all 5 functions in one place,
before fight_ob()) would have hit exactly that. This was the single
highest-impact fix in this pass by file count (resolved compile errors
across the whole challenger-NPC family in one shot).
Follow-on fix needed once query_competitor resolved: inherit/char/
challenger.lpc's own competition_with() override had killertemp=ob;
with no local declaration anywhere in the function — a genuine
pre-existing typo (not something the restore introduced). Every sibling
file using the identical killertemp=ob; idiom elsewhere in this lib
(japanese.lpc, questguai.lpc, chinese.lpc) declares it as a plain
local object; matched here (object killertemp; added to the function).
11. Pre-existing content typos fixed via the lpcc sweep
kungfu/skill/guxing-sword.lpcAND its duplicatekungfu/skill/ fengxiao-xinfa/guxing-sword.lpc:"...星光瞬闪+NOR+"」..."— missing closing quote before string concatenation (§10's exact pattern), fixed to"...星光瞬闪"+NOR+"」...".d/shushan/zhenyaota/npc/yaoguai4.lpc: atell_object()call split across two lines with a stray leading"on the continuation line ("点武学"+then"+chinese_number(...)— extra quote), fixed by removing the stray quote.- 3 orphaned non-LPC
.c→.lpc-renamed files (§12's exact pattern):u/ken/{11,bb1,test1}.lpcwere plain Chinese test/scratch NOTES ("大家 好,这是一个测试" / "我用来测试乱码的" — "hello, this is a test" / "I use this to test garbled text"), not LPC code at all. Confirmed nothing references them; renamed to.orphaned-text.
Confirmed NOT needed (and how confirmed)
- §4 (master's lazy
load_object()-during-compile recursion invalid_read/valid_write): readadm/obj/master.lpc— both applies only everfind_object(SECURITY_D), neverload_object(). Not present. - §7 (
get_root_uid/get_bb_uid): both already implemented inmaster.lpc, returningROOT_UID/BACKBONE_UID. - §8c/§15n (
this_player()-override footgun / custom securityd ACL blocking mid-connection lazy compiles):securityd.lpc'svalid_writecorrectly substitutesprevious_object()(the real calling object), notthis_player(), as the identity to check — read the whole file, nothis_player()-clobbering pattern present.valid_readdoesn't gate on connected-player status at all except forsecurityd.lpc/security%self-protection, so a fresh unauthenticated connection's lazy compiles are never denied. Confirmed empirically too: the live registration test exercised several never-preloaded lazy compiles (feature/attack,feature/command,feature/damage,feature/message,feature/move,feature/name,feature/skill, severald/register/npc/*files) with zero "Read access denied"/"access denied" anywhere indebug.log. - §15o (missing
get_include_path()breaking mid-connection#includes): all the angle-bracket local headers checked (dbase.h,weapon.h,name.h) genuinely live in/include/(the configured global include path), not next to their including file — noget_include_path()needed, and confirmed via the same live-registration test above (multiple lazily-compiledfeature/*files, zero#includeerrors). - §15l (
master.lpc create()destructingSIMUL_EFUN_OB): readcreate()— just awrite()line, nodestruct()call anywhere. - §15p (DNS/intermud daemon in preload):
adm/etc/preloadalready had#/adm/daemons/network/dns_mastercommented out in the raw archive itself — nothing to exclude. - §15m (unguarded
restore()crashing a daemon'screate()):chinesed.lpc/emoted.lpc/adversed.lpcall call barerestore()increate()with nocatch(), but the actual boot produced zeroIllegal mapping format/restore-related errors indebug.log— no stale/corrupted save data shipped for any of the 3. - §15u (dormant phone-home/anti-piracy destructive function): grepped
adm/daemons/*.lpcforrm/shutdown/mass-delete patterns gated on opaque checks — every hit (profiled.lpcresetting its own profile file,versiond.lpc's legitimate periodic-reboot-on-sync-failure,natured.lpc's guild-data cleanup) is ordinary admin/maintenance logic, nothing resembling a licensing gate. - is_killing() type-mismatch family (the exact shape that broke the player-body class on
nitan_ceshi):feature/attack.lpcdeclaresvarargs int is_killing(object ob)and IS called directly with a string arg (is_killing(ob->query("id"))) at 2 call sites in the same file — a real type mismatch on paper, but the live boot (inherit/char/ char.lpcsuccessfully compilingfeature/attackwith zero errors, and the registration test reaching the game world) confirms this driver does NOT enforce it as a hard error here (likely because the parameter is inside avarargsdeclaration) — not a live bug, left alone. .c→.lpcrename-width bug (nitan-family[0..<3]extension-strip variant): grepped for\[0\.\.<3\]/\[0\.\.<4\]near.lpc/.cfilename contexts — zero hits; the handful of[0..<2]slices found elsewhere (channeld.lpc,versiond.lpc,configd.lpc,commandd.lpc) are unrelated string-trimming, not extension-stripping.- §8f (
TYPE * name1, name2;comma-list array-modifier bug): many candidate lines exist (mixed *name,value;etc.) but this is a speculative pattern only worth fixing when it actually produces a "Bad assignment (TYPE vs TYPE*)" compile error (per §15f's own "don't bulk-fix speculatively" guidance) — the boot and lpcc sweep produced zero such errors, so left untouched. - §15f (bare
arraytype declaration): zero occurrences found via grep.
Known residual issues (documented, not fixed — non-critical content)
- 3 files with a silent, non-diagnostic "Fail to load object" after the competitor-subsystem restore:
kungfu/class/generate/indian.lpc,european.lpc,japanese1.lpc(all "international challenger" event NPCs). Their own compile produces zero error/warning text at all, yetlpccstill reports the load as failed. Ruled out: missing macros (none), missing content (all referenced items —seng-cloth, etc. — exist on disk), a shared inherited-file problem (a sibling file in the same directory,chinese.lpc, compiles clean). Given these are deep, never-preloaded quest-event NPCs with no bearing on registration/core gameplay, and per AGENTS.md §6b's own guidance that isolated single-filelpccruns (no player, no room graph) are a recognized source of false-shaped failures, this was left as a documented gap rather than chased further. diary_write(ob, msg)— called from exactly one file (d/taoyuan/npc/hongniang.lpc, a wedding-officiant NPC) via#include <diary_write.h>, which doesn't exist anywhere in the archive. No reference implementation exists to restore faithfully (unlikeadd_light, this isn't obviously a no-op-safe cosmetic — it's a named "diary" feature with unknown intended behavior) — left as a documented content gap, single file, non-critical.- **
temp/ken*/temp/lonely*scratch files** (9 of 35 fail): these are ephemeral one-linemixed temp(object ob){return me->query(...);}-style snippets, artifacts of wizards using an in-gameeval-style debug command that happened to get captured into the archive — not real content, expected noise. - A handful of deep skill-file syntax errors (
kungfu/skill/wushuang- sword.lpc,club-sword.lpc,wulainizou-unarmed.lpc, and similar) remain from genuinely malformed pre-existing code (mismatched parens/braces predating this conversion) — none reachable from registration; left as-is per the project's stated "breadth over depth" policy for the remaining long tail.
Registration flow
Read adm/daemons/logind.lpc's actual callback chain before testing (per
AGENTS.md's standing warning about hidden pre-id prompts): logon() prints
a "Select 国标码 GB or 繁体 BIG5 (gb/big5):" line, but this is a soft
prompt, not a gate — input_to(get_id, ...) fires next regardless, and
get_id() only special-cases the literal input "big5" (sets a flag and
re-shows the whole banner+prompt); ANY other input (including a normal
English id) falls straight through to the real id-validation logic. So the
very first --send can just be the real login id directly, no separate
blank/gb answer needed.
Full chain confirmed by reading the source: get_id → (existing user)
get_passwd or (new user) confirm_id (y/n) → get_name (Chinese
name, no separate y/n confirmation when a real name is typed — only
random-name generation goes through get_resp) → new_password →
confirm_password → gift-attribute selection (select_gift
0-4/set_gift/get_gift y/n) → get_email → get_gender (m/f) →
make_body()/init_new_player()/enter_world().
Verified twice, in two separate continuous mudclient.py sessions
(before AND after restarting the driver to pick up the feature/
attack.lpc competitor-subsystem restore, to make sure that change didn't
regress the core player-body class every character depends on):
1. qinfeng → y → 秦风 → test12345 → test12345 → 0 → y →
[email protected] → m → look → quit
2. linfeng → y → 林风 → test12345 → test12345 → 0 → y →
[email protected] → f → look → quit
Both runs: Chinese name accepted with no rejection, no separate
confirmation prompt (matches the source), gift/email/gender flow completed
normally, and the character landed in an actual room ("世外桃源" / Peach
Blossom Spring — the real starting room, not a void/error state), with a
correct room description, exits, NPCs (水笙/狄云) listed, and the news
system firing normally. A third quick test confirmed the *existing-user*
path (re-entering linfeng) correctly routes to a password prompt instead
of character creation, and 3 wrong-password attempts correctly disconnect
with the expected message. debug.log was clean of any
error/access-denied/crash lines across all three sessions (only the usual
first-boot *Warning: unable to open stat file domain_stats/author_stats
lines, and ordinary compile warnings — no 执行时段错误, no
Segmentation, no Fail to load, no access denied).
lpcc sweep
Ran twice (once before the deeper §15b/copy-paste-content fixes, once after, to measure improvement): 11995 total files both times.
- 1st pass (after mechanical fixes + §15h/§14/§15w/§8e/§15s/panguanbi/ SSERVER+F_NOCLONE fixes): 11737 pass / 258 fail (97.8%).
- 2nd pass (after restoring the whole
feature/attack.lpccompetitor subsystem +add_light/keep_heart_beatstubs): 11760 pass / 235 fail (98.0%). - A few more fixes landed just after the 2nd sweep finished (2×
guxing- sword.lpcmissing-quote typo,yaoguai4.lpcstray-quote typo, 3 orphaned scratch files renamed away from.lpc) — not re-swept a third time given diminishing returns, but each was individually re-verified clean via a direct single-filelpcccheck. Effective current pass rate is slightly above 98.0%.
Memory stayed healthy throughout both sweeps on this 23GB host (never dropped below ~16GB available, well clear of the OOM risk threshold in AGENTS.md §6b) despite a concurrent agent running another lib's sweep at the same time.
Process notes
- Driver launched via
run_in_background: true(Bash tool), never a barenohup ... &. Killed by exact PID only (never apkill -fpattern) — confirmed via/proc/<pid>/cwdbefore every kill, since another agent's driver process shares the identicaldriver config.fluffoscommand line and was running concurrently for most of this session (libs/haiyang2, laterlibs/yanhuangwuhun). - Restarted the driver once mid-session (after the
feature/attack.lpccompetitor-subsystem restore) specifically to verify that change didn't regress the player body class, per the standing reminder that LPC objects don't recompile just because the source file changed on disk.
Re-verification pass: driver rebuild + formatter + WASM (2026-07)
- LPC formatter applied to all
.lpcunderwork/(11,992 total, 11,796 written, 42 unchanged, 154 self-checked errors left untouched as expected on legacy code). Reformatted files includedata/area.lpc(a data file authored as LPC array literal) — cosmetic only, verified no content change beyond whitespace. - Native re-test against the freshly rebuilt driver (
~/src/fluffos/build-debug/src/driver, rebuilt from latest upstream master): clean boot, zero real errors indebug.log. Full registration flow re-verified end-to-end with a fresh real Chinese name (秦风测/qftest) through the gift-attribute/email/gender flow, landing in 世外桃源, withlook/score/quitall producing correct output — confirms all the prior fixes (the#define nosave nosave/protected protectedmacro rewrite, §15h, §14, §15w, §8etail(), §15s, the restoredfeature/attack.lpccompetitor subsystem, etc.) survived the reformat and the new driver build intact. - WASM test (
scripts/wasm_client.jsagainstbuild-wasm/src): boots cleanly, zero fatal/undefined-function errors. Registration is blocked under WASM by the knownquery_ip_number()limitation:adm/daemons/logind.lpc'slogon()callsBAN_D->is_banned(str)wherestr = query_ip_number(ob);band.lpc'sis_banned()doesif (!site) return 1;thenif (sscanf(site, "%s.%s.%s.%s", ...) != 4) return 1;— under WASMquery_ip_number()doesn't return a real dotted-quad, sois_banned()returns 1 ("banned") and every connection is destructed at the very firstlogon()call with "本站正在进行内部调整..." before ever reaching the id/name prompt. Confirmed this is the documented driver-side WASM limitation (not a mudlib bug) — the exact same lib boots and completes full registration cleanly natively (see above). Not patched, per standing instruction. (Superseded by the 2026-07 WASM-enablement pass below — now patched.)
WASM-enablement pass (2026-07): loopback gates + admin seeding
Standard pass per AGENTS.md §1.3b/§1.3e/§1.5:
adm/daemons/band.lpc: newis_local_site(site)helper (loopback / empty / malformed IP ⇒ local).is_banned()short-circuits to 0 for local sites (this was THE WASM login blocker documented in the earlier re-verification pass: malformed WASM IP ⇒ "banned" ⇒ instant destruct).vaild_allow_address()(per-account allow-ip lock) returns 1 for loopback.adm/daemons/logind.lpc:
- logon(): ban_cnt > 12 per-IP pending-connection cap — loopback
exempt.
- get_id(): the netclub/public-ip per-IP multi-login caps
(ip_cnt > 12 / > 4) — loopback exempt.
- get_passwd(): 30-second "你刚退出游戏" relogin load throttle —
loopback exempt (the 600s kickout penalty is punishment/game design,
kept). Also removed a leftover debug printf("%O\n", ob) in
get_name() that printed /clone/user/login#N at every new player.
- No
uptime()startup-grace gate exists in this lib (only cosmetic uptime uses in check_cpu/uptime display) — nothing to bypass. - Admin seeded:
fluffos/Mud@2026/ 浮浮, rank(boss)viaadm/etc/wizlist. Lineage quirk discovered:feature/dbase.lpc'sset()has an anti-steal-power gate ("Add by Lonely") that silently refusesset("password", ...)on any object whose id has(boss)wizhood unless this_player()'s euid IS that id — so registering an id that is ALREADY in the wizlist as (boss) dead-loops at the password step (confirm always mismatches against old=0). Correct order: register as a plain player first, then addfluffos (boss)to the wizlist and restart. Verified after restart: login banner shows 权限〖巫师协会懂事〗(boss),update /d/register/entry.lpcsucceeds. - Retest: fresh normal registration (
regtest/秦风测) end-to-end into 世外桃源, look/score/quit fine; test saves removed. debug.log clean except one pre-existing content bug surfaced by updating /d/city/wumiao.lpc:/d/city2/npc/wizer.lpc:22callsexert_function(10)(string-typed param, hard compile error) — a genuine pre-existing content bug unrelated to this pass, room loads fine at boot (NPC clone fails only when wumiao is recompiled), left documented. Runtime churn (u/lonely/logcompile-warning append) reverted viagit show HEAD:.
WASM long-sit boot-watch pass (2026-07)
200s scripts/wasm_boot_watch.sh sit: completely clean, zero grep hits
beyond the known-benign early Unable to open log file:
"log/debug.log" line — no new findings, no fix needed. (This lib's own
adm/simul_efun/object.lpc file_owner() uses a different, already-
correct 2-arg sscanf(file, "/u/%s/%s", name, rest) shape that doesn't
have the 3-arg misattribution bug found live on sibling zhonghua2 and
ported to 7 other libs in this batch — checked and confirmed fine,
nothing to port here.)
WASM 修复摘要(迁移自 meta.json 的 group_note)
状态已从过时的 limited 修正——这份档案自己的 README 和 group_note 里从未记录过任何缺陷说明,本轮重新测试也没有发现:管理员登录(fluffos/Mud@2026)干净正常,权限已通过这份档案自己的最高阶层字符串确认('★ 您目前权限:〖 巫师协会懂事 〗(boss)'),quit 正常。
§7.86 跨库扫描修复(留言板 post 崩溃)
BULLETIN_BOARDinherit+ 多余replace_program()致命形状(AGENTS.md §7.86,post命令崩溃):全档案 115 处命中,已删除多余的replace_program(...)调用(保留inherit),逐文件保留原有行尾格式(CRLF/LF 按文件原样)。本次为跨库 §7.86 扫描修复(触发原因:该 bug 已在 6+ 个互不相关的血统家族独立确认,属于近乎普遍的拷贝粘贴模式),仅做编译检查(驱动干净启动、端口正常监听),未做完整 §10.7 深度游玩测试。
深度功能测试 / Deep functional test (AGENTS.md §10.7)
Read doc/help/newbie in full first (5-part in-game newbie guide, credited
"By 黑客(lonely)"): covers stat-roll ranges, personality/character choice
(光明磊落/狡黠多变/心狠手辣/阴险奸诈, each with a mechanical effect),
sect recommendations by weapon type, and a Q&A section explicitly naming
gc e n + learn zhu literate as the free literacy-training route (gc
= 扬州中央广场).
NEW bug found and fixed: every single connection crashed inside logon(), before the id prompt, on a genuinely fresh checkout
First boot attempt (driver launched clean from libs/yxcs, port up in
~1s) produced, for every connection attempt: new_conn_handler: logon()
on object clone/user/login#N has failed, the user is disconnected in
the driver's own debug.log — a total, silent connection block with
zero player-visible banner text (matches the exact symptom class in
AGENTS.md §7.9/§7.11: the driver's own crash-summary line carries no
LPC stack trace).
Root cause, found via the second, LPC-level debug.log
(work/log/debug.log, written by error_handler()'s own
write_file(LOG_DIR "debug.log", ...) — see the log_error()
discussion above; check BOTH log locations per AGENTS.md's standing
instruction, this bug was invisible in the first one):
执行时段错误:*Wrong permissions for opening file /log/file/cat_file for append.
"No such file or directory"
呼叫来自:/clone/user/login.lpc 的 logon() 第 7 行
呼叫来自:/adm/daemons/logind.lpc 的 logon() 第 115 行
呼叫来自:/adm/obj/simul_efun.lpc 的 cat() 第 291 行
呼叫来自:/adm/obj/simul_efun.lpc 的 log_file() 第 11 行adm/daemons/logind.lpc's logon() — the very first thing every new
connection's login.lpc calls — does cat(WELCOME) to print the login
banner. adm/simul_efun/file.lpc's cat() unconditionally calls
log_file("file/cat_file", ...) as its own audit-log side effect
*before* actually printing anything, and log_file() itself was a bare
write_file(LOG_DIR + file, text) with no directory guard at all —
a fresh checkout never ships work/log/file/, so the write throws, the
throw is never caught anywhere in the logon() call chain, and the
entire apply aborts before the banner (or the id prompt after it) ever
gets sent to the connecting socket. This is a new confirmed instance of
AGENTS.md §7.11 ("missing runtime directories and the silent
write_file abort") — same shape as the xajhxo precedent
(log_login() → uncaught log_file() write into a never-shipped
directory, killing registration one step earlier than the visible
symptom), except here it fires on every connection, not just at one
step of character creation, because cat(WELCOME) sits at the very top
of logon() itself.
Fix: patched log_file() itself (adm/simul_efun/file.lpc), not
just the one call site, since it's a shared simul_efun used by dozens of
call sites across the whole tree — added the missing assure_file()
guard (this file already has its own assure_file() helper, same
pattern as the xajhxo fix; needed a one-line forward declaration since
assure_file() is defined later in the same file and this compiler
doesn't resolve same-file forward references without one):
void assure_file(string file);
void log_file(string file, string text) {
assure_file(LOG_DIR + file);
write_file(LOG_DIR + file, text);
}Verified: killed the driver, restarted clean, reconnected —
work/log/file/cat_file now gets created on first write, banner prints,
id prompt reached, zero logon() ... has failed lines in either
debug.log for the rest of the session.
Also required (pure operational setup, not a code bug, but a
fresh-checkout prerequisite worth recording): the archive shipped with
neither libs/yxcs/log/ (the driver's own real debug.log, §5.2 —
CWD-relative, not mudlib-relative) nor work/log/ (the mudlib-virtual
LOG_DIR target used by the LPC code above) on disk at all. mkdir -p
log work/log/nosave work/log/wiz before boot; without it, debug.log
itself never gets written (silent, not even the crash-summary line makes
it to disk) and log_error()'s own write additionally throws during
preload compile-warning logging (self-healing since it's already inside
preload()'s outer catch(), but pollutes preload output).
Defensive fix applied alongside (not confirmed as a live crash this
pass, but matches the exact AGENTS.md §7.9 shape and the underlying data
files are explicitly gitignored — libs/*/work/adm/daemons/iduser /
.../users, per this project's own .gitignore comment "user-id
counters... not meaningful shipped content"): logind.lpc's logon()
did i_user = atoi(read_file(__DIR__"users", 1)) (and the same shape
for iduser and maxonline) with no stringp() guard — on a fresh
checkout where those counter files don't exist yet, read_file()
returns int 0, and atoi() on a non-string argument is exactly the
§7.9 "fresh-checkout crash bomb" pattern. Guarded all three with
stringp(...) ? atoi(...) : 0. (maxonline already existed on this
checkout so this one wasn't empirically confirmed as live here, but
users/iduser were both genuinely absent and this guard is cheap
insurance regardless of which exact site would have thrown first.)
Registration — real Chinese name, full flow
Continuous session via a small custom Python telnet-IAC-stripping client
in tmux (this environment has no telnet or nc-with-negotiation
binary available, so scripts/tmux_mud.sh — which shells out to
telnet — doesn't work here; wrote a ~90-line drop-in replacement using
the same IAC-strip logic as scripts/mudclient.py, kept in the
scratchpad, not committed).
qinfengb (rejected once first as qftest2 — digits not allowed, "你的
英文名字只能用英文字母") → y → 秦风波 (real Chinese name, accepted
immediately, no separate confirmation prompt — matches the logind.lpc
source read in the earlier pass) → test12345 ×2 → gift-attribute 0
(random) → y → [email protected] → m → landed in 世外桃源
(/d/register/entry), correct room description, water笙/狄云 present,
news system fired. look/score/i all correct at this state.
Then the personality-choice sub-flow (not covered by the earlier
registration-only pass): east → 陆天抒 (光明磊落 branch) → out →
「阎罗殿」(reincarnation hall, 地藏王) → born 扬州人氏 → landed in
/d/city/kedian ("有间客栈"). score afterward correctly shows
性格:光明磊落, correct stats, food/water bars full (§8.9 pattern:
confirmed NOT present here, bars start full).
Combat — safe sparring via the training-dummy stat-mirror pattern
cmds/std/fight.lpc's actual logic read first (per AGENTS.md's standing
warning against assuming a "safe" NPC without checking the real
accept_fight gate): a can_speak-having NPC's accept_fight(me) must
return 1 for fight to proceed. d/shaolin/npc/mu-ren.lpc (and an
apparently-orphaned identical copy at d/city/npc/mu-ren.lpc — see
"observations" below) matches the exact §10.7-documented dummy shape:
set("no_die", 1), and accept_fight() deletes its own skills/stats
and copies the attacker's own skill map + str/int/con/dex/qi/jing/neili
onto itself before the fight starts (a genuine mirror match, not a
scripted-weak opponent). Admin-cloned one into the player's current room
(clone /d/shaolin/npc/mu-ren) since none of this lib's dummy instances
happen to be placed along the 世外桃源→扬州 walking path used above.
fight mu ren in a no_fight-clear outdoor room ran a full multi-round
exchange (both sides landing and missing hits, HP-state narration
escalating normally) and resolved with the player conceding
("这场比试算我输了,佩服,佩服!") — no crash, no stuck state,
score/look immediately afterward both correct.
Skill acquisition — organic path AND admin shortcut, both verified
Organic: per the newbie doc's own "gc e n" hint and the board
item_desc text in d/city/shuyuan.lpc ("学文化的格式是 learn zhu
literate!"), gave money to 朱丹臣 (d/city/npc/zhu.lpc, aliased zhu)
via give 10 silver to zhu (money supplied by admin clone
/clone/money/silver 20 + give, since a level-14 newbie starts with no
cash) → NPC's own accept_object() credited a mark/朱 balance → learn
zhu literate → "你听了朱丹臣的指导,似乎有些心得。你的「读书写字」
进步了!" — real accept-logic path, no shortcut, works end to end.
Admin shortcut: cmds/wiz/copyskill.lpc (copyskill <target>) —
copies a target's entire skill map + skill_prepare + combat stats onto
the caller. Ran copyskill qinfengb from the admin account: "你口中念
念有词,只见一道红光笼罩了你和秦风波。" — no dedicated single-skill
grant command exists in cmds/wiz/ (checked the whole directory; the
closest is this bulk stat/skill copy), documented honestly rather than
assumed.
quit, debug.log, reconnect after a real gap
No new-account quit-deletes-account grace period found in this lineage
(unlike the nitan family): logind.lpc's registration chain only calls
ob->save()/user->save() once, inside enter_world(), at the very
end of the full flow (after gender selection) — by the time a player can
even type quit, the account is already durably saved, so there is no
partial-registration window to worry about. cmds/usr/quit.lpc read in
full: no lockout for wizardp(), and for non-wizards a pker_starttime
window is punitive-PK-cooldown design, not a fresh-account grace period.
quit from 「东大街」 (outdoors, mid-conversation with 朱丹臣): dropped
one worthless Cloth item as expected content-consistency (§7-adjacent
but plainly intentional — "因为这样东西并不值钱,所以人们并不会注意到
它的存在" is a normal drop-message, not an error), printed "欢迎下次再
来!", connection closed cleanly. Both debug.log (driver-level) and
work/log/debug.log (LPC-level) checked immediately after — zero new
error/crash/access-denied lines beyond the already-documented,
pre-existing d/city2/npc/wizer.lpc:22 exert_function() type-mismatch
content bug (unrelated to this session, confirmed via grep this bug's
own earlier pre-existing note in this same file).
Used the post-quit interval productively (reverted incidental resave
noise on data/{login,user}/f/fluffos.o, spot-checked earlier
prior-pass fixes — the nosave nosave/protected protected macro
rewrite, F_NOCLONE→F_UNIQUE, SSERVER→F_SSERVER — all still
intact, grepped 6 sibling same-lineage libs for the same
log_file()-missing-assure_file() shape found above (see "cross-lib
observation" below), and drafted this NOTES.md section) — then
registered a second throwaway character, persisttest/李持久
(female, so the §8.9-adjacent gender-conditional init_new_player()
money/combat_exp bonus path got exercised too), specifically to redo
the persistence check cleanly (the first attempt, on qinfengb, was
invalidated by deleting its own .o save files as part of the
resave-noise cleanup *before* actually reconnecting to confirm — logged
that mistake so a future pass doesn't repeat it: do the persistence
reconnect BEFORE any save-file cleanup, not after).
persisttest quited from 世外桃源, then reconnected after a genuine
~1-2 minute additional wall-clock gap (on top of the several minutes
already spent on the interval work above) via a fresh telnet
session (real disconnect+reconnect, not a resumed connection):
banner printed clean, persisttest + password → recognized as an
existing account (no "creates a new person" prompt this time,
confirming the id correctly round-tripped through save/reload) →
"☆ 您现在是第 二 次光临浴血重生" / "☆ 您上次连线的地址是 127.0.0.1" /
"☆ 您上次退出本游戏的时间是:[ 2026年8月7日21点36分 ]" (matches the
exact prior quit time) → score showed the exact same character:
中文姓名 李持久, 性别 女性, stats 膂力25/悟性22/根骨18/身法15 (the exact
roll accepted at registration), 钱庄存款 二十两白银 and 实战经验 50
(both from the female-branch init_new_player() bonus, confirming
user->save()/reload round-trips that data correctly too). Full state
persistence confirmed. quited again cleanly, debug.log/work/log/
debug.log both still clean (same pre-existing wizer.lpc content bug
only, no new errors).
发现但判定为既有设计、未改动的现象
d/city/shuyuan.lpc'svalid_leave()deliberately blocks non-wizard players from goingnorthintoshuyuan2("那是朱熹的 私人寝室!!" — explicitnotify_fail, not a broken/accidental gate). The room's own flavorlongdescription ("那就是当今大儒朱先生了") and the newbie doc's "朱熹处给钱" phrasing both point at 朱熹 (zhuxi.lpc, the NPC actually living in the blockedshuyuan2), but the REAL, reachable literacy teacher is 朱丹臣 (zhu.lpc, present in the accessibleshuyuanroom, and the room's own in-gameboarditem spells out the correctlearn zhu literatecommand). This is intentional content design (a padlocked "boss's private room" flavor choice) with slightly misleading flavor text/doc-vs-actual-NPC mismatch — a content/documentation nit, not a programming bug; left untouched.d/city/npc/mu-ren.lpc(a byte-for-byte near-duplicate of the lived/shaolin/npc/mu-ren.lpctraining dummy, differing only inno_get/combat_exp increment) appears to be genuinely unreferenced — grepped the wholework/tree for bothcity/npc/mu-renand a relative__DIR__ "npc/mu-ren"from anyd/city/*.lpcroom and found no call site. Orphaned dead content (a leftover duplicate from map development), not wired into any room'sobjectsmapping; harmless, left as-is.
Cross-lib observation (not fixed this pass — out of scope, yxcs-only pass)
The log_file()-missing-assure_file() shape fixed above in
adm/simul_efun/file.lpc is present, unfixed, in every other checked
sibling of this lib's ES/XKX lineage (§11): xkx2001, rzrmud,
bmxkx2001, kxkj, yueyingqiyuan, wuhanzhan all ship the identical
unguarded void log_file(string file, string text) {
write_file(LOG_DIR + file, text); }. Whether any of them actually hits
the crash live depends on whether their own logon()/registration chain
routes through an equivalent cat()-audit-log or other log_file()
call before the id prompt (not checked here — that's each lib's own
§10.7 pass to make). Flagging for whichever future dive picks one of
these up: check work/log/debug.log (not just the driver's own
debug.log) for a Wrong permissions ... for append trace through
log_file() before assuming registration is clean.
§9 formatter
Ran format-corpus.mjs on both edited files (adm/daemons/logind.lpc,
adm/simul_efun/file.lpc) — both reformatted clean, 0 errors. Checked
all 3 documented blind spots: grep -rnE ':\s:\s*[a-zA-Z_]+\(' — zero
hits in either file; no case-label lines touched by either diff (no
manual diff-review needed); grep -rl '\\ n' — zero hits in either
file. Re-booted and re-tested the full flow above against the
reformatted files (this NOTES entry's own registration/combat/skill/quit
walkthrough was run AFTER formatting, not before).
WASM 未验证说明
Per this project's build state this pass: WASM build permanently
blocked (emsdk hardcodes storage.googleapis.com, denied by the
proxy — confirmed via curl -sS $HTTPS_PROXY/__agentproxy/status). The
fixes above (both the new log_file()/assure_file() fix and the
logind.lpc counter-file guard) are pure LPC-level runtime-error
guards with no WASM-specific code path — expected to apply identically
under WASM once a build becomes available, but genuinely unverified
under WASM this pass; the earlier WASM-enablement pass's own findings
(loopback ban-bypass, admin seeding) are untouched and still apply.
深度功能测试(2026-08-13,round two,新驱动重测)
针对驱动升级(quest_times/win_times %-operator 修复 + Warning/warning
大小写回退兼容)做的重测。核对上面记录的所有修复(新连线 logon()
崩溃、log_file()、counter-file 防护、宏重写等)逐项确认代码仍然
生效;win_times 的 %-operator 也已用
to_int(query("win_times")) % 5(d/city2/npc/refereew.lpc:146、
d/taoyuan/npc/{jinyong,gulong}.lpc)。
本轮新发现并修复的 PROGRAMMING bug(上一轮 §10.7 深挖未覆盖到)
1. feature/dbase.lpc 的 set() 密码写保护是 tybxjh/wlhd 那一类
已确认的 bug 形状:if (prop == "password") if
(wizhood(this_object()->query("id")) == "(boss)") if
(this_player()) if (geteuid(this_player()) !=
this_object()->query("id")) return;——注释明确写着"Add by
Lonely to fix a steal-power bug",本意是防止别人冒充覆盖既有
(boss) 级账号的密码,但 wizhood() 纯粹读 wizlist 文件,不检
查 dbase 里是否真的已经存在密码。本轮实测 fluffos 的注册/重
连都正常(这份档案里 this_player() 在密码 set() 那一刻的
euid 恰好已经和目标 id 一致,所以没有触发拦截——和 tybxjh 的具
体触发时机不同,但代码形状完全一致,属于潜在缺陷,不是已经在
本档案上实测复现的活跃崩溃)。按已确立的标准修法加上
mapp(dbase) && dbase[prop],只在密码已经存在时才拦截,不影响
首次创建。
2. §8.9 食物/饮水初始化判断的对象错了——上一轮深挖遗漏:
adm/daemons/logind.lpc 的 enter_world() 里
ob->query("age") == 14(应为 user)。已改成
user->query("age") == 14。
3. get_resp()(系统随机中文名接受分支)一处调试残留
printf("%O\n", ob)(AGENTS.md §7.34-class)——上一轮深挖用的是
手动输入中文名分支,没有触发这条泄漏:紧跟在中文名字确认之
后,把连线桩物件的原始引用直接回显给正在注册的新玩家。已删除;
get_name()(手动输入分支)本来就没有这个残留,核对确认。
实测过程
管理员 fluffos/Mud@2026(此前深挖已注册并提交存档)用真实密码
重新连线两次(先重启驱动应用上面三处修复,再各做一次独立的登录+重
连验证),落地此前保存的地点,score 显示食物/饮水满格。两个
debug.log 位置(驱动级 log/debug.log 和 LPC 级
work/log/debug.log,本档案自己此前记录过必须都查)全程干净,无
运行时错误。驱动按精确 PID 结束;测试期间产生的存档时间戳增量已
git checkout -- 还原。启动前按此前记录的前置条件手动创建了
log/、work/log/{nosave,wiz} 目录(均已确认被 .gitignore 正确
忽略,非代码问题)。
§7.100 修复(ROOM 基类的同一"多余 replace_program()"形状,全档案扫描第 6 批)
- 删除 2,530 处存活的
replace_program(ROOM);相关行,与普查记录一致。 本库有五套独立的建房工具副本,全部命中同一形状:clone/misc/ roommaker.lpc、obj/roommaker.lpc、obj/rmmaker.lpc、u/lonely/obj/roommaker.lpc、u/lonely/obj/roommk.lpc(后两个 "Lonely" 变体各含 3 处room_code/str拼接模板命中)。 - 验证:真实
build-debug驱动干净开机、端口正常监听,debug.log中 零 "cannot replace"/"cannot bind" 行。
``§7.112`` residual-gap closure (2026-08-20)
Corpus re-scan (grep -rl 'call_out("death_stage"' ... | filter for missing guard) found unguarded init()-scheduled death_stage() call_out chain(s) in d/death/npc/bgargoyle.lpc that the original two-wave sweep (see AGENTS.md §7.112) missed -- same reconnect-triggered duplicate-chain bug, different filename/lineage. Added the standard query_temp("death_stage_active")/set_temp/delete_temp re-entry guard, adapted per file's own exit points. Compile-verified via lpcc --batch.
§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-08-24): shop buy and 拜师 sect apprenticeship — the two flows every prior §10.7 pass on this lib had skipped
Audited the full history above and confirmed neither a shop purchase nor
a completed sect apprenticeship had ever been exercised on this lib,
despite the newbie doc's own §3 sect-recommendation text implying a real
system existed. Closed both gaps this pass, via two concurrent
scripts/tmux_mud.sh sessions (admin + a fresh throwaway player
qinmaiwu/秦买物, registered end-to-end same as the original pass) so
the admin could goto <player> + clone/give money without needing
quit-and-restore round-trips.
Shop purchase — found and fixed a real crash bug (vendor.lpc §-class, list/buy at ANY shop with a stale vendor_goods entry)
d/city/zahuopu.lpc (扬州 杂货铺, reachable in 3 moves from the newbie
start room: kedian → west → beidajie1 → south → guangchang → east
→ dongdajie1 → south → zahuopu), NPC 杨永福 (d/city/npc/yang.lpc,
inherit F_VENDOR_SALE). First list command thrown by a real player
crashed outright: 这里发现了BUG,请用SOS告诉巫师。
work/log/debug.log:
执行时段错误:*call_other() couldn't find object '/u/xiha/fd'.
程式:/feature/vendor_sale.lpc 第 149 行
物件: /d/city/npc/yang#294
呼叫来自:/feature/vendor_sale.lpc 的 do_vendor_list() 第 149 行yang.lpc's vendor_goods array lists "/u/xiha/fd" as its first
entry — confirmed via the raw archive (raw/socket/yxcs/u/xiha/ only
ever shipped workroom.c, never an fd.c) that this file never
existed at all, not a casing mismatch. feature/vendor_sale.lpc's
is_vendor_good(), do_vendor_list(), and (transitively, via
is_vendor_good()) do_vendor_buy() all called methods directly on
vendor_goods string entries with no existence guard, so this one
dead reference broke list (and would have broken buy too, for
anyone who managed to name it) for every player at this shop, every
time — the exact class already cataloged in AGENTS.md's mohuanshiji
precedent ("worth checking as a standing step on any future lib's
feature/vendor.lpc-style shop test").
Fix followed this codebase's own existing idiom for the identical
problem in the sibling feature/dealer.lpc (file_size(ob[i] +
".lpc") > 1, log the stale entry, skip it rather than crash) — added
the same guard to all three loops/lookups in feature/vendor_sale.lpc
(is_vendor_good(), and both loops inside do_vendor_list()),
logging a vendor_error line instead of throwing. This is a
missing-defensive-check programming bug (no existence check before an
unconditional -> call), not a content restoration — the dead
/u/xiha/fd entry itself was left in yang.lpc's vendor_goods
array untouched, matching the give.lpc/ask.lpc QUEST-daemon
precedent's remedy of guarding the call site rather than fabricating
the missing target.
Verified live after a driver restart: list now prints all 16 real
items (skipping the dead entry silently), and buy budai (麻布袋,一
两白银) correctly deducted exactly 1 tael from the player's 20-tael
starting balance (二十两银子 → 十九两银子) and added 布袋(Budai) to
inventory — real purchase, correct change/inventory math confirmed
end-to-end.
Sect apprenticeship (拜师) — clean pass, no bug found
Full recruit/apprentice two-command handshake (cmds/skill/
recruit.lpc + cmds/skill/apprentice.lpc + feature/apprentice.lpc's
recruit_apprentice()) read in full first. Picked 丐帮 (newbie doc's
own §3 recommendation for 拳脚/unarmed fighters) — specifically 左全
(kungfu/class/gaibang/zuo-qu.lpc, one of the 七袋弟子, reachable from
guangchang via enter shudong → /d/gaibang/inhole) since his
attempt_apprentice() only gates on gender == "男性" (the simplest
of the gaibang roster's per-NPC stat/gender gates — siblings he-bj/
li-sh/ma-jw/yu-hx/liang each gate on a different stat
threshold, jian/peng refuse everyone outright).
apprentice zuo (test char already male, 光明磊落 personality) →
"你想要拜左全为师" → 左全 accepted immediately (no stat gate hit) →
"你跪了下来向左全恭恭敬敬地磕了四个响头,叫道:「师父!」恭喜您成为
丐帮的第二十代弟子。" score before vs. after: 头衔 changed 【布衣平
民】→【叫 化 子】, 称谓 changed 普通百姓→丐帮第二十代弟子, 你的师傅
changed 目前还没有→左全. Full apprenticeship mechanism (recruit/
apprentice pending-state handshake, family mapping population,
assign_apprentice() title generation) works correctly end-to-end —
no bug found, clean pass.
Formatter note
Could not run the §9 LPC formatter (~/src/fluffos/tools/lpc-syntax/
bin/format-corpus.mjs) this pass — node is not installed/on PATH
in this session's shell environment (checked which node, nvm,
common install paths; none found). The feature/vendor_sale.lpc edit
itself hand-matches the existing codebase's own indentation/brace
style (copied directly from the sibling feature/dealer.lpc idiom, no
::, case, or CJK-string edits involved, so the formatter's three
known blind spots don't apply here regardless). Flagging for whichever
future pass has a working node available: re-run the formatter on
this one file and re-verify.
Testing setup note
Two concurrent scripts/tmux_mud.sh sessions (admin fluffos, throwaway
player qinmaiwu/秦买物) driven with only ASCII/pinyin commands past
the initial Chinese-name registration step (done via a one-shot
scripts/mudclient.py call first, per this project's standing
tmux-mojibake caution) — no mojibake observed on the ASCII-only
in-play commands, consistent with the false-alarm pattern being
specific to multi-byte *input* during registration, not general
gameplay. Test character's save file was never observed on disk under
data/user/q//data/login/q/ despite score/reconnect showing
correctly persisted state across the two tmux sessions — most likely a
net-dead in-memory reattach rather than an actual disk restore (the
first tmux session was never sent quit, just closed); nothing to
clean up on disk either way since no qinmaiwu.o file exists. Driver
killed by exact PID after testing; both tmux sessions stopped.
§7.19 enable_player() reentrancy fix (2026-09-01)
Corpus-wide mechanical fix (AGENTS.md §7.19, Batch F of 6). feature/command.lpc's
enable_player() had no reentrancy guard: NPC init() (e.g.
d/shushan/npc/zhangmen.lpc) -> setup()/reset_me() -> enable_player()
-> enable_commands(), which can synchronously re-invoke the same object's
init() (driver docs BUGS note; live-verified mhxy/wuhanzhan precedent), and
revive()/wakeup()/wakeup2() re-invoke enable_player() while already
living(), ruling out a bare living() guard. Fixed with the standard
in_enable_player_now true reentrancy flag (mhxy's reference fix). Verified
via single-file lpcc --batch PASS.