Great Tang Journey West (rzrmud)

✅ 可玩

大唐西游 YWX人造人

rzrmud

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

▶ 开始游玩 · Play Now

站点自称"YWX人造人"(原开发者的昵称/团队名),北美总站,自 2006 年 2 月 3 日运行至今(存档信息显示已有五百多个注册玩家,是这批 archive 里"真实运营过"证据最扎实的一个)。与本项目转换的"梦幻西游"(mhxy) 同属西游记神话世界观的一支,但引擎实现是独立的一支(不使用 nitan/Lonely 家族那套全局属性存取机制,而是每个对象自带属性存取方法,架构上更规范)。新角色从长安城"南城客栈"起步,白素贞、唐三藏、店小二等《西游记》经典角色以 NPC 形式登场,成长线围绕门派拜师、五行攻击/防御属性与道行修真境界展开,整体节奏偏休闲,并附带较完整的新手礼包机制。

English

A North America-hosted Journey to the West game, self-branded 'YWX Cyborg' after its original developer/team, continuously running since February 2006 with over five hundred registered player accounts on record — among the most solidly 'actually operated' archives in this collection. It shares its mythic Journey to the West setting with sibling game mhxy but runs on an independently engineered codebase, with per-object attribute accessors rather than the shared global-store architecture common to the nitan/Lonely family. New characters begin at the South City Inn in Chang'an, greeted by classic characters like Bai Suzhen and Tang Sanzang, and follow a cultivation-focused progression built around sects, Five Elements attack/defense attributes, and Taoist cultivation realms, with a fairly generous newbie starter-kit system.

README

内容亮点

在线试玩

https://mudlibs.fluffos.info/rzrmud/

管理员账号 / Admin account

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

本地运行

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

游戏端口:40020

NOTES · 移植与修复记录

rzrmud — 大唐西游 YWX人造人 (Great Tang Journey to the West)

Archive: rzrmud.20130220.tar.gz. Port: 40020. Status: done (boots clean, connects, plays through the age-verification gate, MOTD, username validation, and into new-player registration with zero crashes).

What this is

