On this page I will try to detail various ways of storing data.

DBREFs

There are all sorts of applications of MUSHcode that require you to store DBREFs, I will list some different ways of storing them. Please note that most of these techniques can be easily adapted to store things other than dbrefs.

The most basic way to store dbrefs is a list in an attribute. However there are various ways to do this in mushcode, each having advantages and disadvantages.

(Note: I will be using a list delimiter of | for the following examples, just so you can see, you can also use a space for the delimiter just as easily by omitting the delimiter argument or changing it to %b.)

The most basic ways of adding dbrefs to a list is just by manually appending it to the end.

[set(me,LIST:[v(LIST)]|#123)]
This will just grab the current value of LIST, and append a '|#123' to the end, nothing fancy.

However, this has a small disadvantage, if the list doesn't already have a dbref in it, then it'll put an unnecessary | at the beginning. This can be gotten around in a couple ways, the first is to use an [if(hasattrval(me,TEST),append code,just set() it)] but that just seems unnecessary to me. I personally prefer to use squish().

[set(me,LIST:[squish([v(LIST)]|#123,|))]
This will cut off any leading or trailing |'s and squeeze multiple ones in the middle into single ones. The end effect: No unnecessary leading or trailing delimiters, and any null elements in the list are removed. Which I find is just perfect, unless you want null elements for some reason. I suppose you could also use trim() to just get thes ones at the ends however the second and third arguments can swap depending on which server you're on, so I try to avoid it because I can never remember which is which.

These previous ways are great for basic stuff, but they also don't take into account duplicate entries, but there is an easy way to add a dbref and automatically remove duplicates and sort the list, I'd like to introduce you to setunion() if you haven't met yet.

[set(me,LIST:[setunion([v(LIST)],#123,|,d)]
This adds #123 to LIST, after removing duplicates and sorting by dbref, you can even put a whole list of dbrefs in place of #123, although you could do that with previous code too for the most part. However unlike the other functions setunion() sorts the result(there's no option to make it /not/ sort which I kinda think sucks.), thereby destroying whatever order it was in before, and the order of the list can be important in several situations.

Alright that takes care of the basic ways, these are all good for storing one attribute full of dbrefs, however there is a limit to how many characters can fit into an attribute, as I recall it's 8191(if you know about computers you know why, 8 KB -1 for the null terminator). So depending on database size, and the maximum length of the dbref string, which say for a 30000+ object database like 8bit, you're looking at #30000 which is 6 characters, plus 1 for the delimiter between each one which makes about 7 per dbref(it's always best to use the maximum something could be in these calculations to be safe). So if you do the math(8191/7) that works out to about 1170, however I don't think it's wise to fill an attribute to the absolute limit because a few times I tried and it got cut off early for some reason, so I'd recommend a limit of a few short of that. I usually just round it down to 1000 dbrefs per attribute, but you could go maybe 1150 if you wanted I suppose. I also suppose you could boost the number that'd fit if you edit()ed out the '#' to about a 1365 with a safe maximum of about 1350, but still, there /is/ a limit. Now this is /plenty/ for most normal applications, but if for some reason you need to store more you'll have to use some more complicated methods, for example my explorer assistant records every room that has been visited, which since 8bit has several thousand rooms, couldn't possibly fit in a single attribute. Thus I came up with a solution, which I latter replaced with an even better solution, but I'm getting ahead of myself, let me tell you about my original solution since it has advantages of it's own(although also disadvantages).

My original solution was a very basic idea, check whether the new dbref will fit in the current attribute, and if it won't then make a new attribute and place it there.

It was something like: [setq(A,v(CURATTR))]
[switch(add(strlen(v(%qA)),strlen(#123),1),>8000,[setq(A,inc(%qA))][set(me,CURATTR:%qA)])]
[set(me,%qA:[squish([v(%qA)] #123)])]

The first part grabs the current attribute and stores it in the A q-register, the second part checks if the combined length would be greater than the maximum length of the string and if so increments to the next attribute, the final part adds the dbref to whatever the current attribute is at that point.

The above code has the advantage of maintaining the order of the dbrefs, and bypasses the string length problem, however it also has problems: First of all, checking if a dbref has been recorded is a little tricky, I suppose you'd either have to iter() through the attributes with a match() or use regrep(), which in a related way leads to the problem of checking for duplicates.
The solution I came up with I think was pretty smart, it allows for an virtually infinite storage of dbrefs, and it's easy to look it up because they're indexed. I thought that dbrefs are basically just numbers with a # in front, so I tossed out the #, then divided the dbref by the number I thought could fit in an attribute, 1000. I then took that number and used it as the number of the attribute I stored it in, for example #15161 would be stored in attribute_15. To further save space I also used mod() to get the remainder after dividing and only stored that, making each dbref only take a maximum of 4 characters(including delimiter.) Saving a lot of db space. So #15161 would store '161' in attribute_15. This also makes it easy to check if a specific dbref is in a list, because you can use the same formula to break down the dbref in question, find out what attribute it's in, then check it. This code is a little complex so I won't include a code example for this one. Plus I'm tired right now.

Storing dbrefs associated with other information

Many times it is necessary to store information related to dbrefs. One of the simplest ways of doing this is naming an attribute with the dbref in it, like ATTR_#123.


Back