[crossfire] Crossfire Plugin System v2.0

2005-10-15 Thread Yann Chachkoff
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 

Re: [crossfire] Crossfire Plugin System v2.0

2005-10-15 Thread Nicolas Weeger
While we're at it :)
* could we use names more explicit that EVENT_GDEATH and EVENT_GKILL?
I'd say EVENT_PLAYER_DEATH and EVENT_KILL, less confusing
* EVENT_GKILL takes *two* parameters (what was killed and by who), only
one is used in plugin. And parameters should be inverted imo, first what
was killed, then by who (seems logical to always send affected item
first, then what object affects it imo)

Ryo

___
crossfire mailing list
crossfire@metalforge.org
http://mailman.metalforge.org/mailman/listinfo/crossfire