A different lineage from the "NT/nitan/Lonely" family (archives #21/#22) — generic-looking MudOS 0.9.20-era mudlib, 9096 .c files, bundled with prebuilt 32-bit Linux driver binaries (driver, driver_2s_64bit_int, ignored — we use our own fluffos build). Archive nests the actual mudlib root one level down at rzrmud/world/.

Notably, this lib's adm/obj/simul_efun.lpc does not define a global set/query/delete at all (unlike the nitan family) — every object that uses bare query(...)/set(...) relies entirely on its own inherit NPC;-style base class providing them locally. This is the architecturally *correct* pattern (see AGENTS.md §15's writeup of why the nitan family's simul_efun-based version is broken on this driver) — no this_object()-during-simul_efun-call trap here since the fallback path essentially isn't used.

Fixes applied

None beyond the standard mechanical pipeline (convert_lib.sh's encoding/rename/ref-fix/static→nosave passes). Booted clean and reached deep into the login flow (age gate → MOTD → username validation → "new player" registration sub-flow asking for an English name) on the first attempt, zero runtime or compile errors in debug.log.

Known content gap (not fixed — see AGENTS.md §13)

scripts/lpcc_check.sh sweep: 9096 files, 8865 pass / 231 fail (97.5%). The largest failure clusters are a genuine but narrow content gap, not an engine bug:

Interactive test result

Connects, full ASCII-art banner renders, no crashes through: age- verification prompt → MOTD/rules screen → username prompt (validates length/alphabetic correctly) → "new" registration path → English-name sub-prompt (also validates correctly). Did not create a full character or play further into the game world (out of scope for this pass).

Post-hoc fix: UTF8-native is_chinese/registration (AGENTS.md §15h)

Applied in a later batch pass across the whole project: is_chinese/is_chinese2 in the shared chinese.lpc simul_efun fragment used GBK byte-range checks that silently never match real Chinese text once strings are UTF-8 (this driver's str[i] returns a Unicode codepoint, not a GBK byte). This broke character registration specifically -- any real Chinese name was rejected. Fixed the range check to test the CJK Unicode block instead, and halved the GBK-byte-calibrated length bounds in check_legal_name to match. See AGENTS.md §15h for the full writeup; confirmed via a real interactive registration test (Chinese surname + given name reaching the next prompt).

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

WASM-enablement pass (2026-07-24): loopback-allow + admin seeding

Gates patched (same 西游记-lineage shapes as mhxy/mohuanshiji; loopback = 127.0.0.1, any 127.*, or an empty/malformed non-dotted-quad string, which is what current WASM builds return):

Admin account: fluffos, 登陆密码 Mud@2026, 管理密码 Mud@2026admin (this lineage sets the admin/recovery password FIRST and requires the two to differ), Chinese name 浮浮, granted (admin) via /adm/etc/wizlist (normalized CRLF→LF). Verified: real-flow registration reaching 南城客栈, re-login ("您使用了登陆密码成功登陆!"), update /adm/daemons/band.lpc succeeds. Saves at data/login/f/fluffos.o + data/user/f/fluffos.o (untracked, not gitignored — orchestrator must add; note this lib also ships a large pre-existing tracked player base under data/user/, which was left untouched). Fresh normal registration (秦风/testqa) re-verified end-to-end and its saves removed. debug.log: only transient cold-cache "Eval interrupted / Too long evaluation" lines during the first world entry (lazy compiles of big content files; a warm-cache login+look+score session afterwards added zero new error lines) — same known mega-content shape as mhxy, not introduced by this pass.

深度功能测试 / Deep functional test (2026-07-24, round two)

First real *playthrough* pass on this lib (all prior passes verified only registration + look/score/quit + admin login, or watched boot output/WASM). Read doc/help/newbie in full first — it correctly named the fight-vs-kill safety distinction, apprentice/learn syntax, the general command set, and pointed at help combat/help menpai. Played as an ordinary new player through registration, exploration, a real (non-lethal) fight, organic skill-learning and sect-joining, a shop list/buy attempt, a real quit (including mid-combat), a real wall-clock-gap reconnect via the restore/login path, native driver (build-debug). Found and fixed three distinct bugs, one of which is a genuinely new class for this project's catalog.

Test characters (both kept, not cleaned up, as representative playthrough evidence):

Several other ids (linshuang, linxue, linxue2, linxueqi, linxueb) were created and abandoned during trial-and-error discovery of this lib's exact registration-prompt sequence (id must be 3–8 plain English letters, no digits — several attempts failed that check) and their save files were deleted before finishing; not left behind.

Bug 1 (NEW bug class): reconnecting mid gift-allocation permanently strands a new character with every command silently blocked

File:line of the fix: obj/user.lpc's reconnect() (~line 252); structural root is adm/daemons/logind.lpc's enter_world() (the no_giftmove("/d/wiz/init") routing) and d/wiz/init.lpc's init() (schedules the auto "start" trigger only on the room's original entry).

``lpc // BEFORE: void reconnect() { set_heart_beat(1); set_temp("netdead", 0); remove_netdead_enemy(); remove_call_out("user_dump"); remove_call_out("do_net_dead"); tell_object(this_object(), "重新连线完毕。\n"); } // AFTER: (see obj/user.lpc for the full comment) — appends: if (query("no_gift") && objectp(env = environment(this_object())) && base_name(env) == "/d/wiz/init") { env->get_start0(this_object()); } ``

Bug 2 (existing AGENTS.md §7.17 class, applied proactively): unbounded init()/reset() reentrancy — this lib has the identical vulnerable shape in 15 files

std/room.lpc's setup() calls this_object()->reset(); synchronously as the last step of every room's create() — the exact structural precondition for AGENTS.md §7.17 (found live on xiyouji). Grepped for the vulnerable create_identity()/force-load-by-path shape (call_other(where, "???")) and found it copy-pasted, byte-identical, into 15 of this lib's ~16 sect/zone "senior disciple" entrance NPCs (the 16th, d/npc/zhangmen.lpc, has the same create_identity() function defined but its own init() never calls it, so it's inert — checked, not fixed):

d/jjf/npc/zhangmen.lpc          d/qujing/kusong/npc/zhangmen.lpc
d/nanhai/npc/zhangmen.lpc       d/qujing/wudidong/npc/zhangmen.lpc
d/sea/npc/zhangmen.lpc          d/qujing/wuzhuang/npc/zhangmen.lpc
d/xueshan/npc/zhangmen.lpc      d/kunlun/npc/zhangmen.lpc
d/death/npc/zhangmen.lpc        d/shushan/npc/zhangmen.lpc
d/sanxian/npc/zhangmen.lpc      d/moon/npc/zhangmen.lpc
d/lingtai/npc/zhangmen.lpc      d/pansi/npc/zhangmen.lpc
d/death/npc/guiwang.lpc (calls the same "/d/death/new-walk2" room)

Applied the exact §7.17 fix, mechanically, to all 15 files plus std/room.lpc: 1. std/room.lpc: nosave int resetting_now; guard at the top/every return path of reset(). 2. Each of the 15 files: nosave int in_init_now; guard around the whole body of init(). 3. Each of the 15 files' create_identity(): prefer environment(this_object()) over the call_other(where, "???")/find_object(where) force-load when it already matches where by base_name().

One mechanical mistake caught by compile-checking every edited file with lpcc before restarting the driver (not just eyeballing the diff): my first pass inserted the new nosave int in_init_now; declaration between the two existing inherit NPC;/inherit F_SAVE; lines — Illegal to inherit after defining global variables. — moved it after both inherits. All 15 files plus std/room.lpc, obj/user.lpc, d/wiz/init.lpc compile clean (lpcc config.fluffos <file>, checked individually, zero error:/Fail to load object lines).

Live verification: walked a fresh linqx all the way to /d/jjf/front_yard2 (练武场, the room directly analogous to xiyouji's front_yard2 — houses this lib's d/jjf/npc/zhangmen.lpc, title "大唐 天下兵马大元帅") — first visit of this boot for that room, post-fix: no crash, debug.log line count unchanged, exactly one zhangmen NPC present (not a duplicated pair, which is what the unfixed bug produces). Only /d/jjf/front_yard2 was live-verified this way; the other 13 sect/zone rooms were fixed by code-shape match only, per this project's own established practice for this exact bug class (§7.17's own writeup did the same for 8 of xiyouji's 9 sects) — honestly unverified live. Suggestive supporting evidence found by accident: during this same session, work/data/zhangmen/zhangmen_ao_guang.o (the *East Sea Dragon Palace* sect's persisted zhangmen-NPC save — d/sea/npc/zhangmen.lpc, a room I never navigated to) got silently rewritten mid-session with drastically degraded stats (combat_exp 1,200,000 → 100,000, all skills 200 → a flat 60, daoxing 1,500,000 → 100,000) — consistent with a duplicate, freshly-initialized clone's create_identity()/ init_identity() overwriting the good save via a background heartbeat/wandering-bot visit, i.e. exactly this bug's signature, happening on a sect I never touched. Reverted that file (pre-existing tracked shipped data, not part of my intended fix, restored via git restore) rather than "fix" it by hand — but it's worth citing as independent evidence this bug class is real here, beyond the one room directly reproduced.

