Wednesday, March 26, 2008

So....busy

So Phoenyx has been an absolute machine in churning out new code, and I have been struggling to get caught up. Things are a little tense and hectic right now, because of a lot of RL things. Nothing bad, just lots of...well, stuff. Buying a car, for instance.

The commands table rebuild is done and functioning, and for that all credit goes to Phoenyx. I am deep in the DB module rebuild. It's making progress, just slow-agonizing-painful-I-wish-I-had-more-time progress.

Updates as they happen.

Thursday, March 20, 2008

Objects - The Who and Why

Okay, so there's been a lot of talk about "objects" in relation to PurlMUSH. They've been talked about as if they are the greatest thing since sliced bread(they are) and as if they are going to save the world(virtually speaking) and butter toast(not a chance). This is going to be my attempt to communicate what objects are and what they aren't, and why Phoenyx and I are charging forward with the object-oriented banner held high and proud.

So, in typically "me" style, let me make an analogy for you. Let's take a clock radio as our example. Now, 75 years ago, if you had wanted a clock radio, you would have had to make a circuit board. You would have had to solder the components to the board. You would have had to make a case for it. You would have had to fashion buttons. You would have had to connect the wire. And it would have worked. It would tell time, it would broadcast radio stations, it might even have an alarm if you decided that you wanted it to.

Now, if you want a clock radio, you can go down to Sears and buy a pre-built, ready-to-use, no-soldering-required clock radio. This "object" that you just bought would work just fine, right out of the box. It already has all the components of a clock radio, is aware of what it needs to do in order to fulfill its role as a clock radio, and all you have to do is take this "object" and put it wherever a clock radio is needed.

The first clock radio, the one lovingly soldered together and carefully assembled? That's the original code, and the way a lot of code is written. All of the component parts assembled together carefully putting each piece in place. It's functional, maybe not the easiest thing to use, and unless you have a well-made box to put it in, you can see all of its parts. (And who likes to let their parts hang out for everyone to see?)

The second one, the one you bought at Sears? It is the new version of the code on which Phoenyx and I are working diligently. It has everything packaged up into a nice object, with which we can work.
Each "object" will represent an object in the database. In the original implementation, the database was what is called 'an array of hashes'.

So, here's how that worked. An array is a numbered list of items. For example:
  1. Bob
  2. Suzie
  3. Charles
  4. Diana
That is an array. Array element #1 is Bob. #3 is Charles. Etc. Because it's numbered, and because the default standard in MUSH is to reference things by what is called a 'database reference number' or dbref, an array is a logical way to organize things.

A hash is a referenced list. For example, if I was going to make a hash about this blog, it might look something like this:
  • Name = Culturing a Purl
  • URL = http://purlmush.blogspot.com
  • Started = February 2008
The words 'name', 'url', and 'started' are called the keys of the hash. And everything on the right-hand side of the = sign are called the values of the hash. Now, every object on a MUSH has attributes. These attributes have a name (Description, Alias, cmd_where) and a value. So, a hash makes a lot of sense as a way to organize the attributes.

If you put the two together, you are going to get an array of hashes. So, in the current implementation, I can refer to the name of room #10 like this:

$db[10]{"name"}

The $ tells Perl that it's a variable. Meaning a label that holds stuff. The [10] part tells the code what number in the array to look for. The {"name"} tells it which key in the hash to retrieve the value for. Now, you might ask yourself: But Santiago, this makes so much sense, why would you want to go and change that? Yes, it makes sense, but to a coder, it's cumbersome and in-elegant. Elegance is everything to a coder.

Under the new system, the arrays of hashes and all of that will be contained within an object. And the whole db will be inside one object. So, if we want the name of object #3, we'll do this:

$db->name(3)

Nicer, eh? An object is a piece of data that includes the methods we will need to be able to manipulate or report that data. So, with this object-oriented method, we can do things like the following. Let's say object #12 wants to set an attribute on #3:

$db->setAttr(12, 3, "foo", "You're a foo master!");

And that will set an attribute named foo on #3 with the value 'You're a foo master!". This attribute will be recorded as having been set by #12. Previously, we would have had to do this:

$db[3]{"foo"} = "You're a foo master!";

And that's just to set the attribute. That doesn't take into account keeping track of who set it, when, or anything else. The other nice thing is that setAttr, as a method of the $db object, will know whether #12 is even allowed to set attributes on #3. Previously, the code had to do all the tests for this in the main body of the code. Now, it's a matter of the object knowing how to do it, instead.

