Show HN: I rewrote the 1990's LambdaMOO server
174 points| cmrdporcupine | 2 years ago |github.com | reply
I've always wanted to see this kind of thing modernized and further developed. Over the last 25 years or so I've worked on similar but novel & improved things, but never finished.
So I decided to just re-implement LambdaMOO and use that as a base, instead and keep compatibility as a goal, but build it out on a more modern foundation that takes advantage of multiple core machines, newer network protocols, newer connectivity methods, uses MVCC transactions for the shared database etc.
LambdaMOO is a somewhat extensive system in that it is composed of compiler, a virtual machine, an object database, user permissions system, network runtime. In some ways it's kind of like a shared, text-based Smalltalk image/runtime... So quite a bit to implement and get right before it all works together.
The big challenge throughout has been slavishly maintaining backwards compatibility so existing "cores" (databases) work.
It's not done, but it's darn close. Would like for people who are into this kind of thing to check it out, and maybe even help.
Many of the technical aspects here are still provisional, but this is the start. Constructive assistance welcome.
(Yes, it's a rewrite in Rust, but that's not really the point, even though that's a cliche that's fun.)
[+] [-] NelsonMinar|2 years ago|reply
Pavel Curtis is still out there, LinkedIn says he recently left his job at Microsoft after 20 years. He also runs a puzzle shop: http://www.pavelspuzzles.com/site/
[+] [-] sshumaker|2 years ago|reply
[+] [-] skulk|2 years ago|reply
I have some questions:
[+] [-] cmrdporcupine|2 years ago|reply
But sticking with compatibility has allowed me to enforce development discipline, basically. And then I'll move it onwards from there. I have many ideas. And a product concept (if I could find an investor...). But I felt it important to start with a thing with existing foundation and use cases before doing the exciting stuff/changes.
Re: world state / transactions -- yeah, basically all I/O and mutations happen in a transactional context, and then at commit time conflicts are resolved; if they're not resolve-able, the transaction is retried in a new state. As for overhead, yes potentially maybe a lot, but it's also a solvable problem; this is how an MVCC SQL database (like, even Postgres) works. TLDR it's likely inefficient now, but I believe I can make it efficient. And I think it's the best way to solve the shared world state problem and still meet user's expectations of consistency. Original LambdaMOO had a global interpreter lock and only one user was mutating the world at a time, in their given tick slice. Not gonna scale.
Re: the MOO client, it's `rmoo.el`: https://github.com/lisdude/rmoo -- it's been around for a long time (25, 30 years?) and it and/or MOO.el (another emacs one) are how/why I learned emacs in the first place. I had to minor patch my local copy to make it work with emacs 29.1, though I don't know elisp well enough to say whether my patch is the right thing to do or not, so...
EDIT: I just re-read and saw you asked whether each new verb call creates a new state, and actually it's not that. It's each new command or network transaction, which can in fact lead to a chain of verb (method) calls. Recall a MUD has a command loop, so basically a transaction begins at command entry, and commits when all the invoked methods/verbs provoked from that complete.
[+] [-] branon|2 years ago|reply
[+] [-] cmrdporcupine|2 years ago|reply
From "A Rape In Cyberspace: "no hate, no anger, no interest at all. Just…watching. Others were more actively unfriendly. “Asshole,” spat Karl Porcupine, “creep.” But the harshest of the MOO’.. "
I was Karl Porcupine. Quite young then, though.
[+] [-] fzzzy|2 years ago|reply
I've also wanted to give each object an isolated environment (make each one an actor), but I haven't thought too deeply about how exactly that would work and look. I've been planning in the back of my head to do this at some point in the next year, and was planning on implementing on top of the original codebase, but if there's a rust version, I'll use that.
I know it wouldn't be compatible with existing cores, but I'd be using it as the backend for a graphical ui anyway.
How did you go about converting the code? Did you just read through it, or did you start with a c to rust tool? I always thought the programmers manual and codebase were quite concise and readable.
One last thing, there were patches in the 90s to add journaling on top of the checkpoint system... Did those ever get merged into the main codebase?
Thanks for doing this! I'm excited!
[+] [-] cmrdporcupine|2 years ago|reply
Mixture of approaches. No automatic translation. After bringing over the AST and opcodes, etc most of it I wrote without reference to the original code, with the functionality in mind. Where MOO was doing something a bit funky, I often wrote code with a second window open to look at how they were doing it. But in general it came down to running a core over and over again and finding how it broke. MOO has some unexpected behaviours in spots that grew over time. If I were to start over with this, I'd invest the energy in ripping out parts of MOO and turning them into a library and then write tests that run them side by side through the same opcode sequence and compare output. But MOO was built quite monolithic, so that's hard.
Re: maps, MOO's value types are immutable/copy-on-write. So while I want a map type, a typical HashMap may not make a lot of sense, as it would be doing a deep copy on each addition. Some kind of functional persistent map would probably be appropriate. Syntactical sugar for maps would be nice, and I will probably add it later. But I'm also not as concerned with the MOO language itself, as I see it as only one language among potentially many to run on the system.
"I've also wanted to give each object an isolated environment (make each one an actor)"
Maybe related; I intend on reworking the object reference system such that object numbers and $sysobj-references are a form of published capabilities. That is, I will be introducing "private" objects with some sort of signing & publishing & capability style references, and slowly deprecating object numbers. But that's all post 1.0 stuff.
[+] [-] fzzzy|2 years ago|reply
Websockets and utf8 as well. Lovely.
[+] [-] trollied|2 years ago|reply
[+] [-] cmrdporcupine|2 years ago|reply
Check out blightmud. It's kind of tinyfuge-the-next-generation.
[+] [-] blipvert|2 years ago|reply
[+] [-] tromp|2 years ago|reply
[+] [-] kevinsync|2 years ago|reply
[+] [-] erikarn|2 years ago|reply
https://github.com/ingwarsw/tinyfugue
-adrian / erikarn
[+] [-] stavros|2 years ago|reply
[+] [-] VadimPR|2 years ago|reply
[+] [-] rhinoceraptor|2 years ago|reply
One of the bigger challenges with the web UI is that HTTPS isn't really optional anymore, and the enCore database has a ton of `http://` links. So it requires a reverse proxy in front that can rewrite those, luckily in Nginx it's possible to use a small Javascript program to do it.
[+] [-] smirya0|2 years ago|reply
Does it use async I/O / is it one thread still?
You might find this conversation interesting about multi-threading in LambdaMOO: https://groups.google.com/g/moo-talk/c/omF68ZM9rZc/m/B3f-jj4...
[+] [-] cmrdporcupine|2 years ago|reply
There's still ticks and time limits, but they're there to impose time / resource limits, not used to control access to shared state.
Tick-based time-slicing to the database is one reason why LambdaMOO (and its offshoots like toaststunt, etc.) has intrinsic scalability limits. (In the 90s, LambdaMOO-the-actual-MOO used to lag like a son of a bitch under load...)
(This is not to say the actual impl of MVCC I have right now is ideal. It's a work in progress. I just defer to RocksDB's conflict resolution, and it is built on assumptions of "single writer, multiple readers" at its foundation, which isn't ideal for what I'm doing... )
[+] [-] nrr|2 years ago|reply
I hadn't looked at doing this in Rust yet, so it'll definitely be interesting to give the code a read, particularly with the focus toward modernization.
[+] [-] Shekelphile|2 years ago|reply
I also found this project randomly on github at one point, not sure how far along it got to being usable: https://github.com/verement/etamoo
[+] [-] cmrdporcupine|2 years ago|reply
If I'd seen that a year ago, I'm not sure I would have started. Hard to say.
I admire Haskell, but I could never really grok it.
[+] [-] clouddrover|2 years ago|reply
telnet lambda.moo.mud.org 8888
[+] [-] unknown|2 years ago|reply
[deleted]
[+] [-] tromp|2 years ago|reply
[+] [-] fleeno|2 years ago|reply
A while back I wrote a MU*-style system in Ruby, using js as the scripting language. It has a web based tool that gives object owners a URL for each object, which lets them edit the attributes and code in a better way than just line oriented editing. It also lets external services call back to that object to trigger actions.
I never did anything much with it though.
[+] [-] jonmarkgo|2 years ago|reply
[+] [-] unknown|2 years ago|reply
[deleted]
[+] [-] zellyn|2 years ago|reply
Very fun. I expect the parallelism will also be strikingly better with a modern design and implementation!
Very nice!
[+] [-] mindcrime|2 years ago|reply
I've had similar thoughts, so let me say "Congrats, this is awesome"! It definitely warms the cockles of my heart to see work like this. I just wish I had the free cycles to work on something similar (or even contribute to your project). But there are too many demands on my time right now. :-(
[+] [-] unknown|2 years ago|reply
[deleted]
[+] [-] unknown|2 years ago|reply
[deleted]
[+] [-] gilmore606|2 years ago|reply
[+] [-] cmrdporcupine|2 years ago|reply
This is what MOO was effectively mostly doing already, through a big ol' single threaded interpreter we all took turns on. Only one task was running at a time (sort of, you could suspend() and return later, and then all bets were off on consistency). It's just... that doesn't really scale too well.
[+] [-] cpeterso|2 years ago|reply
[+] [-] thelibrarian|2 years ago|reply
[+] [-] worthless443|2 years ago|reply