BZWB’s object base class
August 8, 2007 at 8:47 am | In Uncategorized | Leave a CommentFor any of you interested in developing additional object support and/or helping to maintain BZWB, in the next few posts I’ll be publishing some preliminary documentation on code specific to dealing with BZW objects.
Here is the base class of all BZW objects in BZWB: the DataEntry class:
//////////////////////////////////////////////////////////////////
class DataEntry {
public:
// universal getter method
virtual string get(void) = 0;
// universal setter method
virtual int update(string& data);
// universal setter method with a binary message
virtual int update(UpdateMessage& msg) { return 1; }
// universal output method
virtual string toString() {
return string(“# unknown DataEntry”);
}
// constructor to initialize the header and keys
DataEntry(const char* header, const char* keys);
// constructor to initialize the header and keys and data
DataEntry(const char* header, const char* keys, const char* data);
// destructor (does nothing)
virtual ~DataEntry() { }
// is the key supported?
bool isKey(const string& key);
// does a line have a key?
bool hasKey(string& line);
// helper method: ensures that a key occurs only once (useful for calling from update())
bool hasOnlyOne(vector<string> lines, const char* key);
// helper method: ensures that a line has the proper number of elements
bool hasNumElements(const string& data, unsigned int numElements);
// helper method: prints out unused key/value pairs
string getUnusedText() ;
// get the supported keys in the form “<key1><key2><key3>….”
string getKeyString(void) { return keys; }
// get the keys as a vector of strings, where each string is a key
vector<string> getKeys(void);
// get the header
string getHeader(void) { return header; }
// get the text
string getText() { return this->text; }
// set the header
void setHeader(const char* c) { this->header = string(c); }
// set the keys
void setKeys(const char* c) { this->keys = string(c); }
// set changed
void setChanged() { this->changed = true; }
void setChanged(bool value) { this->changed = value; }
protected:
string header;
string keys;
string text;
bool changed;
};
///////////////////////////////////////////////////////////////////////////
Let’s take a closer look at this class. It’s commonly known among map-makers that the BZW format specifies map objects as key/value pairs encapsulated within a header line containing the object type and a footer line marking the end of the object. DataEntry is designed to deal specifically with that format.
You’ll notice that both constructors have parameters for a header and a list of keys. The header argument, as the name implies, is a pointer to a C-style string (i.e. an array of chars) that spells out the type of object this is (i.e. “box”, “pyramid”, “teleporter”, “mesh”, etc) as it would appear in BZW-formatted text. The keys argument is a bit different–it contains a list of all of the keys this object supports, encapsulated within < and >. For example, the key list for “box” would be “<position><size><rotation>”. In the latter constructor, a third parameter–the data parameter–is a pointer to the textual representation in BZW format of the object. This is important for the update() methods.
Instead of having a bunch of type-specific getter and setter methods, DataEntry employs a single getter and two setter methods: get() and the two update()’s, respectively. The purpose of get() is to return all of the object’s data as a string, formatted as BZW text. In implementation, get() merely calls toString() and returns toString()’s result. toString(), as the name implies, is where the code responsible for converting any relevant data a derived class holds into a BZW-formatted string of text. As such, toString() will vary greatly between objects in implementation.
The first update() method takes only a string as an argument. It is expected that the string is the BZW-formatted representation of the object, because the purpose of the update() methods is to parse the passed string and set object-specific data from it. As such, it should also be able to catch syntax errors and blank/incomplete data strings (fortunately, BZWB has a BZW parsing API to make this task relatively easy; more on that later). The first update() method is called mainly for construction/initialization purposes. The second update() method, which takes a reference to an UpdateMessage, serves as an event-handler. The UpdateMessage class is a type-safe message class designed to pass editing messages to objects, and necessary data which which to act upon the message. Currently, these would include:
- setting the position (the new position is supplied in the message)
- moving the position by a displacement (the displacement is supplied in the message)
- setting the spin values about the X, Y, and Z axes (the spin values are supplied in the message)
- changing the spin values by a displacement (the displacement for each value are supplied in the message)
- setting the object’s scale (the scale is supplied in the message)
- scaling the object by a scale factor (the scale factor is supplied in the message)
- recomputing the object’s transformations (a vector of pointers to the new transformations is supplied in the message)
This update() method is called from the Master Configuration Dialog to pass changes on to the object it was configuring, as well as from the code that handles 3D manipulation of the 3D Blender-style cursor. How you wish to handle these messages is entirely up to you.
Since the header and key list of all objects in BZWB are vital to object processing, DataEntry provides some simple getters and setters for getting/setting the header and key string, and they’re pretty easy to understand. More important are the hasOnlyOne(), isKey(), hasKey(), and hasNumElements() methods, because these assist with parsing BZW text. isKey(), as the name implies, returns true or false as to whether or not the object supports the key it was passed. hasKey() takes a key/value pair as an argument and returns true or false as to whether or not that key/value pair has a supported key. hasOnlyOne() takes a vector of strings as its first argument (each of which is a key/value pair), and a key as its second, and returns true or false as to whether or not there is only one string with that key. This is a primitive method for catching key multiplicities or absences that are undesirable (i.e. multiple or non-existent “name” key(s)). hasNumElements() takes a key/value pair as a string as its first argument, and the number of expected line elements (i.e. contiguous substrings separated by spaces, tabs, \r, \n, etc), and returns true or false depending on whether the given line has that many elements. This is important for catching malformed lines, such as “position 0 1″.
One interesting feature about DataEntry is that it’s designed to store the BZW data it CAN’T parse as a string. This is important because if the BZW spec changes, DataEntry-derived classes can simply ignore text it doesn’t recognize without bailing. Also, when saving a world, the unused text is still written out to the file, preserving map attributes that BZWB doesn’t (yet) recognize. The method getUnusedText() returns a string containing the key/value pairs that the object doesn’t know how to interpret (i.e. lines that begin with a key that is not in the key-string).
The final two methods, the two forms of setChanged(), are in place to mark objects as having been changed. I haven’t used them in a long time, but to the extent of my knowledge setChanged() is called when the object is manipulated in the 3D scene (but not from a dialog box). They are depricated; do not use them.
Check back soon for further code documentation
.
No Comments Yet »
RSS feed for comments on this post. TrackBack URI
Leave a comment
Blog at WordPress.com. | Theme: Pool by Borja Fernandez.
Entries and comments feeds.