Ultimate Demon Realm (nitan_san)

✅ 可玩

泥潭三 / 《終極魔界》

nitan_san

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

▶ 开始游玩 · Play Now

站点内部自称"泥潭"(nitan),是 NT/nitan/Lonely 系列真正的"三代"正宗版本(登陆横幅本身就打出"一入泥潭深似海"字样,驱动版本标注"MudOS v22.2b14 NT-Build")。实际连线看到的招牌是《終極魔界》,与它的近亲 nitan_ceshi 一样是套在"泥潭"引擎上的一层皮肤——逐文件比对显示两者远不止"血缘相近":`d/`(中原城市地图,如长安、北京、洛阳,以及峨嵋、华山、崑崙、恒山、嵩山五大门派和更外围的边疆地区)路径下约 98% 的同名文件字节完全相同,是同一份被写好的江湖世界;只有内功心法、玩家指令、管理员守护进程等引擎层分化明显(约三分之一文件不同),说明这更像是同一套代码在不同时期留下的两份独立快照,而不是各自从零开发的作品。新角色同样取姓名、选性格、"洗"天赋后,由盘古在"生命之谷"安排投胎,才算正式踏入江湖,世界观基于盘古开天、转世投胎的创世神话;也和 nitan_ceshi 一样不需要外部 MySQL 数据库,注册、存档全部走本地文件。

English

The true 'third generation' release of the NT/nitan/Lonely engine lineage — its login banner literally reads 'once you enter the Mire, it runs as deep as the sea.' Like its close relative nitan_ceshi, it's branded in-game as 'Ultimate Demon Realm,' a skin over the shared nitan engine. A direct file-level comparison shows the two are near-total duplicates of the same authored world rather than independently evolved games: about 98% of matching-path files under d/ — the same Central-Plains cities, the same Five Great Sects, the same frontier zones — are byte-identical, while the two diverge much more in their engine layers (kungfu skills, commands, admin daemons each differ in roughly a third of files), pointing to separate later snapshots of one shared codebase. Character creation follows the same creation-myth path: choose a name and personality, reroll stats, and be delivered into the world by Pangu at the Valley of Life. It shares its sibling's independence from any external database — registration and saves are entirely local-file-based. A separate git-hosted mirror of this exact codebase is also in this collection as nitan3, confirmed byte-identical across 15,235 of 15,236 shared files and marked as a duplicate of this entry.

README

在线试玩

https://mudlibs.fluffos.info/nitan_san/

管理员账号 / Admin account

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

本地运行

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

游戏端口:40055。文件数量较多,驱动启动后需要约二十秒完成预加载。

NOTES · 移植与修复记录

nitan_san — 泥潭三 (NT/nitan/Lonely mudlib lineage)

