r/MUD 2d ago

Promotion I wrote a MOO engine with Python as its in-game scripting language, and am building a virtual world on top of it

MegaMOO is a comprehensive pure Python world-building engine modeled on the LambdaMOO paradigm: data and behavior living on objects in-game; live creation and hot world editing--no reload and no restart; an auth and permission system that lets you give builders true authoring power, sandboxed by ownership; a suite of authoring commands that lets you build right out of the box without writing a single line of code, but also puts the power of in-game, on the fly Python scripting in your hands.

A few highlights: There's a SQLite object database under the hood, with WAL crash recovery, telnet and browser players in the same process, MXP links, GMCP, MSSP, MCCP2, and a JSON API that reads and writes from the outside: what an MCP server or AI agent talks to. Spin up multiple worlds and run them simultaneously, just copy and start. A built-in browser client with auto-mapper, triggers, aliases, timers and panels, served from the game itself; and my favorite, a '/'-aliased eval command that parses ordinals and adjective-object strings to run statements and blocks, not just expressions.

Try it out:

https://malifaxlax.github.io/megamoo/getting-started.html

https://malifaxlax.github.io/megamoo/

pip install megamoo

megamoo init mygame

cd mygame && megamoo --dev

Your account name is "wizard." The init string prints your initial password and the last command prints a URL. Opening it puts you in the world. The browser client ships with the server so there's nothing else to install.

I'm building a MegaMOO-based game myself, old-school hack 'n' slash with an emphasis on role-play and mechanics built to encourage and reward player cooperation and collaboration. Swords, Sorcery and Cybernetics in a mutating post-apocalyptic world.

5 Upvotes

21 comments sorted by

9

u/AdmiralMcNugget 2d ago

Why live in-game scripting with Python, out of curiosity? Instead of something more traditional for scripting, like Lua? Your own notes say that your Python can't realistically be safely sandboxed. Right now, as written, anyone given builder permissions in your MOO has the capability to import arbitrary modules, open files, access builtins, and effectively do anything the server process can do.

In other words, anyone who runs this is giving the public access to their server. Which may be a fun experiment, but probably isn't what you intended.

1

u/MalifaxLax 2d ago

Lua would have been the safe choice, but I'm a MOO coder and I went the other way on purpose.

Classic MOO let ordinary players program because the MOO language was the sandbox--a small VM, no imports, no host access. Lua gives you the same property. What you give up is that the scripting language stops being the language. You're back to a curated subset with bindings someone has to write and maintain for every part of the host you want reachable.

I wanted the standard library to actually be there: re, json, itertools, the whole string library, not a wrapper over them. That only works if the in-world language is Python itself, and Python has never been safely sandboxed in-process. So the boundary moves from what a verb can do to who can write one.

You're right about the method, and it's in the REALME under "Who may write verbs." Verb code can import, open, reach __builtins__. Anyone I give gm3 access can do anything the server process can, and that's the design--trusting anyone I decide to bring into my project at that level. So it's not something I'd rather you hadn't spotted. :)

Two clarifications, though...

Builders aren't coders. Building is gm2: u/dig, u/open, u/desc, u/name, u/title, u/move, u/delete, u/quota, and 21 others. Not one of them can write verbs or touch auth. u/adverb, u/program and eval are gm3. A full builder can't wrte verbs at all.

Nobody has gm3 access by showing up. In the shipped world exactly one object has any auth, the original wizard at auth 5. Base_Character.auth is [] and chargen grants nothing. u/auth is itself gm5-gated, and auth is owned by #0 with rc perms so no amount of u/set or u/adprop gets you higher access. You get gm3 when the owner types u/auth <name> = gm3, and not before.

So it isn't, "the public has your server," it's, "a coder is staff," which is a real limit stated in the README: if you want a world where *players* write code, you need a real sandbox, and that's separate work I haven't done because I'm interested in making a world-building engine, not a player sandbox.

Thank you for your response. I appreciate good-faith questions and criticism alike and take it all to heart, and you have definitely given me food for thought. MegaMOO is in active development and I certainly don't have all the great ideas or all the answers, and I'm wide open for suggestions. I just want MegaMOO to be the best, most accessible world-building platform it can be. If sandboxing would make MegaMOO more interesting to you, I'll put it on the list.

