immaster (a MudCore-framework LPC tutorial mudlib)

✅ 可玩

immaster (菜鸟飞天传)

immaster

更新 fdf581a 2026-09-12 源码 下载 ZIP 上游 flyinrookie/immaster

▶ 开始游玩 · Play Now

A small, real Chinese-language LPC learning project built on 'MudCore', a modern (2019-2020) FluffOS-native engine framework (github.com/oiuv/mudcore) that immaster's own README describes as 'ongoing building of the mudlib, as a learning project'. immaster itself supplies only the thin content layer: a short outdoor/indoor tutorial map (game/world/tutorial/ -- start room, courtyard, backyard, forest, stream, waterfall, cave, tomb, cliff, treehouse, a random-maze-capable dungeon system, ~12 rooms total) plus a couple of player commands (help, test); MudCore supplies the actual account/login/registration flow, save/restore, room/movement/action dispatch, wizard tools, and a set of daemons (combat, chat/emote, virtual-object/maze, database, time-of-day, Chinese-name validation). There is no combat content, no NPCs, and no items in this specific archive -- the tutorial world is pure exploration -- and this is the archive's genuine, intentional scope, not a conversion gap: MudCore's own combat/NPC/item primitives compile and are fully present in the engine layer, immaster's game/ layer simply never uses them yet (an in-progress learning project, per its own README). Login uses a real account (English login ID) + password + Chinese character-name + gender registration flow, with save/restore verified to survive a real driver restart. A hardcoded engine account name (getuid()=="teamug") is automatically granted wizard privileges on login -- register with that id to get wizard commands (eval, whoami, update, dump, etc.), no separate seeding step needed.

README

A small, real Chinese-language LPC learning project built on top of MudCore (<https://github.com/oiuv/mudcore>), a modern FluffOS-native engine framework. immaster's own README calls it plainly: "Ongoing building of the mudlib, as a learning project." It supplies only the content layer -- a short tutorial map -- while MudCore supplies the engine underneath (accounts, login/registration, save/restore, movement, command dispatch, wizard tools, and a set of daemons).

Source: git clone https://github.com/flyinrookie/immaster (commit 43382dc, July 2020), plus MudCore pinned at the exact commit (88d5d3a) immaster's own git submodule record points to. Slug immaster, number 940, port 40242.

Highlights

Status

Boots clean against ~/src/fluffos/build-debug/src/driver: all ten MudCore daemons preload in order, Initializations complete. every time. 127 of 128 files pass a full lpcc_check.sh sweep; the one failure is a pre-existing orphaned/dead file in the original archive (never inherited or referenced anywhere, and missing a data file it depends on) -- not a conversion regression. Full detail in NOTES.md §2.

Verified live with raw socket sessions: full registration flow, login with restore, look, movement between rooms, say, help, the archive's own test command, and a clean quit -- plus save/restore confirmed across an actual driver restart.

WASM status: playable. Shared WASM driver. New-character registration (wasmim, Chinese name 浮浮, Mud@2026, m, after the GBK y/n prompt) into 茅草屋, south to 前院, and quit, verified with scripts/wasm_client.js. Play: https://mudlibs.fluffos.info/immaster/

Local run

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

Game port: 40242.

NOTES · 移植与修复记录

immaster -- porting notes

Source: git clone https://github.com/flyinrookie/immaster (commit 43382dc, July 2020, last commit "modify notes"). The upstream README describes it plainly: "Ongoing building of the mudlib, as a learning project." It is a real, from-scratch Chinese LPC tutorial/learning project, genuinely new to this collection (not a duplicate of any existing lib).

0. Not a standalone mudlib -- a thin content layer on a pinned engine

immaster's own README.md is explicit that it is built on "MudCore" (a separate, actively-developed FluffOS-native engine framework, <https://github.com/oiuv/mudcore>) via two git submodules declared in .gitmodules (ext/mudcore and a stale unused duplicate engine/mudcore entry, plus ext/www/engine/www for a browser terminal client). Every #define in immaster's own system/include/globals.h (MASTER_OB/LOGIN_D/COMMAND_D/ROOM/etc.) resolves to a one-line inherit CORE_X; wrapper file that points at the matching MudCore object (CORE_MASTER_OB etc., defined in MudCore's own include/mudcore.h). Without MudCore, system/core/kernel/master.lpc's inherit CORE_MASTER_OB; alone fails to resolve and nothing compiles. This is a required build dependency, not optional bundled content -- unlike imud's optional-only Intermud-3 extension modules (AGENTS.md §2.3), immaster's entire engine (login/registration, save/restore, movement, command dispatch, wizard tools, combat/chat/database/time-of-day/virtual-object daemons) lives in MudCore, not in immaster itself.

git ls-tree on immaster's own commit records the exact pinned submodule commit: ext/mudcore -> 88d5d3a6db7054f4934a6bb3dc753c5cc295e595 (May 2020, close in time to immaster's own last commit -- a compatible, contemporaneous snapshot, not whatever MudCore looks like today; the live MudCore repo has moved on substantially through 2025 and was NOT used). That exact commit was fetched from MudCore's real git history and merged into this lib's work/ext/mudcore/ tree, exactly as git submodule update would have produced. ext/www (a static HTML/JS xterm.js browser client pinned to 513af2e, MudRen/www) was deliberately not included: it is plain browser-side JS/CSS, not LPC, contributes nothing to the driver-side mudlib, and is unrelated to the raw-socket verification this project uses -- immaster's own README calls it optional ("using the web client included in ext/www can access the game from browser"). .gitmodules itself was removed from work/ (no real submodules exist in this project's flat work/ layout, and it referenced the stale duplicate engine/-prefixed paths that were never populated).

