What is TeenyMUSH?
If you've seen a TinyMUSH server, then TeenyMUSH is a TinyMUSH like server writen from scratch from a different perspective. If you haven't seen a TinyMUSH server then TeenyMUSH is server which gives you a virtual blank piece of paper where you can make your own places or objects. When a person connects to a TeenyMUSH server, they might find themselves in a room with a description such as 'Cheers - A place where everyone knows your name'. It might contain a Bartender named Sam that responds to questions. There are even exits going to other places so that you might explore other parts of the world. If you don't like Cheers, maybe you'll open your own restaurant and call it Milliways. But either way, TeenyMUSH is the software that will make it happen.
How does TeenyMUSH differ from TinyMUSH?
MySQL or memory database
Built in web server with websocket support
@telnet for socket based communication via MushCode
Automatic formatting of MushCode into multi-line readable code
Attributes may span multiple lines via &&attribute command
run() function to run @commands as functions
@while loops
Crash detection / resumption
@reload - Code can be updated while running
More understandable command execution order
Written in Perl
What does TeenyMUSH run on?
TeenyMUSH should run about any computer that has perl 5 and the right modules. TeenyMUSH has been heavily tested on x86 Xubuntu 18.10 and initially a Raspberry Pi. The code has also been lightly tested on a Drobo 5n NAS and my Samsung S7 Edge running Android using Perl and Termux. I'd be happy to hear from anyone running TeenyMUSH on any odd hardware.
Where can TeenyMUSH be found?
The source code can be found at [https://github.com/c-hudson/teenymush](link url). The development MUSH server can be found online at teenymush.dynu.net 4096. Its MUSH based web server can be found at [http://ascii.dynu.net](link url). The current version of this document can be found at [http://ascii.dynu.net/faq](link url). All are welcome.
What is TeenyMUSH's status?
TeenyMUSH is a work in progress. It's development server has been up and running for over two years. As of the writing of this document, the server has been up for a month without crashing... even while implementing new code and debugging heavily. A few complicated games/objects have been ported over from TinyMUSH and run without problems. Not everything from TinyMUSH will but hopefully it will as more of the internal @commands and @functions are written. Running TeenyMUSH will be an adventure for some and fun for others.
Configuration
TeenyMUSH has multiple options which can be set to control how it behaves. These options can either live in the teenymush.conf file or on object #0 inside the database. Some options can only live in the teenymush.conf as they are used to access the database. To set a config option in the database, use
@set #0/conf.option = value. Keep in mind that attributes inside the database maybe multiple lines for use in the login screen. All teenymush.conf entries are interpreted as single lines that will be evaluated (i.e. %r,%b,%t are supported).
See [http://ascii.dynu.net/faq](link url) for more details...
Database Options
TeenyMUSH supports either MySQL or an internal memory database. Both have their advantages and disadvantages. You'll need to decide which one you need but if you're unsure, you'll probably want to go with the memory database. Conversion from MySQL to the memory db is currently supported. Conversion from memory db to MySQL is not supported but will be. Listed below are some thoughts...
MySQL provides a robust environment for data management. It has the most power and hopefully should use less memory on larger worlds. Administrators will also be able to access or modify data from outside the server if needed. This may allow you to integrate data from within the MUSH into other projects. Keep in mind, TeenyMUSH does not do backups of MySQL databases and you are responsible for backing things up yourself. Luckily, this is pretty simple. See below example.
MySQL setup: Once the MySQL database has been created and you have a user that has permission to access the database, run the tm or teenymush.pl script. This will prompt for user name, password, etc that is required for connecting to MySQL. When the script connects to the database, it will also create the required tables and objects.
Sample MySQL backup cmd:
mysqldump --quick --single-transaction <database> --password=<password> > mushname.db.sql
The internal memory database is smaller and easier to setup. You loose the ability to administer the data outside the MUSH but you gain a smaller foot print. If the server crashes, it will attempt to write out a full database. If it fails, you may loose some of the most recent changes to the database. The server will also attempt to write a full database dump every hour. All non-crash database writes are done in small chunks and are intermixed with normal activities to prevent the system from lagging during backups. Anything changed during a backup will not be saved to disk until the next backup to preserve consistency. All backups are written to the dumps folder.
Add the below options to your teenymush.conf.
conf.memorydb=1
conf.mudname=<mud>
conf.backup_interval=<seconds>
Web Server Support
TeenyMUSH has a built in web server that has full access to the MUSH engine, if you so wish it. Think about being able to use almost any @command or function to publish information about the goings on of your mush. This should make it rather trival to keep people informed about the inner workings of your MUSH via the web.
TeenyMUSH supports a security model where only $commands in objects held by the webobject can be run. Any commands in the +who command will run normally as if the request was coming from a connected player.
Take the following bit of code '&who security_object=$+who:@pemit %#=[lwho()]'. If someone enters in the url of http://server_machine:8000/+who, it would match the +who command on the security_object. A similar command of 'http://server_machine:8000/@pemit/*adrick=foobar' would not work and would return a 'huh?' webpage. This assumes that the security_object is housed in the webobject's inventory. Arguments can also be passed via the same type of command. Keep in mind that any slashes will be converted to a space. I.E. 'http://server_machine:8000/+page/adrick=test' would run the '+page adrick=testing' command.
Configuration can be done with '@set #0/conf.httpd=<port>' and '@set #0/webobject=#dbref'. These control which port the mush listens to for httpd requests and which object the mush runs commands as. These can also be added to the teenymush.conf file. All http responces will be prefixed with the contents of the 'http_template.txt' file in the txt folder.
Websocket Support
TeenyMUSH also supports web sockets. This allows real time two way communication between your web browser and the MUSH. Typically this is used to provide the user with a web based mudding client to access the MUSH without downloading any programs. Web sockets can provide access to MushCode in real time. For example, there is a connect 4 game that you may play against people logged into the MUSH. When a person makes a move, the results are sent in real time the web user and the MUSH player.
Configuration and use of the websocket is a little tricky as it requires a corresponding set of html files for it to work. There's really too much to go into to describe it properly. Two examples are provided that are used by the interactive connect 4 game [sample_connect4.html] or grapenut's websocket client [wsclient.html]. The sample files will need to live in the txt folder. Grapenut's websocket client will need to be downloaded seperately at https://github.com/grapenut/websockclient and copied into the txt folder as well. Hopefully people will be able to figure out what needs to change to fit their website and environment. The 'conf.websocket=<port>' is required.
MushCode engine
TeenyMUSH is different in that everything is run in the expected order. This eliminates the need for complicated code when you need to string bits of code together. For example a '@dolist lnum(2)=@pemit me=##;think done' would result in 'done' followed by 0 and 1 on standard TinyMUSH. In TeenyMUSH, the result would be 0, 1 and then the done. This is because TinyMUSH throws everything into a queue and does not preserve execution order. TeenyMUSH does preserve execution order.
Mush Sockets
TeenyMUSH supports sockets over the internet via @telnet or url(). The url() is for http/https connections and @telnet is more flexible and can be adapted to support multiple protocols. Url() puts received data into the %{data} variable. @telnet received data can be retrieved via a ^-listen style attribute or via the input() function depending upon if the object is set SOCKET_PUPPET or SOCKET_INPUT. The ^ character is replaced with a ! for socket listens.
Limitations:
Any object wishing to use url() must be set SOCKET_INPUT by a wizard. @telnet requires an object be set SOCKET_PUPPET or SOCKET_INPUT by a wizard. An object may only have one socket open at any time.
url() example:
&&URL_LISTEN object=^htt://":
@switch 1=
lt(strlen(%2),25),
@@ ignore,
DEFAULT,
{ @while ( url(http://tinyurl.com/api-create.php?url=htt%1://%2)) {
@switch %{data}=
#-1 CONNECTION FAILED,
say TinyURL is unavailable [connection failed],
#-1 PAGE LOAD FAILURE,
say Weather is unavailable [page load failure],
#-1 DATA PENDING,
@@ ignore,
httptinyurl*,
: %{data};
}
}
This example waits and listens for someone to say a http://url longer then 25 characters. It then connects to tinyurl.com and spits out the shortened url from the website. The url function() returns only 1 until it has finished providing all data input via the %{data} variable. The MUSH also does not pause for this code to run. The socket is closed when all data is read, the execution of the attribute finishes, or when the other end closes the socket. @triggering another attribute will not any issues.
SOCKET_PUPPET example:
RESPONSE: !link"></a>:say [edit(edit(%1,<p>,),</p>,)]
FORTUNE[C]: ^ says, "FORTUNE":
@telnet www.fortunecookiemessage.com 80;
@send GET / HTTP/1.1;
@send Host: www.fortunecookiemessage.com;
@send Connection: close;
@send User-Agent: curl/7.52.1;
@send Accept: /;
@send ;
In this example, the code waits for someone to say fortune in uppercase. It then opens a connection to www.fortunecookiemessage.com and waits listens for a string that contains 'link">' followed by '</a>'. The "!" signifies that it is only listening (similar to ^-listen) for input from an open @telnet connection. The edits() remove the <p> and </p> that may or may not be part of %1.
The advantage to using SOCKET_PUPPET verses SOCKET_INPUT is that it is a little more efficient. Code is only run when new input comes in. This doesn't mean that SOCKET_INPUT does a bad job of looking for input, but it will spin a few extra cycles if the network is slow. SOCKET_PUPPET is also handled more like standard MushCode and the code can be mush simpler. The downfall of SOCKET_PUPPET is that it is less flexible because it only has access to the current line of data at any particular time (outside of setting &attributes).
Multi-line Attributes
TeenyMUSH supports a '&&attribute object=data' command. Once the command is started, it will not be finished till a blank line is received. A single period can be sent to indicate a blank line within the attribute. This allows the coder to format their attributes as desired for better readability. If you choose to use the MUSH's built in formatting, one can always @squish the attribute back into a more standard single line TinyMUSH format.
Code Readability
MushCode typically requires that all code is on one line. Good coders can get around some of this this by use of @trigger, u(), and careful crafting of code. One of TeenyMUSH's answers to this is by formatting Mush code for you. Any attribute that looks like it contains MushCode is automatically formatted into a multiple line code with indentation. Don't like how TeenyMUSH formated code? Attributes entered as multi-line attributes are never formatted.
Run() function
Mush code has traditionally had @commands and functions() that do the exact same thing. TeenyMUSH tries to get around the duplication of code by allowing @commands as functions. Certain looping commands may not be called as functions. Some examples of these would be @dolist, @wait, @find, and @while.
Reloading of Code
TeenyMUSH supports the reloading of code via the @reload command. When this command is issued, the server will check for any changes in the source that have happened since the last reload of code / startup. Sending the server a kill -HUP <PID> will also accomplish the same thing. This should prevent the need to restart the server for updates to the code.