Bug 3 (NEW bug class): uncatchable eval-cost abort during the START_ROOM's cold first compile can permanently strand a logging-in player with no environment

File:line: adm/daemons/logind.lpc's enter_world() (~line 916, the !catch(load_object(startroom)) block) and its structural fallout in cmds/usr/quit.lpc (~line 75).

`` 执行时段错误:*Can't catch eval cost too big error. 程式:/adm/daemons/logind.lpc 第 916 行 ` preceded by an ordinary *Too long evaluation trace rooted in /feature/save.lpc's restore(), called (via feature/vendor_sale.lpcstd/char/npcsave.lpc) from /d/city/npc/xiaoer.lpc's create(), called (via make_inventory()) from /d/city/kezhan.lpc (南城客栈, this lib's START_ROOM) — i.e. the START_ROOM's own first-ever compile of this boot cascades into populating it with the shopkeeper NPC, whose restore() (small save file, ~1.5KB — the *cost* here is the cumulative eval budget of the whole synchronous first-time compile chain, not one expensive operation) tips the eval-cost counter over the limit. Unlike an ordinary *Too long evaluation, this second, immediately-following error is explicitly marked uncatchable by the driver — it aborts enter_world() entirely at that exact point, skipping every line after it, including the existing if (!environment(user)) user->move(START_ROOM); safety net a few lines further down (a comment there, "by canoe 修改多物品时突然quit 不能进mud Bug", shows the original authors already anticipated and patched a *similar*-shaped bug once — but that fallback is itself inside the same synchronous call and is just as exposed to this uncatchable-abort class). The player is left fully connected but with environment(me) == 0look degrades gracefully ("你的四周 灰蒙蒙地一片,什么也没有" — this lib's std look already handles a null environment), but quit does not: message("system", ..., environment(me), me) passes the literal integer 0 where message() requires a string/array/object, throwing *Bad argument 3 to EFUN message() and aborting quit() itself before it reaches me->save() — so the character is stuck with no room and can't even cleanly log out (though the character's on-disk save is unaffected, since the abort happens before save()` runs).

Memory-growth investigation (informational — not fixed, not conclusively a bug)

Mid-session, the orchestrator force-killed a driver instance of this lib that had grown to 8.2GB RSS and climbing, out of shared-host safety concerns. Investigated afterward with tight self-imposed RSS caps (killed my own test instances well before any risk threshold):

What was tested and confirmed working

Not verified live (explicit, not silently skipped)

Process-hygiene note (self-reported)

Early in this session, before fully internalizing AGENTS.md §10.5's "kill by exact PID, verify cwd first" rule, I ran ps aux | grep driver after a background driver of mine appeared to have died (a stray SIGTERM — see below), saw two driver config.fluffos processes, and killed both by PID without checking their cwd first. Both turned out to belong to other libs (xuanjianlu, shzs) — i.e. two other agents' sessions, not mine. New processes for those same two libs appeared moments later (either those agents' own retry logic, or purely coincidental relaunches by their sessions — I have no way to tell which after the fact). Flagging this prominently rather than burying it: if either of those sessions lost work because of this, that's on this session's account. From that point on I verified readlink -f /proc/<pid>/cwd before every kill. Separately (and unrelated to that mistake): this lib's own driver was killed by a genuine external SIGTERM at least twice during this session even when launched via the tool's run_in_background option — matches AGENTS.md §10.5's already-documented "stray SIGTERM between tool calls" environment quirk; not a mudlib bug.

Fail-closed retrofit (2026-07-24)

Same correction as the sibling mhxy/mohuanshiji: the loopback carve-out originally ALSO treated any empty/non-string/unparseable IP as trusted-local (fail-open, defensive against an older WASM query_ip_number() bug now fixed upstream). Tightened to strict loopback only across band.lpc (×4), securityd.lpc's match_wiz_site, ipd.lpc (falls back to "未知地区" for unparseable input instead of "本地连接"), and logind.lpc's local_conn flag. Re-verified loopback login, look, update, and quit all still work after tightening.

logind.lpc's do_counter(): the AGENTS.md §7.9 fresh-checkout bomb, live on the published site (2026-07-29)

Reported live: the WASM page at mudlibs.fluffos.info/rzrmud/ was permanently stuck at "connecting…" — fluffos_connect() genuinely returning -1, traced via the Logs tab to new_conn_handler: logon() on object obj/login#0 has failed with the underlying error *Bad argument 1 to sscanf, Expected: string Got: 0 inside do_counter() (adm/daemons/logind.lpc:1152, called from logon() via encoding()):

int do_counter() {
  int number;
  string file;
  file = read_file(FileName);   // FileName = "/adm/daemons/UserNumber"
  sscanf(file, "%d", number);   // crashes when read_file() returns 0
  ...

UserNumber (the visitor counter) is gitignored runtime data (libs/*/work/adm/daemons/UserNumber in the repo .gitignore), so it never exists in a fresh checkout — including the CI runner that packs the WASM site. It happened to exist on this session's own local disk (leftover from earlier local testing), which is exactly why every prior local verification pass here missed it: read_file() only returns 0 (triggering the crash) when the file is genuinely absent, and locally it never was. Textbook instance of the exact class AGENTS.md §7.9 already catalogs, just not one that had been found in this lib specifically before. Fixed with the standard stringp() guard; re-verified against a freshly packed local site with the file deliberately moved aside (reproducing the real fresh-checkout condition) — connects and reaches the registration prompt cleanly. Three more copies of the identical do_counter() exist (u/canoe/logind.lpc, u/canoe/lbak.lpc, adm/daemons/log_bak.lpc) but none are inherited/loaded by anything — wizard-workspace backups, left alone per the standing "don't fix dead code" policy.

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

深度功能测试第二轮 / Deep functional test round two (2026-08-15, post driver-upgrade re-test)

驱动于 2026-08-12 升级(引入 PR #1343/#1344、quest_times 语料修复) 后的重测。独立复核第一轮(2026-07-24)的三处修复均仍在代码中:obj/ user.lpc::reconnect() 的礼物精灵恢复补丁、do_counter()stringp() 防护、log_error() 的大小写无关 "arning:" 警告过滤门 (这处已经是正确写法,未触发本 session 在 nt1 上踩过的小写坑)。

标准检查清单发现并修复的问题

现场验证

驱动干净启动(build-debug),以管理员账号 fluffos/Mud@2026 登 录,确认 目前权限:(admin),落地既有存档房间"南城客栈"(确认账号 存档正确持久化,无 nt1 那种"注册未满 30 分钟强行 kill 驱动导致密 码从未落盘"陷阱——本档案的账号是早前 pass 正常 quit 播种的,本轮 只是复用)。update /adm/daemons/logind 成功,确认 file.lpc/config.fluffos 两处修复编译干净、不影响正常巫师指令。 两次快速重连(各自独立 fluffos/Mud@2026 登录)均正确显示 目前权限:(admin)quit 均产生正常告别提示与断线。debug.log 全 程检查(1283 行):仅 4 处无害的宏定义/未使用变量相关误配匹配,无真 实错误。

本轮修改的文件

§7.100 sweep (2026-08-19)

Fixed the corpus-wide inherit ROOM; ... replace_program(ROOM); redundant-replace bug (AGENTS.md §7.100). 262 live occurrences deleted: 261 via scripted sweep (fix_710_room.py), plus 1 hand-fixed roommaker-tool template (obj/roommaker.lpc, simple string-builder variant). 7 already-commented-out instances left untouched. No real .lpc source found under work/data/. Verified via build-debug driver boot: clean compile, port 40020 listening, zero new "cannot replace"/"cannot bind" debug.log lines.

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

AGENTS.md §7.19 fix: enable_player() reentrancy from init()

feature/command.lpc's enable_player() (wrapper around enable_commands()) was reachable from an NPC's init() (via the shared std/char.lpc setup() chain), and enable_commands() is only safe to call from create() -- calling it again on an object already living() makes the driver re-invoke that same object's init() as a side effect, which recursed back into enable_player() on the same call stack until "Too deep recursion" aborted the boot on a room's first-ever visit. Fixed with a true reentrancy flag (in_enable_player_now, set at entry, cleared before every return), NOT a living()-gated guard -- disable_player() in the same file legitimately re-calls enable_commands() while already living() (sleep/wakeup via cmds/std/sleep.lpc, revive via feature/damage.lpc), which a living() guard would silently break. Verified via lpcc --batch single-file compile check (PASS). Part of the corpus-wide §7.19 sweep (Batch C).