OK, well the solution is that we don't "just" have a GUID.
In my playing around with making these plugins work, I have identified three things that characterize a "thing" on the MUD:
- A unique identifier (GUID) so you know one item from another one
- Some fixed, or rarely-changing, attributes, like description, mob type, name, class, race, faction, level etc.
- Some attributes that change rapidly, for example hit points during a battle, level (for a player), mana etc.
Now the GUID is absolutely required for making sure that you address an action to the correct thing. For example, if there are five mobs in the room, and you are in a group of five, your strategy may be to hit one of them with all five of you, or to maybe sheep one, stun another, sap a third, and then take on the remaining two. Even if the mobs are in every other way identical, the GUID is needed to distinguish one identical thing from another one.
The fixed attributes (like a lengthy room description) are what are candidates to be cached, since that is likely to be the major part of the attributes, therefore taking up bandwith to transmit, but change infrequently.
Finally, the volatile attributes, like current HP, or weapon wear-and-tear, are not good candidates for caching.
My basic strategy is to send from server to client those three things (GUID, attributes, volatile attributes) however since the fixed attributes change rarely we merely send a hash of the attributes. An example of this is the "where am I" message:
location={uid="r.2";hash="390422BACF";}
This tells the player s/he is in room r.2 and the room's attributes, hashed, are 390422BACF.
Now the server knows the attributes of this room actually are:
type="room";name="Limbo";desc="You float in a formless void, detached from all sensation of physical\nmatter, surrounded by swirling glowing light which fades into the\nrelative darkness around you without any trace of edge or shadow.\n";terrain="city";area="52E6691941";
And you can test that in MUSHclient by doing this:
s = [[type="room";name="Limbo";desc="You float in a formless void, detached from all sensation of physical\nmatter, surrounded by swirling glowing light which fades into the\nrelative darkness around you without any trace of edge or shadow.\n";terrain="city";area="52E6691941";]]
print (utils.tohex (utils.md5 (s)))
It prints "390422BACF6924FE26C933EF2C26AF07" - I have chosen to truncate the hash to 10 characters (40 bits).
Now what the server does is store that text string in a STL map under the key "390422BACF".
The first thing the client does upon seeing this location message is to see if it knows of "390422BACF" in its in-memory table. If not, it looks on its SQLite database for it. And as a last resort it asks the server to please send the data corresponding to "390422BACF". The server *will* know how to do that, because it stored the data in memory the moment it produced the hash in the first place.
When the response arrives at the client end, the client saves it in memory, and writes it to the database. That way it *never* needs to ask for that particular item again. Not if the server is rebooted, not if the client is restarted, and not 10 years in the future. The reason is, that since the data is stored, keyed by the hash of the data itself, it must necessarily always be the right data. (This is how Git stores your files internally BTW).
Since the data being stored is simply a string of text, it is resistant to:
- The data format being changed (the hash would change too)
- More fields being added (the hash would change)
- Spelling mistakes being corrected (the hash would change)
What the client does upon seeing the hash for "390422BACF" describing this room is to get the actual data (from memory, the database or the server) and then parse that data at runtime to extract out the room name, description, etc.
The only real potential problem is that the data format may change, or be expanded, resulting in a whole lot of stuff on the database that will never be used. To combat that you simply store it with a date/time stamp, and then periodically clean up the database by deleting old records. If they are in fact redundant, well and good, you have saved some disk space. If not, they will be re-downloaded next time they are required.
David Haley said:
What I mean is that invariably you will need to refresh these attributes from time to time, for example as corpses deteriorate, if room descriptions change with the seasons, etc.
(Speaking of which, how will you handle dynamic room descriptions?)
Well you have two alternatives. One is to simply allow the new descriptions to generate a new hash. For example, on my test database I now have a number of items like this:
dsc="The corpse of the bone naga is buzzing with flies."
So in this case, the GUID stays the same (it is the same item) but the description has changed, so a new hash has been downloaded. This is probably pretty OK, it just means that instead of one entry on the database the naga might have 5 or 6 (one for each stage of decomposition).
Alternatively, you could override the description, that is, move it to the "volatile" part of the message. This probably defeats the savings of caching a bit, but could be considered as another approach.
The same would apply to dynamic room descriptions - whatever the description is, if it is the same as another room's it will generate the same hash, if not, it will get a new one.
|