Atrinik Server  4.0
plugins.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
30 #include <global.h>
31 #include <loader.h>
32 #include <toolkit/packet.h>
33 #include <toolkit/string.h>
34 #include <plugin.h>
35 #include <faction.h>
36 #include <arch.h>
37 #include <artifact.h>
38 #include <plugin_hooklist.h>
39 
40 static void register_global_event(const char *plugin_name, int event_nr);
41 static void unregister_global_event(const char *plugin_name, int event_nr);
42 
43 #define PLUGIN_HOOK_DEFINITIONS
44 #include <plugin_hooks.h>
45 
48 
56 static atrinik_plugin *find_plugin(const char *id)
57 {
58  atrinik_plugin *plugin;
59 
60  if (!plugins_list) {
61  return NULL;
62  }
63 
64  for (plugin = plugins_list; plugin; plugin = plugin->next) {
65  if (!strcmp(id, plugin->id)) {
66  return plugin;
67  }
68  }
69 
70  return NULL;
71 }
72 
80 static void register_global_event(const char *plugin_name, int event_nr)
81 {
82  atrinik_plugin *plugin = find_plugin(plugin_name);
83 
84  if (!plugin) {
85  LOG(BUG, "Could not find plugin %s.", plugin_name);
86  return;
87  }
88 
89  plugin->gevent[event_nr] = 1;
90 }
91 
99 static void unregister_global_event(const char *plugin_name, int event_nr)
100 {
101  atrinik_plugin *plugin = find_plugin(plugin_name);
102 
103  if (!plugin) {
104  LOG(BUG, "Could not find plugin %s.", plugin_name);
105  return;
106  }
107 
108  plugin->gevent[event_nr] = 0;
109 }
110 
121 object *get_event_object(object *op, int event_nr)
122 {
123  object *tmp;
124 
125  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
126  if (tmp->type == EVENT_OBJECT && tmp->sub_type == event_nr) {
127  return tmp;
128  }
129  }
130 
131  return tmp;
132 }
133 
139 void display_plugins_list(object *op)
140 {
141  char buf[MAX_BUF];
142  struct dirent *currentfile;
143  DIR *plugdir;
144  atrinik_plugin *plugin;
145 
146  draw_info(COLOR_WHITE, op, "List of loaded plugins:");
147  draw_info(COLOR_WHITE, op, "-----------------------");
148 
149  for (plugin = plugins_list; plugin; plugin = plugin->next) {
150  draw_info_format(COLOR_WHITE, op, "%s, %s", plugin->id, plugin->fullname);
151  }
152 
153  snprintf(buf, sizeof(buf), "%s/", PLUGINDIR);
154 
155  /* Open the plugins directory */
156  if (!(plugdir = opendir(buf))) {
157  return;
158  }
159 
160  draw_info(COLOR_WHITE, op, "\nList of loadable plugins:");
161  draw_info(COLOR_WHITE, op, "-----------------------");
162 
163  /* Go through the files in the directory */
164  while ((currentfile = readdir(plugdir))) {
165  if (FILENAME_IS_PLUGIN(currentfile->d_name)) {
166  draw_info(COLOR_WHITE, op, currentfile->d_name);
167  }
168  }
169 
170  closedir(plugdir);
171 }
172 
178 void init_plugins(void)
179 {
180  struct dirent *currentfile;
181  DIR *plugdir;
182  char pluginfile[MAX_BUF];
183 
184  if (!(plugdir = opendir(PLUGINDIR))) {
185  return;
186  }
187 
188  while ((currentfile = readdir(plugdir))) {
189  if (FILENAME_IS_PLUGIN(currentfile->d_name)) {
190  snprintf(pluginfile, sizeof(pluginfile), "%s/%s", PLUGINDIR, currentfile->d_name);
191  init_plugin(pluginfile);
192  }
193  }
194 
195  closedir(plugdir);
196 }
197 
198 #ifdef WIN32
199 
205 static const char *plugins_dlerror(void)
206 {
207  static char buf[MAX_BUF];
208  DWORD err = GetLastError();
209  char *p;
210 
211  if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, buf, sizeof(buf), NULL) == 0) {
212  snprintf(buf, sizeof(buf), "error %lu", err);
213  }
214 
215  p = strchr(buf, '\0');
216 
217  while (p > buf && (p[ -1] == '\r' || p[ -1] == '\n')) {
218  p--;
219  }
220 
221  *p = '\0';
222  return buf;
223 }
224 #endif
225 
231 void init_plugin(const char *pluginfile)
232 {
233  int i;
234  LIBPTRTYPE ptr;
235  f_plug_event eventfunc;
236  f_plug_prop propfunc;
237  f_plug_init initfunc;
238  f_plug_pinit pinitfunc, closefunc;
239  atrinik_plugin *plugin;
240 
241  ptr = plugins_dlopen(pluginfile);
242 
243  if (!ptr) {
244  LOG(BUG, "Error while trying to load %s, returned: %s", pluginfile, plugins_dlerror());
245  return;
246  }
247 
248  initfunc = plugins_dlsym(ptr, "initPlugin", f_plug_init);
249 
250  if (!initfunc) {
251  LOG(BUG, "Error while requesting 'initPlugin' from %s: %s", pluginfile, plugins_dlerror());
252  plugins_dlclose(ptr);
253  return;
254  }
255 
256  eventfunc = plugins_dlsym(ptr, "triggerEvent", f_plug_event);
257 
258  if (!eventfunc) {
259  LOG(BUG, "Error while requesting 'triggerEvent' from %s: %s", pluginfile, plugins_dlerror());
260  plugins_dlclose(ptr);
261  return;
262  }
263 
264  pinitfunc = plugins_dlsym(ptr, "postinitPlugin", f_plug_pinit);
265 
266  if (!pinitfunc) {
267  LOG(BUG, "Error while requesting 'postinitPlugin' from %s: %s", pluginfile, plugins_dlerror());
268  plugins_dlclose(ptr);
269  return;
270  }
271 
272  propfunc = plugins_dlsym(ptr, "getPluginProperty", f_plug_prop);
273 
274  if (!propfunc) {
275  LOG(BUG, "Error while requesting 'getPluginProperty' from %s: %s", pluginfile, plugins_dlerror());
276  plugins_dlclose(ptr);
277  return;
278  }
279 
280  closefunc = plugins_dlsym(ptr, "closePlugin", f_plug_pinit);
281 
282  if (!closefunc) {
283  LOG(BUG, "Error while requesting 'closePlugin' from %s: %s", pluginfile, plugins_dlerror());
284  plugins_dlclose(ptr);
285  return;
286  }
287 
288  plugin = emalloc(sizeof(atrinik_plugin));
289 
290  for (i = 0; i < GEVENT_NUM; i++) {
291  plugin->gevent[i] = 0;
292  }
293 
294  plugin->eventfunc = eventfunc;
295  plugin->libptr = ptr;
296  plugin->next = NULL;
297  plugin->closefunc = closefunc;
298 
299  initfunc(&hooklist);
300  propfunc(0, "Identification", plugin->id, sizeof(plugin->id));
301  propfunc(0, "FullName", plugin->fullname, sizeof(plugin->fullname));
302 
303  if (!plugins_list) {
304  plugins_list = plugin;
305  } else {
306  plugin->next = plugins_list;
307  plugins_list = plugin;
308  }
309 
310  pinitfunc();
311 }
312 
318 void remove_plugin(const char *id)
319 {
320  atrinik_plugin *plugin, *prev = NULL;
321 
322  if (!plugins_list) {
323  return;
324  }
325 
326  for (plugin = plugins_list; plugin; prev = plugin, plugin = plugin->next) {
327  if (!strcmp(plugin->id, id)) {
328  if (!prev) {
329  plugins_list = plugin->next;
330  } else {
331  prev->next = plugin->next;
332  }
333 
334  plugin->closefunc();
335  plugins_dlclose(plugin->libptr);
336  efree(plugin);
337  break;
338  }
339  }
340 }
341 
345 void remove_plugins(void)
346 {
347  atrinik_plugin *plugin;
348 
349  if (!plugins_list) {
350  return;
351  }
352 
353  for (plugin = plugins_list; plugin; ) {
354  atrinik_plugin *next = plugin->next;
355 
356  plugin->closefunc();
357  plugins_dlclose(plugin->libptr);
358  efree(plugin);
359  plugin = next;
360  }
361 
362  plugins_list = NULL;
363 }
364 
370 void map_event_obj_init(object *ob)
371 {
372  map_event *tmp;
373 
374  if (!ob->map) {
375  LOG(BUG, "Map event object not on map.");
376  return;
377  }
378 
379  tmp = emalloc(sizeof(map_event));
380  tmp->plugin = NULL;
381  tmp->event = ob;
382 
383  tmp->next = ob->map->events;
384  ob->map->events = tmp;
385 }
386 
393 {
394  efree(tmp);
395 }
396 
416 int trigger_map_event(int event_id, mapstruct *m, object *activator, object *other, object *other2, const char *text, int parm)
417 {
418  map_event *tmp;
419 
420  if (!m->events) {
421  return 0;
422  }
423 
424  for (tmp = m->events; tmp; tmp = tmp->next) {
425  if (tmp->event->sub_type == event_id) {
426  /* Load the event object's plugin as needed. */
427  if (!tmp->plugin) {
428  tmp->plugin = find_plugin(tmp->event->name);
429 
430  if (!tmp->plugin) {
431  LOG(BUG, "Tried to trigger map event #%d, but could not find plugin '%s'.", event_id, tmp->event->name);
432  return 0;
433  }
434  }
435 
436  return *(int *) (tmp->plugin->eventfunc)(0, PLUGIN_EVENT_MAP, event_id, activator, tmp->event, other, other2, tmp->event->race, tmp->event->slaying, text, parm);
437  }
438  }
439 
440  return 0;
441 }
442 
454 void
455 trigger_global_event (int event_type, void *parm1, void *parm2)
456 {
457  for (atrinik_plugin *plugin = plugins_list;
458  plugin != NULL;
459  plugin = plugin->next) {
460  if (plugin->gevent[event_type]) {
461  (plugin->eventfunc)(0,
463  event_type,
464  parm1,
465  parm2);
466  }
467  }
468 }
469 
477 void trigger_unit_event(object *const activator, object *const me)
478 {
479  for (atrinik_plugin *plugin = plugins_list; plugin != NULL;
480  plugin = plugin->next) {
481  LOG(INFO, "Running unit tests for plugin: %s", plugin->fullname);
482  (plugin->eventfunc)(0, PLUGIN_EVENT_UNIT, 0, activator, me);
483  }
484 }
485 
510 int trigger_event(int event_type, object * const activator, object * const me, object * const other, const char *msg, int parm1, int parm2, int parm3, int flags)
511 {
512  object *event_obj;
513  atrinik_plugin *plugin;
514 
515  if (me == NULL || !(me->event_flags & EVENT_FLAG(event_type)) || !plugins_list) {
516  return 0;
517  }
518 
519  if ((event_obj = get_event_object(me, event_type)) == NULL) {
520  LOG(BUG, "Object with event flag and no event object: %s", STRING_OBJ_NAME(me));
521  me->event_flags &= ~(1 << event_type);
522  return 0;
523  }
524 
525  /* AI event and we don't want this type of events. */
526  if (event_type == EVENT_AI && !(event_obj->path_attuned & EVENT_FLAG(parm1))) {
527  return 0;
528  }
529 
530  if (QUERY_FLAG(event_obj, FLAG_LIFESAVE) && activator->type != PLAYER) {
531  return 0;
532  }
533 
534  if (event_obj->name && (plugin = find_plugin(event_obj->name))) {
535  int returnvalue;
536 #ifdef TIME_SCRIPTS
537  struct timeval start, stop;
538  uint64_t start_u, stop_u;
539 
540  gettimeofday(&start, NULL);
541 #endif
542 
543  returnvalue = *(int *) plugin->eventfunc(0, PLUGIN_EVENT_NORMAL, event_type, activator, me, other, event_obj, msg, parm1, parm2, parm3, flags, event_obj->race, event_obj->slaying);
544 
545 #ifdef TIME_SCRIPTS
546  gettimeofday(&stop, NULL);
547  start_u = start.tv_sec * 1000000 + start.tv_usec;
548  stop_u = stop.tv_sec * 1000000 + stop.tv_usec;
549 
550  LOG(DEBUG, "Running time: %2.6f seconds", (stop_u - start_u) / 1000000.0);
551 #endif
552  return returnvalue;
553  } else {
554  LOG(BUG, "event object with unknown plugin: %s, plugin %s", STRING_OBJ_NAME(me), STRING_OBJ_NAME(event_obj));
555  me->event_flags &= ~(1 << event_type);
556  }
557 
558  return 0;
559 }
static void unregister_global_event(const char *plugin_name, int event_nr)
Definition: plugins.c:99
#define FILENAME_IS_PLUGIN(_path)
Definition: plugin.h:211
#define plugins_dlopen(fname)
Definition: plugin.h:196
const char * race
Definition: object.h:174
#define STRING_OBJ_NAME(__ob__)
Definition: global.h:264
Definition: map.h:504
char fullname[MAX_BUF]
Definition: plugin.h:228
int trigger_event(int event_type, object *const activator, object *const me, object *const other, const char *msg, int parm1, int parm2, int parm3, int flags)
Definition: plugins.c:510
void remove_plugin(const char *id)
Definition: plugins.c:318
const char * slaying
Definition: object.h:180
void map_event_obj_init(object *ob)
Definition: plugins.c:370
#define plugins_dlclose(lib)
Definition: plugin.h:198
#define PLAYER
Definition: define.h:122
uint32_t path_attuned
Definition: object.h:255
#define QUERY_FLAG(xyz, p)
Definition: define.h:761
#define EVENT_OBJECT
Definition: define.h:481
#define EVENT_FLAG(x)
Definition: plugin.h:170
void(* f_plug_init)(struct plugin_hooklist *hooklist)
Definition: plugin.h:188
static atrinik_plugin * plugins_list
Definition: plugins.c:47
void(* f_plug_prop)(int *type,...)
Definition: plugin.h:186
#define EVENT_AI
Definition: plugin.h:101
void(* f_plug_pinit)(void)
Definition: plugin.h:190
#define PLUGINDIR
Definition: config.h:37
#define FLAG_LIFESAVE
Definition: define.h:1125
static atrinik_plugin * find_plugin(const char *id)
Definition: plugins.c:56
void init_plugins(void)
Definition: plugins.c:178
struct sound_ambient_match * next
Next match rule in a linked list.
Definition: sound_ambient.c:39
struct mapdef * map
Definition: object.h:139
#define PLUGIN_EVENT_NORMAL
Definition: plugin.h:59
void display_plugins_list(object *op)
Definition: plugins.c:139
const char * name
Definition: object.h:168
#define LIBPTRTYPE
Definition: plugin.h:194
struct obj * below
Definition: object.h:114
struct map_event * next
Definition: map.h:506
void init_plugin(const char *pluginfile)
Definition: plugins.c:231
int trigger_map_event(int event_id, mapstruct *m, object *activator, object *other, object *other2, const char *text, int parm)
Definition: plugins.c:416
void trigger_unit_event(object *const activator, object *const me)
Definition: plugins.c:477
#define plugins_dlsym(lib, name, type)
Definition: plugin.h:200
static void register_global_event(const char *plugin_name, int event_nr)
Definition: plugins.c:80
int8_t gevent[GEVENT_NUM]
Definition: plugin.h:231
struct atrinik_plugin * next
Definition: plugin.h:234
#define plugins_dlerror()
Definition: plugin.h:202
struct map_event * events
Definition: map.h:583
struct atrinik_plugin * plugin
Definition: map.h:514
LIBPTRTYPE libptr
Definition: plugin.h:222
#define PLUGIN_EVENT_UNIT
Definition: plugin.h:65
object * get_event_object(object *op, int event_nr)
Definition: plugins.c:121
uint8_t type
Definition: object.h:360
f_plug_event eventfunc
Definition: plugin.h:216
void trigger_global_event(int event_type, void *parm1, void *parm2)
Definition: plugins.c:455
char id[MAX_BUF]
Definition: plugin.h:225
void *(* f_plug_event)(int *type,...)
Definition: plugin.h:184
struct obj * inv
Definition: object.h:123
#define PLUGIN_EVENT_MAP
Definition: plugin.h:61
#define GEVENT_NUM
Definition: plugin.h:163
uint32_t event_flags
Definition: object.h:243
Definition: map.h:536
f_plug_pinit closefunc
Definition: plugin.h:219
void map_event_free(map_event *tmp)
Definition: plugins.c:392
#define PLUGIN_EVENT_GLOBAL
Definition: plugin.h:63
void remove_plugins(void)
Definition: plugins.c:345
object * event
Definition: map.h:509
uint8_t sub_type
Definition: object.h:363