
Home - Forum - Code - Articles - Links - Files
Arcana writes:
I have a new Fuzzball MUCK and it doesn't run any programs at all because I don't have any of the libraries installed. Can you help...?
Libraries are a very useful part of MUF coding, just like in any language: they save you from having to reinvent lots of wheels. Here's how to make the best of them.
call primitivePUBLIC keywordPUBLIC keyword againA MUF library is a MUF program object with some definitions set on it. Definitions are like $defs in your program, but instead are added from some database object with the $include command, and are not spelled out literally in your program. (If you don't care to know for now how to make your own libraries, skip ahead.)
Here is a simple example of making a definition on a program:
@program firstlibrary.muf 1 1000 d i : main "Yarf!" pop ; . c q @set firstlibrary.muf=L @set firstlibrary.muf=_defs/sayhello:"Hello!" .tell
@program firstprogram.muf 1 1000 d i $include firstlibrary.muf : main sayhello ; . c q
As you can see if you run firstprogram.muf, $include-ing a program with its property _defs/sayhello set to "Hello!" .tell is like putting $def sayhello "Hello!" .tell in your program.
We had to @set our firstlibrary.muf Link_OK, because we intend anyone's program to be able to use our library. This doesn't actually matter in the example, since we aren't calling any word in firstlibrary.muf. Since the program itself doesn't have any actual content, but we still need at least one word to compile it, we include the dummy :main word.
At this point you might think this makes it trivial to write a self-modifying program by $include-ing a library and having the program then setprop what the properties mean, but that won't work. Just like $defs and macros, the definitions are read and incorporated into the MUF when you compile (issue the c command in the MUF editor) the program. Writing a self-modifying program (such as any @@muf globals you may've run across that are like the @mpi command, only for MUF) involves either @forcing a wizard or player to recompile a program, or modifications to the Fuzzball server.
call primitiveThis above is the simplest example for a library: note that no word in the firstlibrary.muf program ever gets called. Most libraries are written to execute functions that won't fit in @settable properties (at least not readably), and thus make use of the call primitive to call a word in the library MUF.
But this implies the library needs a piping function for in the :main word, right? The man page says when you call a program you can't call a specific word:
call ( d -- ?? ) Calls another program d. d must have been compiled already. d will inherit the values of ME, LOC, TRIGGER, and all other variables.
What the manual doesn't say is call can also be used like this:
call ( db str -- ?? ) Calls word str in program db. db must have been compiled already. Word str must have been declared 'PUBLIC'. db will inherit the values of ME, LOC, TRIGGER, and all other non-local variables.
So if our "Hello!" .tell were actually a :sayhello word in our firstlibrary.muf(#123FLM1), we would set our _defs/sayhello prop like this:
@set firstlibrary.muf=_defs/sayhello:#123 "sayhello" call
Most library authors would use '"$lib/firstlibrary" match "sayhello" call' given that our library is globally @registered as lib/firstprogram, but I prefer to not waste time doing the match, and not every potential library author can @register something globally. Since you can't selectively $include a library, one might also put the dbref in another _def, so it only needs changed once to change effectively in multiple _defs:
@set firstlibrary.muf=_defs/ref_firstlibrary:#123
@set firstlibrary.muf=_defs/sayhello:ref_firstlibrary "sayhello" call
PUBLIC keywordWhat about this PUBLIC keyword in our new definition of call? Well, we wouldn't want just any program to be able to call a normal program's words arbitrarily. The library author must explicitly state what words in a program are callable from other programs; using this keyword would make our program look like:
@program firstlibrary.muf 1 1000 d i : sayhello "Hello!" .tell ; : main "Yarf!" pop ; PUBLIC sayhello . c q @set firstlibrary.muf=L @set firstlibrary.muf=_defs/ref_firstlibrary:#123 @set firstlibrary.muf=_defs/sayhello:ref_firstlibrary "sayhello" call
Note that even though we don't need it, we have still included the dummy :main word. If our library had multiple routines to call--as most do--it would be confusing as to which one would run if you called the program itself. By including the dummy :main function, any program doing #123 call on our firstlibrary.muf(#123) program would have a predictable result: nothing.
As with most things, there's an easy way out of installing libraries: prefab databases have all the basic libraries already installed and configured. This option doesn't really work if you need a special library not in any of the available databases, or if you already have some building or coding installed on your muck--you would have to @archive and rebuild or reupload the code. That's why this is the easiest way,
not the best way.
For vanilla Fuzzball MUCKs, the database available at belfry.com with the Fuzzball distribution works great. Unfortunately, as of this writing (21 August 2001), that's about it.
Usually, since the author doesn't expect all script installers to know every little idiosyncracy about the code, libraries are available in uploadable script format (more on porting scripts). The only challenge (as well as in the below method) is to make sure to upload libraries in the right order: even library authors like the convenience of using others' code, after all, so some libraries may first require other libraries (especially the standard, basic ones in the fbmuf distribution at belfry.com) be installed.
PUBLIC keyword againSometimes, however, you don't get uploadable script format. These will install just like porting a regular program, but you'll also have to add the _defs so the program is $include-able. Since the author really can't expect you to know how to set it up yourself, the _defs/ for these libraries are usually dead formulaic. Use @list to find all the words the library declares PUBLIC, then do:
@set program=_defs/word:dbref "word" call
You might use "$lib/whatever" match or a ref_program definition as mentioned above--it's personal preference. Other than that, that's it. program is the program, dbref is its dbref (such as #123), and both cases of word are the name of the word declared PUBLIC.