info.html · 介绍 · play.html · 游玩 · llms.txt · 下载与本地运行 · ZIP · GitHub
游戏配置和进游戏后的横幅上写的都是《狂想空间》,压缩包文件名里的"新狂想空间II"其实是收藏站点自己加的标题,并非游戏本名。这是一套 1995 年起源自"ES II"(Eastern Stories II)架构的老牌 Mud 引擎,2002 年由台湾巫师 wade 发布,与本项目里的 es1_win、esI、xkx2001、辽宁热线站等多个库同属 ES II 大家族。背景设定是一个"古代中国"的江湖世界,主打门派、帮派制度和轻功、内功养成;新手报到的"狂想空间新手入门房间"里直接给出新手介绍、指令快速上手、帮派说明、小秘技等导览,非常照顾第一次玩这类 Mud 的玩家。创角时要在体格、定性、悟性、胆识、根骨、灵性、容貌七项属性间分配天赋点数,另有一项"根骨/福气"按剩余点数自动计算。
English
Both the game configuration and the in-game banner call it "Rhapsody Realm" — the archive filename's "New Rhapsody Realm II" is a title the collecting site added, not the game's real name. It's set in an "ancient China" jianghu built around sects, gangs, and the cultivation of qinggong (lightness skill) and neigong (internal power); the newcomer's start room lays out a full orientation menu (introduction, quick command reference, gang/sect overview, tips) aimed squarely at first-time MUD players. Character creation distributes points across seven stats — physique, willpower, comprehension, courage, bone structure, spirituality, and appearance — with an eighth, "bone structure/fortune," auto-computed from whatever points remain. It's a venerable mudlib engine dating to 1995 ("ES II" / Eastern Stories II architecture), released in 2002 by Taiwanese wizard wade, and belongs to the same large ES II family as this project's es1_win, esI, xkx2001, and Liaoning Hotline Station archives, among others.
README
内容亮点
- 本地/浏览器连线现已豁免所有 IP 封禁、重连限制与同 IP 人数上限。
在线试玩
https://mudlibs.fluffos.info/kxkj/
管理员账号 / Admin account
- id:
fluffos - 密码 / password:
Mud@2026 - 显示名 / display name: 浮浮(Fluffos)
- 权限 / level:
(manager)—— 本 libsecurityd.lpc权限表 (wiz_levels)的最高一级(高于(admin)),通过/adm/etc/wizlist名单授予(fluffos (manager))。
警告:这是一个公开的默认密码,仅供本地/浏览器试玩。正式对外开服前
请务必修改此默认密码。
本地运行
cd libs/kxkj
~/src/fluffos/build-debug/src/driver config.fluffos游戏端口:40047。
NOTES · 移植与修复记录
kxkj — 狂想空间 (Fantasy Space) II
Archive: 新狂想空间II.rar ("New Fantasy Space II", #53). Port: 40047.
Status: done (boots clean, full registration flow verified
end-to-end including a real Chinese name entering the game world).
What this is
The archive's own top-level readme (狂相空间II.txt) identifies it as
"狂想空间II" ("Fantasy Space II"), a Taiwanese source drop dated
October 2002 ("这套源码来自台湾!2002年10月份的狂想空间II"), crediting
the Taiwan wizard wade for the release. The archive's *actual*
self-identified name in config.fs (name : 狂想空间, no "II"/"新")
and the live in-game banner both say plain "狂想空间" — noted here
since it differs slightly from the archive filename, per the task's
convention (no separate slug rename needed; kxkj is
kept as the working slug since it was pre-assigned).
A second file, 小熊泥苑.txt, is a collector-site readme (from the
archiving site "小熊泥苑", http://dtxy.126.com) explaining that this
particular archive is a BIG5→GB-converted copy of the original Taiwan
"狂想空间" source, not a separate game — consistent with the wade/2002
Taiwan credit above. In-game credit line: 以 ESII 为架构改编,初次架于
1995 9 22,感谢 annihilator & elon & mineral — confirms this is
genuinely built on the "ES II" (Eastern Stories II) mudlib base,
the same lineage already seen in es1_win(#12)/esI(#13)/xkx2001
(#25)/rzrmud(#23)/bmxkx2001(#45) — master.c's header
comment says exactly // for ES II mudlib / original from Lil /
rewritten by Annihilator (11/07/94). adm/obj/{master,simul_efun} +
adm/simul_efun/*.c fragment layout (not adm/single/), matching that
family. Admin accounts per the readme/wizlist: bear/wade
(manager), banyan (arch).
Raw archive: 14,440 files under raw/fsII/ (the mudlib root — no
nesting, config.fs sits directly at top level), 12,089 of them
renamed .c→.lpc. A prebuilt Windows MudOS.exe binary and its
bin/ support scripts are bundled alongside the source (ignored, per
AGENTS.md — we use our own driver build).
Fixes applied
1. AGENTS.md §15h, standard shape, adm/simul_efun/chinese.lpc:
is_chinese()'s GBK lead-byte range check (strlen(str)>=2 &&
str[0]>160 && str[0]<255) rewritten to a CJK Unicode codepoint
check (strlen(str)>=1 && str[0]>=0x4e00 && str[0]<=0x9fff).
2. AGENTS.md §15h, check_legal_name() in adm/daemons/logind.lpc:
byte-count bound < 2 || > 12 → character-count bound < 1 || > 6
(message text already said "必须是 1 到 6 个中文字", confirming the
halved bound, not a guess); removed the i%2==0 && even-byte-offset
gate in the per-character is_chinese() sliding check so every
character position is checked (previously only every other
character was checked under UTF-8 semantics).
3. AGENTS.md §15p: /adm/daemons/network/dns_master was present in
adm/etc/preload — removed proactively before the first boot
attempt, per standing policy.
4. NEW variant of AGENTS.md §8d/§15o (absolute-path angle-bracket
#include), found here — this is the most impactful fix in this
pass. 359 files across the lib write #include < immediately
followed by an already-absolute path (leading /), e.g.
std/armor/cloth.lpc's #include </open/open.h> and ~350 zone
files' #include </open/open.h>/#include </open/badman/badman.h>
etc. Read the driver source
(compiler/internal/lexer_utils.cc's inc_open()) to confirm the
root cause: angle-bracket resolution unconditionally joins each
configured include directories entry with the given name
(path + "/" + name), with no special-case for a name that's
already an absolute path — so <...>-style absolute includes can
never resolve, regardless of get_include_path() or preload timing
(unlike the quoted "file" form, whose merge() helper explicitly
detects and handles a leading / as "absolute from mudlib root").
Fix applied: added master::get_include_path() (the standard
§8d/§15o shape, prepending the compiling file's own directory plus
:DEFAULT:) AND, since get_include_path() is only consulted for
VM-context (mid-connection) compiles per §15o's documented caveat —
confirmed here too, lpcc alone still failed on this file even
after adding the apply — blanket-converted every #include <ABSOLUTE_PATH>
(grep -rlZ '#include *<\s*/[^>]*>' | xargs sed -E
's#include *<[[:space:]]*(/[^>]*)>#include "\1"#') to the quoted
form, which resolves absolute paths unconditionally via merge()
with no VM-context dependency. 359 files fixed in one shot, 0
remaining. This was NOT just cosmetic: /std/armor/cloth.lpc is
the starting-clothes item every new character equips at the end of
registration, and (more importantly) /open/newhand/newhand.lpc
(STARTROOM) transitively depends on this same pattern — before
this fix, every brand-new character's press_enter() silently fell
through to VOID_OB (catch(load_object(STARTROOM)) failing
twice, per the existing degrade-to-void fallback in
logind.lpc), landing the player in /obj/void.lpc's "精灵圣域/天
外天" placeholder room instead of the real newbie room, AND
triggering an unrelated-looking infinite error-spam loop (next item).
5. Discovered via the interactive test (not proactive), root-caused
to item 4 above, no separate code fix needed: with the character
landing in VOID_OB (whose path top-level dir is obj, not
open), adm/daemons/check_w_r_y.lpc's anti-cheat "did a player
wander outside /open" heart_beat check fired every second,
calling CBIP_D->record(...) to log it to a hardcoded path
(/u/b/bss/record/no_in_open — the original site's bss wizard's
home directory, which doesn't exist in this archive: only
/u/bear and /u/w exist under /u). write_file() failed
(mkdir() can't create /u/b/bss/record in one shot since its
parent /u/b/bss doesn't exist either), throwing a runtime error
that aborted check_w_r_y.lpc's main() before it reached the
line that would have set its "already recorded, don't retry" flag —
so the failure retried, and re-failed, every single heartbeat tick
forever, flooding debug.log with *Wrong permissions for opening
file ... for append. once per second. Once item 4's fix let the
character land in the real /open/newhand/newhand room instead,
this check's dir!="open" condition is false and it never fires at
all — confirmed by re-running the full registration test after the
fix and finding zero occurrences of this error in debug.log. Left
unfixed (no code change needed): this is a real environment/content
gap (bss's missing home directory) that simply never gets
exercised once characters correctly land inside /open; fabricating
a /u/b/bss/record directory tree for a wizard account that isn't
part of this project's scope isn't warranted.
Fixes applied — found via the lpcc_check.sh sweep (post-boot-test pass)
The interactive boot/registration test alone doesn't exercise most of the game-content tree (rooms/items/NPCs never touched by the registration path). Running the full sweep afterwards, per AGENTS.md's pipeline, surfaced these additional genuine bugs (triaged by grouping the 624 initial failures by error-message shape before fixing anything, per §6b):
6. NEW bug shape, not yet in the catalog: #include of a file that
itself declares a global variable, positioned textually BEFORE
inherit — "Illegal to inherit after defining global variables."
(74 initial failures). The compiler enforces inherit must precede
any global-variable declaration in the ASSEMBLED token stream, which
includes anything spliced in by an earlier #include, not just
literal declarations in the file itself. Two shapes found:
- 67 files, /open/gblade/room/n_area{0..66}.lpc: each does
#include "n_area.h" (declares string *n_area_msg = ({...});)
THEN inherit ROOM; — one shared header, one shared bug, fixed in
one shot by swapping the two lines' order in all 67 files (grep
confirmed all 67 share byte-identical first-3-line structure
first, then a scripted swap, then re-verified all 67 via
lpcc/spot-check).
- 5 standalone files with a bare object user; (or int mean;)
declared directly before their own inherit:
open/main/obj/super-cloth.lpc, open/japan/obj/super-cloth.lpc
(both copies of the same "雀皇飞云裳" item), open/mogi/village/
obj/mcc.lpc, open/beggar/skill/pdarray.lpc, and u/bear/start.lpc
(whose actual culprit was #include "/include/basic_skill.lpc",
which declares mapping basic_skill = (...), sitting before its
inherit ROOM; — same root shape as the header case above, just a
different header). Fixed by reordering each file's own
declaration/include to come after its inherit line. All 6 file
groups (74 files total) re-verified clean via lpcc afterward.
- Caught and self-corrected a real mistake while fixing this:
my first attempt at the 67-file bulk fix used a sed one-liner
that (due to a copy/paste test fragment sed -i '2,3{2!d}' left
in a loop meant only as a dry-run check) actually deleted the
inherit ROOM; line from all 67 files instead of moving it.
Caught immediately by re-checking file contents before trusting
the result, restored by re-inserting inherit ROOM; right after
the #include line, then re-did the fix correctly (moving
inherit to BEFORE the #include, since the include's spliced
content — not just its own line position — is what has to follow
inherit). Verified via a systematic post-check (grep -c "^inherit
ROOM;$" == 1 in every one of the 67 files) before moving on.
7. NEW gap, ..-relative #include (driver disallows .. in
include paths entirely, both quoted and angle-bracket forms, per
docs/lpc/preprocessor/include.md and confirmed in
compiler/internal/lexer_utils.cc's legal_path() check):
- 27 files under /open/start/{npc,room,obj}/*.lpc used
#include <../start.h> to reach /open/start/start.h (a real,
existing file one directory up) — fixed by rewriting to the
absolute quoted form #include "/open/start/start.h" (safe/exact,
no content change, start.h itself was never missing).
- 27 files under /open/cold/*.lpc used #include "../cold.h"
to reach a cold.h that (unlike start.h above) does not exist
anywhere in the raw archive at all — a genuine content gap, not
a path-syntax issue alone. Reconstructed a minimal cold.h
defining only the two macros actually referenced anywhere in this
zone's own files (COLD_ROOM, COLD_NPC — grepped for
\bCOLD[A-Z_]*\b across open/cold/*.lpc first to confirm
COLD_OBJ is never used and no obj/ subdirectory exists there
either, so it was deliberately not guessed/added), using the
exact same path-prefix macro style as the sibling zones already
defined in open/open.h (SNOW/SNOW_ROOM/SNOW_NPC/SNOW_OBJ
etc.) — this is the same kind of "reconstruct one small, obviously-
patterned missing macro header" precedent as xyzx3's
WQA_ROOM fix (AGENTS.md §8g variant), not fabricating game
content, since none of the actual room text/logic needed guessing.
All 54 files (27+27) re-verified clean via lpcc afterward.
Net effect on the sweep: 130 additional files fixed beyond the two
proactive §15h/§15p fixes (74 inherit-ordering + 54 ..-include +
2 header/config side effects), taking the pass rate from the initial
sweep's 94.8% (11,465/12,089) up to the final number below.
Confirmed NOT needed (checked by reading the source, not assumed)
- §4 (
load_object-in-valid_read/valid_writerecursion): this lib'smaster.lpcalready wraps the lazySECURITY_Dload incatch()with anobjectp()result check (if( !catch(ob=load_object(SECURITY_D)) && objectp(ob) ) return ...; return 0/1;), the samecatch()-guarded shape already proven safe on sibling ES-II libs (es1_win,rzrmud,xkx2001) — no additional reentrancy-flag guard needed. Confirmed via a full clean boot + interactive registration/gameplay test producing zero recursion/stack-overflow symptoms. - §7 (
get_root_uid/get_bb_uid): both already implemented inmaster.lpc, returningROOT_UID/BACKBONE_UIDdirectly. - §14 (2-arg
valid_override):master.lpc'svalid_override(file, name)is 2-arg, but it already unconditionally allows any file under/adm/simul_efun/(if( file[0..15] == "/adm/simul_efun/" ) return 1;) — this generalizes past the specific 3-arg/main_filecase §14 describes (it allows the whole directory, not just the real simul_efun compilation unit), so no#included-simul_efun-fragment override was ever at risk of rejection. Confirmed by reading the function and cross-checking the boot log for zerovalid_overriderelated denials. - §8f (
TYPE * a, b;forgotten-star bug): grep found 268 instances of theTYPE *name1, name2;shape (e.g.mixed *cnd, err;,object *enemy,who,user;), but spot-checking several confirmed each is intentionally mixed (the starred variable is genuinely used as an array viakeys()/sizeof()/indexing, the un-starred ones are genuinely scalar, e.g.err = catch(...),user = query_leader()) — this is normal, correct C-style declaration usage in this lineage, not the Dead-Souls-specific copy/paste bug §8f documents. No fix applied. - §15/§15b family (nitan-lineage bare simul_efun
set/query/deletedbase architecture bug):feature/dbase.lpcimplements real, localset/query/delete/addmethods (viainherit F_TREEMAP;), andlogind.lpc/other objectsinherit F_DBASE;directly — the architecturally-correct per-object pattern, same asrzrmud/es1_win. Confirmed by readingfeature/dbase.cbefore boot; no simul_efun-shared-storage bug exists here. tail()missing-efun (§8e): grep found zero calls totail(/efun::tail(anywhere in the lib.arraybare-type declarations (§15f): zero matches for thearray name;/array name = expr;shape.- Case-sensitivity data-file bugs (§15g/§15k): not investigated exhaustively (no symptom pointed at one), but the WELCOME/MOTD/etc paths in
login.hall matched real on-disk casing, and the boot + full registration/gameplay test produced no missing-file symptoms. - Encoding stragglers:
convert_lib.shreportedlossy=0(no invalid-byte drops at all, unlike several prior libs). A follow-upfile-classifier sweep flagged 12 files (include/lock.h[1-byte, effectively empty], plus 11.lpc/.hfiles underopen/) as "data" instead of "text" — verified each is a false positive offile's heuristic (short files / heavy box-drawing and ANSI-color content confusing its classifier), not an actual encoding problem: every one round-trips clean throughiconv -f UTF-8 -t UTF-8andcats as correct, meaningful Chinese/English text (e.g.open/heaven/castle/room/sky0.lpcreads "//天界之城 Edit By Del" and a correct long-description block). No further conversion needed.
Known lpcc-sweep failures NOT fixed (pre-existing content bugs/gaps, not driver-compat)
Triaged the remaining failure categories after the fixes above; none of these are on the registration/boot path (confirmed via the clean interactive test) and all are pre-existing authoring issues in the original archive, not artifacts of this conversion pass:
- ~22 files, "Illegal character 0xNN" in item/skill flavor text (
/nets/god/god_*wizard-tier equipment,/obj/board/immo_b,/obj/turtle_blood,/open/beggar/skill/kang_s, and others): decorative ANSI-color-macro item names missing their+concatenation operators between bare macro tokens (HIB/HIW/NOR) and adjacent quoted box-drawing characters (confirmed via the raw pre-conversion bytes — the underlying GBK byte0xA1F5correctly decodes to "□" WHITE SQUARE either way, so this is a genuine missing-+authoring bug, not an encoding artifact). Not a single uniform shape across all 22 (some are missing+between string segments, at least one has a bare box-drawing character sitting on its own source line entirely outside any string/expression) — spot-checked several to confirm the variety before deciding NOT to risk a blanket regex fix; these are all decorative wizard/misc item names, never touched by registration. - 1-2 files, "Undefined function set"/"set_name" (
open/snow/npc/medical_boy.lpc,u/w/wade/npc/money.lpc): theinherit F_VENDOR;line is explicitly commented out (// inherit F_VENDOR;) — this looks like a deliberately disabled/work-in-progress NPC (the original author's own comment marker, not something broken by conversion), not restored since there's no way to know whether commenting it out was intentional. - ~15 files, "Cannot #include stdio.h"/"uid.h"/
/u/c/cage/lib/door.h:adm/daemons/network/{mail_serv,pingd,pingtcp,telnetd}(unused network utility daemons, none inadm/etc/preload),include/{crypt, cstrip,replace,touch}(oddly-placed personal admin-utility scripts),open/killer/{home,room}/rb*(a door-based sub-area referencing a specific wizard's personal library,/u/c/cage/lib/door.h, which doesn't exist in this archive), andu/w/wade/text3d(a personal test file). All orphaned/dead/personal content per AGENTS.md §12/§13 — not fabricated, not fixed, never reached by any live code path.
Config notes
config.fluffos adapted from the lib's own config.fs (converted to
UTF-8 before any other edit, per AGENTS.md §5). Dropped three
driver-obsolete keys the boot log flagged (reserved size, binary
directory, swap file — all warned "obsolete line in config file,
please delete" on the first boot attempt). maximum local variables
(50) and living hash table size (100, in the "not currently used"
section) both trip a harmless "invalid new value, resetting to
default" warning — cosmetic only, left as-is (matches the archive's
original values, not something we need to correct). Created
work/adm/tmp/ (referenced by the original swap file directive,
long removed from the config but the dir doesn't hurt to have) and the
sibling log/ directory (driver's log directory resolves relative
to CWD, not mudlib root, per AGENTS.md §6).
Registration-flow transcript (verified end-to-end)
Read adm/daemons/logind.lpc's full callback chain before scripting
the test (logon → get_id → confirm_id → get_name → new_password →
confirm_password → get_email → get_gender → get_points ×7 →
enter_world → press_enter) — no hidden BIG5/client-version pre-id
gate in this lib (the very first prompt is the real English-id
prompt). Point allocation is 8 attributes/160 points average 20 each,
but only 7 of them (str,cps,int,cor,con,spi,per) are prompted
individually — the 8th (kar) is auto-computed as the remainder the
moment the per prompt is answered, going straight to enter_world()
with no further prompt.
Ran via python3 scripts/mudclient.py 127.0.0.1 40047 --timeout 45
--idle 1 in one continuous connection, --send sequence: english id
→ y (confirm new char) → real Chinese name "秦风二" → password
→ password again → email → m (gender) → 20×7 (attribute points) →
` (press enter) → look → quit`.
Outcome: id accepted, confirmation accepted, "秦风二" (a genuine
2-character Chinese name) accepted by the fixed is_chinese/
check_legal_name, password/email/gender/all 7 attribute prompts
all proceeded correctly, character creation completed, and the
character was dropped into the real starting room
("狂想空间新手入门房间" — "Fantasy Space Newbie Room", under
/open/newhand/newhand), with the room's full Chinese description,
exits, a same-session news bulletin, and birthday-reminder message all
rendering correctly. look re-displayed the same room correctly.
quit produced a clean goodbye ASCII-art banner and disconnect
message ("你离开狂想空间了。" — "You have left Fantasy Space."). Zero
crashes, zero permission-denied errors, zero debug.log runtime
errors for the whole session (only harmless "Unused local
variable"/"Illegal to declare nosave function" compiler warnings,
which this mudlib's error_handler happens to echo to the connected
client live — pre-existing/cosmetic behavior, not something introduced
by this pass, not fixed).
(An earlier attempt reusing the already-registered id qinfeng from a
first, pre-fix test run correctly hit the "already registered, enter
password" branch instead of character creation — expected, not a bug;
and a follow-up attempt with a fresh id within the same 10-second
window correctly hit logind.lpc's per-IP anti-flood throttle
("请勿连续尝试,请您稍后再连线。", same shape as AGENTS.md §15j) — also
expected, resolved by waiting past the in-memory 10s window, not a
restart.)
Re-verified again after ALL fixes above (including the sweep-driven
inherit-order/..-include fixes) with a fresh id/name (qinfengc /
"秦风三"), on a freshly-rebooted driver: identical clean outcome,
same real starting room, same clean quit, and this time zero
debug.log output at all beyond the harmless compiler-warning echoes
(confirming the check_w_r_y.lpc/cbipd.lpc error-spam from item 5
above is genuinely gone now that the character lands in /open/...
instead of VOID_OB).
lpcc sweep
scripts/lpcc_check.sh libs/kxkj/config.fluffos
libs/kxkj/work, run twice:
1. First pass (before the sweep-discovered fixes above):
total=12089 pass=11465 fail=624 (94.8%).
2. Final pass (after fixing the 74-file inherit-ordering bug and the
54-file ..-include bug, both described above): total=12089
pass=11595 fail=494 (95.9%). The remaining 494 failures were
re-triaged by error-message shape and confirmed to be exactly the
"known, not fixed" categories documented above (decorative-item
+-concatenation typos, 1-2 deliberately-disabled NPCs, and
orphaned/personal-wizard/dead-network-utility content) — zero new
or unexplained failure categories introduced by any fix.
Ran concurrently with other agents' sweeps on this host both times;
memory stayed healthy throughout (available — the metric that
matters, not the free column, which dipped much lower due to normal
page-cache usage — stayed in the 13-19GB range out of 23GB total for
essentially the whole run, spot-checked repeatedly via free -h).
Re-verification pass: driver rebuild + formatter + WASM (2026-07-23)
- LPC formatter applied to all
work/*.lpc(12089 files): 12064 reformatted, 24 already-clean/unchanged, 1 self-checked error (skipped, expected on legacy code). - Native re-test against the rebuilt driver (
~/src/fluffos/build-debug/src/driver): booted clean (only pre-existing compile warnings, no fatals). Full registration flow re-verified end-to-end with a fresh real Chinese name ("秦风廿二") — English id → confirm y/n → Chinese name → password ×2 → email → gender → 7 attribute prompts (all20) → entered the real starting room (狂想空间新手入门房间);look/score/quitall produced correct Chinese output.log/debug.logwas completely clean (no output at all beyond driver startup). Reformat + new driver build introduced no regressions. - WASM test (
scripts/wasm_client.jsagainstbuild-wasm/src): boots cleanly — the only preload-time errors are the expected non-fatalUndefined function socket_create/socket_bind/socket_closeinadm/daemons/ftpd.lpc(nosocketspackage under WASM). Full registration flow completed successfully under WASM with a real Chinese name ("秦风测试") through the identical prompt sequence, reaching the same starting room,look/quitboth correct. The knownquery_ip_number()WASM limitation is visible but purely cosmetic here: the welcome banner's "您正以位址 ... 连线中" line prints a blank IP instead of127.0.0.1under WASM, but this lib doesn't gate login on the IP's format anywhere, so it has no functional effect — a clean, fully-playable WASM result.
WASM-enablement pass (2026-07, loopback/uptime/throttle + admin seed)
Standard WASM-first pass per AGENTS.md §1.3(b)/(e) and §1.5. Loopback =
127.0.0.1, any 127. prefix, or an empty/non-string/malformed IP
(covers older WASM query_ip_number() garbage). Gates patched:
adm/daemons/cbipd.lpc::check_ip()(~line 7): loopback short-circuitreturn 0— the banned-IP list ("此 IP 目前已被停用") can never hit local connections.adm/daemons/relog_ip.lpc::check_ip()(~line 38): loopback short-circuitreturn 0— the auto-ban ("重连太多次被ban 3天") can never hit local connections.adm/daemons/banmultid.lpc::ban_multi()(~line 17): loopback short-circuitreturn 1(allowed) — the per-IP concurrent-login cap no longer applies to local connections.adm/daemons/logind.lpc::logon()(~line 204): the 10-second per-IP reconnect block (blocks[ip] > time(), "请勿连续尝试") is now loopback-exempt. This removes the README's old "wait ~15s between test connections" caveat for local play.adm/daemons/logind.lpc::new_destruct()(~line 1176): loopback connections are no longer recorded into theblocks[]mapping or the auto-ban counters (they just destruct cleanly) — repeated local testing can no longer poison/adm/etc/relog_ip.- No
uptime()startup-grace gate in this lib.
Admin seed: registered fluffos / display 浮浮 / password Mud@2026
through the real flow (id → y → Chinese name → password x2 → email →
gender m → seven "20" talent allocations → empty send → world). Granted
(manager) — the TOP rank of this lib's wiz_levels (above (admin))
— by appending fluffos (manager) to /adm/etc/wizlist. Verified:
relogin as fluffos → update /adm/daemons/banmultid →
"重新编译 ...成功!".
Lineage quirk worth knowing: the relogin path checks the LOGIN
object's save (/data/login/<c>/<id>.o), but registration/quit never
writes it (ob->save() is commented out in enter_world, and
cmds/std/quit.lpc destructs the body without saving the link object).
The login save is only written by the NET-DEAD path
(obj/user.lpc::net_dead() → link_ob->save()). So to make a fresh
account relogin-able, end its first session by dropping the connection
(client timeout), NOT by quit — that is how
data/login/f/fluffos.o was produced here. (Pre-existing behavior,
documented rather than changed.)
Retest: fresh normal registration (qfkxkj / 秦风) re-verified
end-to-end into the newbie welcome area with look/score/quit
correct; test saves removed. No new errors in log/debug.log.
Save files for the orchestrator to add (both paths tracked, not
gitignored; data/user/f/ and data/login/f/ are NEW directories):
libs/kxkj/work/data/user/f/fluffos.olibs/kxkj/work/data/login/f/fluffos.o
WASM 修复摘要(迁移自 meta.json 的 group_note)
狂想空间基础版(更晚的快照)。
§7.86 跨库扫描修复(留言板 post 崩溃)
BULLETIN_BOARDinherit+ 多余replace_program()致命形状(AGENTS.md §7.86,post命令崩溃):全档案 14 处命中,已删除多余的replace_program(...)调用(保留inherit),逐文件保留原有行尾格式(CRLF/LF 按文件原样)。本次为跨库 §7.86 扫描修复(触发原因:该 bug 已在 6+ 个互不相关的血统家族独立确认,属于近乎普遍的拷贝粘贴模式),仅做编译检查(驱动干净启动、端口正常监听),未做完整 §10.7 深度游玩测试。
深度功能测试 / Deep functional test (AGENTS.md §10.7)
先读 doc/help/newbies/newbie/newbie2:本档案是台湾巫师 wade 于 2002 年发布
的 ES II 架构老牌 MUD,与本项目的 es1_win/esI/xkx2001/kxkj1(同游戏
不同快照,见 AGENTS.md §11)同属一个大家族。新手流程:设 8 项天赋(膂力/
定性/悟性/胆识/根骨/灵性/容貌/福缘,共 160 点自由分配)→ 进入
狂想空间新手入门房间 → enter 正式进入 → give cloth to girl 帮助新
手房里的小女孩 → down 两次进入中央驿站/大马路一带。
修复的程序性 bug
无。全程 debug.log 干净(仅编译期无害警告),未发现 §7.11/§8.9/§7.34 等已 知类别的确认实例。
发现但判定为既有设计、未改动的重要现象(务必记录,供后续同宗 ES II 库测试参考)
fight 指令对"不会说话"的生物(动物)走的是真实杀伤分支,可能导致角色
真的死亡——现场以 (manager) 账号验证:在 d/snow/eroad2 对野狗
(d/snow/npc/dog.lpc)使用 fight dog,系统提示"看起来野狗想杀死你!",
数回合后角色"气血"归负、陷入半昏迷、最终"你死了",被送往 阴曹入口(真
实死亡,非"昏迷后自动恢复")。追查 cmds/std/fight.lpc 源码:
if (obj->query("can_speak")) {
me->fight_ob(obj);
obj->fight_ob(me); // 双方都是"点到为止",安全
} else {
me->fight_ob(obj);
obj->kill_ob(me); // 对方是真杀,玩家一方仍是 fight_ob 但对方不是
}can_speak 在全部 d/ 目录下没有任何 NPC 文件显式 set() 过(只在
adm/daemons/race/human.lpc 等种族档案里设为 1),换言之只有走过种族初始
化流程的人形角色(玩家、以及归属人类种族的 NPC)才会落入安全的
fight_ob()/fight_ob() 双向分支;纯野生动物(dog.lpc/crazy_dog.lpc
等,未经种族初始化)会让对方调用 kill_ob(),对玩家是真实杀伤。现场用
fight trainee(淳风武馆 的"武馆弟子",人形 NPC,无自定义
accept_fight(),走默认 NPC::accept_fight())复测:对话式的挑衅讯息
("你对着武馆弟子说道:...领教...的高招!",与动物分支的"你大喝一声,开
始对XX发动攻击!"用词不同),全程零受伤,武馆弟子力竭后"跌在地上一动也
不动了"(昏迷,随后自行"清醒了过来"),确认这才是"点到为止"分支。
判定为既有设计,不是 bug:fight.lpc 自己的 help 文本("这种形式的
战斗纯粹是点到为止...不会真的受伤")和 newbie 文档的"就算你昏了也没关
系"都是针对"打人"(人形对手)语境说的,武侠类 MUD 里"野兽不懂收力、人可
以点到为止"是常见且合理的题材设定,并非程序逻辑缺陷——fight/kill_ob
的分流本身工作正确,只是文档的措辞没有明确排除动物这一类目标,容易让新
测试者(或新手玩家)误以为对任何生物用 fight 都绝对安全。未做任何代码
改动。给未来同宗 ES II 库测试的提醒:挑选"安全陪练"测试对象时,务必
先确认目标是人形 NPC(或亲自读一遍其 accept_fight()),不要直接假设名
字看起来温和的生物("野狗"这类)就安全;已检查 kxkj1(本库唯一已完成
§10.7 的同游戏姊妹库)现有 NOTES.md,未记录同一现象,值得下次碰到时留意。
测试覆盖
- 注册:英文 id
kxkjdeep→ 中文名 秦风廿八 → 密码abc12345(×2)→ 邮箱 → 性别m→ 8 项天赋各20→ 落地狂想空间新手入门房间。look/score/i均正常;score面板的 食物/饮水以表情符号(^o^)而非数字条显示,属本档案自有 UI 风格,非 bug。全程 debug.log 干净。 - 新手引导:
enter进入正式世界,give cloth to girl对新手房间 的小女孩成功;down两次抵达中央驿站/大马路一带(中央驿站本身有no_fight标记,"这里禁止对打",符合交通枢纽的安全区设计)。 - 安全切磋:见上方专节——
fight对人形 NPC(武馆弟子)安全,对动物 (野狗)是真实杀伤;用后者现场复现了"死亡",用前者复现了正确的"昏迷 →自动清醒"流程。两者都不是程序 bug。 - 技能/门派习得(正规组织路径):
join(/open/gsword/room/ swordhouse的剑士公会三长老柳毅)成功加入剑士公会,设定class属性;apprentice teng(仙剑派第三代掌门人郑士欣,/open/gsword/ room/g5-1)因掌门年事已高被引导select七位弟子之一(选了首徒张乘 风);apprentice fon(/open/gsword/room/g1-1)正式拜入仙剑派第五 代弟子;learn force from fon成功习得基本内功,score确认武学伤 害力等数值相应提升。注意:apprentice要求玩家class属性与目标一 致(cmds/std/apprentice.lpc第 60-62 行),所以必须先join公会 设定职业,才能对该职业名下的门派掌门/弟子拜师——这是本档案自己的两段 式设计,未改动。 - 技能习得(管理员快捷路径)——本档案没有:搜遍
cmds/adm/未找到 任何直接对玩家set_skill()/improve_skill()的管理员命令;skillpass/skilldel是技能翻译表(中英文对照)管理,不是玩家个人 技能等级设定。如实记录:本库不提供这类快捷方式,管理员若要提升角色 技能仍需走正规的join+apprentice+learn/exercise流程。 - 退出/重连:
quit正常结算(无强制删号规则)。按本档案已有 NOTES 记录的"注册/quit 从不写入 LOGIN 对象存档,只有净断线路径才写"的既有 发现,本轮改用Ctrl-C断开原始 socket(模拟净断线)而非quit来 结束第一段连线,约 16 分钟后用同一 id/密码重连,提示"重新连线完 毕。",look/score确认所在房间与状态完整保留。
进程卫生附注
清理了两处与本次修复无关的测试残留:(a) 因现场验证死亡机制而写入
work/open/death/death_record(一个跨玩家共享的历史死亡记录文件)的一
行"fluffos浮浮被dog野狗所杀"条目,已用 git checkout HEAD -- 还原;
(b) 一次 dump 指令尝试产生的诊断文件 work/OBJ_DUMP,已删除,未纳入
本次提交。
WASM 未验证说明
按本 session 约定:emsdk 固定从 storage.googleapis.com 拉取,被本
session 出站代理策略拒绝(curl -sS $HTTPS_PROXY/__agentproxy/status
返回 403),WASM 编译/运行验证本轮继续跳过,仅做原生驱动(linux-debug
预设,ASAN/UBSAN)下的完整 §10.7 测试。
深度功能测试第二轮 / Deep functional test round two (2026-08-14)
第一轮(上一节)确认零程序性 bug;本轮独立复核第一轮结论,并新增修复。
新发现并修复的 bug
- AGENTS.md §7.106 第 4 种路径变体:
cmds/apr/update.lpc的main()里present(file, environment(me))在environment(me)为 0 时崩溃(*Bad argument 2 to present())。本库属于 ES II wade/kxkj 血统,走的是apr而非wiz/adm/imm目录,是本项目 第一次在此路径命中该崩溃类。修复:
``lpc
// 修复前
if ((obj = present(file, environment(me))) && interactive(obj))
// 修复后
if (environment(me) && (obj = present(file, environment(me))) && interactive(obj))
`
已跨库扫描确认同一路径变体还命中 kxkj1、kxkjii2、
njhhdxdes2hx、xbtxiii(含本库共 5 库),随本库一并提交、已推送
(独立 commit 413ad703415`)。AGENTS.md §7.106 已补充"第 4 种路径
变体"小节记录这批库。
adm/simul_efun/file.lpc:两处既有类别的实例,本库此前未修: 1.cat(string file, int trans)(2 参数变体,本库特有签名)缺少read_file()空值防护,read_file(file) || ""修复; 2.log_file()缺少assure_file()目录预建保护,且其定义在assure_file()自身定义之前(本驱动不容忍前向调用未声明函数, 参见本 session 在dtsl上的发现),补上void assure_file(string file);前向声明 +log_file()内的assure_file(LOG_DIR + file);调用。
复核第一轮已有结论(独立验证,非盲信原记录)
- 全库 grep
log_error(/logind.lpc两处printf分支:均已有正确 的错误级别门控与参数校验,无 §7.34/§8.9 已知类别的未修实例。 config.fluffos的maximum evaluation cost为1500000,高于本 项目已知的问题阈值(300000/700000),无 §7.90 类崩溃风险,无需调整。- 第一轮记录的"
fight对动物走真杀伤分支、对人形 NPC 走安全分支"现 象复核代码未变,cmds/std/fight.lpc的can_speak分流逻辑与第一 轮描述一致,仍判定为既有设计,非 bug。
现场验证
驱动干净启动(PID 1630062,linux-debug/ASAN 预设),以管理员账号
fluffos/Mud@2026 登录,确认 目前权限 -> 【 天 帝 】(manager)
(角色所在地为第一轮死亡测试遗留的真实存档位置"阴曹入口",非 bug)。
用 update /adm/daemons/logind 验证真实写入权限(重编译成功,确认
file.lpc/update.lpc 两处修复编译干净);update /cmds/apr/update
自我更新命令本身无可见输出(命令对象在执行中自毁重载的正常边界情
况,非 bug,debug.log 确认编译无错误)。debug.log 由 570 行增至
673 行,逐行核对零已知错误特征,仅编译期无害警告。两次快速重连(各
自独立 fluffos/Mud@2026 登录)均正确显示
目前权限 -> 【 天 帝 】(manager),quit 产生正常告别横幅与断线
提示。
本轮修改的文件
work/cmds/apr/update.lpcwork/adm/simul_efun/file.lpc
深度功能测试第三轮 / Deep functional test round three (2026-08-18)
第一、二轮已确认注册/新手引导/fight 安全分流/正规拜师/quit-净断线重连均
正常。本轮先读完第一、二轮记录,确认无重复,转向前两轮未覆盖的系统:经
济(商店买卖)、布告栏(真实发帖/读取)、帮派(cmds/clan/ 整套子系
统)、以及死亡后的完整"奈何桥→鬼门关→酆都城门→黑白无常"复活流程(前两
轮只读过 /open/death/start.lpc 源码,从未真正走完全程)。另确认本库
adm/obj/master.lpc::standard_trace() 用 sprintf("%O", error["object"])
格式化,并未调用 file_name(),AGENTS.md §7.111(file_name(error["object"])
未判空导致的崩溃)不适用本库,无需修补。
修复的程序性 bug
无。全程 debug.log 完全干净(未生成该文件,即零运行时错误),只有编译
期无害警告。
新覆盖并确认工作正常的系统
- 经济 / 商店:
open/capital/room/cshop.lpc(inherit /std/room/shop的正规商行)sell cloth真实卖出(物品从背包移除,店主给出合理反 馈);open/start/room/s5.lpc的小贩 NPC(inherit F_VENDOR)list/buy tea from vendor在余额不足时正确走notify_fail("你的钱 不够。")失败分支,未崩溃、未静默丢失物品。(顺带发现feature/finance.lpc:262有一行if (wizardp(this_object())) printf ("total=%d\tamount=%d\n", total, amount);调试输出,只对巫师身份的 角色可见——判定为刻意保留给巫师看的诊断辅助,不是崩溃或静默失败,未 改动。) - 布告栏(真实发帖):
/open/trans/room/room4.lpc("中央驿站",经call_other(.., "???")惰性加载/obj/board/start_b)post <标题>→ 编辑器.结束 → "留言完毕。",版上留言数从 26 增至 27;read 1正确读出旧文章内容。确认第 §7.86 节此前修的"多余replace_program()"崩溃点在真实post流程下确实不再触发。 - 帮派 / 公会子系统(
cmds/clan/,前两轮完全未测):c_list正确 列出全部 5 个真实存在的帮派(十三吉祥/阴曹地府/傲云山庄/红莲教/天道 无极,adm/daemons/clanvd.lpc::fs_clan()扫描/open/clan/子目录并 过滤系统保留目录)及四项排行榜;c_index列出完整帮务说明文件索 引;help c_deposit/help c_donate文本正常。c_create/c_join读 代码确认均为合理的既有设计门槛(c_create需要wiz_level>=5;c_join需先被现有帮众邀请),非 bug,未做门槛测试(不适合用巫师账 号測試玩家专属流程)。 - 死亡→复活完整流程(前两轮只读代码,本轮首次现场走通全程):从
/open/death/start(阴曹入口)经north×5 依次穿过奈何桥头 →奈何桥上→奈何桥尾→鬼门关(白无常)→酆都城门(黑无常),在酆都城门 停留不动,open/death/npc/bgargoyle.lpc::init()于玩家进入房间时自 动排程 5 段对话(每段间隔 5 秒),全部播完后自动ob->reincarnate()+DEATHROOM->end_death(ob)+ 食物/饮水回满,并 将玩家送回STARTROOM("狂想空间入口处",与新角色注册落地点相同)。 现场验证:score面板从"(鬼气)"状态变回正常称谓显示、精气神回满 100%、食物/饮水回满 300/300,look确认房间已切换。唯一前提: 必须在酆都城门原地停留满约 25 秒(5 段 ×5 秒)让call_out链跑完; 中途再移动房间会让链条在下一次present(ob)检查时静默中止(此设计 与许多 MUD 的"NPC 触发对话需玩家留在原地"惯例一致,不是 bug)。另确 认:任何鬼魂身份的玩家一旦quit/断线重连(走press_enter()),logind.lpc:867的if (user->is_ghost()) startroom = DEATHROOM;会 强制把其重新丢回/open/death/start(阴曹入口)——不管之前走到迷宫 多深处,都会从头开始;判定为刻意的防卡关设计,不是 bug。 阎罗王(Ghost king,open/death/npc/king.lpc):这是复活迷宫外 的一个独立小彩蛋(kneeze下跪给standby属性加值,用于某种"免死 符"周边玩法),与黑白无常的自动复活机制无关,未深入测试(超出本轮 程序性 bug 排查范围,且看起来是内容/玩法而非崩溃点)。
排查但判定非 bug(读代码确认,未改动)
/open/death/start.lpc::valid_leave()的south/up分支是死代 码:函数体对"south"("想回家吗"警告后需要连续尝试 5~9 次才放 行)和"up"(back_road>=10时走旧版"手动重生"逻辑)都有完整实 现,但该房间自己的exits映射里这两个方向都被注释掉了(只留"north"),玩家从来无法在这个房间打出south/up指令(会得到 "什么? south? 请用 help cmds 查询指令。",因为驱动只给已注册的出口 自动生成移动指令)。由于本库真正、可达、已现场验证工作正常的复活路 径是上面那条"黑白无常自动复活"流程,这段死代码不影响任何真实游玩路 径,只是历史遗留(大概率是从更早的版本继承下来、后来把手动重生改成 自动化时忘记清掉的旧逻辑)——不是崩溃、不是静默失败,未改动。- 一开始怀疑
goto /open/center/room/inn会静默吞掉传送(写了个隔离 测试,重开全新驱动作为连线后第一条指令复现),但排查后发现这是测 试脚本的假象**,不是 mudlib bug:本库登录成功后会先打印一条"-- 请按 Enter 键继续 --",要求先按一次 Enter 才会真正开始处理后续输 入;连线后发的第一条"真实"指令实际上被这次按键吞掉了(对任何指令都 会重现,不只goto)。加一条空指令吃掉这次"按 Enter"提示后,同一个goto立刻按预期工作。记录此陷阱供以后同 lineage(ES II)库测试参 考,此次未误报为 bug、未做任何代码改动。
现场验证摘要
驱动 linux-debug(ASAN/UBSAN)预设,两次全新冷启动分别验证:(1) 管理
员账号 fluffos/Mud@2026((manager) 权限)用于经济/布告栏/帮派/死亡
复活流程测试;(2) 全新注册角色 kxkjrthb / 中文名"秦风卅一"(英文 id
只能纯小写字母,无数字——首次因误用带数字 id 被反复拒绝后遭防灌水机制
断线,重新用合规 id 后一次成功注册)验证新手引导(enter→
give cloth to girl→down)流程与第一轮结论一致,down 第二次进入的
是暗室("四周到处黑沉沉的, 看也看不清。",需要光源,属正常暗房设计非
bug)。两条会话全程 log/debug.log 均未生成(零运行时错误)。
进程卫生附注
测试产生的存档churn(data/board/start_b.o 因真实发帖测试、
data/user/f/fluffos.o 因管理员多次登入/移动/复活状态变化)已用
git checkout -- 还原;测试用的全新角色存档
(data/user/k/kxkjrthb.o,未跟踪)与临时创建的 u/f/(供 eval 指
令使用的巫师工作目录,未跟踪)均已删除,未纳入本次提交。驱动进程按
PID 精确 kill(非 pkill 模式匹配)。
§7.100 跨库扫描修复(ROOM 基类同款 replace_program() 致命形状)
- 同款
inherit ROOM; ... replace_program(ROOM);冗余自替换(AGENTS.md §7.100):work/下 1,310 处存活匹配,全部为标准独立行形式,脚本一次 性删除,无不规则残留。房间生成工具obj/roommaker.lpc检查过——它的 heredoc 模板本身没有把这行冗余调用写进生成结果,不受影响,不需要修。data/下的其余.lpc源文件(自动加载装备等)额外核查过,无命中。 验证:真实 debug 驱动干净编译启动、端口正常监听,debug.log无新增 "cannot replace"/错误行。
``§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 open/death/npc/bgargoyle.lpc, open/death/npc/wgargoyle.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): 3 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.
深度功能测试第四轮 / Deep functional test round four (2026-08-21) —
c_create/c_join 缺口补测
第三轮把 c_create/c_join 判定为"合理的既有设计门槛...未做门槛测试"。本轮
专门用两个全新的普通玩家账号(非巫师)把这条路径真正走通一次,同时顺带发
现并修复了三个独立的真实程序性 bug(其中一个影响面很大,波及全库任何未在
原始码里显式写 .lpc 后缀的出口)。
修复的程序性 bug
1. cmds/std/go.lpc(严重,影响全库所有出口移动):第 42 行判断"目标
路径是否已经有 .lpc 后缀"时,切片长度写错——exit[arg][sizeof(...)-2..
sizeof(...)-1] 只取最后 2 个字元,却拿去和 4 字元的 ".lpc" 比较,
永远不相等。后果不是"多余地""重复追加一次"这么简单:由于
exit = env->query("exits") 传回的是房间物件内那个 mapping 的引用,
exit[arg] += ".lpc" 会真的原地修改房间的 exits mapping、且每次
都会追加,不管上次追加过没有。凡是源码里 exits mapping 值没有显式写
.lpc 结尾的出口(很常见的写法,例如 newhand.lpc 的
"enter": "/open/common/room/inn"),第一次有人走这个方向时"侥幸"补上
一次 .lpc 能正常到达;但只要再有第二个人(甚至同一人重连后再走一次)
尝试同一个出口,就会变成 ...inn.lpc.lpc、...inn.lpc.lpc.lpc……
file_size() 找不到这个不存在的路径,玩家会看到"这个方向云雾深锁, 无
法进入, 请通知 wiz!!"——且这个 mapping 是房间的常驻实例数据,一旦第二
次出现问题就会在这次开机剩余时间内对所有玩家永久失效,直到重开机。
现场用三个连续注册的全新角色复现:第一个角色(重连后)成功用
enter 从新手房抵达"狂想空间入口处";第二、三个角色的同一条 enter
立刻失败;用 eval((manager) 权限)直接读出该房间当时的 exits["enter"]
值确认为 "/open/common/room/inn.lpc.lpc.lpc.lpc"(4 次累加,与四次尝
试对应)。修复:把切片改成后 4 字元(sizeof(...)-4..sizeof(...)-1,
并加上 sizeof(...)<4 短字串防护),update 热更新后用 eval 手动把
受污染的活体 mapping 修回 "/open/common/room/inn.lpc",随后新角色的
enter 恢复正常且不再继续污染(lpcc --batch 单独编译通过,git
status 复核无存档 churn)。
- 同一处切片错误的另外三个实例,一并修正(均为纯粹的 2 vs 4 字元
写错,非本次修复的核心,但顺手扫到,风险极低):
- cmds/adm/update_dir.lpc(管理员批量重编译某目录的工具):
if (files[i][0][len-2..len-1] != ".lpc") continue; 永远为真,
这个指令其实对任何目录都是彻底的空操作,从未真正编译过任何档
案。改成 4 字元切片 + 短字串防护。
- cmds/imm/ls.lpc、cmds/imm/lstree.lpc(巫师用的目录列表工
具):同样的比较错误纯属外观问题——.lpc 档案永远被归类
进"其他"颜色(洋红)而非应有的档案类型色,不影响任何功能。一并
改成 4 字元切片,保持三处修法一致。
- 全部 4 个文件用 lpcc --batch 单独编译验证通过(含既有的无害
unused-variable 警告),修复后重开一次全新驱动,log/debug.log
完全没有生成(零运行时错误)。
2. cmds/clan/c_create.lpc:CLANV_D->create_clanv(cid)
(/adm/daemons/clanvd.lpc)这个函数根本不存在——只有一份从未合并
的巫师个人存档 clanvd.acky(不同的、不兼容的旧版帮派编号系统重写)里
才有同名函数。本驱动对 -> 呼叫不存在的函式是静默返回 0、不报错(现场
用 eval 验证过),所以 if (CLANV_D->create_clanv(cid))
ob->set("clan/name", cname); 这个条件永远为假,导致帮主自己的
clan/name 栏位从未真正被设过(CLAN_D 自己的帮派登记表里的
name 字段不受影响,是分开设的,所以帮派本身显示正常,只有帮主个人
角色数据缺这个栏位)。这不只是"少显示一个名字":c_join.lpc 判断
"对方是否已经加入其他帮派"用的正是 ob->query("clan/name")
(不是 clan/id),栏位缺失会让帮主的这项检查失真。修复:拿掉这个死
引用的判断式,ob->set("clan/name", cname) 改成无条件执行,与紧接着
的另外四个 clan/* 栏位写法一致。现场验证:修复前用 eval 直接呼叫
CLANV_D->create_clanv(...) 确认回传 0;修复后完整走一次 c_create,
this_player()->query("clan") 五个栏位(id/name/rank/passwd/
title)全部正确,c_list 也正确显示新帮派名称与帮主。
3. adm/daemons/cland.lpc::clan_query():紧邻的 clan_set()
(上面 8 行)对 undefinedp(clans[clan]) 有防护,clan_query() 却没
有,两者本应对称。现场真实触发过一次崩溃(测试过程中一度出现
/open/clan/<id>/ 目录先于 CLAN_D 数据登记存在的状态——细节见下方
c_create 小节——此时 c_list 会因为 clans[clan][what] 对不存在的
clan 键值做二次索引而崩溃:执行时段错误: *Value being indexed is
zero. 程式: /adm/daemons/cland.lpc:165)。修复:比照 clan_set()
的写法补上 !undefinedp(clans[clan]) 防护,未命中时安全返回 0(与既
有"没有这个字段就是 0"的调用惯例一致)。lpcc --batch 编译通过,
update 热更新后复测 c_list 恢复正常。
c_create/c_join 缺口的最终结论
用 kxjtesta/kxjtestb(两个全新注册的普通角色,密码从略)实测,过程中
读代码 + 现场复现,理清楚了第三轮没深入看的两层机制:
c_create的!me->query("clan") || wiz_level(me) < 5门槛不是笔误, 是刻意设计,且原因藏在adm/daemons/logind.lpc里一段带作者署名的注 释和代码(约 1043-1048 行):
``lpc
// 帮派wiz, 玩家总管才可以有帮派 by ACKY
if (!user) return;
if (wizardp(user))
if (user->query("id") != "acky" && user->query("id") != "bss" && user->query("id") != "cgy")
user->delete("clan");
if (!CLAN_D->have_clan(user->query("clan/id")))
user->delete("clan");
`
也就是说:**任何巫师账号每次登入/重连都会被强制清空自己的 clan/*
数据,只有三个写死的账号 id(acky/bss/cgy,本档案里的原始开发者/
管理员 id,cgy 本人在既有存档里确实就是"恶魔城"帮的真实帮主)例外。
c_create 要求呼叫者自己先有帮派数据,正是把"能开新帮"的权限锁定在这
三个特定管理员账号上(一个刻意的、极窄的管理员专属功能,不是给普通巫师
用的),可以反复开帮但不受一般巫师权限变动影响。这与档案里 5 个真实帮
派全部是原始存档自带内容(而非任何一次现场 c_create 产生)完全吻合。
现场把一个刚用 promote(游戏内建管理指令,账号 fluffos/(manager)
执行 promote kxjtesta (admin))临时提升为 (admin) 的普通测试角色拿来
测试时,两次独立重连都验证到这条清空逻辑确实会把 kxjtesta 的
clan/* 清空**(先用 eval 手动补上 clan/id 通过前置条件、验证
c_create 真的能跑通并生效,重连后再用 eval 复查,栏位又变回空)——
这不是巧合触发一次,是每次重连都必然发生,与源码逻辑完全对应,确认属
于既有设计,未做任何改动(这也是为什么第 2 项 bug 修复時仍然只用
eval`——游戏内建的管理工具——去补足前置条件,而不是绕过或修改这条清
空逻辑本身:这是在满足一个真实的前置条件,不是在跳过一个安全检查)。
c_create命令本身完全能正确工作(见上方 bug 2/3 的修复与验证): 在同一个连线内用eval补上clan/id前置条件后,c_create kxjtesta 测试帮壹 tstclan1成功创建了一个全新帮派,CLAN_D->have_clan()/clan_query()确认帮派数据正确登记,kxjtesta自己的五个clan/*栏位全部正确。c_join的邀请/接受双分支都验证通过:kxjtesta(帮主, rank 1)在 同一房间对kxjtestb执行c_join kxjtestb,走的是"邀请"分支 ("你诚挚地邀请秦风乙加入测试帮壹。");kxjtestb执行c_join kxjtesta走"接受"分支("妳决定加入测试帮壹。")。事后用CLAN_D->clan_query("tstclan1","members")验证成员列表正确变成({"kxjtesta","kxjtestb"}),c_list里"测试帮壹"一行的人数栏也从 1 正确变成 2。全程零崩溃、零debug.log错误。- 一个真实的、与 bug 无关的内容缺口(现场发现,未改动,如实记录): 游戏内没有任何指令能创建一个全新帮派的实体房间目录
/open/clan/<id>/room/hall.lpc——c_room_make/c_build都要求"你必须 已经站在自己帮派的地盘里"才能扩建,但地盘的第一个房间(home指向的hall.lpc)本身从未被任何在线指令写出过;c_list/c_index依赖fs_clan()扫描/open/clan/底下的真实目录,所以一个刚c_create出来、还没有人手动建房间的帮派不会出现在c_list里。为了 验证c_list/c_index在有真实房间存在时能否正确显示(本轮任务的要 求),临时手写了一个最小的open/clan/tstclan1/room/hall.lpc测试用占位房间(验证完毕后已删除,未提交);这证实了 5 个真实帮派的 地盘房间全部是原始档案自带内容、从未真正走过"纯指令创建"这条路——与上 一条"只有 acky/bss/cgy 能开新帮"的发现相互印证:新帮派的实体房间历史 上应该也是这三位管理员手动建档的,不是靠玩家指令自助完成的。判定为既 有内容缺口而非程序 bug(没有崩溃、没有报错,纯粹是"这个指令链条里少了 一环"),未新增任何代码去补造这个建房功能。
标准清单快速核对(本 session 新发现,确认本库现状)
adm/daemons/combatd.lpc的bounce除以零崩溃(4 库确认过的 bug):grep -n bounce全文件零命中,本库不受影响。chacha.lpc的death_stage()重入锁泄漏(另 4 库确认过):find -iname chacha.lpc零命中,本库没有这个文件;本库自己的open/death/npc/bgargoyle.lpc等复活 NPC 已在 §7.112 残留缺口补丁中 单独确认修过(见上方 2026-08-20 小节),与此项无关。- §7.30
feature/skill.lpc未初始化 mapping 存取器防护:复核确认已 有mapp(x) ? x : ([])防护(本 session 早前的 §7.30 语料库扫描已修 过),本轮未再改动。 nitan6/nt6血统的 F_DBASE 继承 bug(feature/attack.lpc/damage.lpc被当成与 dbase 基类平级的兄弟继承,导致裸query()/set()静默失效):读std/char.lpc确认本库的继承写法是inherit F_DBASE; inherit F_ACTION; ... inherit F_ATTACK; ... inherit F_DAMAGE; ...——F_DBASE与F_ATTACK/F_DAMAGE确实是平级(兄弟) 继承,但这正是 LPC 多重继承的标准/正确写法(同一个物件内所有直接 inherit 的函式表会合并进同一张扁平符号表,F_ATTACK/F_DAMAGE内部 裸query()/set()调用会正常解析到F_DBASE提供的实作);另外确 认feature/attack.lpc/feature/damage.lpc自己都没有定义会覆盖掉F_DBASE版本的同名query/set函式。属正常写法,非 bug;本库死 亡/复活、战斗(第一、二轮)等测试早已现场验证过这条链路真实可用,属 于任务描述里预判的"大概率是不相关血统"。
进程卫生附注
- 全程用了两次全新冷启动驱动(PID 各自独立,均按精确 PID kill,未用
pkill),第二次冷启动仅用于最终回归验证(enter正常 +c_list显示回原本的 5 个真实帮派、无崩溃)。 - 测试期间产生的所有存档 churn 均已
git checkout HEAD --还原或删除,未纳入提交:adm/etc/wizlist/wizboss(promote写 入的临时提升记录)、data/clan.o(测试帮派数据)、data/user/f/fluffos.o(活动时间戳 churn)、data/user|login/k/ kxjtest{a,b,c,z}.o等全部测试角色存档(未跟踪,直接删除)、u/f/、u/k/(eval指令需要的巫师工作目录,测试用)、open/clan/tstclan1/(测试用占位帮派房间,见上)。 - 测试角色密码均已设置但不记录明文(
kxjtesta/kxjtestb等),仅以 账号 id 指代。
AGENTS.md §7.19 sweep (2026-09-01): enable_player() reentrancy from init()
Same corpus-wide bug class as mhxy/wuhanzhan (AGENTS.md §7.19): this
lib's feature/command.lpc enable_player() wrapper (around the raw
enable_commands() efun) is reachable from an NPC's init() via a
redundant create()-then-init()-calls-setup()/reset_me() chain --
confirmed via a body-aware static scan of every init() in this lib: 6
NPC files call setup()/reset_me() from init() (e.g.
d/snow/npc/waiter.lpc and the open/gblade/npc/pker*.lpc family),
after create() already made the object living(). Calling
enable_commands() a second time on an already-living() object makes
the driver re-invoke that object's own init() as a side effect,
re-entering the same chain while the original call is still on the
stack -- genuine reentrancy, crashing with "Too deep recursion" (most
likely on an NPC's first-ever preload/compile).
feature/damage.lpc's revive() calls enable_player() again while
the object is still living() (kept alive across the disable_player()
interval by that lib's own internal re-enable_commands()). This
confirms a bare if (living(this_object())) return; guard would be the
WRONG fix -- used the same true reentrancy-flag fix as mhxy instead: a
nosave private int in_enable_player_now; set for the duration of the
wrapper's body, guarding only genuine same-call-stack reentrancy while
leaving the legitimate revive re-enable unaffected. This lib's
enable_player() (unlike most others in the sweep) already had one
early return, if (!this_object()) return;, right at the top -- added
in_enable_player_now = 0; before that return too (rewritten as a
2-line block) alongside the fall-through exit at the end, so both
return paths clear the flag. Verified via a single-file lpcc --batch
compile check (PASS) -- not individually live-boot-tested.
深度功能测试(§10.7,2026-10-04)— negative range ends
scripts/lpc_fix_negative_ranges.py: 21 line(s) in 10 file(s) count a range from the end with < (x[a..-1] -> x[a..<1], x[-2..] -> x[<2..]; KB 06 §7.209). In this driver a negative constant end gave "" / ({ }) and a negative start the whole value, so each of these returned the wrong slice; the compile warning A negative constant as the second element of arr[x..y] is gone from the files that compile. Range lvalues (s[0..-1] = text, the prepend idiom) are left alone. A paired compile of the changed files at HEAD and in the working tree showed no new error.
深度功能测试(§10.7,2026-10-04)— <../x.h> includes resolve: 5 more files load
8 files include a header named relative to themselves in angle brackets (#include <../badman.h>); the driver refuses .. in
a <...> name. adm/obj/master.lpc now answers include_file() with "./" + path for such a name (KB 04 §6.1). lpcc
--batch loads 6 of the 9 files that carry such an include (HEAD: 1); open/start/room/bad{2,3,4}.lpc still fail, their
../badman.h is not in the archive. The lib's warnings pass has not been done (the master itself still declares nosave
functions; stray Big5 backslashes in open/ files).
深度功能测试(§10.7,2026-10-04)— stray backslash before a closing quote
A Big5 character whose second byte is 0x5C was written with one extra backslash after it (the old driver read 5C 5C as one backslash and so completed the character) and the UTF-8 conversion kept it (KB 03 §4.4). Before a closing quote it escapes the quote, the string runs into the next line and the file does not compile. scripts/lpc_fix_big5_quote_backslash.py deletes it when the character before it encodes to cp950 with 0x5C as second byte and the quote ends an expression. Here: open/scholar/room/newplan/npc/guard8.lpc (set_name("…豹\", …)) and data/autoload/scholar/secret_book.lpc (the force and dodge skill names ending in 功\). lpcc --batch: guard8 now loads; the book compiles and fails only when loaded without a this_player().
深度功能测试(§10.7,2026-10-05)— here-document terminators
scripts/lpc_fix_heredoc_terminator.py --all --apply: 5 here-document block(s) repaired (3 with the terminator glued to the last text line, 2 with it indented), so End of file in text block no longer hides the room or object behind them: open/capital/wind-rain.org/obj/bird-blade.lpc, open/capital/obj/bird-blade.lpc, open/capital/room/king/kr4-5.lpc, open/prayer/room/westarea/t.lpc, open/prayer/room/uhen/16.lpc. The terminator must start its line (the lexer's own test, KB 04 §6.10); a glued one lost its newline in the GBK -> UTF-8 conversion together with a half character, which stays out.
深度功能测试(§10.7,2026-10-04)— paths named in another case
The archive comes from a case-insensitive host: files are stored as BAGUA0.lpc, longjing.C, d/SHAOLIN/, the code names them in lower
case (__DIR__ "bagua0", "tea/longjing", "/d/shaolin/..."), so the rooms, NPCs and items behind them could not be loaded (a .C file is
not an .lpc file; KB 03 §4.5). scripts/lpc_case_paths.py --convert --apply kxkj: 14 file(s) renamed to lower case (.C -> .lpc,
.H -> .h) and 26 path reference(s) in 22 file(s) rewritten to the new spelling; 0 skipped, 0 ambiguous. Load check of the 60 objects that were renamed, edited or name a renamed path (HEAD against the working tree, an object is the same under any spelling of its path): 46 PASS -> 60 PASS, 0 that loaded before fail now, 14 more load.
14 files moved (13 .lpc, 1 .C); mostly under open/main/room (13), open/killer/home (1). A rescan with scripts/lpc_warnings.py kxkj is still due: the renamed files are compiled for the first time.
深度功能测试(§10.7,2026-10-05)— room base survives a raising NPC
scripts/lpc_resilient_room.py --apply: make_inventory() of std/room.lpc loads each inventory object as if (catch(ob = new(file)) || !objectp(ob)) return 0;. new() of a file that is not there returns 0 (the room just lacks that NPC), but new() of a file whose create() raises (a skill file for set_skill() this archive never had, a carry_object() item that is not there, a header that never shipped) raised inside the room and the room did not load at all. The wrong-case renames of this lib (the section above) make the NPCs behind them reachable for the first time, so a room that holds one with such a content gap would have gone from "NPC missing" to "room missing"; now it loads without that NPC, as it did before. The room base compiles and loads with the change (HEAD against the working tree). KB 03 §4.5.
深度功能测试(§10.7,2026-10-05)— tail() simul_efun
scripts/lpc_add_tail.py --apply: cmds/apr/tail.lpc calls tail(file), an efun of the MudOS this archive ran on that FluffOS does not have (Undefined function tail: the command did not compile). adm/simul_efun/file.lpc now defines void tail(string file): the last 10 lines of the file, written to the player. Load check (HEAD against the working tree): 1 of the 1 tail command file(s) failed to load at HEAD, all load now, and the simul_efun file loads. KB 04 §6.2.
深度功能测试(§10.7,2026-10-07)— 兵器的 actions 函数指针
set("actions", (: WEAPON_D, "query_action" :));:旧 MudOS 把 (: 字符串, "函数" :) 当作 call_other 函数指针,本驱动把它当作表达式函数指针,求值只得到字符串 "query_action"。没有对应兵器技能时 feature/attack.lpc 直接用兵器的 actions,COMBAT_D 拿到的不是 mapping,reset_action() 后仍不是,记一条 bad action 就不出招——拿着这些兵器打不出攻击。改成别的兵器早已用的 (: call_other, WEAPON_D, "query_action" :)(KB 04 §6.10):std/weapon/throwing.lpc、std/weapon/stick.lpc、std/weapon/whip.lpc、std/weapon/sword.lpc、std/weapon/lance.lpc、std/weapon/arrow.lpc、等共 13 个。改动的文件在 HEAD 与工作树分别加载(新进程),无回退。
深度功能测试(§10.7,2026-10-07)— 编译警告整理
scripts/lpc_warnings.py kxkj --fix 加 scripts/lpc_fix_no_effect.py --apply:共改动 1744 个 .lpc 和若干 .h。HEAD 与工作树分别加载(新进程):1654 -> 1654 通过,无回退;改过的头文件的 68 个包含者 68 -> 68 通过。
手工:
open/mogi/castle/obj/tunsword.lpc、daemon/class/swordsman/obj/tunsword.lpc、tunsword2.lpc、open/poison/obj/esword.lpc:set("actions", (: __FILE__, "query_action" :))——__FILE__是字符串,本驱动把它当作表达式函数指针,求值只得到字符串"query_action",COMBAT_D拿不到招式就不出招(KB 04 §6.10);改成(: call_other, __FILE__, "query_action" :)。esword.lpc第 28 行的名字本身被编码弄坏、整个文件编译不过,HEAD 也一样,未动。adm/daemons/logind.lpcget_id():只在#ifdef MAX_USERS分支用的四个局部变量,声明挪进同样的条件里。- 未动:
open/scholar/npc/fall.lpc、open/scholar/room/newplan/npc/guard4.lpc里单独一行的(: perform_action, "…" :);只造了函数指针、从不调用——要不要让这些 NPC 真的出招是内容设计,不在本次范围。
启动时警告 91 -> 0;新进程登录正常。
深度功能测试(§10.7,2026-10-07)— 群发信件没有收信人
obj/mailbox.lpc send <group> <file> <title>:循环里 mail["to", groups[i]]; 是什么也不做的表达式(LDMud 多值 mapping 的写法),每封信都没有 to 字段;改成 mail["to"] = groups[i];。新进程编译通过。
深度功能测试(§10.7,2026-10-08)— .lpc 后缀的定宽切片
.c 改名 .lpc 时只改了字符串没改切片宽度:f[<2..] == ".lpc" 拿两个字符比四个字符,永远不成立(!= 永远成立),按后缀筛文件、去后缀的代码因此从不运行或截成 x.l(KB 06 §7.238)。scripts/lpc_lpc_suffix_slice.py --apply 改了 1 处比较、0 处去后缀(如 adm/daemons/network/httpd.lpc);改动的文件 HEAD 与工作树分别加载(新进程),无回退。
- 2026-10-10:编译警告第二轮(按驱动报告逐条修):按位 & 改逻辑运算 0 处,返回类型/原型 5 处,NPC+F_UNIQUE 的 init() 0 个,带初始化的未用局部变量 4 个,只在 #if 分支用的声明移进分支 0 个文件;改动 8 个文件,HEAD 与工作树各载入一次无回退(8 objects; HEAD PASS 7, tree PASS 7; regress 0; newly loading 0),这些文件的警告 9 -> 0。
深度功能测试(§10.7,2026-10-11):“无副作用表达式”警告复查(批 4)
daemon/class/officer/cmds/powerup.lpc:count + count / 2;结果被丢弃,官职战力少算三分之一;改为count += count / 2;。open/scholar/npc/fall.lpcin_combat():十行(: perform_action, "…" :);只造函数指针不调用;作者意图(逐个出招)无法确定,改成注释保留原列表,行为不变。open/scholar/room/newplan/npc/guard4.lpc:(: perform_action, "universe.tengin" :),同上改为注释,delete_busy()照旧执行。- 改动的对象 HEAD 与工作区都能载入,无回退。
深度功能测试(§10.7,2026-10-12):编译警告收尾
可编译文件中的编译警告 62 → 0,不加 pragma,逐条在源头修;可编译文件 11632 → 11635。先用 lpc_twin_port.py 把 kxkj1 同日的修正搬过来(18 个文件逐 token 相同),其余按本库代码手改。
发现的真 bug:
- 7 个首领(
open/capital/npc/officer-wu.lpc及npcbak/两份、open/tailong/npc/inn.lpc、open/wu/npc/{sky_yan_jen,win_jen,yan_din_lee}.lpc)战斗喊话里写(: "cmd god_kee" :):这是返回字符串的函数,从不施展 god_kee;改为(: command, "cmd god_kee" :)(本库其他 NPC 用的command("cmd god_kee")同一命令)。 feature/vendor.lpc自己inherit NPC;,d/snow/npc/keeper.lpc、waiter.lpc、open/capital/npcbak/solder_officer.lpc在前面又继承一遍:Illegal to redefine 'nomask' function,从来载不进来;删去叶子那行后载入(kxkj1 同法)。- 十几个 NPC 的
(: "random_move" :)从不走动,改为(: random_move :);open/poison/npc/bigsnake.lpc、snakeking.lpc的(: "special_att" :)改成真指针,并修好special_att()把敌人数组当对象传给tell_room()的错(随机咬一个敌人,kxkj1 同法)。
其余:
- 冗余继承 4 处删去;
ITEM+F_LIQUID容器的long()两份:照驱动原来的选择写出liquid::long(raw)(29 个文件,含搬来的)。 feature/damage.lpc有一个全局临时变量int i(还有ghost死亡标志):open/gblade/npc/{cook,foolboy,shouhon,wen-fun}.lpc、open/scholar/npc/boy.lpc自己的计数器i改名ncount(nosave),open/mogi/dragon/npc/older.lpc从未使用的i删去,open/killer/mon/ghost/npc/bghost.lpc的object ghost = this_object()改名self_ob;open/capital/npcbak/g1.lpc的leader改名helper。都与原来一样是各自的变量,行为不变。daemon/skill/gwhip.lpc的skill_improved改成基类签名;open/start/npc/b_guard.lpc的greeting()改void;4 个港口房间与cmds/adm/make_room.lpc加原型(调用在定义之前)。feature/liquid.lpc本库已是max / 4一档,不需要 kxkj1 的那处修正。
改动的 58 个对象 HEAD 与工作树各载入一次:HEAD PASS 54,tree PASS 57,regress 0,新载入 3(上面 3 个 NPC);open/gblade/npc/wen-fun 两边都在 create() 装备一把不存在的 /u/l/longhair/... 刀时失败,open/clan/new_heaven/room/room3 是贴进来的终端记录,本身不是代码,未动。lpc_audit_removed_locals.py 0 处待看。
- 2026-10-14:新驱动(FluffOS 970d9f09)报
Float value truncated to int(#1426)。47 个文件 98 处:赋值、初始化、return 改写成to_int(...)(值不变,只是写明截断);x op= 浮点先把浮点转成整数再运算(系数小于 1 时 x 直接变 0),改为x = to_int(x op ...):/daemon/skill/shasword.lpc(me_lv *=)、/open/beggar/skill/shasword.lpc(me_lv *=)。改动的对象新进程各载入一次,无回退(scripts/lpc_fix_float_trunc.py,KB 04 §6.10)。 - 2026-10-14:21 个存档文件(留言板 16 个、其他 5 个;
data/board/acelan_b.o,data/board/adam_b.o,data/board/cccc_b1.o…)还是原档案的 GBK 编码,没有转成 UTF-8,restore_object()报Invalid utf8 string后对象以空数据启动(表情守护进程没有表情、留言板没有帖子、玩家无法载入)。scripts/lpc_save_encoding.py逐个按 GB18030 解码,结果按存档格式解析通过才写回(KB 03 §4)。
- 2026-10-14:1 个文件因
Type of returned value doesn't match function return type ( int vs void )整份不编译:声明为void(或没写类型)的函数却返回值,旧驱动照样把值交给调用者。调用者要用返回值的(add_action 处理函数、命令、辅助函数)改为它实际返回的类型:attempt_apprentice()。新进程比对 HEAD 与工作树:1 个对象,新增载入 0,回退 0(scripts/lpc_fix_void_return.py,KB 04 §6.3)。
- 2026-10-14:1 个文件用了颜色宏(
HIW、NOR)却没有#include <ansi.h>(首个错误syntax error, unexpected L_STRING);开头补上;8 个文件的函数声明为int(或void)却返回字符串、对象(int query_seal() { return "…"; }),旧驱动照样把值交给调用者;改为实际返回的类型(scripts/lpc_fix_void_return.py)(KB 04 §6.1、§6.3)。新进程比对 HEAD 与工作树:9 个对象,新增载入 1,回退 0。
独孤九剑招式表越界(2026-10-15,KB 06 §7.243)
daemon/skill/lonely-sword.lpc 的 query_action() 按 15 招写的取招表(action[random(9) + 6] 等),文件里只有 8 招:100 级时有解谜标记 200 次出招 160 次报 Array index out of bounds,没有标记 99 次。加 pick_action(),越界时取最后一招;实测 0 次。
存档读不出来:转码损坏(2026-10-15,KB 03 §4.4)
/data/board/guilty.o、/data/board/skillswy_b.o 在转码时坏了:原档里孤立的 GBK 前导字节被 iconv -c 连同后面的引号一起丢掉,restore_object() 报 Illegal mapping format,读档的对象(玩家、留言板、信件、表情)从空白开始。按 raw/ 原档重新解码(孤立字节丢掉、引号保留),驱动核对全部能读回(scripts/lpc_save_encoding.py --from-raw、scripts/lpc_save_restore_check.py)。
存档读不出来:BIG5/GBK 0x5C 字后的反斜杠(2026-10-15,KB 03 §4.4)
/data/board/bss.o、/data/board/dancer.o、/data/board/hide_b1.o、/data/board/sun.o、/data/bss_record/heart.o、/u/w/wade/chinese.o:第二字节为 0x5C 的字(功、许、么、俞、賊……)MudOS 存档时写成 \\,转成 GB 后字保留,多出的一个反斜杠转义了后面的引号(成功\", 字符串收不了尾),或反过来,MudOS 当作被 0x5C 转义的引号成了字符串的结尾(出\"俞" >)。restore_object() 报 Illegal mapping format,留言板等从空白开始。在出错处去掉或补上这一个反斜杠,直到能读回(scripts/lpc_save_encoding.py --from-raw),驱动核对全部能读回。
留言板 mblade_b 读不出来(2026-10-15,KB 03 §4.4)
data/board/mblade_b.o 原档里一篇留言的标题是 "师□,,少了右引号(GBK 的“□”是真字符),restore_object() 报错,整个板子空白。补上引号,驱动核对能读回。
NPC 带着本库没有的物品,载入失败(2026-10-15,KB 06 §7.73)
1 个文件、3 处在 create() 里 carry_object("<本库没有的文件>")->wear()(或 wield()、set_amount()):carry_object() 得 0,接着的调用报 Bad argument 1 to EFUN call_other(),NPC 根本载入不了,该有它的房间里就少了这个人。多是从别的系统搬来的 NPC 用了原系统的物品路径(最常见:/d/snow/npc/obj/thin_sword、/d/snow/npc/obj/pink_cloth、/d/snow/npc/obj/shoe)。每处改为 { object carried_ob = carry_object(...); if (carried_ob) carried_ob->wear(); }(scripts/lpc_guard_carry_object.py):NPC 照常出现,只是不带这件东西;文件补回来(或是虚拟对象)照样会带上。载入检查:改动的文件改前能载入 0 个,改后 0 个(0 个原来载入不了),没有退步;其余 1 个另有原因(多为 set_skill() 了本库没有的武功)。
去掉的预定义宏 SAVE_EXTENSION(2026-10-18,KB 04 §6.11)
老版 MudOS 给每个 LPC 对象预先定义了 SAVE_EXTENSION(".o");FluffOS 的 ChangeLog(COMPAT_BUSTER 一条)把它删了,改用 __SAVE_EXTENSION__。本库没有自己 #define 这个宏,用到它的文件一律 Undefined variable 'SAVE_EXTENSION',整个对象载入不了。改成 __SAVE_EXTENSION__(scripts/lpc_fix_predefined_macro.py):adm/daemons/network/netmail.lpc、obj/token.lpc。token 是帮派领袖信物;netmail 是网络邮件守护进程(本库缺 mailer.h 等头文件,改后仍载入不了)。改后用 lpcc 逐个载入这些对象:1 个通过,1 个还有别的错误(adm/daemons/network/netmail:/adm/daemons/network/netmail.lpc:17: error: Cannot #include mailer.h)。
move() 的目标房间文件不存在时不再抛错(2026-10-18,KB 06 §7.96)
feature/move.lpc 的 move() 把 err = catch(dest = load_object(dest)) 当存在检查,可目标文件不存在时 load_object() 返回 0、catch 不触发,接着 dest->receive_object() 抛出 Bad argument 1 to EFUN call_other()。留言板 std/bboard.lpc 的 setup() 把自己 move() 到 location 房间,那是巫师的私人房间时(档案里没有这个文件),留言板连同刷出它的房间一起载入不了。catch 之后补上 if (!objectp(dest)) return 0;(kxkj 系是 ob),移动失败、对象留在原处。抽样(每库 300 个对象)里原先因此失败的 31 个对象,现在 15 个能载入。
set_skill() 遇到本库没有文件的武功不再抛错(2026-10-18,KB 06 §7.256)
feature/skill.lpc 里的 set_skill()、map_skill()、prepare_skill() 碰到没有武功文件的名字就 error("F_SKILL: No such skill (…)"),调用它们的 NPC create() 整个中断:NPC 载入不了,刷出它的房间也少一个人。本库有 1 个对象设了本库没有文件的武功(1 个名字,最多的是 fonxanforce)。三处都改成 return:这一门武功不给、不映射,对象照常载入,只是少了它(缺的武功本身仍是内容缺口)。抽样载入这些对象:1 个里 1 个通过。(scripts/lpc_guard_set_skill.py)
全局头文件丢了 1 个宏(2026-10-19,KB 04 §6.16)
/include/globals.h 里没有定义 MAILDIR,用到它们的物件(名单里 1 个)编译时报 Undefined variable/Undefined function,整个物件载入不了(编译器在第一个未定义的名字上停下,后面的错误和警告都看不到)。同系的库在各自的头文件里都有这几行:照其中和本库共有文件最多的那个库,原样补到 /include/globals.h 最后一个 #define 之后,宏体里出现的路径在本库里都存在。名单里的物件除了这几个宏之外还有别的错误,暂时仍载入不了。(scripts/lpc_restore_defines.py)
BIG5 的 0x5C 尾字节(扩展)(2026-10-19,KB 06 §7.266)
BIG5 里 功 等字的第二个字节正好是 0x5C(反斜杠),作者在它后面多写了一个 \,转 UTF-8 后这个多出来的 \ 跑到了收尾引号前面,把引号转义掉,字符串一直吃到文件后面。scripts/lpc_fix_big5_quote_backslash.py 原先只在引号后面跟 , ) ; } ] + 或行尾时才删;这次把“引号后面紧跟颜色宏再接字符串”(HIY"功\"HIR"』")也算进去,删掉多余的 \。
RANK_D 对 0 的称呼(2026-10-19,KB 06 §7.273)
adm/daemons/rankd.lpc 的 query_respect()、query_rude()、query_self()、query_self_rude() 里 4 个函数开头补上 if (!objectp(ob)) ob = this_object();。NPC 在 create() 里写 "…" + RANK_D->query_respect(this_player()) + "…"(inquiry 对话、chat_msg),驱动自己跑 reset() 时没有人在场,this_player() 是 0。旧驱动里 0->query("age") 返回 0,称呼走默认分支;新驱动直接报 Bad argument 1 to EFUN call_other(),房间的 make_inventory() 吞掉错误,被打死的 NPC 再也刷新不回来。用 scripts/lpc_reach_census.py --walk 找到(xkx100 的武当弟子、一灯、汴梁书生…);修在守护程序里,不动 1,800 个 NPC 文件。
两个斜杠开头的物件路径(2026-10-19,KB 06 §7.276)
2 个文件、2 处物件路径写成 //…(如 carry_object("//clone/cloth/hic_cloth")):/open/gsword/room1/blood/room1/r1.lpc、/open/gsword/room2/lee.lpc。当年的驱动不介意(路径先被规范化);新驱动把原样的字符串交给 master 的 valid_read(),securityd 按 //clone 查目录,NPC 的 euid 没有权限,报 Read access denied.,NPC 载入不了。改成一个斜杠。
补回本库没有的基类文件,第二轮(2026-10-19,KB 04 §6.15、§6.18)
宏有定义、基类文件却不在档案里:继承它的对象载入时报 Inherited file '…' does not exist!,编译扫描看不到这一类(scripts/lpc_missing_inherits.py 能列出)。同系的库里有同一个文件,原样拷来(scripts/lpc_restore_bases.py);基类和继承它的对象 include 而本库没有的头文件一起带来。每个基类补回后单独载入,再载入使用它的对象,载不进来、或一个用户也载不进来的撤掉了。
/std/room/class_guild←kxkj1:1/1 个继承它的对象载入
逐个与 HEAD 对比载入,没有退步。
旧驱动的类型宽松:缺省参数、无类型形参、数组初始化、class 变量(2026-10-19,KB 04 §6.19、§6.20)
原来的 MudOS 把调用少传的参数补 0、把没写类型的形参当 mixed、不检查变量的声明类型与初始值,也允许变量叫 class;这个驱动在编译时全部拒绝,整个物件载入失败。修了 5 个文件:/cmds/arch/edguild.lpc、/obj/dagger.lpc、/open/capital/npc/master_chen.lpc、/open/capital/npcbak/master_chen.lpc、/u/w/wade/npc/lover.lpc(scripts/lpc_round_files.py 的修复轮:调用处补写 0、无类型形参补 mixed、string X = ({...}) 补星号、void 函数的返回值,以及 class 变量改名 pick_class)。逐个文件在 HEAD 和改后载入对比:这些文件里 5 个原来载入失败、现在载入,没有退步。
x == "a" || "b":后面的字符串常量永远为真(2026-10-19,KB 06 §7.281)
if (arg == "yuyou" || "yu you") 里的 "yu you" 是非空字符串,永远为真,整个条件对任何 arg 都成立;作者要的是每个字符串都和变量比较。在每个字符串前补上变量和运算符(scripts/lpc_fix_literal_or.py;forrest2.lpc 是 dir == "north" && "south",手工改成 (dir == "north" || dir == "south") && ...):/daemon/skill/moon_sword.lpc(1 处)。
一个巫师目录里的 NPC 多出来的局部变量(2026-10-19,KB 04 §6.10)
u/w/wade/npc/lover.lpc 的 string who, dir, master, item; 四个局部变量都没有用到(这个文件因为前面的修复才开始能载入,终局扫描才看到警告),删掉。
比较链的人工修正(2026-10-20,KB 06 §7.282)
daemon/class/blademan/obj/mkblade.lpc:注释写明 sharp 在 8 以上的武器和材质为 blacksteel / crimsonsteel 的刀剑(倚天剑、屠龙刀)不会被血气特攻溶毁,条件却写成 material != "blacksteel" || material != "crimsonsteel"(永远为真),这两把刀照样被毁;改成 &&(两处)。
if (x = 常量):条件里写成赋值的比较(2026-10-20,KB 06 §7.290)
if (arg = "button" || arg = "按钮")、if (!arg || arg = "") return 0;、else if (check = 0 && tempB != ""):把 == 写成了 =,条件的值就是那个常量,分支对所有非零数和任何字符串(连 "" 都算)永远成立、对 0 永远不成立,变量还被覆盖;驱动对此没有任何警告。每一处 = 改成 ==(scripts/lpc_fix_cond_assign.py,共 2 处)。改动:/daemon/skill/dragon-blade.lpc(1 处)、/daemon/skill/lungshan.lpc(1 处)。
登录密码超过 255 字节:crypt() 抛错(2026-10-20,KB 06 §7.294)
驱动的 crypt() 对超过 255 字节的密钥直接报错(Error in crypt(), check your salt),老驱动则按任意长度散列。在登录提示符下输入 256 字节以上的密码,密码检查那一行就抛错,连线停在一个裸的 > 提示符上,登录走不完(password 指令的旧密码检查同样);用 300 个 x 当参数的扫描发现的。/adm/obj/simul_efun.lpc 里补了一个同名的 simul_efun crypt(key, salt):只有超长的密钥才被截短(先截到 255 个字符,再逐字符截到 sizeof(to_buffer(key)) <= 255,限制按字节算,一个汉字占三个字节),再交给 efun::crypt();普通密码原样散列,已存的密码散列不受影响(scripts/lpc_add_sefun.py crypt)。
(: 函数 :) 指针指向对象自己没有定义的函数(2026-10-22,KB 06 §7.355)
item_desc / inquiry / chat_msg_combat 里的 (: 函数名 :) 指向本对象(含包含文件、继承的父类)没有函数体的函数:编译不报错,用到时驱动报 *Undefined lfun pointer called: 函数名(look 某物、ask NPC about 话题 直接出错,战斗 / 闲聊里的指针在 NPC 的 chat() 里出错,这一拍心跳的后半段被跳过)。scripts/lpc_scan_callout_targets.py --kinds=lfun。 还剩 4 个函数没有补(other 4):原型还在函数体丢了、或者根本没写过,没有可以直接补回的捐赠(别的库同一路径的文件里没有这个函数,或者它还要用本库没有的辅助函数、签名不同),不编造:/daemon/class/killer/obj/ninja-force.lpc:force_damage、/daemon/skill/darkforce.lpc:force_damage、/daemon/skill/ejinforce.lpc:force_damage、/daemon/skill/god-try.lpc:sp_attack2。
log/ 下的日志子目录没有人建:写日志的 write_file() / log_file() 报错(2026-10-22,KB 06 §7.358)
这个库的代码往 log/ 的 2 个子目录写日志:log/RECORD(adm/daemons/channeld.lpc)、log/sky(daemon/class/bandit/master_du.lpc)。压缩包、git clone 和站点包里都没有这些目录(本地启动没有写过它们,gen_keep_dirs.py 没记),write_file() 对不存在的目录抛 *Wrong permissions for opening file /log/dlog/money for append. "No such file or directory",调用它的函数在写日志那一行中断,后面的奖励、标志、步骤都没有执行。本库的 log_file() 会自己建目录(实测,或读源码:nitan 系的 assure_file()),所以这里只记了直接用 write_file() / save_object() 写的目录。把 log/RECORD、log/sky 记进 scripts/wasm_keep_dirs.txt(scripts/lpc_keep_log_dirs.py;站点和 pristine 树按它建空目录)。证明(scripts/lpcc_eval.py,在 /adm/daemons 这类目录下的求值对象里写 /log/zzdirprobe/...,新进程)见 KB 06 §7.358 的实测表。
汉字按字节切片的老写法没有换成按字符:改法名 "澄" + name[2..3]、辈分判断 name[0..1] == "澄" 等 1 处(2026-10-22,KB 06 §7.360)
原档按字节算字符串区间(一个汉字 2 字节):name[2..3] 是名字的第二个字,name[0..1] == "澄" 问名字是不是以「澄」开头。转成 UTF-8 之后,这个驱动的区间和 strlen() 都按字符算(strlen("澄观") 是 2,"澄观"[0..1] 是两个字),老算术原样留着、意思全变:各派掌门的辈分判断(name[0..1] == "澄")永远不成立。
本库 1 处(1 个文件):与汉字常量比较 1 处。例:msg[0..1] != "【" → msg[0..0] != "【"(/feature/message.lpc:45)。scripts/lpc_fix_gbk_slice.py 把下标按字符重算(社区的 UTF-8 版 xkx100utf8 里就是同样的写法,作对照);没有改的:截断(name = name[0..7],现在最多 8 个字,只是放宽)、ASCII 的区间(fname[0..3] == "room"、ctime(time())[4..19])和上下文看不出是汉字的区间。证明(scripts/lpcc_eval.py,bixiecanyang;其余各库是同一份文本):让澄字辈掌门 attempt_apprentice() 一个名叫「张三」的访客,HEAD 的法名是 慧,改后是 慧三;抽样 28 个库的 HEAD / 工作树加载对比 0 退步。工具不幂等([0..3] 折半得 [0..1],又是对齐区间),改过的文件记在 scripts/gbk_slice_converted.txt,不要重跑。
按字节写的汉字循环、茶馆猜诗和同盟频道标题(2026-10-23,KB 06 §7.363)
老档按字节做「一个汉字」:while (i--) if (i % 2 == 0 && !is_chinese(name[i..<0])) 只检查偶数下标,奇数位上的拉丁字母(张a)会过;茶馆猜诗 mixup() 用 strlen(str)/2 再 j=j+j、str[k..k+1] 交换两字节;泥潭系 channeld 的 switch (strlen(fname)) case 4/6/8/10 和 strlen(family)==4/6 按字节长度给同盟 / 门派名加空格。本驱动的 strlen() 和区间都按字符算。scripts/lpc_fix_byte_char.py:去掉奇偶项、把区间改成 name[i..i],按字符重写 mixup() 并把 strlen(first)>=14 折成 7,频道标题的 case / 门派长度改成字符数(对照 aoxiangtianji)。本库 汉字循环 / is_chinese 区间 1 个文件。证明(scripts/lpcc_eval.py):sjplii 的 check_legal_name 在 HEAD 接受「张a」、改后拒绝,两边都接受「张三」;xkx100 的 clubpoem->mixup("离离原上草") 得到「离离原草上」(真交换汉字);nitan_san 两字同盟名得到 【 兄 弟 】。关键对象加载通过。
Gsword 出口仍指向 /u/b/bigcat(2026-10-23,KB 06 §7.371)
剑客区已在 /open/gsword/,出口与 mob 路径仍写 /u/b/bigcat/…。scripts/lpc_fix_bigcat_gsword.py 在目标存在时改写;无对应文件的 ntree/wtree/etree 出口删除。本库 36 处。证明:kxkjii2 的 forest3 HEAD 北向 /u/b/bigcat/room/forest4,改后 /open/gsword/room/forest4 可加载;tree1 只剩南向回 tree。
巫师区出口 faceoff / rence / niulang / yihua(2026-10-23,KB 06 §7.372)
/u/f/faceoff/、/u/r/rence/、/u/onskyer/niulang/、/u/skinys/yihua/ 对应区域已在 /open/world1/faceoff/bird/、/open/prayer/、/d/niulang/、/d/yihua/。scripts/lpc_fix_wizard_area_exits.py 在目标存在时改写,仍缺失的出口行删除。本库 12 处。证明:dreamofseven wood5 四向可加载;xlqy_new2007 天河东西向 niulang;kxkj kitchen7 → prayer。
/open/ 上残留的 == !"…" / || "…"(2026-10-23,KB 06 §7.280 / §7.281 Also)
机械修复器曾把 /open/ 当成巫师家目录跳过;本库的可玩世界就在 open/。
open/badman/ride/deserter.lpc:class == !"bandit"(实为 == 0)使非山贼驯驼奖励永不触发 → != "bandit"。
open/killer/room/doorm.lpc:str == "all" || "corpse" 恒真,任意 sac 抽干气血 → str == "corpse"。
证明:lpcc_eval.py kxkj 加载 doorm;fighter != "bandit" 为 1。
小火龙学者/毒师闪避分支恒假(2026-10-23,KB 06 §7.282 Also)
open/fire-hole/npc/small-dragon.lpc:class == "scholar" && class == "poisoner" 恒假 → ||。
与 kxkjii2 同源;/open/ 不再被 cmp_chain SKIP。
/open/ 上残留的条件赋值(2026-10-23,KB 06 §7.290 Also)
15 文件:gring 的 str = "guard ring"、密道 arg = "water"/"light"、麻将 check = 0 等 → ==。
证明:gring / waterm / mj 可加载。
/open/ 上丢失引号的 shout/say(2026-10-23,KB 03 §4.6 Also)
open/poison/npc/low.lpc(庄静柔)里 command("shout …) / say 在 GBK 转换后丢了引号,机械 closer 仍留下非法中文拼接,对象无法加载。手改为 command("shout 好!" + me->query("name") + "能成功寻回月石,看来本教复兴有望了。");(say 同形)。lpc_fix_eaten_quote.py 的 SKIP 不再把 /open/ 当巫师家。证明:lpcc_eval 加载 NPC,name() 为庄静柔(HEAD FAIL)。
/open/ 上残留的 score/HP 条 *2(2026-10-23,KB 06 §7.365 Also)
lpc_fix_display_pad.py 曾把 /open/ 当巫师家跳过;本库可玩世界在 open/。
open/killer/obj/two.lpc 的 tribar_graph:bar_string / blank_string / bmin_string(○)上的 * 2 在字符区间下把半条画满。SKIP 去掉 open,并教会识别 bmin_string。证明:lpcc_eval tribar_graph(10,15,20) HEAD 二十个●,改后十个●+五个⊙+五个○。
/open/ 上残留的 force 当 wound(2026-10-23,KB 06 §7.241 Also)
open/steeple/obj/npc/npc48.lpc:receive_wound("force", 10000) 而本库 wound 只认 gin/kee/sen → add("force", -10000)。证明:lpcc_eval receive_wound("force",…) 报错,add 正常;NPC 可加载。
/open/ 上残留的 .c 路径字面量(2026-10-27,KB 06 §7.356 Also)
lpc_fix_dotc_path.py 曾把 /open/ 当巫师家跳过。open/killer/home/r0u.lpc 的货物表仍写 "/open/killer/npc/train_a.c",档案是 train_a.lpc;显式扩展名按原样解析,new() 得 0。改为 .lpc。证明:lpcc_eval HEAD new(...train_a.c) 为 0,改后 new(...train_a.lpc) 为对象。
open 下死出口由对侧房间修好(2026-10-27,KB 06 §7.257 Also)
lpc_fix_dead_exits 的 SKIP 曾把 /open/ 当巫师目录。本库本批出口改写见该提交(大小写/错名,由对侧出口回指判定)。证明见 KB。
对象路径残留 .c 后缀(2026-10-27,KB 06 §7.356 Also)
set("objects"/"exits", …) 与 __DIR__"….c" 在改名为 .lpc 后仍带 .c 时,new/load_object/房间 reset 找不到文件(血池房 inv=0)。凡旁有对应 .lpc 的,去掉 .c 后缀。证明:HEAD stone2 reset 后 inv=0;改后 inv=1(/d/youxia/obj/blood)。
深度功能测试(2026-10-27,§6.25 one-arg message_vision)
message_vision("…") 补第二参(me / TP / this_player())。
深度功能测试(2026-10-27,§6.10 未知 pragma save_binary/optimize)
删除本库中 FluffOS 不认的 #pragma save_binary / #pragma optimize… 行。