Storm Rises Again II (Tsinghua Remake)

✅ 可玩

风云再起Ⅱ(清华仿写版)— fy2qh

fy2qh

🔑 fluffos / Mud@2026 更新 85d6a35 2026-09-02 源码 下载 ZIP

▶ 开始游玩 · Play Now

经逐文件核实,本档案与本批次的 `fy2` 实际上是同一份源码的另一个流传副本(只是打包驱动、玩家存档快照不同),"清华仿写版"更像是当年某个下载站/镜像站给这份拷贝起的名字,而非独立重写的版本。内容与 `fy2` 完全一致(详见该库介绍):以古龙武侠为背景,"金钱帮"新手门派、风云广场留言版与探花诗台、完整表情系统等均可体验。

English

File-by-file comparison confirms this archive is actually another surviving copy of the same source code as the sibling game fy2 (differing only in bundled driver and player-save snapshot) — the “Tsinghua remake” label looks like a name a download or mirror site gave this particular copy at the time, rather than an independent rewrite. The content is identical to fy2: a Gu Long-style wuxia world where players can join the beginner-friendly Money Gang, browse the Fengyun Square message board and the Poetry Terrace, and use a full set of emotes.

README

内容亮点

在线试玩

https://mudlibs.fluffos.info/fy2qh/

管理员账号 / Admin account

警告:公开架站前请务必修改此默认密码。

本地运行

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

游戏端口:40091

NOTES · 移植与修复记录

风云II (清华仿写版).ZIP → fy2qh

Status: DONE — boots clean, full registration + post-login commands verified

Lineage confirmation: this is (almost) literally fy2, not an independent "imitation"

Despite the archive's title implying a from-scratch clone ("清华仿写版" = "Tsinghua imitation/rewrite edition"), this is evidence-based, not assumption-based, confirmed to be the *same distribution* as already-shipped fy2 (archive #17, 风云再起Ⅱ/Hohai University), not an independent codebase sharing only a name:

Conclusion: this archive is not an independent "imitation" build — it's the exact same 风云再起Ⅱ codebase and content as fy2, redistributed by a different site/mirror (name suggests a Tsinghua University hosting of the same public release) bundling a different MudOS driver binary and a different snapshot of player save data. Given this, every fix already proven on fy2 was ported directly rather than rediscovered.

Fixes applied (all ported directly from fy2, verified identical need)

1. AGENTS.md §15h (GBK byte-range Chinese-character detection) — applied proactively before the first boot, using fy2's own already-fixed copy as the exact reference diff: - adm/simul_efun/chinese.lpc's is_chinese(): GBK lead-byte range check (strlen(str)>=2 && str[0] > 160 && str[0] < 255) → CJK Unicode codepoint range check (strlen(str)>=1 && str[0] >= 0x4e00 && str[0] <= 0x9fff). - adm/daemons/logind.lpc's check_legal_name(): byte-count length bound (< 2 || > 12, message already says "一到六个中文字" / "1 to 6 Chinese characters") halved to character count (< 1 || > 6); removed the i%2==0 && even-byte-offset gate so every character position is checked, not just every other one. - Confirmed via two independent full interactive registrations, both with real Chinese given names (see below) — both accepted on the first attempt with no rejection.

No other fix was needed — every other proactive check (below) came back clean, matching fy2's own "zero fixes needed to boot" outcome exactly.

What was checked and confirmed NOT needed

Known, accepted, non-fatal issue

`` 执行时段错误:*restore_object(): Invalid utf8 string while restoring dbase. 程式:/feature/save.lpc 第 19 行 物件: /adm/daemons/emoted ` data/emoted.o (the daemon's seed emote-table save file) was flagged by convert_lib.sh as a LOSSY conversion (invalid GBK bytes dropped) — per AGENTS.md §1, a handful of save-data .o files can have genuinely undecodable bytes; this is seed/example data, not source, and the driver boots and reaches Accepting telnet connections` regardless. Not fixed (matches project convention for this exact class of issue).

Interactive test — full registration flow (TWO independent runs, one continuous connection each)

