LPUniversity Mudlib

✅ 可玩

lpuni

更新 4b67bae 2026-10-27 源码 下载 ZIP

▶ 开始游玩 · Play Now

A classic English-language LPC teaching/reference mudlib, positioned by its own lpmuds.net description as not ready for play -- a base for learning to build a lib without dealing much with the driver. What shipped is more complete than that framing suggests: a full login/registration/security/command-dispatch/help/mail/message-board/news/channel/Intermud-3 engine including a real first-boot admin-setup wizard, plus one small real starting domain: an entrance room with a greeter NPC leading north to a single upstairs floor holding a cafe (complete with a serving station and stained tables), a bar, a lounge, a bathroom, and a backroom, all connected to each other rather than the "three upstairs floors" a first pass at this description assumed. There is no combat/stats system at all. Also makes a real outbound Intermud-3 network connection at boot, same as imud/tmi2/skylib.

README

An English-language classic LPC teaching/reference mudlib. Per its own lpmuds.net description, LPUniversity was never meant to be a finished game -- "not ready for play... provides a chance to build a lib from the ground up without having to deal much with the driver." What actually shipped is more complete than that framing suggests: a full login/registration/ security/command-dispatch/help/mail/message-board/news/channel/Intermud-3 engine (including a real first-boot admin-setup wizard), plus one small real starting area -- "LPUniversity Cafe" -- with a greeter NPC and real room descriptions. There is no combat/stats/limbs system at all.