config.example.ini's websocket http dir : www / external_port_1 : websocket 8000 (a second, browser-facing listen port MudCore optionally supports, backed by include/mysql.h... no, by ext/www) was likewise not configured -- this project's config.fluffos opens a single plain telnet port, matching every other lib in this collection.

0.5 One filename-level tooling fix (not a driver-compat fix)

doc/notes/driver工作流程.md (a Chinese-language *filename*, not just content) was renamed to doc/notes/driver-workflow-notes.md. This is unrelated to the LPC/driver conversion -- the file compiles/loads nothing, it's plain documentation -- but this project's own git-based tooling (scripts/safe_commit_batch.sh's owned-path check, which reads git diff --cached --name-only) breaks on a non-ASCII filename because git octal-escapes it by default (core.quotePath), producing a string that no longer starts with the literal libs/<slug>/ prefix the script checks for. Renaming the one offending file sidesteps this cleanly without touching the shared script. Its content (in Chinese) was left untouched.

1. Conversion

Pure-ASCII/UTF-8 archive already (GitHub-native, written directly in UTF-8) -- confirmed by convert_lib.sh: 192/211 files already valid UTF-8, 19 correctly skipped as genuinely binary (map JPG/SVG images under doc/map/), zero lossy conversions. 128 files renamed .c->.lpc.

Critical: the .c->.lpc rename hit the §7.118 file_size(X+".c") gate-check bug family in 6 separate MudCore engine sites, all auto-fixed by convert_lib.sh's own literal-.c"-reference sed pass (confirmed by direct inspection before ever running lpcc, matching the dreamofseven precedent in AGENTS.md's bug catalog):

Also auto-fixed by the same sed pass: master.lpc's own #include "master/error.c" / "master/valid.c" / "master/preload.c" (raw C-preprocessor #include of what are themselves .c-turned-.lpc files) and simul_efun.lpc's equivalent 14-file #include chain -- all 16 literal .c" references correctly became .lpc".

One additional non-gate .c->.lpc reference was auto-fixed as a side effect and is harmless/cosmetically-correct either way: simul_efun/path.lpc's resolve_path("here") branch used to return file_name(environment(this_player())) + ".c" (a cosmetic path label for a wizard cd here-style shell helper, never itself used as a file_size()/load_object() argument); it now returns + ".lpc" instead, which is if anything more accurate post-rename.

Zero manual static->nosave/protected collisions (the codebase already uses nosave/private/protected/nomask natively -- zero raw static keyword occurrences anywhere in the tree, matching a codebase written directly against a modern __SENSIBLE_MODIFIERS__ driver).

2. lpcc_check.sh: 127/128 pass