Archive: archives/泥潭三.rar (archive #61). Port: 40055. Status: done (boots clean, connects, full registration flow verified end-to-end with real Chinese names, reaching an actual game room — no MySQL backend needed).

What this is

The mudlib's own config (config.cfg) self-identifies name : 泥潭 ("Nitan"/"Mud Pit") and internet mud name : nitan.3 — i.e. this genuinely is "泥潭三"/"Nitan III", matching the archive's own title exactly (no slug discrepancy worth noting beyond the ASCII-ization to nitan_san). The live banner branding is actually 《終極魔界》 ("Ultimate Demon Realm") — a re-skin/theme layered on top of the underlying "nitan" engine, the same "self-ID differs from live banner" relationship documented for several other libs in this project (wmkj #55, nitan_ceshi #60). u/lonely/welcome (the actual banner used, distinct from a generic adm/etc/welcome template also present but unused) explicitly renders "泥潭" ASCII art with "一入泥潭深似海" and "驱动版本: MudOS v22.2b14 NT-Build" — this really is the flagship/eponymous "Nitan" game the whole "NT/nitan/Lonely" family in this project is named after.

Extracts to raw/nitaniii/ (one directory level, not top-level) — work/ was built directly from that. 15,252 raw files / 13,559 .lpc after conversion (+2 for two new simul_efun fragments added during this pass) — a genuine mega-lib, well inside the "risky for a full lpcc sweep" bracket established by xo_final (7,174 files) and confirmed again by the sibling archive #60 (nitan_ceshi, 13,497 files) processed concurrently this same session.

Lineage confirmation

Confirmed same "NT/nitan/Lonely" engine family as nitan170911/nitan6 (and, per its NOTES.md, the concurrently-processed sibling nitan_ceshi, archive #60) via direct diff against nitan170911's raw archive, but this is yet another distinctly-laid-out snapshot, not a byte-identical fork of either:

Compared against sibling archive #60 (nitan_ceshi), whose NOTES.md was available by the time this pass finished (both processed concurrently by separate agents): the two are clearly close cousins, not identical — both self-identify internet mud name : nitan.3 and share the adm/ single/ layout, the "Lonely for nt2" master.c credit, the same core "NT/nitan/Lonely" simul_efun architecture, and (remarkably) the exact same set of driver-compat bugs (§15h × chinese.lpc/named.lpc/logind.lpc, the LONELY_IMPROVED-gated missing-efun family including the identical bignum count() gap, the is_killing typo in clone/user/user.lpc:792, and the eventd.lpc/storyd.lpc .c.lpc rename-width bug) — strong evidence the two archives are sibling snapshots of the same underlying codebase at a similar point in its evolution, independently confirming each other's fixes were correct rather than one agent copying the other's work. Differences found: this lib's feature/dbase.lpc/adm/simul_efun/ wizard.lpc composition matches nitan_ceshi's (§15's core bug does NOT apply to either — see below); this lib's u/lonely tree already has rmtree() folded directly into adm/simul_efun/file.lpc (already wired into simul_efun.lpc via that file's existing #include), whereas nitan_ceshi needed a separate fix to wire in a disconnected standalone /u/lonely/rmtree.lpc; this lib's data/topten/ directory exists (no missing-content gap there, unlike nitan_ceshi); and this lib fixes the quest set_information bug at its true shared root (widening one signature in inherit/misc/quest.lpc) rather than leaving it as documented-but-unfixed content noise (see item 9 below) — nitan_ceshi's own quest daemons still show this failure in its NOTES.md, whereas this lib's does not, after the fix.

Crucially, §15's core dbase architecture bug does NOT apply here — verified by reading feature/dbase.c directly, same as nitan_ceshi: it already has real, local set/query/delete methods (not just storage variables) — precisely the shape §15's fix prescribes for nitan170911/nitan6. adm/simul_efun/wizard.c here is a tiny 2-function file (wizhood/wiz_level) with no set/query/delete fallback at all. Confirmed zero efun::set(/efun::query(/ efun::delete(/efun::addn( call sites anywhere in the lib. This snapshot's dbase architecture was never broken the way nitan170911/ nitan6's was — the single biggest fix-class in the whole project simply doesn't apply to this branch of the lineage, confirming (a second time, independently of nitan_ceshi) that "same family name" does not mean "same bugs" even within one mudlib lineage.

Fixes applied (with why)

1. config.fluffos: master file/simulated efun file set to /adm/single/master / /adm/single/simul_efun (this snapshot's actual layout). 2. adm/simul_efun/chinese.lpc's is_chinese() (§15h): GBK byte-range check (str[i] < 161 || str[i] == 255, i % 2 alternating-lead-byte gating) rewritten as a CJK Unicode codepoint range check (0x4e00-0x9fff); min-length bound strlen(str) < 2 (bytes) → < 1 (chars); dropped the i % 2 gate entirely (every index is already one character now). 3. adm/daemons/logind.lpc's check_legal_name() (§15h): internal strlen(name) < 2< 1; both call sites' maxlen argument check_legal_name(arg, 4)check_legal_name(arg, 2) (confirmed correct by the prompt text itself: "不要超过两个汉字" = maxlen 2); combined surname+name length gate strlen(fname) < 4< 2. 4. adm/daemons/named.lpc (§15h, the PATH()/sliding-window family): #define PATH(name) (name[0..1] + "/" + name) ("first GBK char", 2 bytes) → name[0..0] (first character); every strlen(name) < 2 empty-name guard → < 1; the similar-name sliding-window check's window widths name[i..i+3]/name[i..i+5] (2/3-GBK-char byte windows) → name[i..i+1]/name[i..i+2] (2/3-character windows), loop bound i <= l - 4i <= l - 2, inner i + 6 <= l guard → i + 3 <= l, pre-check strlen(name) < 4< 2. 5. securityd.lpc's valid_read/valid_write (§15n): this lib has a genuinely custom ACL (exclude_read/trusted_read/exclude_write/ trusted_write tables, not the simple find_object-only pattern) — added the standard early-allow for func == "load_object" / "recompile_object" / "include" at the top of both applies, before any ACL-table logic, so the driver's own compile-time source/#include loading (triggered by the registration flow lazily touching never-preloaded /adm objects) is never denied by a fresh not-yet-authenticated connection's default "(player)" status. 6. master.lpc: added get_include_path() (§8d/§15o) — wasn't defined at all. Fixes ~15 files under kungfu/class/ultra/, clone/ weapon/, u/lonely/quest3/, adm/daemons/huanjing2003/ that #include <local.h>-style same-directory headers (convert_lib.sh's own local-angle-bracket-to-quotes pass already converted the ones it could detect offline at preload/bare-lpcc-check time; this apply additionally covers compiles triggered live, mid-connection, per §15o's driver-source note on init_include_path()). 7. adm/etc/preload: commented out /adm/daemons/network/dns_master (§15p, standing policy) — intermud/cross-mud daemon, never needed for registration-flow testing. (No literal .c-suffixed entries needed §15c's fix — this file already stored bare extension-less paths.) 8. LONELY_IMPROVED-gated efun::X() calls to efuns that never existed on this (or any) FluffOS build#define LONELY_IMPROVED is unconditional in include/globals.h (the *global* include file, so these branches are always compiled in, not a real feature toggle). Checked every real FluffOS .spec (~/src/fluffos/src/packages/*/ *.spec) to confirm each is genuinely absent, not misspelled: - adm/simul_efun/file.lpc's file_lines(), adm/simul_efun/ message.lpc's sort_msg() (efun::sort_string), adm/simul_efun/ util.lpc's sort_string()/filter_color()(efun::filter_ansi)/ file_crypt()/file_valid() — each already had a working pure-LPC #else fallback written right there in the same function; flipped the guard from #ifdef LONELY_IMPROVED to #if 0 at each of these 6 call sites so the existing fallback is always used instead of reimplementing anything. - count_add/count_mul/count_sub/count_div/count_lt/ count_gt/count_le/count_ge/count_eq/big_number_pow in util.lpc: wrap a bespoke arbitrary-precision bignum arithmetic efun (count(n1, op, n2)) with no #else fallback at all — a hard compile-blocker for simul_efun.lpc itself (confirmed: this alone stopped the driver from booting past simul_efun). This helper is used across ~230 files (grep hit count) — mostly combat/currency/ experience math throughout kungfu/, d/, clone/, adm/daemons/. Implemented a real, from-scratch arbitrary-precision decimal-string signed integer arithmetic library (new file adm/simul_efun/ bignum.lpc: schoolbook add/sub/multiply, digit-by-digit long division, sign-aware comparison — handles both int and numeric- string inputs uniformly via sprintf), #included into simul_efun.lpc before util.lpc (function-defined-later-in- same-file ordering rule, §8b) and rewired util.lpc's efun::count( calls to bare count(. Chose a genuine bignum implementation over a simpler 64-bit-int-cast shortcut specifically because the sibling archive nitan_ceshi's NOTES.md documents that shortcut crashing at runtime on a real numeric-string call site (count_mul(..., "50000") during NPC stat setup) — a real bignum library sidesteps that whole class of bug by construction, at a modest one-time implementation cost. 9. inherit/misc/quest.lpc's set_information() wrapper (§8g-style, new): declared its own info parameter as string, but the real implementation it delegates to (adm/daemons/questd.lpc's set_information(object, string, mixed)) already declares it mixed — and 9 quest clone templates (capture/deliver/defend/ explore/trace/search/supply/judge/shen, all under clone/ quest/) legitimately pass a function pointer (: ask_npcN :) here, not a string. This overly-strict local type rejected every one of them at compile time (Bad type for argument 2 of set_information ( string vs function )), first surfacing as a crash in adm/daemons/quest/ capture.lpc's own heart_beat()start_quest()new(...) the first time the crontab-driven quest-generation daemon tried to instantiate one. One shared root cause, not 9 separate bugs (§8g) — widening this single signature to mixed info resolved all 9 at once, confirmed via a clean subsequent boot with zero set_information errors in debug.log. 10. adm/daemons/timed.lpc:349 (§15f): array localtime = localtime(realtime); — bare array as a full type-by-itself declaration (silently fails to register a usable variable on this driver), compounded by naming the variable identically to the localtime() call assigning to it (syntax error, unexpected L_DEFINED_NAME / Illegal LHS / Value indexed has a bad type: "function " on every subsequent localtime[...] use). This is on the direct preload path (timed's real-time crontab tick, touched by every connecting player's uptime-banner routing). Fixed by renaming to mixed *lt and using lt throughout the function. 11. adm/simul_efun/ntefun.lpc's process_function(array fp) (§15f-style, new variant): same bare-array bug, but on a *function parameter* declaration rather than a local variable — void process_function(array fp) is a hard parse error (Missing type for argument / syntax error, unexpected L_IDENTIFIER) on this driver, and since this file is #included directly into simul_efun.lpc, the error was fatal to the whole simul_efun compile. Fixed to mixed *fp. 12. adm/simul_efun/message.lpc's message() wrapper (§15s): several internal callers (message_system(), channeld.lpc's do_channel()) invoke this with a literal 0 as the 4th ("exclude") argument, which flows straight to the real message() efun — this driver rejects a raw int 0 there (Bad argument 4 to EFUN message() Expected: object, array, Got: int(0)). First surfaced as a crash in channeld.lpc's do_channel() broadcasting the quest-daemon's own startup announcement (a "系统报告" channel message), which happens during normal preload-adjacent daemon activity, not something registration- flow-specific but reachable very early regardless. Fixed once at the shared root: exclude || ({}) before delegating to efun::message(). 13. clone/user/user.lpc:792: if (is_killing(ob)) — pre-existing content typo. is_killing(string id) (feature/attack.lpc) takes a string id, matching every *other* call site in the whole codebase (feature/attack.lpc itself, 20+ other files, all correctly pass ob->query("id")/me->query("id")) — this one direct (non-call_ other) call passed the raw object instead (Bad type for argument 1 of is_killing ( string vs object )). Since this is a direct function call (not ->), the driver's static type checker enforces the parameter type strictly, and this single call site blocked /clone/ user/user — the player body class itself — from compiling, silently breaking character-creation completion right after gender selection (same shape/impact as §15b's query_shadowed() finding on tianxia, archive #50 — "the player body class fails to compile" is now a confirmed recurring failure mode across at least 3 unrelated libs in this project). Fixed to is_killing(ob->query("id")). 14. adm/daemons/eventd.lpc and adm/daemons/storyd.lpc (new .c.lpc rename-fallout variant, extending §2): both do get_dir(DIR + "*.lpc") then strip the extension via a hardcoded fixed-width slice, map_array(names, (: $1[0..<3] :)) — correct for the *original* 2-character .c extension, but leaves a trailing l on every name now that the extension is 4 characters ("emei.lpc"[0..<3]"emei.l", not "emei"). This directly caused eventd.lpc's own preload-time collect_all_event() to fail with call_other() couldn't find object '/adm/daemons/event/emei.l' on every boot. Fixed both to [0..<5] (cutoff moved by the same +2 the extension grew by). Not fixed (same shape, not observed failing, not exercised by the registration-flow test, per §6b/15f's "fix what surfaces" convention): adm/npc/luban.lpc (1 occurrence, a housing-key admin NPC) has the identical [0..<3] pattern. 15. d/city/npc/paimaishi.cc.lpc: a genuine LPC object (an auctioneer NPC, referenced extensionlessly from d/city/pmc.lpc) that the raw archive shipped with a .cc extension instead of .cconvert_lib.sh's blind *.c*.lpc rename never touches .cc files, so this one was silently left un-renamed and un-loadable (the extensionless reference resolves via .c/.lpc fallback only, never .cc). file/convert_lib.sh's text-detection correctly still UTF-8-converted its contents despite the odd extension. Renamed to .lpc to make it loadable. Not otherwise verified clean: an lpcc spot-check on this file alone (not exercised by the registration-flow test — it's an un-preloaded city NPC) surfaces 3 genuine-looking pre-existing content errors (Undefined variable 'who'/'amount', a stray syntax error, unexpected '}') — this file was also flagged LOSSY conversion (invalid bytes dropped) during the encoding pass, so these may be encoding-corruption fallout (per AGENTS.md's iconv -c adjacent-byte-eating gotcha) rather than original-archive bugs; not chased further given it's off the tested path — flagged here for whoever next touches city-zone NPCs.

Confirmed NOT needed (checked, didn't apply)

Interactive test transcript / outcome

Driver booted on port 40055 (libs/nitan_san/config.fluffos), cd'd into libs/nitan_san per the log directory convention. Multiple full end-to-end registration runs via mudclient.py in continuous sessions (single connection per run, so logind.lpc's new-account IP throttle never had a chance to trigger, per §15j):

Run — id qinfengsi, surname 秦, given name 风, gender male: banner renders correctly (UTF-8 Chinese intact, ANSI colors correct — the "GB or BIG5" pre-id prompt confirmed as a genuine pre-id gate, not a hidden literal-check trap per §15q, since sending the id directly worked immediately), uptime/online-count lines print clean, username validates, confirm-new-character prompt appears, surname/given-name both accepted on the first try (validating the §15h fix — single-character Chinese surname and given name, the exact case documented as broken pre-fix across ~20 other libs in this project), admin password set+confirm, normal password set+confirm, gender selection, player body (/clone/user/ user) compiles and loads (validating the is_killing fix), reaches "目前权限:(player)", and lands in an actual room:

注册房间
 为保障每一位玩家的权益,本游戏实行新玩家电子邮件注册制度...

look correctly re-displays the room; quit correctly triggers the intentional (non-bug, matches the §15j "anti-throwaway-account" family) new-account confirmation gate: "你的账号是新建的,本站规定新建账号必须 连续在线半小时才能被有效保留,退出该游戏将删除你的账号,你确定要放弃 该帐号而退出吗?(y/n)".

Follow-up runs (fresh ids qinfengliu/surname 秦 given-name 岭, then qinfengba/秦淮): confirmed the duplicate-name rejection works correctly ("对不起,这个名字和 qinfengsi 的名字重复了" when accidentally reusing "秦风" a second time), confirmed answering n at the quit-confirmation gate correctly aborts the quit and resumes play ("您选择了放弃退出(quit), 继续游戏。"), and confirmed look/quit both work identically across independent sessions.

log/debug.log shows zero errors across the final (post-all-fixes) boot and every subsequent test run — the only lines matching "error"/"错误" anywhere in log/stdout.log are the literal config-key names mudlib error handler/trap crashes echoed at startup, not actual errors. (The visible "编译时段错误:... Unknown #pragma, ignored." lines streamed to the connecting client mid-session are cosmetic: this driver apparently mirrors compiler *warnings* — not errors, despite the label text — to the connected player for every never-before-touched file it lazily compiles during that player's own action chain; every file in this lib emits this exact one warning, "Unknown #pragma, ignored", for a #pragma this driver doesn't recognize but tolerates. Harmless, matches zero corresponding debug.log entries, and does not interrupt the underlying command flow.)

One unreproduced instability, noted per this project's established "flag, don't block on" convention (cf. yueyingqiyuan's NOTES.md): a single test run's driver process was found gone (Connection refused on the next connect attempt) shortly after that run ended with an *unanswered* quit-confirmation prompt (client disconnected without sending y/n). No crash trace of any kind appeared in log/stdout.log or log/debug.log (a real SIGSEGV/native crash on this driver normally prints a backward-cpp stack dump, per §8/§15l precedent — none appeared here). Attempted deliberate reproduction twice more (reaching the same quit-confirmation prompt, then letting the connection drop without answering) — did not reproduce either time; the driver survived. Given several other agents' driver/lpcc processes were running concurrently against this same host throughout this pass (confirmed via ps/free -hwuhanzhan #58 and nitan_ceshi #60, both mid-flight at the time), an environmental cause (transient host memory pressure, a concurrent process interaction) is more likely than a genuine mudlib or driver bug — flagged here for future investigation, not treated as blocking given it didn't reproduce across 2 further clean full-registration runs plus a final boot-only verification, all with the driver still running and responsive when explicitly killed at the end of this pass.

lpcc sweep

Not run. 13,559 .lpc files — squarely in the mega-lib bracket this project has already established as risky (xo_final, only 7,174 files, already drove this same 23GB host to ~214MB free with heavy swapping; nitan170911 at ~54,600 and nitan6 at ~23,100 both had their sweeps killed/skipped for the same reason). Compounding factor this session specifically: multiple other agents' driver/lpcc processes were confirmed running concurrently against this host for most of this pass (wuhanzhan #58, nitan_ceshi #60, jhfy, moniHuafu at various points) — free -h showed free memory drop as low as ~830MB at one point mid-session. Per this archive's own task instructions and AGENTS.md §6b, skipped the full sweep entirely and relied on the boot + multi-run interactive-connect test above, which is what found and fixed every real bug in this pass (the count() bignum gap alone would have been a hard blocker for a bare lpcc --batch sweep too, being a simul_efun.lpc-level compile failure — that class of bug doesn't need a sweep to find, a single boot attempt already surfaces it).

A single targeted lpcc spot-check (not a full sweep) was run on one specific file of interest (d/city/npc/paimaishi.lpc, item 15 above) and found 3 pre-existing content errors unrelated to any of the fixes in this pass — noted there rather than chased, since the file is off the tested path (an un-preloaded, never-visited city NPC).

Re-verification pass: driver rebuild + formatter + WASM (2026-07-23)

WASM-enablement pass (2026-07-23): loopback-allow + uptime bypass + admin seeding

Same patch set as sibling nitan_ceshi (identical gate shapes):

Admin account: fluffos, normal password Mud@2026, 管理密码 Mud@2026admin, Chinese name 浮浮 (姓浮名浮 + full-name confirm step). Granted (admin) via /adm/etc/wizlist (目前权限:(admin) shown at entry). Verified: real-flow registration, reconnect, and update /adm/daemons/band.lpc succeeds. Saves at data/login/f/fluffos.o + data/user/f/fluffos.o (untracked, not gitignored — orchestrator must add). Fresh normal registration (秦/风/testqa) re-verified end-to-end; test char saves removed; debug.log clean.

Fail-closed retrofit (2026-07-24)

Same correction as documented in detail on sibling nitan_ceshi (identical gate shapes): the uptime()/multi-login-cap carve-outs' "only apply the gate if the IP parses AND isn't loopback" logic silently exempted malformed IPs too; tightened to "apply the gate unless the IP is strictly loopback". band.lpc's explicit !stringp-as-loopback clauses tightened the same way, with its original malformed-format fail-safe (return 1 = banned) restored. Re-verified loopback fluffos login, look, update /adm/daemons/band.lpc, and quit all still work after tightening.

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

nitan_ceshi 的手足快照。状态已从过时的 limited 修正——这份档案自己的 README 里从未记录过任何缺陷说明,本轮重新测试也没有发现:管理员登录(fluffos/Mud@2026)被识别为巫师账号("没有设置巫师专用密码"的提示按预期出现,只是装饰性警告),干净地进入游戏世界,quit 干净。和 nitan6(015)、nitan_ceshi(041)是同一家族/同一流程。

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

§10.7 深度游玩测试尝试记录(本轮未完成,供下次接续)

注意:本节标题故意避开候选库挑选脚本 grep 的关键词("深度"+"功能"+ "测试"连写),因为本轮没有完成实机验证——这样下次巡检还会把 nitan_san 挑出来重新尝试,而不是被误判为"已完成"。

已应用、高置信度的程序性修复(源码层面已核实,未做完整实机验证)

本库和刚测完 nitan_ceshi(同一 "NT/nitan/Lonely" 血统,见本文件顶部 "手足快照"说明)共享同一个 §7.11 类缺陷(运行期目录缺失 + 无保护的 write_file()),三处调用点全部按 nitan_ceshi 已确认的修复手法处理:

三处改动均逐字对照 nitan_ceshi 已验证成功的写法,模式高度成熟(本 session 至此已有 15+ 次独立确认实例),有很高把握是正确的,但本轮未 能通过实机注册流程验证,见下方原因说明。

未完成实机验证的原因:本 session 环境下这份快照的驱动预载异常缓慢

连续 4 次尝试从 config.fluffos 所在的库根目录启动原生驱动 (~/src/fluffos/build/src/driver config.fluffos,linux-debug 预设, ASAN/UBSAN),全部未能在预载阶段结束前完成:

对照:体积/文件数几乎相同的手足库 nitan_ceshiwork/ 目录 82M/13913 个 .lpc+.h 文件,本库为 79M/13852 个,几乎一样)在同一套 驱动/同一 session 里稳定在 90 秒到 2 分钟内完成预载并可连线——按日志 行数估算,nitan_san 每文件的预载耗时比 nitan_ceshi 慢了一个数量级 以上。本文件最上方"状态:done(boots clean, connects...)"的描述来自 更早一轮测试(很可能是不同驱动/环境下做的),并非本轮结论——本轮 在本 session 的原生 ASAN 驱动下反复复现了这个异常缓慢的预载,怀疑与 ASAN 在这份快照某处特别深/特别大的结构上开销异常有关,但没有进一步深 挖具体是哪个文件/子系统(超出本轮已投入的时间预算)。对比过 config.fluffosmaximum buffer size/maximum byte transfer 等几个 数值比 nitan_ceshi 大不少,time to clean up/swap/reset 只有 nitan_ceshi 的一半),没有找到能直接解释 10-20 倍预载耗时差异的单一 配置项,未做进一步论证前不下结论。

遗留给下一次巡检:直接从这里接着做——三处源码修复已经就位且高置 信度正确,欠缺的只是实机验证(注册、安全切磋、正规/快捷两条技能路 径、quit/重连持久化,参照 nitan_ceshi 的完整清单)。如果下一次驱动 恰好在一个不被容器重启打断的窗口里顺利跑起来,直接接着走完 §10.7 清 单、把正式的深度测试小节写进来即可,不需要重新调查源码层面的 bug。

追加证据(第 5 次尝试,2026-08-07 22:xx):这次驱动进程本身连续跑 了满满 58 分钟都没有被容器重启打断(和前几次不同),依然没有监听 40055 端口——debug.log 编译警告行数到 10069 行(比第 4 次同一时间点 的 9483 行略多,说明确实还在缓慢推进,不是卡死),RSS 涨到约 12GB, 系统可用内存降到 715MB,为避免和后续巡检的驱动争抢仅剩的 4 核/内存, 主动按记录的 PID(2509,连同其 nohup 包装进程 2508)杀掉了这次尝试。 这基本排除了"纯粹是容器重启运气不好"的猜测——即便给到接近一小时 的不被打断的窗口,这份快照在本 session 的原生 ASAN 驱动下依然无法完 成预载,说明这确实是这份快照本身内容层面的问题(不是环境抖动),值 得下次单独开一轮做根因排查(例如二分预载顺序、逐段注释掉大块内容试 探是哪个子系统异常慢),而不是继续盲目重试同样的"整个驱动等一小时" 打法。

WASM 未验证说明

按本 session 约定:emsdk 固定从 storage.googleapis.com 拉取,被本 session 出站代理策略拒绝(curl -sS $HTTPS_PROXY/__agentproxy/status 返回 403),WASM 编译/运行验证本轮继续跳过。

深度功能测试(2026-08-12,round two,新驱动重测——补完上方"尝试记录")

重要更正:上方"§10.7 深度游玩测试尝试记录"一节记录的"预载异常缓慢(10-20 倍于手足库 nitan_ceshi,怀疑是内容层面问题)"结论是错的,根因是测试用的驱 动构建本身,不是这份档案的内容。 那几次尝试用的是 ~/src/fluffos/build/ src/driver(ASAN/UBSAN 插桩构建);本轮改用这个项目其余所有 round-two 测 试统一使用的 ~/src/fluffos/build-debug/src/driver(无插桩的纯 debug 构 建),预载在 33 秒内完成、干净监听端口——和手足库 nitan_ceshi 的量级 完全一致,之前记录的"10-20 倍差异"、"疑似内容层面问题,值得单独开一轮根 因排查"的结论应视为撤销:这纯粹是 ASAN 插桩对这份档案某处开销异常大的代 码路径的固有减速,不是这份档案本身有问题。以后测试这份档案(或任何类似 "预载异常慢"的档案)优先换用非插桩的 build-debug 排除这一类假阳性,而 不是花时间做二分排查。

已应用的三处 §7.11 修复(上方已记录,本轮现场验证)

toptend.lpc/file.lpc::log_file()/master.lpc::log_error()assure_file() 三处改动(含从 nitan_ceshi 移植来的 quest.h/ toptend.lpc 修复)均现场验证:干净注册流程正确显示"你名列最近十大富翁/ 高手排行榜第五名!",log/debug.log 总行数在整个流程中保持 365 行不变。

新发现并修复:log_file() 的 euid 提权在 assure_file() 内部被自己撤销

adm/simul_efun/file.lpclog_file()seteuid(ROOT_UID) 再呼叫 assure_file(),但 assure_file() 自己的实现在结尾做了 seteuid(getuid()) ——把调用者刚设置的 ROOT 权限撤销了,等 log_file() 接着呼叫 write_file() 时,实际跑在撤销后的低权限下,对 /log/nosave/ 这种没有单 独走白名单的路径命中"Wrong permissions for opening file ... for append." (本轮由 cmds/usr/quit.lpcconfirm()→"y"确认删号分支触发,写 /log/nosave/register 的注销记录)。修复:assure_file() 返回之后、 write_file() 之前再呼叫一次 seteuid(ROOT_UID),恢复调用者原本设定的权 限。现场验证:注册一个抛弃用测试角色(zhaoliuqi),真的走完 "quit"→"y"确认删号流程,log/nosave/register 文件被正确创建并写入 "Aug/12/2026 ... zhaoliuqi(zhaoliuqi) commits a suicide from 127.0.0.1",debug.log 总行数全程保持 365 行不变(对照修复前的 stale 报 错行仍在文件靠前位置,是修复前那次尝试留下的,本轮没有再新增一条)。

新发现但未修:随机送货任务系统的 /inherit/item/combined 运行期"No

program"报错

adm/daemons/quest/deliver.lpcheart_beat()(送货任务生成,本轮因 quest.hset_information 类型修复而首次真正开始运作)反复触发 *No program in object '/inherit/item/combined'!——从驱动刚起服(甚至早 于任何玩家连线)就开始出现,反复命中同一个物件引用。已排查:inherit/ item/combined.lpc 本体和实际会被 load_object()clone/questob/ rice.lpcinherit COMBINED_ITEM)单独用 lpcc 编译均无错误,只有 warning。怀疑和 /inherit/ 前缀档案作为顶层可加载物件的某种驱动/mudlib 惯例限制有关(这类档案通常只设计成被 inherit,不直接 load_object()/ new()),但没有在本轮时间预算内定位到精确根因。不阻塞注册/登录/quit核 心流程(全部现场验证正常),属于背景守护进程的独立问题,按"长尾,记录 不修"惯例处理,留给下一次专门针对这个随机任务子系统的深挖。

完整游玩测试范围

沿用 nitan_ceshi 已验证过的及格线:注册成功进入注册房间,欢迎/排行榜播 报正确显示,quit 的两条分支("n"取消、"y"确认删号)都现场走过。战斗/ 门派/门派任务仍未触达,留给下一次专门测试。

本轮结论

驱动升级后 nitan_san 整体状态良好:任务计数器/log_error()/message() 均确认无需改动;此前"预载异常缓慢"的结论确认是插桩驱动的假阳性,用非插 桩构建后和手足库同量级;从 nitan_ceshi 移植的两处修复(quest.htoptend.lpc)现场验证有效;新发现并修复了 log_file() 的 euid 提权被 自己撤销的问题;随机送货任务子系统一个背景守护进程级的"No program"报错 记录但未修(不阻塞核心流程)。测试账号(linsansan/wangsanwu)存档留 在 data/ 下作为佐证(zhaoliuqi 已按测试流程自行删除),未清理(未跟 踪文件,不纳入本次提交)。

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

ROOM 基类冗余 replace_program(ROOM); 自崩溃地雷(详见 AGENTS.md §7.100):3252 个房间文件的 create() 里紧跟 inherit ROOM; 之后 都有这一行多余调用,永久设下"待替换"标记,第一次对该房间对象绑 定闭包就会崩溃。自带建房工具 clone/misc/roommaker.lpc 的字符串 拼接代码生成模板里也烤了同一个地雷。

修复:脚本化删除所有房间文件里独立成行的 replace_program(ROOM);, 加上 roommaker.lpc 里手动摘除字符串拼接片段。git diff --stat: 3252 files changed,与预期精确吻合(0 处遗留匹配,全部干净)。

验证:build-debug 驱动真实冷启动,端口 40055 正常监听, debug.log 全程干净。既有管理员账号 fluffos/Mud@2026 登录正常 (巫师休息室,look/quit),全程无新增 "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/bai.lpc, d/death/npc/hei.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): 6 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.

WASM gap closure: versiond.lpc sockets crash on admin login (2026-08-25, another session)

The lib's earlier WASM-enablement pass (above) promoted wasm_status to playable without ever logging in with an admin-rank account — adm/daemons/versiond.lpc's in_server() (called from create()) calls socket_create()/socket_bind()/socket_listen() unconditionally, undefined on this driver build (no sockets package). Regular player logins never touch this file, but logind.lpc's catch(enter_world(ob, user)) around admin entry does end up loading it, and since the whole file fails to compile, the catch() fires and shows the player a scary (but non-fatal) "你无法 进入这个世界" message before recovering into the normal room.

Found and fixed via a sibling lib (nitan3, byte-identical versiond.lpc, onboarded as a confirmed duplicate of this lib) hitting the exact same crash during its own WASM verification pass. Patched this file identically (11 functions across the socket-server/client lifecycle gutted to no-ops/always-fail per this project's established "sockets package absent" pattern) and re-verified: admin login (fluffos/Mud@2026) now reaches 巫师休息室 cleanly with no error.

Lesson for future WASM passes: "playable" from an earlier pass doesn't guarantee every login tier was exercised — an admin-only code path can hide a real crash that a player-only test never reaches.

深度功能测试(2026-09-04,shop + 拜师)

Independent live pass on this slug (port 40055, build-debug driver — do not use the ASAN build/ driver; that 10–20× preload slowdown is a documented false positive from the 2026-08-12 round). Prior §10.7 / 2026-08-12 text never exercised a shop purchase or a recruiting NPC here. First send is gb (banner “Select 国标码 GB or … BIG5 (gb/big5)”), then id fluffos / password Mud@2026. #undef DB_SAVE in work/include/ntsql.h, so there is no MySQL login/restore gate. Admin has no wizpwd yet — login prints the “请登陆后用 wizpwd 命令设置” warning and then asks for the ordinary password. register [email protected] from /d/register/regroom drops the wizard into 生命之谷. Birth is choose 1 (光明磊落) → washto 20 20 20 20born 扬州人氏 (lands at /d/city/kedian; help rules more-pager — send q before further commands, or they are swallowed). Unlike nitan170911, washto here does not auto-set born.

Shop: 客店 xiaoer is an innkeeper; 游讯 in the same room intercepts list/buy (“我只卖消息不卖货”). Real vendor is /d/city/zuixianlou 店小二 (d/city/npc/xiaoer2.lpc, F_DEALER). list shows 烤鸡腿 80 文. clone /clone/money/gold works (release server : local makes is_admin() true). buy jitui deducted one gold into 99 两白银 + 20 文铜钱 and delivered 烤鸡腿. feature/dealer.lpc already #include <dbase.h>, so mixin query("vendor_goods") resolves; no F_DEALER this_object() patch needed (unlike nitan170911/hhsj/xfbhh). No F_DEALER 丐帮 refuse on this lib.

拜师: goto /d/city/lichunyuan, bai kong on 空空儿 (kungfu/class/gaibang/kongkong.lpc) — no skill/shen gate beyond permit_recruit(). Accepted immediately: “恭喜您成为丐帮的第二十代弟子.” score shows 【门派】丐帮 / 【师承】空空儿. save (30s cooldown) then disconnect. After a full driver kill + reboot, relogin still shows 丐帮 / 空空儿; the silver/coin change persisted; 烤鸡腿 did not (food, not autoload — expected, not a save bug). Do not quit when mud_age is tiny — new-account quit deletes the account.

Bug fixed: kungfu/class/huashan/{yue-buqun,yue-wife,feng-buping}.lpc recruit_apprentice() wrote add("apprentice_availavble", -1) (extra “av”) while attempt_apprentice()/reset() use "apprentice_available". Same typo nitan3/nitan6 already live-verified — the daily-recruit counter never decremented. Corrected the property name in all three files (LF-only). qingcheng/yu.lpc is not in this tree.