Run 1 — id qinfengtesty (confirm new character) → Chinese name 秦风 (accepted immediately, no rejection — the §15h fix's proof) → password TestPass123 (set + confirmed) → email → gender m → nationality 0 (汉族) → entered the game world at /d/fy/fqkhotel (凤求凰客栈), NPC 店小二 present. score produced a full, correct character sheet ("普通百姓 秦风(Qinfengtest)... 你是一位汉族十岁的男性人类..." with all 12 stat lines, attack/defense values, 参数点). quit dropped starting inventory and disconnected cleanly ("欢迎下次再来!").

Run 2 (separate connection, different id/name/ethnicity, explicit look + score + quit sequence to unambiguously distinguish command output from the automatic on-entry room view) — id zhaoritiany → Chinese name 赵日天 (again accepted immediately) → password TestPass456 → email → gender f → nationality 1 (苗族) → entered the game world at a DIFFERENT starting room, /d/chenxiang/cxcenter (沉香镇中 心 — confirms the nationality-based start-room branch works), with live NPCs (地头蛇 ×2, 卖鱼的, 买鱼的小姑娘) actively emoting in real time (买鱼的小姑娘问道:"这鱼怎么卖?" between my look and score sends — proof this is a live, ticking game world, not a static scripted reply). look produced the room description + exits + NPC list; score produced "普通百姓 赵日天(Zhaoritian)... 你是一位苗族十岁的女性人类..." with correct stats distinct from Run 1's character; quit again dropped starting inventory and disconnected cleanly.

Both runs confirm: real Chinese names are accepted (§15h fix verified twice, independently), the character actually lands in the game world (not a void/missing-room failure per §15aj), and ordinary post-login commands (look, score) produce real, correct, differentiated output (§15ae/§15ar checklist satisfied — no command-dispatch bug present).

Noted, not a bug (same as zzfy's identical finding): get_name() has a pre-existing printf("%O\n", ob); debug line that prints the login object's default toString (e.g. /obj/login#10) right before the password prompt on a successful Chinese name — leftover debug output from the original author, harmless, out of scope to remove.

lpcc sweep

scripts/lpcc_check.sh2839 total, 2766 pass, 73 fail (97.4%). Failures are exclusively pre-existing content gaps (a handful of std/armor/*.lpc files reference PROP_*/TYPE_* constants that were never #included/#defined anywhere in this codebase — a real gap in the original archive, confirmed present identically in fy2 too) plus the emoted restore issue above. Diffed the full list of failing file names against fy2's own lpcc_fail.logzero differences, the identical 73 files fail for the identical reasons in both libs, reinforcing the lineage finding above. Not triaged further given the small count and that none affect the boot/registration/gameplay path exercised.

How to run

cd libs/fy2qh
~/src/fluffos/build-debug/src/driver config.fluffos
python3 ../../scripts/mudclient.py 127.0.0.1 40091 --timeout 25 --idle 0.5 \
  --send "yourid" --send "y" --send "你的中文名" \
  --send "yourpassword" --send "yourpassword" --send "[email protected]" \
  --send "m" --send "0" --send "look" --send "score" --send "quit"

(m/f selects gender; 0-3 selects ethnicity, which determines the starting room; the English id must be pure letters, 3-12 chars, or check_legal_id rejects it and re-prompts.)

Re-verification pass: driver rebuild + LPC formatter + WASM build

WASM-enablement pass (loopback / admin seeding)

Identical to sibling fy2 (风云再起Ⅱ, 011).

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

First real *playthrough* pass on this lib (all prior passes verified only registration + look/score/quit + WASM boot). This lib was flagged as a confirmed byte-identical sibling of fy2 (风云再起Ⅱ, archive #17), which was deep-tested immediately before this pass and found 6 bug classes plus 3 corrupted save-data files (see libs/fy2/NOTES.md's own "深度功能测试" section). Confirmed via diff -rq of both work/ trees: every difference was either (a) exactly the fixes fy2's pass already applied, not yet ported here, or (b) unrelated player-save/log/config noise. All of fy2's fixes were ported directly (same file:line shape, same root cause) rather than rediscovered from scratch, then the full playthrough was run independently on this lib's own driver/port (40091) to confirm each fix actually works live here too, not just by code inspection. Native driver (build-debug) only — WASM not re-verified this pass (all fixes are shared LPC/data-file changes with no WASM-specific risk, stated explicitly rather than silently skipped).

Test characters kept as playthrough evidence (native saves, untracked): duanmuqing/端木青 (male, 金钱帮 third-generation disciple under 荆无命, data/user/d/duanmuqing/, learned 基本剑术 from him, fought 登徒子 to partial HP loss and disengaged safely), muyanqing/慕言卿 (female, used for the final full end-to-end regression after all fixes + revert of diagnostic instrumentation, data/user/m/muyanqing/). Both in the Han-ethnicity start room 凤求凰客栈.

Fixes ported from fy2 (confirmed present here, byte-identical bug shape, now fixed identically)

1. adm/simul_efun/message.lpc — AGENTS.md §7.12, the shared tell_room() 2-arg exclude bug (exclude || ({ })). 2. d/death/npc/bgargoyle.lpc, wgargoyle.lpc, d/death/inn1.lpc — AGENTS.md §7.24, death/limbo code stomping the permanent startroom login-location field. Removed the set("startroom", ...) calls; the move() already handles the immediate post-death placement. Not exercised via an actual live death this pass either (see "Not verified live" below) — ported on the strength of the exact code-shape match to fy2's own already-verified fix. 3. std/room.lpc's make_inventory() — AGENTS.md §7.25, unguarded new()/move() chain. catch(ob = new(file)) || !objectp(ob) plus an objectp() guard at the reset() call site. Same root cause as fy2 (/obj/sbaa/rong.lpc's set_skill("wu-shun", ...) throwing on a skill missing from this archive's tables) — confirmed still present and still failing the same way via this lib's own lpcc sweep (/obj/sbaa/rong still FAILs individually, as expected — a genuine content gap, not a code bug — but no longer takes its owning room down with it: /obj/sbaa/ym was NOT in this lib's own pre-fix lpcc_fail.log extras beyond the known 73, matching fy2's finding that the room recovers cleanly after the catch()). 4. std/bboard.lpc, std/jboard.lpc's setup() — AGENTS.md §7.7-adjacent, unguarded move()/restore() collateral-damaging the owning room/caller. Both calls now wrapped in catch(). 5. adm/daemons/emoted.lpc — AGENTS.md §7.7, same restore()-throws-uncaught shape, silently disabling the entire emote-command system mudlib-wide. catch(restore()) + if (!mapp(emote)) emote = ([]);. 6. d/waterfog/{hall1,jobroom}.lpc, obj/board/{wizard_b,wizard_j}.lpc, feature/alias.lpc — new bug class (stale /d/wiz/ paths from a zone rename to /d/waterfog/), ported identically: exits/"location" fields pointed at the nonexistent old path, and the anti-bot teleport in alias.lpc would have silently dropped an accused player into environment 0. Fixed to /d/waterfog/... (or __DIR__-relative); added an objectp() guard on the alias.lpc teleport as defense in depth. 7. feature/command.lpc's enable_player() — AGENTS.md §7.28, redundant add_action stacking (revive() re-enabling commands on every ordinary combat knockout, not just death). remove_action() before the add_action(), matching fy2's guard shape exactly (not living()-gated, per §7.28's own caution).

Data fix: data/emoted.o, data/board/fysquare_b.o, and data/board/poem_b.o were confirmed byte-identical (md5sum match) to fy2's own pre-fix raw archive copies (libs/fy2/raw/fy/fy/data/... vs libs/fy2qh/raw/fy/data/...) — i.e. this lib genuinely ships the exact same GBK-un-transcoded / embedded-raw-newline corruption fy2's pass diagnosed and fixed, not just a superficially similar issue. Rather than re-deriving the quote-aware \r\n\r transcoding scanner from scratch, fy2's already-fixed, already-verified output files were copied over directly (cp libs/fy2/work/data/{emoted.o,board/fysquare_b.o, board/poem_b.o} libs/fy2qh/work/data/...) — safe specifically *because* the raw inputs were confirmed byte-identical first. Spot-checked all three decode as valid UTF-8 with sane, readable Chinese text before and after copying (not just trusted the copy to have succeeded). Also removed the same three-file debris fy2's pass found and removed: data/emoted.lpc (a stray, unreferenced ~130KB duplicate of the emote database misnamed with an .lpc extension — confirmed unreferenced by any inherit/load_object/call_other here too) and data/emoted.o.new/data/emoted.o.old (stale debris from an earlier abandoned fix attempt, predating this pass).

Live verification (native driver, port 40091)

Net-dead auto-force-quit at the real NET_DEAD_TIMEOUT (900s): reproduced fy2's "stuck net-dead" anomaly, but with new evidence narrowing it to something OTHER than a concurrent-lpcc-sweep confound

fy2's own pass hit one occurrence of a net-dead session's user_dump() call_out apparently never firing at the real 900s mark, flagged as "an unresolved, likely environmental/non-reproducible anomaly" and tentatively attributed to a concurrent lpcc --batch sweep running against the same work tree at the same time as a plausible-but-unproven confound (see libs/fy2/NOTES.md).

This pass reproduced the identical symptom, independently, with that specific confound ruled out: disconnected duanmuqing without quit at 00:47:31, then waited (via two sequential blocking sleep calls totaling ~1050 real seconds, no other process touching this lib's work tree during that window) well past the 900s NET_DEAD_TIMEOUT threshold (due at 01:02:31). At 01:04:59 (~17.5 real minutes post-disconnect), the character was still shown net-dead — no "quits at ..." line had been written to log/USAGE for that session, and debug.log showed zero new content of any kind (not even the routine ambient-NPC compile-warning noise that later reconnects showed). A subsequent reconnect attempt went through the full fresh-login flow (RETURN prompt etc.), not the fast "重新连线完毕" netdead-reconnect path — meaning the interactive body object was no longer around/link-dead-recognized by that point, yet no user_dump/quit completion was ever logged. Zero trace in debug.log, matching the general shape (though not the specific FATAL-crash symptom) of the driver-level anomaly class catalogued in AGENTS.md §10.8 — the driver process itself stayed alive and healthy throughout (confirmed via ps), so this is not a §10.8 FATAL crash, just a scheduled call_out whose effects never became visible.

Follow-up isolated the mudlib code itself as almost certainly NOT at fault: temporarily shortened NET_DEAD_TIMEOUT (include/user.h) from 900 to 12 seconds and added write_file() instrumentation at net_dead()'s call_out() registration and at the top of user_dump()/immediately before command("quit") (both reverted before finishing — diff against fy2's byte-identical copy confirms zero residue). Rebooted, repeated the exact same disconnect-and-wait sequence at the shortened interval: fired perfectly reliablycall_out registered at 01:08:05, user_dump(1) invoked at exactly 01:08:17 (12s later, precisely on schedule), command("quit") completed and logged duanmuqing quits at Sat Jul 25 01:08:17 2026 to USAGE correctly. This strongly suggests net_dead()/user_dump()'s own LPC logic is correct and reliable — the failure mode is specific to *very long* real-time call_out delays specifically, not the code path itself.

Plausible alternative explanation, offered honestly as unproven: this finding spans multiple separate blocking shell-tool invocations (the harness's own tooling constraints cap a single blocking wait well under 900s, so the real wait was assembled from sequential sleep 550 / sleep 400-shaped calls across separate tool invocations, each ending and restarting a fresh tool call). If the sandboxing environment suspends/deprioritizes background (non-foreground-owning) processes between tool-call boundaries as a resource-management measure, a long-delay call_out timed against a clock that doesn't advance (or whose driver-side scheduling loop doesn't get CPU time to notice it) for part of that span could plausibly miss its own firing window in a way a 12-second delay, entirely contained within one blocking call, never would. This would make the anomaly a testing-environment artifact, not a genuine mudlib or even driver bug — but this is offered as a plausible hypothesis, not a proven root cause; no direct evidence (e.g. driver-side scheduler logs) was gathered to confirm or rule it out, and fy2's own occurrence happened within a single, differently-shaped test session. Documented honestly per AGENTS.md's standing instruction to record rather than guess, and to give the human maintainer this corroborating (now twice-independent) data point rather than silently re-flagging it as "unresolved" without the new context. Not treated as a mudlib bug and not fixed — the short-timeout test is strong evidence the actual net_dead()/user_dump() code is correct.

Not verified live, and why

Testing-methodology note: lpcc --batch's blanket load-and-create() can trigger dead admin-utility side effects

While diagnosing an unexpected ~457-file mass-touch of pre-existing shipped player-save data (data/user/*/*.o, all reduced to a harmless key-reordering + one intentional-looking "title_race":0 reset when diffed against the committed originals), traced the cause to adm/daemons/startrace.lpc — a ranking/leaderboard recalculation daemon whose create() unconditionally calls init_race()findthem(), which restore()s and re-save()s every single registered player's save file and resets everyone's "title_race" field to 0 before reassigning top-3 badges. This daemon is not preloaded and not called by any other live code path in this archive (confirmed via grep — genuinely dead/orphaned, presumably meant to be invoked manually by a wizard, never wired up) — it does not run during ordinary gameplay at all. It ran anyway because scripts/lpcc_check.sh's lpcc --batch sweep (run earlier this pass, before ever booting the live driver) loads and compiles *every* .lpc file in the tree by path, which triggers each object's create() exactly like a real load_object() would — including this one. Reverted all 457 incidentally-touched files (git checkout --) back to their committed state after confirming via a full character-level diff that every touched file's content was either an exact match modulo key order, or the intentional-but-unwanted title_race reset — none were genuinely lost/corrupted, so the revert was safe. Left startrace.lpc itself untouched (its behavior is presumably intentional wizard tooling, not a bug, and out of this pass's scope) but flagging the general lesson: an lpcc --batch sweep is not side-effect-free on any lib whose create() functions do more than initialize state — run it (or budget for its side effects) before setting up test-character save data you intend to keep as evidence, and sanity-check git status afterward for surprise touches, same discipline as checking debug.log after quit.

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

此前被错误标记为某个不存在于本项目任何档案的原始压缩包文件名的 duplicate_of;这里的内容其实是完全独立、可游玩的游戏(有自己的 -N 变体编号、自己的端口、自己的 README)——duplicate_of 已清除。

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

Deep functional test round three (2026-08-14)

Independently re-verified against current code rather than trusting the extensive round-two writeup above. All 7 ported fixes plus the 3 data fixes confirmed still present (code/data inspection for all 10, live re-exercise of the highest-value ones). This lib's sibling fy2 picked up 3 NEW fixes earlier this session (not part of the original 7 ported here) — checked and confirmed fy2qh had the exact same 3 gaps, byte-identical down to the line numbers, and applied the same fixes.

New fixes, ported from sibling fy2's own round-two pass earlier this session

1. §7.90-class eval-cost: config.fluffos's maximum evaluation cost : 300000 (same value fy2 had) → 5000000. Not independently reproduced as a live crash here first (unlike fy2, where it was caught live) — applied proactively given the confirmed byte-identical config value, then verified: first login attempt on a fresh boot succeeded cleanly with zero eval-cost errors. 2. adm/simul_efun/file.lpc: same §7.11-class gap as fy2 (log_file() missing assure_file(), cat() missing a null-guard). Fixed identically, including the forward declaration this driver requires. 3. Two printf("%O\n", ob) debug leaks in logind.lpc: byte- identical location (lines 273/308) and shape to fy2's own finding. Removed both.

Re-verified live: the highest-value round-two-ported fixes

Verification method

Booted native build-debug driver, admin login (fluffos/Mud@2026) — clean on the first attempt (confirming the eval-cost fix). update /adm/daemons/logind as the real privileged-action check (succeeded). Two full rapid reconnects, both clean fresh logins (matching fy2's own net_dead() design — never void-parks a disconnected player). Driver killed by exact PID after testing; incidental fluffos.o save-timestamp churn reverted before commit. Did not re-run the extensive net-dead-timeout investigation from the prior pass (already exhaustively documented above, twice-independently reproduced and analyzed — nothing new to add this pass).

Files modified this pass

§7.100 sweep fix (ROOM base-class redundant replace_program())

#define ROOM "/std/room": deleted 525 redundant, live, standalone replace_program(ROOM); lines (kept inherit ROOM;) — 524 caught by the scripted sweep, plus 1 hand-fixed instance in this lib's room-building tool (obj/roommaker.lpc)'s "clone this room" string-builder template, same shape as sibling fy2. work/data/ holds 85 real .lpc source files (per-account starting-equipment templates, same shape as fy2), independently checked and confirmed free of the bug pattern. 3 pre-existing //-commented instances remain untouched, confirmed harmless. Verified via a clean build-debug driver boot (0 new compile errors, port 40091 listening, zero new "cannot replace"/"cannot bind" debug.log lines); no full §10.7 gameplay walkthrough this pass.

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