[crossfire] Crossfire Plugin System v2.0

Yann Chachkoff yann.chachkoff at myrealbox.com
Sat Oct 15 05:21:05 CDT 2005


The small rewrite of the Crossfire Plugin subsystem is nearing completion - finally. I think that a couple of explanations are necessary.

Why ?
-----
The main reason to answer the "why a rewrite" is that the older way of managing plugins was simply too complex and obscure. Using the CFParm structure to pass arguments between the server and the plugins initially seemed a good idea - but it came at the price of an heavy-to-write, heavy-to-use system. Having to fill in a table of CFParms and to ready a return CFParm structure is counterintuitive to what most C programmers usually do.

What will change and how ?
--------------------------

1. Code Internals.

The rewrite somewhat simplifies the code writing. Basically, most server functions are now exposed with the following prototype:

void* cfapi_funct(int* type, ...)

type indicates the type of the return value, as defined by constants in include/plugins.h. The arguments are now transmitted using the more conventional va_args mechanism. There is obviously a drawback in that the server now assumes that the correct parameter values are passed by the plugin - but expecting that the plugin developper passes a correct parameter type isn't too much asking IMHO.

Moreover, a group of "common server function wrappers" has been written. When a new plugin is being developed, the coder should include those common wrappers in its compilation process. Those ensure that (1) the plugin coder doesn't need to directly call the server callback function pointers and (2) limits the possibility of passing wrong argument types. So for example, instead of having to use the void* cfapi_map_create_path(int* type, ...) callback and taking the risk of passing wrong argument types and having to manually manage typecasts and callback bindings, the plugin coder can call the common wrapper char* cf_get_maps_directory(char* str) and use it without worrying on how the plugin-server communication works.

On the server-side, the code is also somewhat simpler, because the CFParm wrapping doesn't exist anymore - calling a plugin event now takes one or two lines, to compare with the dozen (or more) before.

2. Event hooks

The second important change is how the events are bound to objects. Previously, plugins used various event_xxx fields in the object to bind. It has a rather annoying drawback: you couldn't bind more than one action to one event (chains of events weren't possible). The new system uses a new archetype type "EVENT"; the map-maker now wraps the binding in an event_xxx *object* that is stored in the inventory of the bound object. It allows to bind several plugins to a single event in a single object. It also removes the need for supplementary fields and makes the event subsystem more consistent with the "everything is an object" motto.

3. Compatibility with v1.0 of the plugin system

The v1.0 plugins (there are currently 3) are *not* compatible, even at source level, with the v2.0 interface. There is also no effort made to ensure compatibility with objects bound with the 1.0 event_xxx tags, so map-makers will have to adapt them accordingly. Note that it isn't a lot of work - it isn't as if there were thousands of objects to convert.

I could have assured compatibility, but it the work and code complexity it introduced seemed much greater than the work needed to convert the few objects that were using the old system.

A potential problem may arise with players owning scripted objects, as those will cease to work. But unless there are *lots* of such cases (which is doubtful), simple manual exchange with newer versions of the objects from the DMs should suffice.

What about the current plugins ?
--------------------------------

1. CFPython

The CFPython plugin has been rewritten to match the new interface. The occasion to rewrite it has been used to make the CFPython interface cleaner and (hopefully) easier from a Python-coder point-of-view. 

The most important change is the introduction of Python object types wrapping Crossfire entities (Crossfire Objects, Maps, and Players). Available functions are mostly the same (only those rendered obsolete by the new plugin infrastructure were removed), but they are now properties and methods of Python objects.

Examples
CFPython.AcquireSpell(target, spell) now becomes target.AcquireSpell(spell).
CFPython.GetStrength(who) now becomes who.Str.
CFPython.SetStrength(who,val) now becomes who.str = val.

The conversion process is rather straightforward and shouldn't cause trouble - it took me an afternoon to convert all scripts supplied in maps-bigworld/python and I'm no Python specialist.

2. The Animator

The Animator is currently being rewritten to work with the new plugin interface. Apart from the event-binding procedure, there should be no other change in the way it works. Work on it isn't finished, but shouldn't take years to complete, unlike CFPython :).

3. The Logger

The Logger is outdated and already broken for several things. Given that, I think rewriting it from scratch is a better alternative and that's what I'll do next. So no chance that this one will be available in the (hopefully close) CVS submission.

Where is the Patch ? Why isn't it in the CVS yet ?
--------------------------------------------------

A currently functional patch is available at:

     http://lauwenmark.f2b.be/project_rottenplug.patch.151005.tar.bz2
     

It includes a working code against last week's CVS content. Ported maps-bigworld/python content isn't available yet, but should get there pretty soon.

Notice that the current patch isn't quite complete: the documentation rewriting isn't finished, and the Custom Commands support isn't available. It should hopefully work as expected in many cases :)

Why isn't it in the CVS yet ? Well, probably because this is a rather massive stuff, so that I think it is better to ask first ? Or because I still remember the angry mob knocking at my door with torches and nasty faces with the v1.0 submission :D ? A good reason is that I'm a rather mediocre coder, so I feel more comfortable not rushing some crap of mine and thus breaking the CVS.

So now, it is up to you: check that, share thoughts, ask questions, hunt bugs (sure, there are certainly plenty of those, as always with my code :D), etc.

Have fun !


    


More information about the crossfire mailing list