Followed the mandatory §10.4 discipline given the fresh, previously- unverified MudCore engine merge: compiled all 25 MudCore/immaster base classes (master, simul_efun, all 16 inherit/*, all 4 std/room/*, both std/living/*, login/user/void) individually first -- all 25 passed clean -- before running the one full batch sweep. RSS stayed trivial throughout (a ~3.8MB combined tree); no memory concern materialized.

The one failure, /system/core/daemons/nature_d.core (note the unusual .core in the filename, not a typo introduced by this port -- it exists verbatim in the upstream git history, added by commit 61cddc2 nature_d and never renamed despite a later commit literally titled 23e3192 fix time_d file name), is a genuine pre-existing dead-code/content gap in the original archive, not a conversion regression:

3. Boot and live verification

Booted ~/src/fluffos/build-debug/src/driver against config.fluffos repeatedly with Initializations complete. and all ten daemons preloading cleanly every time. __USE_MYSQL__ is defined in this build, and the shipped mysql.h/valid_database() apply reference a (fake, placeholder) local DB credential set, but **no code anywhere in either immaster or MudCore actually calls db_connect()/db_exec()/any db_* efun** -- confirmed by a whole-tree grep -- so this is completely inert; the mysql package being compiled into the driver never gets exercised.

Raw Python socket sessions (this project's preferred verification method) confirmed the full, real registration/login flow: connecting prompts for GBK-encoding preference (answered n, since this archive's is_chinese()/is_english() are already Unicode-codepoint-aware -- pcre_match(str, "^\\p{Han}+$") and a plain a-z/A-Z range check respectively, not GBK-byte range tests, so none of the classic §8.1 byte-range bugs apply here at all), an English-letters-only login ID (digits are rejected by is_english() -- confirmed this is the archive's own intentional design, not a bug: a purely-numeric or alphanumeric ID loops back to re-prompt rather than crashing), new-account confirmation, a 2-10 character pure-Chinese character name (is_chinese()), a password + confirmation (crypt()-hashed), and a gender choice -- landing the new character in the real game/world/tutorial/start_room with correct room text and exits. Verified further: look, movement (south from the start room correctly reaches courtyard, matching the room's own set("exits", ...)), say, help (falls back to game/help/tutorial's real static help text when given no argument, per system/cmds/player/help.lpc's own default), the archive's own test command (system/cmds/player/test.lpc, prints a literal placeholder string -- clearly a scaffolding command the author left in, not something this port added or should remove), and a clean quit.

Save/restore verified across a real driver restart (per the AGENTS.md §7.120 lesson that a single continuous session can mask a save-integrity bug): killed the driver, restarted it fresh, reconnected with the same account ID and password -- password check and restore() both succeeded and the character reappeared in the correct room with its saved state intact.

Wizard/admin access is account-name-based, not seeded separately: MudCore's inherit/command.c's enable_living() grants enable_wizard() unconditionally to any connecting account whose getuid() equals the hardcoded constant WIZARD (immaster's globals.h sets this to "teamug", overriding MudCore's own default "mudren"). Registering a new account with the login ID teamug was confirmed live to grant working wizard commands (eval, whoami, and by extension the rest of ext/mudcore/cmds/wizard/* -- update/dump/get_dir/call_other/etc.) with no other setup step. This plays the same functional role as this project's usual §1.5 admin-account seeding, just via a fixed reserved username rather than a config file or database row -- there is nothing further to seed.

4. No outbound network

Grepped the whole tree (immaster + the merged MudCore engine) for socket_create/socket_connect/socket_bind/socket_listen/ socket_accept/external_start/dns_master/intermud: zero hits. HTTP_PORT/MudCore's optional websocket listen port is inbound-only (a second local listen socket for the bundled browser client, which this port doesn't configure or need) and was not enabled in config.fluffos. This is a fully offline, sandboxed archive like the overwhelming majority of this collection.

5. Scope: a genuinely thin tutorial map, by design (imud/lil precedent)

Per AGENTS.md §2.3's precedent (imud) and the parallel lil case: a thin surface here is the archive working as designed, not a conversion failure. game/world/tutorial/ ships ~12 connected outdoor/indoor rooms (start room, courtyard, backyard, forest, stream, waterfall, cave + cave entrance, tomb, cliff, treehouse, two trail segments) with real, polished Chinese room descriptions and a coherent map (see doc/map/tutorial/TutorialArea.{jpg,svg}, kept as reference images) -- but genuinely no NPCs, no items, and no combat content anywhere in this specific archive. This is not a missing-content bug: STD_NPC/STD_MOB (immaster's own room/living templates, wired up correctly in system/include/stdob.h) are never referenced by any file in game/world/, and MudCore's own combat/char/virtual-object daemons all compile and preload cleanly despite having nothing in this specific lib's content to act on. immaster's own README frames the whole project as "ongoing" ("正在建设中" in spirit) -- ended, per its git history, after about 6 weeks of active commits in mid-2020. Documented here explicitly, per the standing project rule, so a future re-check doesn't mistake "just rooms to explore, nothing to fight or pick up" for a bug needing a fix: it is this archive's real, final, intentionally-thin state.

6. Deep functional test (round two, 2026-08-27)

Full §10.7 methodology pass: one continuous raw-socket session, booted ~/src/fluffos/build-debug/src/driver config.fluffos from libs/immaster/ (killed by exact PID when done, never pkill).

6.1 Bug found and fixed: typo'd exit key breaks reciprocal navigation

game/world/tutorial/trail2.lpc's exits mapping used the key "northest" where every other room in this 13-room map, the sibling room trail1.lpc ("northeast": WORLD_DIR"/tutorial/pool"), and this engine's own canonical direction table (ext/mudcore/cmds/player/go.lpc's default_dirs/r_dirs mappings, which enumerate northeast as a real direction with southwest as its reciprocal, and ext/mudcore/system/daemons/command_d.lpc's default_aliases "ne":"go northeast") all use northeast. Since this engine's go.lpc looks up the exact input string as a mapping key (exit[arg], undefinedp gate), typing the semantically-correct northeast from trail2 failed with the driver's generic 什么? (unknown-command) fallback, while only the typo'd northest actually worked — silently breaking the trail1<->trail2 direction symmetry every other room pair in the map observes (e.g. stream/cliff use east/west, forest/backyard use southup/northdown, etc.). This is a plain one-character-off literal typo (an "obviously wrong variable/string reference"), not a content/design call — the fix doesn't invent anything, it restores the one convention the rest of the file's own siblings already follow.

Fix: "northest" -> "northeast" in trail2.lpc's exits mapping (one line). Verified live: teleported a wizard test character into trail2 via eval, confirmed pre-fix that northeast produced 什么? while northest moved to trail1; applied the fix, reloaded the room live with the wizard update command (no reboot needed), and confirmed northeast now correctly moves trail2->trail1 and southwest moves back, matching trail1's own already-correct exit keys.

Not treated as a new AGENTS.md numbered bug class: unlike the 7 standing cross-cutting patterns checked below, this is a single idiosyncratic literal-string typo local to one file, not a generalizable engine-level shape likely to recur verbatim in unrelated codebases.

6.2 Observations documented, left untouched (content/design, not bugs)

6.3 The seven standing cross-cutting patterns: all checked, all clean

Grepped both immaster's own content and the merged MudCore engine tree for each of the 7 patterns called out for every lib this round:

6.4 Save/restore and account/wizard flow: re-confirmed briefly

Per the task instructions, did not redo the full onboarding investigation (already verified in §3 above) — just re-confirmed: a teamug registration, full 13-room movement sweep (including teleporting via the wizard eval command into the otherwise- unreachable trail1/trail2/pool/waterfall/tomb cluster to exercise those rooms' own exit logic), quit, a real kill + restart of the driver process, and reconnect with the same ID/password — password check, restore(), and the teamug-grants-wizard rule all worked identically post-restart. log/debug.log (created fresh each boot per this project's own .gitignore) stayed completely empty across the whole multi-session test — zero uncaught errors of any kind.

WASM measurement (2026-09-03)

meta.json was already playable from the 2026-08-31 deploy-unblock; the README still said "not attempted." Cold-boot under the shared ~/src/fluffos/build-wasm succeeded with no mudlib-side compile fix. Verified with scripts/wasm_client.js: first prompt is the GBK y/n encoding question (n), then English ID (wasmim, ≥3 letters), new-account y, Chinese name 浮浮 (2–10 chars), password Mud@2026 twice, gender m. Arrived in 茅草屋, south to 前院, quit printed Bye,欢迎下次光临. The existing teamug save was left untouched (unknown password). Shop/combat/death were not exercised this pass.