Databanks

[ LiB ]

Databanks

Before discussing entities, I'd like to show you a special class. In the previous chapter, I mentioned that there is a mixin class called DataEntity , which wraps around a databank .

A databank gives flexibility to the BetterMUD. I'm sure you're used to figuring out what kinds of data you need, programming the data, and then realizing that you might not need an attribute or two. If you create instead a flexible structure that can store an unlimited amount of data, you can easily add variables to your characters while the game is running. If you think this idea is cool, just wait until I show you Python.

The flexible structure I've described requires storing objects with arbitrary names , and what better structure to store them in than an std::map ? If you don't know this already, you should learn that std::map s used with std::string s are practically the coolest thing you can ever do in C++. Examine this code segment:

 std::map<std::string, int> intbank; intbank["pie"] = 20; intbank["cool"] = 30; int a = intbank["pie"];   // 20 a = intbank["cool"];      // 30 

Pretty cool, isn't it? You can insert as many items as you want, and since it's a map, you'll have some decent performance ( O(log n ) for those algorithm-obsessed folks) when inserting or retrieving items. Sure, it's not nearly as fast as accessing variables directly by a memory offset (which is the way that precompiled variables are accessed), but I believe that the time has finally come when the benefits of having such an extensible system far outweigh the need to squeeze every drop of speed out of your system.

Databank Class

The Databank class itself is fairly simple; it's a wrapper around an std::map that allows you to manage the attributes within it easily:

 template< typename type > class Databank { public:     typedef std::map< std::string, type > container;     typedef container::iterator iterator;     iterator begin()     { return m_bank.begin(); }     iterator end()       { return m_bank.end(); }     bool Has( const std::string& p_name )     void Set( const std::string& p_name, const type& p_val )     type& Get( const std::string& p_name )     void Add( const std::string& p_name, const type& p_val )     void Del( const std::string& p_name )     void Save( std::ostream& p_stream )     void Load( std::istream& p_stream )     void Clear()     size_t size() protected:     container m_bank; }; 

You can create databanks of any type you want, since this is a template class: for example, a Databank<int> , or Databank<float> . You can also iterate through databanks to see which variables they hold.

The second grouping of functions allows you to access and use the databank. To make databanks more "consistent," they throw exceptions when you try getting or changing attributes that don't exist, rather than accidentally creating them. Of course, to avoid throwing exceptions, you can first use the Has function to see if an attribute exists.

Since the functions simply wrap around the std::map functions and add exception throwing in the appropriate places, I'm not going to show you the code. You can find this class in /BetterMUD/entities/Attributes.h.

Using a Databank

Using a databank is pretty simple, as you can see from this example:

 Databank<int> bank; bank.Add( "health", 10 ); bank.Add( "strength", 20 ); int i = bank.Get( "health" );    // 10 i = bank.Get( "strength" );      // 20 bank.Del( "health" ); i = bank.Get( "health" );        // *THROWS EXCEPTION* bank.Set( "strength", 30 ); 

A databank is string-based, so you can easily add any variables to it that you want. Every entity (except accounts) in the BetterMUD has a databank that you can use and access through the scripts, which will allow you almost limitless freedom to add variables to characters in the game.

Databanks and Streams

Databanks also have stream loading and saving functions, which makes it easy to load and save databanks to disk. Here's an example of the saving code:

 void Save( std::ostream& p_stream ) {     p_stream << "[DATABANK]\n";     iterator itr = m_bank.begin();     while( itr != m_bank.end() ) {         p_stream << BasicLib::tostring( itr->first, 24 ) <<             itr->second << "\n";         ++itr;     }     p_stream << "[/DATABANK]\n"; } 

This will create files that look like this:

 [DATABANK] health                  10 strength                20 hitpoints               100 [/DATABANK] 

Nice, pretty, and readable. The call to the BasicLib::tostring makes sure there are 24 columns between the start of the attribute and the start of the variable. I could have used the setw function of streams to accomplish the same thing, but problems occur when compilers work in different ways ( strange for a "standard" library, right? C++ still has a long way to go.).

A databank is loaded in a similar way:

 void Load( std::istream& p_stream ) {     std::string temp;     p_stream >> temp;       // extract "[DATABANK]"     while( BasicLib::extract( p_stream, temp ) != "[/DATABANK]" ) {         type t;         p_stream >> t;         Add( temp, t );     } } 

The loop extracts each data tag using the BasicLib::extract function; each pass compares the data tag to see if it is the [/DATABANK] tag. If it is, the loop ends.

If the databank doesn't have an attribute extracted from the stream, it is automatically loaded. This is a particularly useful feature, because it allows you to load a databank from a file without manually adding all the attributes first.

[ LiB ]


MUD Game Programming
MUD Game Programming (Premier Press Game Development)
ISBN: 1592000908
EAN: 2147483647
Year: 2003
Pages: 147
Authors: Ron Penton

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net