Does that mean we don't have to code those tests anymore? No, not at all. They will be built into the object instead of the main code. What it DOES mean though is that our objects will be handling the work load instead of the main body of the code. This will be easier to maintain, easier to manage, and easier to extend.

I hope this helps you understand what some of this rambling has been about. If you don't, e-mail me. :)

Wednesday, March 19, 2008

SO many updates

Okay, where to start:
Here's a good place. Phoenyx Black is in da hizzouse. There is a co-developer on the PurlMUSH project. Phoenyx is da bomb. Plain and simple. Thanks to his impressive input, PurlMUSH is advancing by leaps and bounds and has a much better chance of being a success now.

Other updates:
The command parser has been rebuilt by Phoenyx and is waiting my rebuild of the DB load routine before we implement. The command parser rebuild is also going to necessitate a reworking of the existing command subroutines.

The idea of the new command parser is that commands will be able to be registered in the system, their aliases clearly defined, permissions, and the function they are to run will all be structured rather than loosey-goosey as it is now. This will also facilitate developers who will be building extensions to the code later on. (@mail, BBS, etc)

What's up with the DB load routine, you ask? Excellent question my friend. I'll tell you.
The DB loading has been officially abstracted. What this means is that:
  1. The main code doesn't care if the DB is in XML, SQL, HTML, or Elle magazine. As long as there is a module in place that will read in the db and return the appropriate set of objects, we're good.
  2. The db type will be specified in the .cnf file as the dbType parameter.
  3. Other db types can be added. Want PostgreSQL? NO problem! Want db4? Hell, want db2 data on a magnetic tape? No problem! Build a module that lets Perl access the data source, read in the data and return the appropriate objects and PurlMUSH won't care if you're reading octal values off punch cards.
  4. XML will become the "default" format for the flatfiles. Because the XML module will be standard "vanilla" PurlMUSH, you will always be able to read an XML flatfile in, and write an XML flatfile out.
There's one other thing that the new db abstraction means. It means Santiago got suckered into writing the Object classes since the db load routine has to return objects to the code. Yeah, I'd been procrastinating for a long time, but with this revision, I kinda gotta do it. So for more tech-y updates, see the GoogleCode site or the Google Group.

Friday, March 7, 2008

Oh, and...