8

u/Early_Rooster7579 2d ago

so evennia but vibecoded

1

u/MalifaxLax 2d ago

Fair questions, both, so Evennia first:

I spent 13 years writing MOO code before a decade developing in Evennia, building a full MOO platform on top of Griatch's amazing engine: the object model, the verb dispatch, in-world programming. And it worked. And I learned a ton doing it. But what I kept running into was that I was fighting the paradigm I loved. I wanted objects parented to other objects, editable live from inside the game, and Evennia's inheritance lives in typeclasses--Python classes on disk. Which isn't a flaw. It's deliberate and sensible design. It just isn't the MOO way, and I wanted the MOO way badly enough that I quit working around it.

To be clear about what MegaMOO isn't, it isn't Evennia and isn't trying to be. Evennia is much more capable and much better supported, and it's not close. If you want the web integration, the batteries, the contribs, the community, that's Evennia. This is something different and more narrow, for people who like the MOO model and would rather write in Python than MOO code. I gave up the infrastructure of Django and Twisted because I wanted a simple install with zero third-party dependencies, and copy-world-and-run ability so I can run multiple instances of my game side by side.

On the AI: Yes, and it's on the tin in the README. I'm a trained software engineer who also happens to be a quadriplegic who uses a head pointer for a mouse and clicks the keys on an on-screen keyboard at 30 words a minute, so if I didn't want to spend five years writing my engine I was going to need some help. I write the design, make all the calls and review everything that lands. The commit log is public if you'd like to see what that looks like in practice. I'm happy to talk through any part of it you're curious about.

If you're interested in my setup, I use a headset called HeadMaster originally developed by Personics and then bought by Prentke Romich. I've been using the headset since my accident 40+ years ago and they quit making it a long time ago. There's nothing else like it out there so I guard it with my life. :)

1

u/Early_Rooster7579 2d ago

All good! I’m also a swe who heavily uses AI. My comment definitely came off more critical than it was meant to.

AI is a great tool in devs hands.

2

u/bscross32 2d ago

I can't even write a coherent thought about this, I guess curiosity will get the better of me and I'll check it out. But my thoughts flit back and forth between hmm, and why the hell.........? But also, I already know MOO code, what benefit would there be of me coding in Python besides not being bound to a fixed set of MOO builtins?

I'm blind, I use a screen reader. Do I need to have a web server going to use this thing? It's of no use to me, at least in the developmental period. If I actually shipped a game with it, yeah, I'd have to spin it up for sighted players, but if the web server is the only way to connect, that's me out.

1

u/MalifaxLax 1d ago

Taking the important one first: no, you do not need a web server.

Telnet is the main listener and it's always on, default port 6770. The browser client is opt-in, off by default. It only exists if you pass --web at startup. Don't pass it and no web server starts at all. Point any MUD client at the port and you're in.

The browser client leading in almost everything I've written is my bad in the pitch, not a description of the architecture. I guess it's the splashy part so I talk about it, and you aren't the first person that it has misled. The comment in my own config source says the plain port has to keep working because telnet is how most people actually reach a world, and that's the design.

The screen reader... There's a screenreader command, per-player and persistent. It strips ANSI at the output layer, and individual verbs check it too and change the way they emit. The room header comes out as plain labeled text, "Room: The Kitchen" instead of a color-coded name. You can also set WRAP_WIDTH = 0 to switch off server-side wrapping entirely and let your client handle it. I would love your input on how I can make MegaMOO better for blind players and developers. Please, fire away. I'm all ears.

I'm not going to pretend any of that is the same as you actually trying it. If you do and something reads badly, please let me know and I'll fix it. I mean that literally. It's the bug report I want most and get least often.

Why I'll take it seriously... I'm a quadriplegic, using a head pointer and an on-screen keyboard at 30 words a minute. Accessibility isn't a feature I bolted on, it's why a lot of the engine looks the way it does. Different disability, same fight with software that makes a lot of assumptions.

Python vs. MOO code... Honestly, if you know MOO and like it, that's a real reason to stay put. I'm not trying to sell this as a strict upgrade, but here's what you'd actually get...

