Nebula

This document decribes both the problems with the current nebula implementation, as well as some possible improvements.

Problems

There are a number of fairly serious problems with the current implementation of Nebula. These are discussed below, with minimal changes required for these.

XML Parsing

Currently XML documents are parsed using alena, an XML parser written by me (nash). Alena has a number of serious problems. Firstly it is a fairly poor XML parser, fialing to handle any character sets aside from UTF8 (and hence ASCII). Although UTF8 is the prefered unix XML encoding format, ucs16, iso-8859-* and other sets are quite common, not to mention ms formats.

Other missing features include lack of support for processing instructions, DTDs or any other feature of XML. It does not handle CDATA sections. It's interface provides only a document tree, and not any metadata about the document. There is no support for namespaces.

Alena also suffers from other implementation related features. Firstly it leaks memory badly. Secondly the method to free data and loaded trees is not implemented, and is hard to implement due to confusion about what it should do.

In short the current XML parser is ususable for the current needs of nebula, but only just. The memory leaks are unacceptable for a program in production.

Structure

The current structure of the header files is a mess. The original idea of a nebula.h which stores all the neded header files is an okay idea, except that it forces a lot of false dependancies on a lot of files. Additionally addition of new functions can be confusing.

Finally the user of .h to store data which can't be shared causes a lot of problems if one is accidently included in the wrong place.

In short the use of a single .h fle was an interesting experiment, but the results are: use idiomatic solution.

Tree / Parser / Update mess (ala tree.c)

In theory it was quite a nice idea, point the array at file, and bang you have a tree. Additionally click update, point the array at the tree, and bang, all your data is up to date.

In practice there are dozens of special cases, we have to tiptoe around dozens of problems, there are many random functions doing fairly trivial things. Additionally there are quite a few quite nasty functions doing the work. Functions which should be fairly simple.

A specific example of aproblem is the use of <ref> tags within spell descriptions. The code has to jump through quite a few hoops to reform these into a sane string.

On the positive side, the total amount of code is probably reduced as a result of this, however it is more complex code, riddled with special cases.

Naming

Many names in the source are badly defined. In short the nameing convention should be:

Global Varables

This is essentially the same point as the next point, however Nebula has quite a few global variables, some have no real purpose or need, and come about from poor use of properties or callback data in functions.

Additonally some refer to malloc()ed data structures, and the responsibilty for freeing or cleaning them up is at best unclear. This may also lead to memory leaks in many situations.

Lack of MDI

What would be really nice is to load nebula, and be presented with a dialog that asks: What do you want to do - load a character, spelllist, itemlist or maybe create a new character, item or a spellist. It would also be nice to be able to open mulitple windows onto different files at once.

Even better would be multiple windows viewing multiple files at once.

Lack of Integration

Nebula, stardust and alchemist are all fine applicaitons. They share a common library to do common things, however for them to be integrated into the main application they will have to duplicate code between them.

Currently they also lack the ability to spawn and use each others features. You can't just click on a spell list in the spell view and see the spell list for instance.

It would be nice if all the applications were merged together and could be used together. Also one should be able to merge the formats together properly to produce a full character easily.

Proposal

This is a proposal of a fairly major rewrite of Nebula. Ironically most of the code which needs to be changed is mine, as a lot of the code other people have written can be safely transplanted. Anyway first I present the major items, followed by more minor stylistic items.

XML CB parser

Obviously Alena has to go. The logical replacement is libXML. This gives us two main interfaces a tree style interface and a callback (SAX) based one. In short, both have problems.

For saving building a tree and dumping it to disk is the logical choice. Generally this uses very little of the same code used for loading. Hence my proposal is to use a callback interface somewhat similar to SAX, but a little more abstract.

Each module (I'll use skills as an example) registers a list of a tags and functions which are invoked on seeing things like open tags, close tags and character data. This list can refer to other lists recursively, and is parsed in context with the XML document. (If anyone wants to rewrite this to be clearer, please - send me a patch).

<skills> <skill> <name>Hitting Things</name> <ranks>12</ranks> </skill> </skills>

The skills module would register a callback on the skills tag, it would also have a table containing the skill tag, and finally a table containing name, ranks and anything else it expected to find in a skills element. The parser would find the <skills> tag and invoke the open skills callback registered. It would then set its context to be the table refered to in the skills table. The parser then continues, and finds a skill tag, which it then invokes the callback for, and then sets it's current table to be the next one down. It then emits a callback for name, the string Hitting Things, and then the name close tag. This repeats for rank. It then hits the </skill> tag, so pops up a table, then calls the close skill function. This repeats for <skills>.

This parser can be written fairly easily in front of a SAX parser (which libXML supports) and it is fairly easy to see how one implments a lot of parsing code. It results in a lot of small, easy to debug functions, alternatively you can lump groups of functions together into one function.

One of the advantages of this model is that it is VERY easy to make a program which continues to respond to the user while parsing (something we don't do currently at all). Secondly we can do things like load character creation scripts and build and show gui elements within the callbacks from the parser in a VERY natural way.

Namespaces

Namespaces allow some very funky things to be done in the context of this program. Consider stardust and nebula alone. To make a full character we really need to have nebula stats and skills, along with stardust spell lists in the same document. (Or bloat the nebula namespace with all the spell stuff).

Hence the parser can pay attention to namespaces and use a different set of parsing functions depending on the name space. We can go one step futher and supply separate namespaces for skills, stats and characteristics. In fact in theory each section of the character can be in a separate namespace.

If we then have code which takes a document fragment in a namespace (eg <spelllist>) and produces a GtkContainer (or similar) the code to produce nebula or stardust or anything from the same set of files is quite strong.

Now, lets take this one step futher. Nebula opens up a small box, and we click open, and click on a spell list, opening a window which contains a spelllist editor. We now click open on the main window again, and click on a character. This creates another new window, which then opens a window containing the character, one of the tabs contains another spelllist editor (with the spells the character knows). We open a file containing just the skilllist for a particular genre and adjust that, before closing it. We then click new, and new, and we get a dialog asking what we want to create from the available files — a new character, spelllist, a spacemaster character, or maybe a start buildign a genre file...

CVS

The current CVS tree is a mess, it even has the nebula src in the wrong place. I would like to suggest we start a new cvs tree (leave the old one dormant) and use that. I'm not sure what to call the new tree - neb or rmnebula seem the most likely choices.

Random items

The standard naming conventions will be noted, and a indent.pro will be provided so people who use other coding styles can use indent to put the code in a standard format.

Headers will use the standard conventions. No header will include another header, headers will be written so #ifndef wrapeprs will not be needed. All structs will be called 'struct X', and NOT be typedef'ed. No data type will be typedefed.

Although modules will be responsible for taking a xml fragment and producing gui elemetns for it - they will NOT confuse the two.

Textviews will have a global set of tags for use in rendeing items. This will be good for consistency of appearance.

There will be NO global variables. Memory will be explicitly tracked, and free'd. Use of a program to track memory use will be used.

And finally, since I am now officially a Code Nazi ;-), the standard CFLAGS for the program will be: -Wall -O2 -g -W -Wpointer-arith -Werror -Wno-unused-parameter -Wstrict-prototypes Ideally however, CFLAGS will be taken from the users environment.

$Id: newnebula.html,v 1.5 2003/05/05 13:10:33 nash Exp $