TinyMUX

PennMUSH vs TinyMUX

Servers

PennMUSH and TinyMUX are the two most widely deployed servers in the MUSH family. Both descend from TinyMUD through the TinyMUSH lineage, but they diverged early and have followed distinct design philosophies for over thirty years. This article summarizes their technical differences.

Historical Divergence

TinyMUSH 1.0 (Larry Foard) was derived from TinyMUD. From TinyMUSH 1.0, two independent lines emerged. The PennMUSH line passed through MicroMUSH and PernMUSH before Lydia Leong (Amberyl) renamed it PennMUSH in 1992. The TinyMUX line passed through TinyMUSH 2.0, with TinyMUX 1.0 forking from TinyMUSH 2.0.10p6 under David Passmore (Lauren). TinyMUX 2.0 was started in 1998 by Stephen Dennis (Brazil) as a port to Windows NT 4.0. See the History page for the full family tree.

Because PennMUSH descends from PernMUSH rather than from TinyMUSH 2.0 directly, the two codebases share very little code despite sharing a common ancestor. The behavioral overlap is largely the result of deliberate compatibility work rather than shared implementation.

Language and Build System

PennMUSH is written in C (C11 and later) and uses autoconf with a traditional configure/make build. The source tree is organized into src/ for implementation, hdrs/ for headers, and game/txt/ for help text. PennMUSH uses PCRE for regular-expression support and links against OpenSSL for SSL/TLS.

TinyMUX is written in C++ (C++17) and also uses autoconf/automake. The engine is built as a shared library (engine.so) loaded by a thin driver process. Source files live under modules/engine/. TinyMUX uses PCRE2 for regular expressions and links against OpenSSL. The module architecture allows extending the server through dynamically loaded shared objects without recompiling the core engine.

Database Format

PennMUSH uses a text-based flatfile database. Every object and its attributes are written as human-readable lines. This makes the database easy to inspect with standard text tools, but reading and writing it requires parsing every field on every load and save.

TinyMUX historically used a binary hash-file pair (.dir/.pag) for attribute storage alongside a flatfile for object headers. Current development has moved attribute and channel storage into SQLite, with a write-through cache layer (attrcache.cpp, sqlite_backend.cpp, sqlitedb.cpp). The SQLite backend stores objects, attributes, attribute names, channel state, channel membership, and mail in normalized tables with prepared statements. Flatfile import and export remain available for migration and backup.

Expression Evaluation

Both servers evaluate softcode expressions using a percent-substitution and function-call syntax that traces back to TinyMUSH, but the internal parsing strategies differ.

TinyMUX has three distinct parsers: the command parser (command.cpp), the expression/function evaluator (eval.cpp), and the lock (boolean expression) parser (boolexp.cpp). The expression evaluator uses table-driven character classification (isSpecial tables) to locate delimiters, nesting markers, and substitution tokens in a single pass. Function arguments are split by parse_to, which walks the string destructively, inserting null terminators at delimiter positions.

PennMUSH similarly splits parsing into command dispatch, expression evaluation, and lock compilation. Its evaluator (parse.c) uses a recursive approach with a process_expression function that handles substitution, function lookup, and argument splitting. PennMUSH introduced named registers (q-registers addressable by name rather than only by number) earlier than TinyMUX, though TinyMUX later added similar features.

Function and Command Availability

Both servers provide a large library of built-in softcode functions covering string manipulation, math, list processing, database queries, and control flow. The overlap is substantial, but each server has functions the other lacks or implements differently.

PennMUSH tends to expose more functionality through softcode functions, including features like built-in chat-system manipulation functions and extended attribute-tree operations. It offers regedit(), json(), and a family of SQL-query functions for connecting to external databases.

TinyMUX provides many of the same operations under the same or similar names but has historically relied more on commands for administration. TinyMUX includes sql() for inline MySQL queries (when compiled with INLINESQL), a full set of side-effect functions, and math functions tuned for IEEE 754 compliance. Its functions.cpp registers built-in functions through a COM-style class factory.

When the same function name exists in both servers, argument order or delimiter handling can differ, which is a common source of porting problems.

Chat Systems

PennMUSH implements its channel system partially in hardcode and partially through softcode-accessible functions and commands. Channel administration is done through the @channel command, and channels support mogrifier objects that can filter or transform messages.

TinyMUX implements its channel system (comsys.cpp) entirely in hardcode. Channels are managed with @ccreate, @cdestroy, addcom, delcom, and related commands. Channel state, membership, and per-player aliases are persisted to SQLite through write-through helpers. TinyMUX channels support recall (message history), titles, and gag of join/leave notices.

Permission Models

Both servers use a layered permission model built from flags, powers, and attribute access controls, but the granularity and organization differ.

PennMUSH uses a privilege system where flags carry inherent trust levels (e.g., WIZARD, ROYALTY) and powers grant specific fine-grained abilities. PennMUSH also supports attribute trees, where an attribute and all its children can share a single access rule. Lock evaluation is handled through a rich boolean expression language supporting attribute locks, evaluation locks, and indirect locks.

TinyMUX uses flag words (multiple 32-bit words in the fs field of each object) and a parallel powers system (powers.cpp). Commands and attributes carry access bitmasks (e.g., CA_GOD, CA_WIZARD, CA_PUBLIC) checked at dispatch time. TinyMUX distinguishes the God (#1) player from Wizards throughout, with specific checks preventing removal of God’s WIZARD flag.

Softcode Compatibility and Porting

Moving softcode between PennMUSH and TinyMUX requires attention to several areas:

  • Delimiters. PennMUSH defaults to space as the output separator in many list functions; TinyMUX may use a different default or require an explicit separator argument.
  • Registers. Named registers and the setq()/setr() interface are available in both, but the number of numbered registers and scoping rules can differ.
  • Side effects. Both servers support side-effect functions like set() and create(), but availability depends on server configuration.
  • Chat hooks. Channel manipulation is done through different commands and functions; softcode that interacts with the comsys will need rewriting.
  • Substitutions. Most percent-substitutions (%#, %!, %N, %L) are shared. Some newer substitutions may be server-specific.
  • Regular expressions. Both support PCRE-style regular expressions, but PennMUSH uses PCRE (version 1) while TinyMUX uses PCRE2. In practice the syntax is the same for typical patterns.

Performance Characteristics

TinyMUX was designed with performance as an explicit goal. The binary (now SQLite) attribute store avoids full-database text parsing on startup. The fork-and-dump model (on Unix) allows the game to continue running while a child process writes the database. The attribute cache (attrcache.cpp) maintains an LRU cache keyed by object and attribute number to reduce SQLite round-trips.

PennMUSH prioritizes correctness and feature richness. Its text flatfile database means startup involves a full parse of every object, but in practice this is fast enough for the database sizes MUSHes typically reach (tens of thousands of objects). PennMUSH checkpoint dumps rewrite the entire flatfile, which can cause brief pauses on very large databases.

Both servers handle hundreds of simultaneous connections without difficulty on modern hardware. The choice between them is rarely driven by raw performance.

Community and Development Status

PennMUSH is hosted on GitHub and has been maintained by a succession of lead developers: Javelin (Alan Schwartz) from 1995 to 2006, then Raevnos. Development continues with periodic releases.

TinyMUX is also hosted on GitHub and has been maintained by Stephen Dennis (Brazil) since TinyMUX 2.0. Active development continues, with recent work focused on the SQLite storage backend and engine modularization.

Both projects are released under the Artistic License (Clarified), following a joint agreement made in late 2002 among the PennMUSH, TinyMUSH, and TinyMUX development teams.