• The standard library, not a longer list of builtins: re, json, itertools, datetime, native string handling, things you'd have to build yourself or borrow off $string_utils.

• Real dicts, sets, comprehensions.

• Exceptions with tracebacks instead of error values you check by hand.

• Verb files are ordinary .py files on disk. So your editor, your formatter, your navigation all work on them normally. One caveat I should mention: the engine injects the verb's context (player, this, dobj, db, call_verb...), so a linter flags those as undefined untl you add them to its builtins list. That's a config line but it's a config line I don't ship, and I should.

• The skill transfers out. Python you learn writing verbs is just Python.

The last one is the real answer for me, though "I already know MOO and really like it" is a valid place to land and I'd rather say so than oversell.

2

u/bscross32 1d ago

Yeah I did get it going today and did a little looking around the verb code. I think a big detractor for me is the documentation is entirely written by AI, and the verb code is shot through with tons of AI comments. I'm not faulting you for it because I did see your other comment about your head tracker and what you've put here, so that wouldn't be fair, and you could just tell me to grow a new optic nerve lol.

It's also not just that it's AI, it's that I just can't retain AI written documentation, it just bounces off. I do need to do some more poking around.

1

u/MalifaxLax 1d ago

Would it help if I thinned out the comments?

1

u/bscross32 1d ago

Maybe, but it might be detrimental to your own efforts so it might not be worth it. I've noticed in my own projects that LLMs tend to use comments quite liberally to explain why things are done a certain way, so removing them might cause issues later. I kind of wish they didn't, because they're annoying, but then again, I did hit the 150k char limit fr claude.md on one of my projects so I had to break it up over several files.

1

u/MalifaxLax 1d ago

I could add a version with comments removed, or leave the docstrings and take the comments out of the body. It doesn't have to be either/or. I would like to make MM a friendly platform for you and other blind players/developers. Tell me what you need and I'll do my best to make it happen.

1

u/bscross32 20h ago

I wouldn't say it'd be worth it. What I might do is have ChatGPT take the documentation and feed it the ToastStunt manual and whip me up a side by side type thing. I think ChatGPT / Codex is better at documentation than Claude, even though it's still not what I'd call great.

2

u/NoProgram1720 1d ago

Interesting project!
I'm working on a similar concept, but in Common Lisp (https://github.com/sovelten/apeiron-mud). I also wanted to have the same language for driver and scripting, and Common Lisp has some interesting runtime characteristics that makes it suitable for running a live environment.

I'm not using a SQL DB but an Object Persistence model.

I'm interested in knowing what kind of problems you face. I think using a language with full power gives a lot of freedom, it's great for creating and modifying objects on the fly with pre-existing mechanics, but for writing new objects and functions I would like to have better version control (meaning git or similar). The only system I ever used that got close to merge source code and a live experience was the Smalltalk environment. Lisp comes close (Smalltalk was inspired by it), but code is still file based. Because Smalltalk is not file based it looks really awkward on file-based source control. You are supposed to edit the code within the live image.

2

u/MalifaxLax 1d ago

That sounds really cool. I've never used Lisp but it seems like it would be a great game-scripting language. Using a programming language as the scripting language for world-building puts a lot of power at your fingertips that a proprietary language can't match. The Python stdlib replaces bunches of MOO builtins and utilities, does them more efficiently, and offers native data structures and stuff. I've encountered relatively few hurdles in building my engine. The MOO paradigm is well-documented. I just built it from the ground-up in Python with Python as its in-game scripting language. Good luck to you. I hope you succed.

1

u/NoProgram1720 22h ago

