[Crossfire-wiki] [Crossfire DokuWiki] page changed: server_plugin
no-reply_wiki at metalforge.org
no-reply_wiki at metalforge.org
Thu Mar 22 05:44:53 CDT 2007
A page in your DokuWiki was added or changed. Here are the details:
Date : 2007/03/22 05:44
User : ryo
Edit Summary: update
@@ -152,17 +152,30 @@
A plugin can register a custom game command. This command will work exactly like other commands from the player's point of view, accepting arguments and such.
A plugin can override an existing Crossfire command simply by declaring a command with the same name. Server command will be ignored.
+
====== Creating a plugin ======
- Plugins should use the ''common'' plugin helper library, and use provided functions to manipulate Crossfire data.
+ ===== Coding =====
- A plugin should never use ''free'' or equivalent on data the server allocated. A plugin should never directly link to Crossfire library and call functions. This may work on some platforms, but will crash on others (example is Windows).
+ Creating a plugin requires some knowledge of Crossfire's internals.
- A plugin should never change directly a value in a Crossfire object (player structure, ...), but use provided wrapping functions. Ideally, a plugin should not access directly that structure's memory to read values, either.
+ Plugins should use the ''common'' plugin helper library (located in ''[[http://crossfire.svn.sourceforge.net/viewvc/crossfire/server/trunk/plugins/common/|plugins/common]]'' directory), and use provided functions to manipulate Crossfire data. This library handles the actual communication with the server, and does some runtime checks on values.
+
+ **Warning:** a plugin can easily crash the server and/or corrupt files if care is not taken in data manipulation. Some checks are done through ''assert'', but there are times checks can't be done, thus it's the responsability of the plugin writer to take care of the plugin logic.
+
+ Some rules for plugin writing:
+ * a plugin should never use ''free'' or equivalent on data the server allocated. Use provided free functions.
+ * a plugin should never directly link to the Crossfire libraries (''common'', ''socket'', ...) and call functions. This may work on some platforms (Linux seems to handle that just fine), but will not work on others (example is Windows). Thus always use provided common plugin interface
+ * a plugin should never change directly a value in a Crossfire object (player structure, ...), but use provided wrapping functions. Ideally, a plugin should not access directly that structure's memory to read values, either.
+
+ ===== Client updating =====
+ FIXME expand/check: is an object removed automatically from player's inventory? is view updated? is fix_object() called?
+
+ ===== Creating plugin skeleton =====
The simplest way is to look at the template plugin, available in [[http://crossfire.svn.sourceforge.net/viewvc/crossfire/server/trunk/plugins/template/|plugins/template directory of the server sources]]
In trunk, there now is a script, ''plugins/template/create_plugin.sh'', that will automate all steps below, excluding running ''configure && make && make install''. The syntax is: ''create_plugin.sh cftest "Test plugin"'' from the ''plugins/template'' directory.
@@ -177,10 +190,105 @@
* edit this file, to change all occurrences of ''plugin_template'' to ''cftest'' (that fixes paths and a few macros)
* edit ''configure.ac''
* find the line ''AC_OUTPUT([Makefile''
* somewhere in between other lines, add ''plugins/cftest/Makefile''
+
+ Whether you used the script or manually created a plugin, you need to do the following steps:
* run ''autoconf && automake && configure && make && make install''
* your plugin should be installed and ready to run
Now you need to write your actual plugin logic.
FIXME link to common plugin documentation (generated from doxygen hopefully)
+
+ FIXME specific Windows stuff / workspace/project issue
+
+ ===== Plugin internals ===
+ This paragraph only concerns people wishing to write a plugin without using the ''common'' interface, or extending it. It is not intended for everyday use.
+
+ All functions available to plugins share the same prototype, ''f_plug_api'', defined in ''[[http://crossfire.svn.sourceforge.net/viewvc/crossfire/server/trunk/include/plugin.h?view=markup|include/plugin.h]]''.
+
+ ==== Basic data access ====
+ Access (get/set) to properties of the Crossfire objects, maps, structures is done through property wrappers.
+
+ Syntax for wrapper is eg ''cf_object_get_property(int* type, object* ob, int propcode, (property type)* value)''.
+
+ FIXME expand
+
+ ==== Function wrapping ====
+ This wraps specific Crossfire functions. The calling convention (not enforced everywhere, but being worked on FIXME remove when finished) is to send parameters in the same order as the wrapped function, and add as the last parameter a pointer to a variable of the same type as the return value which will receive the actual function return value. The hook return value will be a constant indicating whether the function was called or another error occurred (FIXME expand/check/make that true in the code ;p)
+
+ Let's take for example the wrapper for ''get_ob_key_value''.
+
+ The function prototype is:
+ <code>const char *get_ob_key_value(const object *op, const char *const key)</code>
+ (the return value is a shared string FIXME link when the relevant part exists)
+
+ The ''[[http://crossfire.svn.sourceforge.net/viewvc/crossfire/server/trunk/server/plugins.c?view=markup|server-side]]'' hook is (note the NULL return value, since this is being worked on FIXME remove when fixed):
+ <code>
+ void* cfapi_object_get_key(int* type, ...)
+ {
+ va_list args;
+ const char* keyname;
+ const char** value;
+ object* op;
+
+ va_start(args, type);
+ op = va_arg(args, object*);
+ keyname = va_arg(args, const char*);
+ value = va_arg(args, const char**);
+ va_end(args);
+
+ *value = get_ob_key_value(op, keyname);
+ *type = CFAPI_SSTRING;
+ return NULL;
+ }
+ </code>
+
+ The plugin wrapper function, defined in ''[[http://crossfire.svn.sourceforge.net/viewvc/crossfire/server/trunk/plugins/common/plugin_common.c?view=markup|the common library]]'', is:
+
+ <code>
+ const char* cf_object_get_key(object* op, const char* keyname)
+ {
+ int type;
+ const char* value;
+ cfapiObject_get_key(&type, op, keyname, &value);
+ return value;
+ }
+ </code>
+
+ where ''cfapiObject_get_key'' is the matching hook.
+
+ ==== Linked list handling ====
+ FIXME correct when changed for other types
+
+ In some cases, objects are linked through the use of a ''next'' field, with a ''first_'' pointer somewhere (includes objects, friendly list, maps, archetypes). Since the ''next'' field will certainly be a property for the object, a convention for getting the ''first_'' field is to call this property getter with a NULL value for the object.
+
+ Thus, for the ''partylist'' linked list, the server-side functions looks like (parts edited out):
+ <code>
+ void* cfapi_party_get_property(int* type, ...)
+ {
+ [snipped]
+
+ case CFAPI_PARTY_PROP_NEXT:
+ *type = CFAPI_PPARTY;
+ rv = (party ? party->next : get_firstparty());
+ break;
+ </code>
+
+ and the common library's function is:
+ <code>
+ partylist* cf_party_get_first(void)
+ {
+ int type;
+ return cfapiParty_get_property(&type, NULL, CFAPI_PARTY_PROP_NEXT);
+ }
+ </code>
+
+ whereas access to the next party is done through: FIXME fix when updated for wrapping syntax
+ <code>
+ partylist* cf_party_get_next(partylist* party)
+ {
+ int type;
+ return cfapiParty_get_property(&type, party, CFAPI_PARTY_PROP_NEXT);
+ }
+ </code>
IP-Address : 172.186.46.252
Old Revision: http://wiki.metalforge.net/doku.php/server_plugin?rev=1174304756
New Revision: http://wiki.metalforge.net/doku.php/server_plugin
--
This mail was generated by DokuWiki at
http://wiki.metalforge.net/
More information about the crossfire-wiki
mailing list