Also created a Google Group for it as well (http://groups.google.com/group/purlmush) so that we can have mailing lists go out and such as that. Don't know if it will ever get used, but it's there.

E-mail the group at purlmush@googlegroups.com

Branching out

Okay, so the project now has a GoogleCode page (http://code.google.com/p/purlmush). This will allow for svn, bug tracking, issue reporting.

I'll also post archives of the code there too.

Wednesday, March 5, 2008

Version Change

Given the amount of work that I've put into the code so far and how much it differs now from where I originally started, I have bumped the version up from 0.1 to 0.2. That marks it as a 'stable' version...though still Beta because we're pre-1.0. I don't know if I'm going to get to the point anytime soon where I have a third branch on the version number for builds...but I might get there. I will see if there's a way that I can post the code somewhere publicly without having to go to Sourceforge or something like that. I don't know if I'm ready for that kind of exposure just yet.

README

Welcome to PurlMUSH, a different way to do MUSH. This project is a labor of love more than anything else. It is a determined effort to take the robust and functional platforms provided by PennMUSH and TinyMUX and implement them using the Perl programming language. That means that, by definition, it is a proof-of-concept.

Of course, that also means that you can have fun with it, as well. Everything that has gone into the development of this project is based on the idea of code being fun...and something of an obsession as well.

A little bit of history on this project:
- Originally this project was started sometime around 2000 or 2001, when Santiago downloaded and registered a copy of PerlMUD from Boutell.com. Yes, the software was registered, conferring the rights to modify the code on to the Santiago. The idea was tantalizing...a MU*, in Perl. And thus, PurlMUSH was born.

- Help was solicited from a number of people online, most notably Steele from steelemountain.com, who shared Santiago's vision for doing outrageously cool stuff with the code.

- June 2005 - Project was effectively halted when Santiago began the RL trauma of separating and divorcing his wife. The code was lost to the divorce, and has not been seen since. Baby Jesus cried. The code had been some of the best work he had ever done in Perl.

- February 2008 - A new version of PerlMUD was downloaded by Santiago, and he felt the pull and tug of that earlier obsession. He renewed his license with
Boutell.com and began working on the code in earnest. Friends were able to provide server space, and the work began.

A little bit of the vision for what PurlMUSH might become:
- Fully object-oriented code structure, with each db object type having its own corresponding code object. Ideally, Flags and Logging will get OOP'ed too.

- Well-formed and fully compliant XML database flatfile structure.

- Internal systems such as comm/channels, BBS, Places/Mutter, IC time (with configurable ratios), Cron, and whatever other goodies are considered to be 'standard' softcoded systems on MUSHes today. Myrrdin's amazing softcoded systems are the de facto standard for BBS and Cron, there's two standard places and mutter packages out there, and a million things for IC time and other functionality like weather (Keran's *shudder*) or a +wear-style multi-descer (MANY many of these out there). One of the 'standard' and dreaded jobs that goes into starting a MU* is quoting in these very standard bits of code. Why? Projects like Sandbox Globals Project (SGP, again *shudder*) are built around the idea that your game comes with code. Comes with the systems that you need, "out of the box". Insta-MUSH, just add water.

- Easy to setup. Purl doesn't require compiling. You don't have to know a lot of fancy Unix/Linux commands to get your game running. Pretty much, as long as your server is connected to the Internet, has a "standard" installation of Perl (and eventually ActivePerl for Windows), you will be able to have a PurlMUSH up and running in under five minutes. No, seriously. There will be (eventually) a config script that you will run which will query for the necessary bits in the mush.cnf file, the things that won't be "assumed". For example, IP and hostname, file path for the db, etc. Other configuration options can be changed by hand-editing the file. Once you've been through the config script, you type ./Startpurl (or double-click the icon if you're on Windows) and VIOLA! You have a MUSH.

INSTALLATION
Download the code.
Unpack the code - tar jvxf purlmush-###.tar.bz2 (where ### is the version)
Edit the mush.cnf file to suit your mush and environment.
Type: ./Startpurl &
Connect to the host and port you have specified in the mush.cnf file and log in as the God character (default password: lollipops).

HELP
If you need help with PurlMUSH, first off: RTFM. Read the help files. If those don't help, read the blog (http://purlmush.blogspot.com). If that doesn't help, e-mail purlmush@gmail.com and Santiago will answer your query as best he can.

EXTENDING PURLMUSH
Yes, we want to be able to have modules that extend the functionality of Purl. If you have Perl-fu and want to build and contribute modules, please do so. In time, there will be a central repository for submissions, sort of a CPAN for Purl. For now, just e-mail them to Santiago (purlmush@gmail.com).

Good luck, and happy MUSHing!

Good Ideas = More Work

So, I realized that there were a couple things that I had done before with PurlMUSH that I was going to have to re-do. The first, and one of the most important, is building the cnf parameters into a hash that can be changed using an @config command. As well, I still haven't written the code to have .cnf reloaded when the game does an @reload. This is important...that way a MUSH admin can change config options on the server-side, @reload, and they take effect. A practical example of this would be turning building on.

At the same time I was thinking about that, I realized that we should probably have a config script that nicely prompts the user for things like IP, hostname, name of the MU*, etc. This will gently and pleasantly write the mush.cnf file for them and move them speedily along the path of getting the game up and running. Oooh, here's an idea...have the config script prompt them for a pw for God(#1) and do the md5_base64 encoding on it right into the initial db. In fact, if we made it a requirement that the config be run to write the initial db, that would guarantee a bit more security on the God character. Of course, you could also just have an old db/cnf file that you drop in and away you go...theoretically.

I also remembered that I used to have @module as a command in the original codebase. That allowed you to load in code from an expansion module. I am not sure if I want to go that route again, but I might....the idea is great, but the problem of course is that once you load it in, it's remarkably hard to unload it afterwards. Have to think about that.

Made a few cosmetic changes to the file structure, specifically changing the name of the db file, the executable, and the library file. Did this just to give it its own flavour, more than anything else. mud.db is now mush.db. mud is now Startpurl, and mudlib.pl is now mush_lib.

I also got brave and wrote an initial README. I will post it in another blog posting.

Monday, March 3, 2008

Updated ToDo List

1. Change all db objects to true Object-Oriented code objects - Right now it's an array of hashes. I want an array of objects, indexed by dbref. If that's greek to you, no worries. I'll likely write a more eloquent and explanatory post in the near future about the objects and what they do and why I want to use them.
2. XML db format. I want to dump out the db when it's saved into XML format. This will allow for portability, and a few other things. Plus, XML's cool. Again, proof of concept.
3. Logging - Various levels of logging need to be done, including connection logging, system event logging (db dumps, @reloads, etc), and eventual support for the SUSPECT flag for command logging of suspect players.
4. All code projects have to have a README and a Changelog. I will have to write these. Bleh.
5. PerlMUD comes with a built-in 'topics' feature. I will redesign this to implement channels. Should channels log? Hmmm.
6. We need to be able to do non-standard attributes, so that we can move towards custom locks and things like that. &blah #123=Blah.
7. @mail is needed - Have to harvest some ideas on best way to do this.
8. I am going to hardcode the BBS. Myrrdin's +bb system is so universal. Every game has a BBS. So, this one will too, but it will be a better system, hardcoded.
9. @moniker from MUX. I love having ansified names. I will do this. Yes, I will.
10. An idea from Ti'Anna - @paste. This is a command from MOO where you type @paste , hit enter. THen you paste in a whole whack of text that you want to show them, and type a . on a line to signify that you're done. Then, they get it spammed on their screen. I like this, I will do this.
11. The commands table will need to be rebuilt at some point. I know how I did it before and I don't think I want to do that again. I will have to come up with something new for that.
12. Guests - Guests on a MU* are limited in what they can do. They're like a player...with FAS. If that sounds mean, too bad.
13. WHO - Oh gods...WHO. I hate the current WHO. I have to get it to behave like a regular WHO. And that means building an admin WHO as well.
14. examine - See WHO. Oy.
15. Recycle Bin - This was something I had done before. When you @recycle an object, it goes into the recycle bin, and can be @restore'd. One time only. Once something else is @recycled, your object is lost.
16. inventory - See examine, see WHO. Oy x 2.
17. Help files need to be reformatted, rewritten, and constantly, constantly, constantly updated. Ow. Programmers hatelovehatelovehate documentation.
18. news file functionality - It's gotta be there. Why? Cause it's a standard.
19. Rebuild setting the various standard attr's (fail, ofail, succ, osucc, etc). Each one has its own subroutine, which is just dumb.
20. Book objects need to be revisited. Not sure on these.
21. Names need to be able to have spaces.
22. @teleport needs to have arrive, depart, oarrive, odepart messages.
23. I seem to remember that @find/@search stunk. I may have to revisit this.
24. @aconnect - Things to do when you connect.
25. @dolist - Make a list of things to do and do them
26. Creatures - You can't currently page a Creature, but everything else "seems" to work. I should probably add in a filter that prevents output from going to the owner if the owner and the object are in the same room.
27. Do I want to do @power? Probably. But, ew.
28. OMFG. I just realized that gags are based on player name, not dbref. FIX THIS!

Updated Done List

  1. ; (semicolon) needs to be changed so that it does an emote with no space between the character's name and the text - DONE. This turned out to be simpler than I expected, though I don't know why I expected it to be hard.
  2. IP/Site stored as attributes on a player - DONE. No +alts command yet, but I need to rebuild @search/@find first. But, now it works and will record both site and IP. Admin WHO reports IP if no site stored (box with no reverse DNS lookup for instance)
  3. WHO - Admin and Mortal WHO look better. Not 100% yet but much better.
  4. Time Format - Fixed so that it's proper 00:00 format.
  5. Although I thought it was in there already since it was in the help files, I built in support for 'creatures'. The MU* world knows these more commonly as puppets. Now, not only do creatures exist and relay all that they see to their owner, but there is a hardcoded way to control your creature. Traditionally, you've had to code your own $command on a MUSH to control a creature. Not so here. You can just use % and it will do whatever you tell it to do. The caveat to this is that you have to register your creature with the MUSH using the @creature command. Syntax is: @creature #123. Once that's done, the creature is entered into the playerIds hash so that it can be referenced as a player...to some degree. There will be some development on this. Yes, I know this is a new way of doing things, but...let's try it out, kthx.

Ansi Redux Redux

Okay, it's official. I kicked ansi's ass. Right after I kicked my own, that is. I'm a moron, and I was having a forest vs. trees moment. The entire issue had to do with the fact that it wasn't evaluating the regular expression I was using for substitution properly, because I had set the wrong flags.

It also was being evaluated by pulling from a hash value.

If all of this is too geeky for you, let me boil it down: I'm an idiot. I fixed it.

For the geeky amongst you, it's the difference between:
$arg =~ s/\%xh/$ansi{"HILITE"}/ge;

AND

$arg =~ s/\%xh/\033[1m/g;

The latter works, the former didn't. Problem solved, now on to my next challenge.