mud/docs/how/mudlib-landscape.txt

671 lines
21 KiB
Text

mudlib landscape - research into the MUD engine ecosystem
this document synthesizes research into existing MUD engines, their architectures,
and their design decisions. useful reference when designing our own mudlib.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
SECTION 1: the mud family tree
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
dikumud (1990)
--------------
the combat MUD ancestor. C, room-based, zone files, tick-based.
spawned the entire diku family: merc, rom, circle/tbamud, smaug.
binary/text zone files define the world. NPCs are templates that get instantiated
via "resets". main loop is tick-based (1/4 second typical). zones have 6 sections:
zone declaration, mobiles, objects, rooms, resets, DIL scripts.
major descendants:
- merc 2.0 was a total rewrite improving code quality, dropping binary formats
- circlemud stayed closer to original diku, cleaner but fewer features
- smaug was the biggest architectural divergence - reintroduced complexity merc
stripped out
- tbamud is the modern circle continuation
lpc/lpmud (1989)
----------------
the big innovation: driver + mudlib separation.
driver is a VM for the LPC language. mudlib is the game framework written in LPC.
this means game logic is hot-reloadable interpreted code while the engine is
compiled C/C++.
drivers:
- fluffos (active, mudos fork, C++)
- ldmud (C, long history)
- dgd (independent implementation)
mudlibs:
- dead souls (beginner-friendly, batteries-included)
- lima (clean modern)
- discworld (the famous one)
- morgengrauen (oldest german lpmud, since 1992)
- realms-mud (rich combat/crafting)
- cdlib/genesis (historically influential)
LPC is C-like, OOP. blueprint objects serve as templates, clones are instances.
objects inherit from parents forming hierarchies. code lives in .c files compiled
by the driver at runtime.
in-world programming: builders write LPC code that gets compiled by the driver
without restart. this is the core appeal of lpc muds.
moo/lambdamoo
-------------
everything-is-an-object. the entire world is a persistent object database.
objects have properties (data) and verbs (methods/commands). verbs are the core
interaction - "put ball in box" parses into a verb call with direct object,
preposition, indirect object.
in-world programming via @program command - attach MOO code to object verbs.
persistence: entire DB in RAM, periodic checkpoints to disk.
fork statement creates background tasks for async work.
modern forks:
- toaststunt: multiple inheritance, HTTP, JSON, threading for sqlite/sort/etc
- stunt: adds map datatype, RESTful interface
mush/mux (tinymud family)
-------------------------
objects with attributes (key-value), flags (booleans), locks (permission
expressions).
two kinds of code:
- hardcoded (C, needs restart)
- softcoded (mushcode, stored in attributes, hot-reloadable)
three parsers: command parser, function parser, locks parser.
building with @dig, @create, @link.
modern engines
--------------
evennia (python/twisted/django)
see section 2 for deep dive. most framework-like of modern engines.
ranvier (node.js)
bundle system where nearly everything is modular. bundles package commands,
areas, items, NPCs, channels, behaviors. network layer is swappable.
unopinionated core.
exventure (elixir)
uses erlang/otp process model. kalevala framework underneath. web client,
telnet, clustering, prometheus metrics, cross-game gossip chat.
coffeemud (java)
most feature-complete MUD codebase. supports everything: MSP, MXP, GMCP, OLC,
built-in web+mail server. d20-style combat with extensive modifier system.
compiled engine + scripted logic pattern:
- gomud (go)
- dragon-mud (go+lua)
- ataxia (rust+lua)
graphicmud (java)
tile-based graphics over telnet via sixel encoding. ECS architecture instead of
inheritance. behavior trees for NPC AI. 4-tier action system with automatic
dependency chaining. multi-connector: telnet, discord, telegram, websocket, MCP.
30+ plugins. symbol system maps each tile to multiple representations (ascii,
cp437, unicode, ansi colors, pixel bitmaps) — client capability detection picks
the best one.
taleweave-ai (python)
AI NPCs via LLMs, discord integration, stable diffusion visuals.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
SECTION 2: evennia deep dive
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
most relevant reference since we're also python.
architecture
------------
dual-process: portal (networking) + server (game logic), communicate via AMP
protocol.
portal handles all protocols: telnet, SSH, SSL, websocket, IRC, discord, grapevine.
server runs game logic, django ORM for persistence.
twisted-based async, event-driven (not tick-based by default).
scripts use ExtendedLoopingCall for timed tasks (tickers).
object model
------------
TypedObject base -> ObjectDB (django model) -> typeclasses (DefaultObject,
DefaultRoom, DefaultCharacter, DefaultExit)
rooms are objects with location=None.
exits are objects with db_destination. they dynamically create CmdExit commands.
typing "north" runs the exit's command which checks locks and traverses.
contents cached via ContentsHandler.
attributes: arbitrary pickled data via obj.db.attrname, stored in DB.
tags: lightweight string labels with categories, fast for filtering.
locks: function-based access control strings like "cmd:perm(Builder) AND
attr(canEdit)".
command system
--------------
commands define: key, aliases, locks, arg_regex, parse(), func().
processing pipeline:
gather cmdsets from session/account/character/room/exits
-> merge
-> match
-> execute: at_pre_cmd -> parse -> func -> at_post_cmd
cmdset merging uses set theory operations with priorities:
- union (default)
- intersect
- replace
- remove
priorities: exits=10, account=0, room objects=lower.
this is how game states work: push a "fishing" cmdset that overrides "throw",
pop it when done fishing. push "dark room" cmdset that replaces default commands.
stack them.
this is genuinely novel - set-theoretic operations on command availability.
session handling
----------------
portal creates PortalSession per connection.
server creates ServerSession, links to Account and Character.
MULTISESSION_MODE:
0 = exclusive
1 = multiple chars
2 = multiple sessions per char
3 = full multi
building
--------
@create, @dig, @link, @open, @desc, @set, @tag, @lock, @typeclass, @spawn
no in-game python execution in base evennia.
prototypes: dict-based object templates with inheritance via prototype_parent.
spawn system creates objects from prototypes.
persistence
-----------
django ORM with any supported DB (sqlite default, postgres for production).
what's unique about evennia
----------------------------
- cmdset merging system is genuinely novel
- typeclass system lets you change object behavior by swapping its class at
runtime
- multi-protocol portal means same game is playable via telnet, web, ssh
simultaneously
- django integration means you get admin panel, REST API, web views for free
- most "framework-like" of all MUD engines - it's a toolkit, not a game
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
SECTION 3: how they all solve the same problems
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
world representation
--------------------
room graph (most common)
rooms as nodes, exits as edges, directed graph. diku, lpc, evennia, ranvier
all use this.
advantage: clear sight lines (same room = visible)
disadvantage: no consistent coordinate system
grid-based
n*m orthogonal grid, each cell ~8 neighbors. used for wilderness areas in some
lpc muds. consistent scale but less flexible.
continuous/coordinate
entities at exact 2D/3D coordinates, descriptions generated from proximity.
modern trend.
advantages: seamless movement, true spatial relationships
challenge: rendering continuous space as text
tile graphics (graphicmud)
3D tile grid (x, y, z) with toroidal wrap. the unique part: tiles render as
actual bitmap graphics via sixel encoding over telnet, not just colored text
characters. symbol system gives each tile multiple representations — ascii
fallback, cp437 glyph, unicode, ansi colors (16/256/24-bit), and pixel-grid
bitmaps. client capability detection picks the richest format supported.
standalone symbol editor for creating tile sets.
OUR APPROACH (from dreambook)
2D toroidal tile grid with terrain types. viewport centered on player. hybrid -
overworld is grid, interiors can be rooms. this is relatively uncommon in the
MUD world.
command parsing
---------------
all MUDs: text in -> parse command name -> extract arguments -> dispatch to
handler -> execute -> text out
simple
split on first space, command + args string
complex (moo)
parse verb + direct object + preposition + indirect object
mush
three separate parsers for commands, functions, and locks
evennia
fuzzy matching against merged cmdset, disambiguation for ambiguous matches
ranvier
modular command definitions in bundles
persistence
-----------
flat files
diku zone files, moo database dumps. human-readable, version-controllable.
ORM/SQL
evennia (django), some modern engines. structured, queryable, scalable.
in-memory + checkpoint
moo model. fast but needs enough RAM.
sqlite
good for embedded single-server muds. ACID compliant, single file.
OUR APPROACH
world definitions in yaml/toml files (version controlled), runtime state in
memory, player data in sqlite.
game loop
---------
tick-based (diku)
fixed interval (1/4 sec), process all queues each tick. synchronous progression.
simple, deterministic.
event-driven (evennia, ranvier, exventure)
no central loop, react to events. tickers optional for periodic tasks. better
for async, scales with concurrency.
turn-based
advance only on player input. good for single-player IF, awkward for multiplayer.
OUR APPROACH (from dreambook)
tick-based (10 ticks/sec), drain input queues each tick. timing-based combat
needs a real clock.
combat
------
diku-style
automatic attacks on timer ("pulse_violence" ~3 sec), player can enter special
moves. hit/miss/damage calculated from stats, armor, weapon, random rolls.
no built-in combat
most frameworks (evennia, ranvier) provide none - you build it.
coffeemud
most complete combat system. d20-style with extensive modifier system.
OUR APPROACH (from dreambook)
timing-based with telegraph/response windows. PL as health AND damage multiplier.
stamina as action economy. diminishing returns on grinding.
communication
-------------
universal pattern: channels with audience types.
say (room)
tell (private)
yell (area)
chat (global)
emote (room action)
ranvier's architecture: channel = name + audience type + formatter functions.
inter-mud: gossip protocol, IMC2, I3.
in-world creation/coding
------------------------
lpc
write LPC code, driver compiles it live. most powerful but requires learning
a language.
moo
@program attaches code to object verbs. everything modifiable from inside.
mush
softcode in attributes. simpler language than lpc/moo but capable.
evennia
no in-game coding. prototypes and building commands only. spawn system for
templates.
ranvier
bundles written externally, loaded on startup.
OUR APPROACH (from dreambook)
world-building DSL for puzzles/triggers/state machines, writable in in-MUD
editor. NOT a full programming language but powerful enough for IF-style
content.
npc behavior
-----------
most muds: simple scripts or state machines. mobs patrol, aggro, flee at low hp.
diku
mobprog/mudprog triggers (on_greet, on_fight, on_death). procedural scripts.
lpc
NPC code in LPC, full programming language. powerful but requires coding skill.
evennia
no built-in NPC system. roll your own with scripts and tickers.
graphicmud
behavior trees. hierarchical node structure (sequence, best-effort, action
nodes). NPCs make decisions via tree traversal each tick. supports conditional
logic, parallel execution, error handling. combat AI: survive, eliminate threat,
patrol, assist.
OUR APPROACH (from dreambook)
not yet designed. behavior trees worth considering.
action architecture
-------------------
how commands turn into world changes.
simple (most muds)
command handler directly modifies state. "kill goblin" -> find goblin, check
conditions, deal damage, all in one function.
graphicmud (4-tier)
rawactions (atomic ops) -> cookedactions (single pulse) -> mudactions (multi-pulse
with conditions) -> commands (user input). actions automatically chain to resolve
dependencies — "attack goblin with sword" generates: walk to sword, pick up,
equip, walk to goblin, attack. planning system handles the sequencing.
evennia
at_pre_cmd -> parse -> func -> at_post_cmd. hooks at each stage but no
automatic chaining.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
SECTION 4: protocols
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
telnet is the base. extensions negotiate via telnet option subnegotiation.
essential
---------
NAWS (RFC 1073)
terminal window size. critical for viewport sizing.
GMCP
generic mud communication protocol. JSON over telnet. the modern standard for
structured data (hp bars, inventory, room info).
MSDP
mud server data protocol. typeless variables, arrays, tables. alternative to
gmcp.
MCCP2/3
compression. zlib over telnet.
useful
------
MTTS
terminal type standard. client capabilities negotiation.
MNES
new environment standard. supplements mtts.
MSSP
server status protocol. for MUD crawlers/listings.
MSLP
clickable links in terminal.
content
-------
MXP
markup for enhanced text (zuggsoft).
MSP
sound protocol (zuggsoft).
MCMP
modernized sound via gmcp (mudlet).
MCP
moo client protocol.
our telnetlib3 already handles
-------------------------------
GMCP, MSDP, NAWS, CHARSET, MTTS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
SECTION 5: clients and what they support
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
top clients by protocol support
--------------------------------
mudlet
gmcp, mssp, mcmp, msp, atcp, msdp, mxp, mmp. lua scripting. the dominant
modern client.
tintin++
gmcp, mccp, mccp3, msdp, mslp, mssp, mtts, mmcp, naws, mnes. terminal-based.
blightmud
tls, gmcp, msdp, mccp2. terminal-based, rust.
mushclient
mxp, mccp, mmcp, mtts. windows only.
cmud
mxp, msp, mcp, mccp, atcp. commercial, windows.
axmud
mxp, gmcp, msdp, mnes, mtts. perl/gtk3.
web clients
-----------
mudportal
mccp, mxp, msdp, gmcp, atcp, mtts. proxy + web client.
grapevine
mud listing with web client.
xterm.js approach
terminal emulator in browser pointing at telnet (our dreambook mentions this).
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
SECTION 6: what's missing from our INDEX.txt
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
repos worth adding for study:
https://github.com/dworkin/dgd
DGD driver - independent LPC driver, not derived from lpmud
https://github.com/EmpireMUD/EmpireMUD-2.0-Beta
EmpireMUD - persistent world map, circlemud derivative
https://github.com/wowpin/dumserver
DUM/dumserver - modern python MU* engine
https://github.com/irmen/Tale
Tale - python MUD/IF framework by irmen
https://github.com/fuzzball-muck/fuzzball
Fuzzball MUCK - tinymuck server
https://github.com/necanthrope/HellCore
HellCore - lambdamoo fork
https://github.com/luciensadi/AwakeMUD
AwakeMUD - community fork, C++
https://github.com/mainframecity/fluxspace
fluxspace - elixir MUD engine
https://github.com/maldorne/mudos
MudOS - historical fork
https://github.com/cotillion/cd-gamedriver
CD MUD driver - alternative LPC driver
https://github.com/DikuMUDOmnibus
DikuMUD Omnibus - 100+ diku-related projects
https://github.com/mudhistoricalsociety
MUD Historical Society - preservation
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
SECTION 7: key takeaways for our design
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
observations relevant to our mudlib:
1. driver/mudlib separation
----------------------------
the driver/mudlib split (lpc model) is the most influential architectural
decision in MUD history.
we get a version of this with python: the engine is the "driver", game
content/logic is the "mudlib". keeping this separation clean matters.
2. composable command sets
--------------------------
command sets that compose (evennia's cmdset merging) are a genuinely good idea
for session modes.
our mode stack (normal/combat/editor/IF) maps directly to pushing/popping
cmdsets.
3. room graphs vs grids
-----------------------
everyone uses room graphs. our tile grid is unusual.
the dreambook's hybrid (grid overworld + room interiors) is the right call - it
gives us the spatial consistency of a grid with the narrative flexibility of
rooms.
4. in-world creation
--------------------
in-world creation is the MOO dream.
we don't need a full programming language, but the DSL for IF/puzzles needs to
be powerful enough that people can create real content from a telnet client.
5. persistence strategy
-----------------------
world in files + player state in sqlite is actually the cleanest approach.
most modern engines do something similar. don't fight the pattern.
6. protocol investment
----------------------
gmcp is the protocol to invest in.
it's what mudlet and tintin++ both support well, and it's how we'll send
structured data (maps, gauges, inventory) to smart clients.
7. tick-based for combat
------------------------
tick-based is right for timing-based combat. event-driven is cleaner for
everything else.
hybrid is fine - main loop ticks, but non-combat systems can be event-driven.
8. prototype/spawn pattern
--------------------------
the prototype/spawn pattern (evennia, diku zone resets) is how everyone handles
mob/item templates.
define once, instantiate many.
9. entity component system
---------------------------
graphicmud uses ECS (composition over inheritance). entities are bags of
components, archetypes define which components they get.
most MUDs use deep inheritance hierarchies (Object -> Item -> Weapon -> Sword).
ECS avoids the diamond problem and makes it easier to add cross-cutting features.
worth considering if our entity model gets complex.
10. capability-based rendering
------------------------------
graphicmud's symbol system — same tile has ascii, ansi, and sixel representations,
client detection picks the richest — is elegant.
we already adapt to NAWS for viewport size. extending this pattern to rendering
quality (plain text -> colored text -> graphics) would let us support everything
from raw telnet to sixel-capable terminals.