Source: a maintained, already-FluffOS-adapted archive (lpuni_fluffos_v1.zip) from lpmuds.net, a now-defunct LPMud archive site. Recovered via the Wayback Machine (<https://web.archive.org/web/20160306051537if_/http://lpmuds.net/files/lpuni_fluffos_v1.zip>) since the original site is down. Slug lpuni, number 177, port 40224.

Highlights

Registration flow

select a name -> (new account?) y -> password -> confirm password -> public e-mail address -> [Hit enter to continue] twice -> lands in a personal workroom (wizard/admin accounts) or the LPUniversity Cafe entrance (ordinary accounts).

Admin account

Verified live: update <path> (this project's canonical ACL/compile- permission check) against a real adm/obj/master.lpc file succeeds.

Status

Boots clean: zero compile errors across repeated fresh-driver boots. Verified live with a real driver session and a raw socket client: the first-boot admin install, look/inventory/who/ls/more/the wizard update command, movement into the real shipped starting domain (with a scripted greeter NPC), and a clean quit. This engine has no combat/ stats system, so there is no score command to verify (confirmed: no file or string literal named score exists anywhere in the archive) -- same precedent as libs/foundation2/.

138 of 151 .lpc files pass a full lpcc_check.sh batch compile sweep; the 13 that don't are all either include-only fragments never meant to compile standalone (the Intermud-3 i3services/*.lpc handlers, textually #included into chdmod_i3.lpc; adm/simul_efun/overrides.lpc, textually #included into the real simul_efun object -- both compile and load fine as part of their real parent file) or an object whose create() legitimately needs a live player context (std_newsclient.lpc) -- see NOTES.md for the full triage.

WASM status: playable. Login, arrival in the starting workroom, and quit are verified under the shared WASM driver (NOTES.md WASM status update). Play: https://mudlibs.fluffos.info/lpuni/

Local run

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

Game port: 40224.

Note: booting this lib makes a real outbound network connection (see Highlights above) -- avoid scripting repeated/automated boots.

NOTES · 移植与修复记录

LPUniversity Mudlib -- porting notes

Source: lpuni_fluffos_v1.zip, a maintained, already-FluffOS-adapted archive from lpmuds.net (a now-defunct LPMud archive site). The live site is down; this exact archive was recovered from the Wayback Machine (<https://web.archive.org/web/20160306051537if_/http://lpmuds.net/files/lpuni_fluffos_v1.zip>) and content-verified (valid zip, non-corrupted, real content such as bin/config.lpuni and license) before this session started. Slug lpuni, number 177, port 40224. The zip bundles a FluffOS 2.9-ds2.07 driver source snapshot (fluffos-2.9-ds2.07/), plus bin/, win32/, etc/ build/install scaffolding -- all ignored, this project uses its own driver. The real mudlib root is the zip's lib/ directory.

LPUniversity is positioned by its own lpmuds.net description as a teaching/ reference base -- "not ready for play... provides a chance to build a lib from the ground up without having to deal much with the driver" -- so a minimal/skeletal feel was expected going in (similar in spirit to libs/genesis/). In practice it's less skeletal than that framing suggests: it ships a complete login/registration/security/command-dispatch/ help/mail/message-board/news/channel/Intermud-3 engine (a real adm/etc/new_install-driven first-boot admin wizard included) *and* one small real starting domain (areas/lpuni/, "LPUniversity Cafe" -- an entrance, three floors, a bar/lounge/cafe/bathroom, and a greeter NPC with real dialogue). No genesis-style from-scratch bootstrap was needed. There is no combat/stats system at all, so (like foundation2) there is no score command to test -- confirmed via grep, not a gap in this port.

1. Conversion

English-language archive (not GBK-encoded) -- scripts/convert_lib.sh against raw/lpuni_fluffos_v1/lib confirmed this: 897/902 files already valid UTF-8, only 1 lossy conversion (a stray non-ASCII byte in a plain text/doc file, not code), 4 skipped as genuine binaries. 151 .lpc files after the .c->.lpc rename, 110 literal .c" references fixed, 0 local angle-bracket #includes needed converting, 7 files touched by the static->nosave sweep (no collisions: no "static... path-literal hits, no #define nosave static/#define protected static shims to neutralize).

2. Compile-time driver-compat fixes

`` string get_root_uid() { return "[admin]"; } string get_bb_uid() { return "[backbone]"; } string creator_file(string str) { string ret; ret = privs_file(str); if (!stringp(ret) || ret == "") ret = get_bb_uid(); return ret; } ` (Same fix class as foundation2/merentha`, this session's other lpmuds.net onboardings -- see AGENTS.md \S2.2's checklist.)

- Opposite-direction instance, same root cause: cmds/file/more.lpc used == ".lpc" (not !=) with the same undersized 2-char slice, so the pager's syntax-highlighted-paging branch for .lpc files could *never* match -- it silently fell through to plain unhighlighted paging for every .lpc/.h source file. Fixed the same way. - Structurally different instance, same root cause: cmds/file/ls.lpc's filename_prefix() used a switch() on a single fixed 2-char slice with a case ".lpc": arm that could never match (the file's own comment even lampshades this: //Will hit default if size>2) -- every .lpc file in a directory listing colorized as plain white/unmarked instead of green. A switch() can't have per-case slice widths, so rewrote as an if/else chain: a <4..<1> check for .lpc first, then the original <2..<1> checks for .h and __SAVE_EXTENSION__ (both genuinely 2 characters, not bugs). - Grepped the whole tree afterward for any other [<N..<1] <op> ".lpc" or [<N..<1] <op> ".h" shape at any width -- these 7 sites (the 5 != command fixes + more.lpc + ls.lpc) were the complete set.

3. Runtime/hygiene fixes (found via live boot + play testing)

4. Checked, present but inert (no fix needed)

5. Checked, not present (from this session's recurring-bug checklist)

6. Live outbound network side effect at boot (by design, not a bug -- same class as imud/tmi2/skylib, see AGENTS.md \S2.3)

Confirmed live, not just read from source: adm/etc/preload loads /adm/daemons/chan_d unconditionally, which pulls in adm/daemons/chmodules/chdmod_i3.lpc (Intermud-3 chat-network support). Within a couple of seconds of every boot, log/i3.log records a real outbound socket_create()/socket_connect() to a live public I3 router:

Notice [I3/socket]: Connecting to *yatmim, 149.152.218.102 23
Success [I3]: Connected.
Notice [I3]: Sending connection details.
Notice [I3]: Sending 'startup-req-3'

This repeated (a fresh connect-and-handshake) on every single boot this session. This is genuine, intentional upstream functionality (not something to patch away), but it means every boot of this lib makes a real outbound connection attempt to a real third-party service -- this lib should NOT be swept into high-frequency automated re-boot/ re-test loops the way this project's other (fully sandboxed) libs safely can be. The lpcc_check.sh compile sweep does NOT trigger this (it never runs create()/preload, so it's safe to re-run freely); only a real driver boot does.

7. Boot and play test

Booted ~/src/fluffos/build-debug/src/driver config.fluffos repeatedly (a small, deliberately-minimized number of boots given \S6 above); zero compile errors, Initializations complete., accepting telnet connections on 40224 every time. Verified live with a raw Python socket client:

Zero uncaught runtime errors in log/log (this codebase's error_handler() log target) across this session's boots and play-testing, beyond the two fixed issues in \S3 above (confirmed absent on the final re-test boots).

Admin account

Verified live: update <path> (this project's canonical ACL/compile- permission check) against a real adm/obj/master.lpc file succeeds.

WASM status update (2026-08-26, another session)

Promoted wasm_status from "" to playable. Same by-now-routine eager-simul_efun sockets gap as several sibling libs from this same source: adm/simul_efun/socket.lpc's dump_socket_status() called socket_status() unconditionally. Gutted to a safe stub (diagnostic admin tool only, not on the boot/login path). Verified with a full scripted WASM session: login (fluffos/testpass123), arrival in the correct starting workroom, channel auto-tuning, and a clean quit ("Fluffos has left LPUniversity... Thank you for visiting LPUniversity") -- the full session, including quit, was captured distinctly this time.

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

Full §10.7 methodology pass -- this lib had never had one before (only the onboarding-tier verification above). Read doc/FAQ and doc/general/commands first (this lib has no dedicated newbie-help command output beyond help/help <topic>); confirmed via source read and live play that this is a genuinely thin teaching base like genesis/foundation2, not a full game: no combat, no stats, no skills/sects, no shops, no death/respawn -- so those parts of the standard checklist are honestly N/A here, not skipped. One continuous session: booted ~/src/fluffos/build-debug/src/driver config.fluffos from libs/lpuni/, registered several fresh English-named non-admin characters one after another on fresh boots (a raw Python socket client, not tmux_mud.sh) to isolate two bugs below, tested look/inventory/get/drop/say/movement/help/who/news/ mail(admin-only)/finger/uptime/version/mudlist, quit, grepped the mudlib's own error log (log/log, this codebase's error_handler() target -- confirmed empty/absent after every clean session), then reconnected after a genuine ~90s wall-clock gap and confirmed a fresh, non-"reconnect-to-body" login with state (last login time, correct starting room) intact. Found and fixed two severe, previously-undiscovered bugs, both filed as new AGENTS.md entries (neither is a pre-existing numbered class):

深度功能测试(§10.7,2026-10-03)— site-like tree, every compile warning

Method: a tree built the way the site builds it (scripts/pristine_tree.sh: tracked files, work/log, the directories wasm_keep_dirs.txt records for the slug). Registration (several accounts, including ones whose first letter has no bucket on a fresh tree), tell/reply/say/emote, save, passwd, the news client, ~20 further player commands, and disconnects at every login prompt and inside passwd/news. All pass (/tmp/fdtest/lp_battery.py, throwaway). Fixed:

1. A brand-new account whose first letter has no bucket yet could not save. setupNew() mkdirs /data/users/<letter>/<name>/ but never /data/users/<letter>/ itself; the tracked tree (and the site zip) only ships the buckets that already hold a seeded account (f/ for fluffos). The very first registration whose name starts with any other letter hit *Could not open /data/users/l/.../....o.tmp for a save right after the welcome banner, i.e. essentially every real visitor. Fixed in setupNew(). 2. The unsupported #pragma save_binary (three files: adm/obj/simul_efun.lpc, adm/obj/master.lpc, adm/daemons/chmodules/chdmod_localNet.lpc) printed "Unknown #pragma, ignored." -- dropped; this driver's pragma is save_types, not save_binary (KB 04 §6.10 lists it as a class). adm/simul_efun/overrides.lpc's efun:: overrides are rejected by this archive's own valid_override() on this driver's compiler internals (Invalid simulated efunction override, pre-existing, out of driver-compat scope -- not touched; the companion "no side effects" warning disappears once the override itself is accepted, so no separate fix needed there). 3. 27 nosave function declarations in the lazily-compiled mail client became protected (scripts/lpc_warnings.py --fix; KB 04 §6.10) -- the same class the round-two pass already found and fixed for the always-loaded files; this lazily-compiled one was a gap in that sweep's coverage. 4. Not fixed, unrelated to this pass: the 11 Undefined variable/send_packet/I3LOG/get_rank errors are the chat/channel Intermud-3 modules this archive ships without their matching chmodules daemon state (pre-existing content gap, same class as round two's §6 note).

Admin-account wizard commands (eval/goto/ls/update/...) were not re-verified this pass (round two already confirmed update/ls/more live); see that section.

深度功能测试(§10.7,2026-10-05)— 主控 author_file()/domain_file()

驱动的 mudlib_stats 包在主控载入时各调用一次 author_file(<主控文件>) 和 domain_file("/")。本库主控没有这两个 apply,所以每次启动都打印 author_file() in the master file does not work, using root_uid as fallback 和 domain_file() in the master file does not work, using bb_ui as fallback 两行,网页版每位访客的终端里都看得到。adm/obj/master.lpc 补上了这两个 apply:作者返回 get_root_uid(),域返回 get_bb_uid(),正是驱动缺少它们时所用的值。域名等于 backbone 域时,驱动让对象沿用创建者的域,与没有这个 apply 时相同(KB 06 §7.222)。用 lpcc config.fluffos /nonexistent.lpc 前后对比,主控载入段只少了这两行。

if (x = CONST): a comparison written as an assignment (2026-10-20, KB 06 7.290)

if (arg = "button" || arg = "pill"), if (!arg || arg = "") return 0;, else if (check = 0 && tempB != ""): = was typed for ==, so the condition is the constant: the branch is always taken for a non-zero number or any string (even "") and never for 0, and the variable is overwritten; the driver does not warn. Every such = became == (scripts/lpc_fix_cond_assign.py, 4 terms). Changed: /adm/daemons/lockdown_d.lpc (4).

A login password over 255 bytes: crypt() raises (2026-10-20, KB 06 7.294)

The driver's crypt() raises (Error in crypt(), check your salt) for a key over 255 bytes, where the old driver hashed any length. A password of 256 bytes or more typed at the login prompt threw an error in the password check and left the connection at a bare > prompt, so the login never completed (the old-password test of password the same); found by the sweep shape of 300 x. /adm/obj/simul_efun.lpc now defines a simulated efun crypt(key, salt) of the same name: only an over-long key is cut (to 255 characters, then character by character until sizeof(to_buffer(key)) <= 255: the limit is in bytes, a CJK character takes three) before it is handed to efun::crypt(); every ordinary password hashes as before and the saved hashes are untouched (scripts/lpc_add_sefun.py crypt).

Misspelled call_out() / input_to() targets (KB 06 §7.349, 2026-10-21)

The timer or prompt named a function one letter off the one the file defines (idle_teme for idle_time, ...): the call is silent for a missing function, so the idle check of the monk guild's inner room never fired. The call and its remove_call_out() now use the defined spelling. Changed: /cmds/adm/wms.lpc.

Combat probe with the seeded administrator (2026-10-22): clean

scripts/play_combat_probe.py lpuni --account ... --clone ...: the administrator cloned /areas/lpuni/mobiles/greeter into its room without a driver line; these greeters refuse kill, so no fight started. (KB 08 §10.16)

无参数时命令对 0 的调用(玩家/--all-dirs 残留,2026-10-27,KB 06 §7.336 Also)

无参数命令把 0 交给 present / sscanf / file_exists 等会运行时报错。lpc_fix_bare_arg.py --all-dirs 在首次使用参数前加守卫。多行 if (arg && !sscanf)(吐纳默认消耗)与已有 can_learn/get_object 守卫的误报已回退;本库本批改动见该提交。