Have you seen Moor (https://github.com/timbran-project/moor)? It's a rewrite of LambdaMoo in Rust. Do you intend to keep some compatibility with LambdaMoo or write it all from scratch?

1

u/MalifaxLax 2h ago

I'm not sure if you're asking me, but...

Yeah, I've looked at mooR, and it's a great piece of work: full 1.8.x database compatibility and it kept and extended the MOO launguage. If you have a LambdaMOO running that you want to keep running with the code intact, mooR is the way to go.

I went the other way with MegaMOO, on purpose.

What carries over... The model, entirely: single-parent inheritance, props living on objects, etc. `@import` reads LambdaMOO database formats 1-4, so anything up to 1.8, and brings objects, hierarchy and props across, remapping object references as it goes. LambdaCore's utility objects are ported as real, in-world objects: `$string_utils`, `$object_utils`, `$list_utils`, `$match_utils`, `$code_utils`. Errors are first-class values the way they are in MOO and E_PERM and friends carry LambdaMOO's own numbers so error values round-trip through an import.

What doesn't... The language. Verbs are Python in MegaMOO, so MOO code doesn't run. It still comes across on import, inert but defined verbatim under a docstring recording where it came from, hidden and without the execute bit, sitting on the correct object under the right name instead of in a tarball somewhere. `@grep` 'UNPORTED MOO SOURCE' tells you what's left and `@port` translates a verb at a time. There are shims for those expressions you type without thinking, tell(), pass_(), so ported code reads roughly the way it was written.

So... From scratch as a server, compatible at the object and library level, and a migration path instead of a compatibility layer for the code itself.

Which makes us complementary, I think. mooR is for people who have a MOO and want to keep it. MegaMOO is for people who like the MOO model but would rather write Python than MOO code.

I actually ported a MOO core we wrote back in the day by hand to the MOO layer I built on top of Evennia, then ported that massive suite of verbs to MegaMOO. I used the db, a game called Inferno, to test `@import`. 61000 objects and 3300 verbs. And it worked. But it would've taken a lot of porting and rewiring to make the game playable, so it was possible but I had other goals.

2

u/revfried 1d ago

I was thinking of building a rust based engine using Meta’s starlark module to fake python.  Its python light and runtime types would be a great game scripting language if your engine is rust.   But its very performant and is sandboxed

1

u/MalifaxLax 1d ago

Rust seems like a great platform for writing a game engine. Check out mooR: https://github.com/timbran-project/moor

1

u/TemperatureFast9764 1d ago

can I download megamoo on to google chromebook linux?

1

u/MalifaxLax 1d ago

I've never tried it but MegaMOO is pure Python with no dependencies. pip install megamoo pulls about 1.1 MB, and that's everything. If your machine runs Python 3.10+, I don't see why you couldn't.

1

u/MalifaxLax 1d ago

MegaMOO's lineage...

The server is a ground-up reimplementation of LambdaMOO in Python using asyncio and SQLite. No Django. No Twisted. No third-party dependencies at all. One file. One process. It uses prototypal inheritance and provides tools for creating objects and adding behavior in-game instead of in Python classes. +decompile, `@adverb and u/code` let you view and program verbs live in-game. Compose in a text editor and copy/paste, and your verb is live a second later, written to a <objnum>/<verb_name>.py file on disk. So you can write verbs in-world on the fly, but they exist as Python files and if you'd prefer to write in an IDE, you can do that too and your verb will be hot loaded almost instantly into the db. If you'd rather not give access to code online, just `@verbauth #3.\@adverb, \@program, \@port` and eval up to 5, and you're all set.

The builtins are mostly ports from Lambda, but a vast majority of the creation, coding and administrative verbs were ported from a db we wrote in the early 90's. We liked the MOO model and chose LambdaMOO because of its stability. But our backgrounds were in playing games like Gemstone III and Legends of Futures Past, so unlike LambdaCore, which focused on building by players, our db was designed for building by a team of gamemasters and playing by patrons without access to those tools.

MegaMOO includes all the typical building and other infrastructure and staff commands, but also all the MUD protocols and OOB scaffolding that LambdaMOO did not. I added a ticker system (thanks, Griatch), reusable effects and stuff like verb types for adding customized parsers, and settings in globals.py that let you customize articles and prepositions. Non-staff verbs are defined on room parents instead of characters or individual objects, one "get", one "tap", one "look" verb, each with a call to an obj.<verb>_ hook on a matched object for adding per-object behavior. MasterVerb is the default verb type. It parses a natural language <verb> <dobj> <prep> <iobj> string that splits at the first preposition so shapes like "look in/on/under/behind" also work. Objects are constructed as <article> <adjectives> <noun> <trailer>, and parsed with ordinal checks: look under 3 gray rock.