[DM-dev] explanation of config object, plus sample
Brought to you by:
acdalton,
henningsen
From: Stephan B. <ste...@ei...> - 2001-04-25 14:52:41
|
I've put together the first go at the config object and it's=20 interaction with other objects. It works something like this: class Configable: virtual void saveToConfig( DMConfigFile &conf,=20 =09const char *prefix =3D 0 ); virtual void loadFromConfig( DMConfigFile &conf,=20 =09const char *prefix =3D 0 ); static string key( const char * prefix,=20 =09const char *suffix ); // util function. Forget it for now. Any classes which want to save to or load from a DMConfigFile must=20 inherit this class and implement save...() and load...(). A sample=20 implementation is here: ------------------------------------------------- SimpleConfigable::SimpleConfigable() : Configable() {} SimpleConfigable::~SimpleConfigable() {} void SimpleConfigable::saveToConfig( DMConfigFile &conf,=20 const char *prefix =3D 0 )=20 { conf.set( key(prefix,"foostr"), string("bar") ); conf.set( key(prefix,"fooint"), 42 ); } void SimpleConfigable::loadFromConfig( DMConfigFile &conf,=20 const char *prefix =3D 0 )=20 { myString =3D conf.getString( key(prefix,"foostr"),=20 =09=09"error - not found" ); myInt =3D conf.getString( key(prefix,"fooint"), -1 ); } ------------------------------------------------- That's it! The usage of the 'prefix' variable becomes necesarry when multiple=20 objects of the same type are stored in the same data stream, or when we=20 want to break it down more heirarchically. It can be used, for example,=20 to store multiple crawlers, by prefixing each one with "crawler.N.",=20 where N is some number which uniquely identifies that crawler. The call=20 to key() simply combines prefix with the user's key, into something=20 like "crawler.1.foostr". If prefix is empty, key simply returns the=20 user's plain key, like "foostr". Saving the object's state to the config file is now as simple as: DMConfigFile c( "myfile.config" ); SimpleConfigable sc; sc.saveToConfig( c );=20 bool okay =3D c.save(); If you have a completely populated DM object, you could save the whole=20 thing to a config file with: DMConfigFile c( "myfile.dungeonconfig" ); dm->saveToConfig( c );=20 bool okay =3D c.save(); dm::saveToConfig() will know how to write it's child objects into the=20 config object, as well as how to read them back via loadFromConfig(). The principal idea is that the config object doesn't know, and doesn't=20 care, about the data. The Configable objects (crawlers, walls, etc.)=20 can do this themselves - THEY'RE the ones interested in it, anyway (and=20 it's no fun to maintain another person's data for them, is it?). This=20 way changes to the Wall data format does not affect the DMConfigFile,=20 which is good. Once the DMConfigFile can add in user-given command line args, objects=20 which load themselves via loadFromConfig() will also have access to=20 those options. That could be used like this: =2E/myapp -dm-maxWallLength 27 main(...) { DMConfigFile conf; conf.addArgs( argv, argc ); =2E.. } Then the Wall class could check for this variable by using=20 conf.getInt( "-dm-maxWallLength" ), limiting it's size if it is set.=20 This is a somewhat useless and arbitrary example, but you get the idea. Reading back the objects will be a bit more effort, but will be wrapped=20 up in helper functions in DMConfig itself, like GetWalls(). The work=20 needed by the client objects (like SimpleConfigable) is the same as it=20 is to save - one line per field we want to save or load. The DungeonMaker object will, upon saving, call saveToConfig() for all=20 of it's Configable children, so they'll all be stored in the config=20 object. It will also read them back on load(), but that's not yet=20 implemented. I hope to have the first loading of basic objects done tonight, but it=20 may take me until tomorrow evening. The best part is that once the=20 save/load is written in the config object, it never needs to be touched=20 when adding new object types (unless we want to add a helper function=20 for it). The class simply overrides save...() and load...() and does=20 that himself. That allows greater flexibility and modularity in=20 development at the cost of a very small amount of work to be done in=20 implementing save...() and load...() for each Configable class. Now, I'm somewhat embarrased at the primitiveness of this approach=20 because it's a very simplified version of what QUB uses. But I was=20 forced to slim it down for several reasons: 1) no XML in DM (and QUB relies on Qt's XML support, so I couldn't port=20 it to DM without Qt-ifying DM). 2) DM doesn't have "too" complex data storage needs. I would love to be=20 able to store data more heirarchically (whole trees of objects, with=20 arbitrary tree depths, for example), but that won't be practical with=20 this approach. At some point if we need a more complex approach I can=20 work on something closer to what QUB uses (which, basically, is a=20 completely generic persistant data storage framework). 3) I'm working with standard C++ classes only, and I don't know much=20 about them (I learned C++ by using Qt). Regardless the restrictions imposed by the environment, however, I=20 think this will suit us well, at least for a first go at DM2. A note about binary data: If I had made this sufficiently generic, it=20 would be a relatively simple matter to extend it to writing binary data=20 with NO changes to the client objects (the only real work would be in=20 writing the binary file parser). To do that I need to add one more=20 layer of objects. I know how it would be done, but I'm not going to=20 implement that just yet. Besides, I'm not up for writing the binary=20 file parser at the moment (one must walk before one runs...). Let's get=20 this system done, and I can rewrite it later if needed (did I mention=20 that I like rewriting?). So, I'm trudging on ahead with that. If someone doesn't like it, please=20 let me know - I'm always open for discussion on these things. See ya! ----- Stephan Beal Generic Universal Computer Guy ste...@ei... - http://www.einsurance.de Office: +49 (89) 552 92 862 Handy: +49 (179) 211 97 67 "Belief makes a hollow place. Something has to roll in to fill it." -- Terry Pratchet |