Atrinik Server 2.5
server/plugins.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00030 #include <global.h>
00031 #include <loader.h>
00032 
00033 static void register_global_event(const char *plugin_name, int event_nr);
00034 static void unregister_global_event(const char *plugin_name, int event_nr);
00035 
00037 struct plugin_hooklist hooklist =
00038 {
00039     query_name,
00040     re_cmp,
00041     present_in_ob,
00042     players_on_map,
00043     create_pathname,
00044     normalize_path,
00045     LOG,
00046     free_string_shared,
00047     add_string,
00048     remove_ob,
00049     fix_player,
00050     insert_ob_in_ob,
00051     new_info_map,
00052     new_info_map_except,
00053     spring_trap,
00054     cast_spell,
00055     update_ob_speed,
00056     command_rskill,
00057     become_follower,
00058     pick_up,
00059     get_map_from_coord,
00060     esrv_send_item,
00061     find_player,
00062     manual_apply,
00063     command_drop,
00064     transfer_ob,
00065     kill_object,
00066     do_learn_spell,
00067     do_forget_spell,
00068     look_up_spell_name,
00069     check_spell_known,
00070     esrv_send_inventory,
00071     get_archetype,
00072     ready_map_name,
00073     add_exp,
00074     determine_god,
00075     find_god,
00076     register_global_event,
00077     unregister_global_event,
00078     load_object_str,
00079     query_cost,
00080     query_money,
00081     pay_for_item,
00082     pay_for_amount,
00083     new_draw_info,
00084     communicate,
00085     object_create_clone,
00086     get_object,
00087     copy_object,
00088     enter_exit,
00089     play_sound_map,
00090     learn_skill,
00091     find_marked_object,
00092     cast_identify,
00093     lookup_skill_by_name,
00094     check_skill_known,
00095     find_archetype,
00096     arch_to_object,
00097     insert_ob_in_map,
00098     cost_string_from_value,
00099     bank_deposit,
00100     bank_withdraw,
00101     bank_get_balance,
00102     swap_apartments,
00103     player_exists,
00104     get_tod,
00105     object_get_value,
00106     object_set_value,
00107     drop,
00108     query_short_name,
00109     beacon_locate,
00110     strdup_local,
00111     adjust_player_name,
00112     find_party,
00113     add_party_member,
00114     remove_party_member,
00115     send_party_message,
00116     Write_String_To_Socket,
00117     dump_object,
00118     stringbuffer_new,
00119     stringbuffer_finish,
00120     cleanup_chat_string,
00121     cftimer_find_free_id,
00122     cftimer_create,
00123     cftimer_destroy,
00124     find_face,
00125     find_animation,
00126     play_sound_player_only,
00127     new_draw_info_format,
00128     was_destroyed,
00129     object_get_gender,
00130     change_abil,
00131     decrease_ob_nr,
00132     check_walk_off,
00133     wall,
00134     blocked,
00135     get_rangevector,
00136     get_rangevector_from_mapcoords,
00137     player_can_carry,
00138     cache_find,
00139     cache_add,
00140     cache_remove,
00141     cache_remove_by_flags,
00142     find_string,
00143     command_take,
00144     object_need_esrv_update,
00145     object_remove_esrv_update,
00146     esrv_update_item,
00147     execute_newserver_command,
00148     find_treasurelist,
00149     create_treasure,
00150     dump_object_rec,
00151     hit_player,
00152     move_ob,
00153     move_player,
00154     get_empty_map,
00155     set_map_darkness,
00156     find_free_spot,
00157     send_target_command,
00158     examine,
00159     push_button,
00160 
00161     season_name,
00162     weekdays,
00163     month_name,
00164     periodsofday,
00165     spells,
00166     &shstr_cons,
00167     gender_noun,
00168     gender_subjective,
00169     gender_subjective_upper,
00170     gender_objective,
00171     gender_possessive,
00172     gender_reflexive,
00173     object_flag_names,
00174     freearr_x,
00175     freearr_y,
00176     &first_player,
00177     &new_faces,
00178     &nrofpixmaps,
00179     &animations,
00180     &num_animations,
00181     &first_archetype,
00182     &first_map,
00183     &first_party,
00184     &first_region,
00185     &logfile
00186 };
00187 
00189 static atrinik_plugin *plugins_list = NULL;
00190 
00195 static atrinik_plugin *find_plugin(const char *id)
00196 {
00197     atrinik_plugin *plugin;
00198 
00199     if (!plugins_list)
00200     {
00201         return NULL;
00202     }
00203 
00204     for (plugin = plugins_list; plugin; plugin = plugin->next)
00205     {
00206         if (!strcmp(id, plugin->id))
00207         {
00208             return plugin;
00209         }
00210     }
00211 
00212     return NULL;
00213 }
00214 
00219 static void register_global_event(const char *plugin_name, int event_nr)
00220 {
00221     atrinik_plugin *plugin = find_plugin(plugin_name);
00222 
00223     if (!plugin)
00224     {
00225         LOG(llevBug, "register_global_event(): Could not find plugin %s.\n", plugin_name);
00226         return;
00227     }
00228 
00229     LOG(llevDebug, "Plugin %s registered the event %d\n", plugin_name, event_nr);
00230     plugin->gevent[event_nr] = 1;
00231 }
00232 
00237 static void unregister_global_event(const char *plugin_name, int event_nr)
00238 {
00239     atrinik_plugin *plugin = find_plugin(plugin_name);
00240 
00241     if (!plugin)
00242     {
00243         LOG(llevBug, "unregister_global_event(): Could not find plugin %s.\n", plugin_name);
00244         return;
00245     }
00246 
00247     plugin->gevent[event_nr] = 0;
00248 }
00249 
00256 object *get_event_object(object *op, int event_nr)
00257 {
00258     object *tmp;
00259 
00260     for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
00261     {
00262         if (tmp->type == EVENT_OBJECT && tmp->sub_type == event_nr)
00263         {
00264             return tmp;
00265         }
00266     }
00267 
00268     return tmp;
00269 }
00270 
00275 CommArray_s *find_plugin_command(const char *cmd)
00276 {
00277     int i;
00278     atrinik_plugin *plugin;
00279     static CommArray_s rtn_cmd;
00280 
00281     if (!plugins_list)
00282     {
00283         return NULL;
00284     }
00285 
00286     for (plugin = plugins_list; plugin; plugin = plugin->next)
00287     {
00288         if (plugin->propfunc(&i, "command?", cmd, &rtn_cmd))
00289         {
00290             return &rtn_cmd;
00291         }
00292     }
00293 
00294     return NULL;
00295 }
00296 
00300 void display_plugins_list(object *op)
00301 {
00302     char buf[MAX_BUF];
00303     struct dirent *currentfile;
00304     DIR *plugdir;
00305     atrinik_plugin *plugin;
00306 
00307     new_draw_info(0, COLOR_WHITE, op, "List of loaded plugins:");
00308     new_draw_info(0, COLOR_WHITE, op, "-----------------------");
00309 
00310     for (plugin = plugins_list; plugin; plugin = plugin->next)
00311     {
00312         new_draw_info_format(0, COLOR_WHITE, op, "%s, %s", plugin->id, plugin->fullname);
00313     }
00314 
00315     snprintf(buf, sizeof(buf), "%s/", PLUGINDIR);
00316 
00317     /* Open the plugins directory */
00318     if (!(plugdir = opendir(buf)))
00319     {
00320         return;
00321     }
00322 
00323     new_draw_info(0, COLOR_WHITE, op, "\nList of loadable plugins:");
00324     new_draw_info(0, COLOR_WHITE, op, "-----------------------");
00325 
00326     /* Go through the files in the directory */
00327     while ((currentfile = readdir(plugdir)))
00328     {
00329         if (FILENAME_IS_PLUGIN(currentfile->d_name))
00330         {
00331             new_draw_info(0, COLOR_WHITE, op, currentfile->d_name);
00332         }
00333     }
00334 
00335     closedir(plugdir);
00336 }
00337 
00342 void init_plugins()
00343 {
00344     struct dirent *currentfile;
00345     DIR *plugdir;
00346     char pluginfile[MAX_BUF];
00347 
00348     LOG(llevInfo, "Initializing plugins from '%s':\n", PLUGINDIR);
00349 
00350     if (!(plugdir = opendir(PLUGINDIR)))
00351     {
00352         return;
00353     }
00354 
00355     while ((currentfile = readdir(plugdir)))
00356     {
00357         if (FILENAME_IS_PLUGIN(currentfile->d_name))
00358         {
00359             snprintf(pluginfile, sizeof(pluginfile), "%s/%s", PLUGINDIR, currentfile->d_name);
00360             LOG(llevInfo, "Loading plugin %s\n", currentfile->d_name);
00361             init_plugin(pluginfile);
00362         }
00363     }
00364 
00365     closedir(plugdir);
00366 }
00367 
00368 #ifdef WIN32
00369 
00372 static const char *plugins_dlerror()
00373 {
00374     static char buf[MAX_BUF];
00375     DWORD err = GetLastError();
00376     char *p;
00377 
00378     if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, buf, sizeof(buf), NULL) == 0)
00379     {
00380         snprintf(buf, sizeof(buf), "error %lu", err);
00381     }
00382 
00383     p = strchr(buf, '\0');
00384 
00385     while (p > buf && (p[ - 1] == '\r' || p[ - 1] == '\n'))
00386     {
00387         p--;
00388     }
00389 
00390     *p = '\0';
00391     return buf;
00392 }
00393 #endif
00394 
00398 void init_plugin(const char *pluginfile)
00399 {
00400     int i;
00401     LIBPTRTYPE ptr;
00402     f_plug_api eventfunc, propfunc;
00403     f_plug_init initfunc;
00404     f_plug_pinit pinitfunc, closefunc;
00405     atrinik_plugin *plugin;
00406 
00407     ptr = plugins_dlopen(pluginfile);
00408 
00409     if (!ptr)
00410     {
00411         LOG(llevBug, "Error while trying to load %s, returned: %s\n", pluginfile, plugins_dlerror());
00412         return;
00413     }
00414 
00415     initfunc = (f_plug_init) (plugins_dlsym(ptr, "initPlugin"));
00416 
00417     if (!initfunc)
00418     {
00419         LOG(llevBug, "Error while requesting 'initPlugin' from %s: %s\n", pluginfile, plugins_dlerror());
00420         plugins_dlclose(ptr);
00421         return;
00422     }
00423 
00424     eventfunc = (f_plug_api) (plugins_dlsym(ptr, "triggerEvent"));
00425 
00426     if (!eventfunc)
00427     {
00428         LOG(llevBug, "Error while requesting 'triggerEvent' from %s: %s\n", pluginfile, plugins_dlerror());
00429         plugins_dlclose(ptr);
00430         return;
00431     }
00432 
00433     pinitfunc = (f_plug_pinit) (plugins_dlsym(ptr, "postinitPlugin"));
00434 
00435     if (!pinitfunc)
00436     {
00437         LOG(llevBug, "Error while requesting 'postinitPlugin' from %s: %s\n", pluginfile, plugins_dlerror());
00438         plugins_dlclose(ptr);
00439         return;
00440     }
00441 
00442     propfunc = (f_plug_api) (plugins_dlsym(ptr, "getPluginProperty"));
00443 
00444     if (!propfunc)
00445     {
00446         LOG(llevBug, "Error while requesting 'getPluginProperty' from %s: %s\n", pluginfile, plugins_dlerror());
00447         plugins_dlclose(ptr);
00448         return;
00449     }
00450 
00451     closefunc = (f_plug_pinit) (plugins_dlsym(ptr, "closePlugin"));
00452 
00453     if (!closefunc)
00454     {
00455         LOG(llevBug, "Error while requesting 'closePlugin' from %s: %s\n", pluginfile, plugins_dlerror());
00456         plugins_dlclose(ptr);
00457         return;
00458     }
00459 
00460     plugin = malloc(sizeof(atrinik_plugin));
00461 
00462     for (i = 0; i < GEVENT_NUM; i++)
00463     {
00464         plugin->gevent[i] = 0;
00465     }
00466 
00467     plugin->eventfunc = eventfunc;
00468     plugin->propfunc = propfunc;
00469     plugin->libptr = ptr;
00470     plugin->next = NULL;
00471     plugin->closefunc = closefunc;
00472 
00473     initfunc(&hooklist);
00474     propfunc(0, "Identification", plugin->id, sizeof(plugin->id));
00475     propfunc(0, "FullName", plugin->fullname, sizeof(plugin->fullname));
00476     LOG(llevDebug, "Plugin name: %s, known as %s\n", plugin->fullname, plugin->id);
00477 
00478     if (!plugins_list)
00479     {
00480         plugins_list = plugin;
00481     }
00482     else
00483     {
00484         plugin->next = plugins_list;
00485         plugins_list = plugin;
00486     }
00487 
00488     pinitfunc();
00489     LOG(llevDebug, " [Done]\n");
00490 }
00491 
00495 void remove_plugin(const char *id)
00496 {
00497     atrinik_plugin *plugin, *prev = NULL;
00498 
00499     if (!plugins_list)
00500     {
00501         return;
00502     }
00503 
00504     for (plugin = plugins_list; plugin; prev = plugin, plugin = plugin->next)
00505     {
00506         if (!strcmp(plugin->id, id))
00507         {
00508             if (!prev)
00509             {
00510                 plugins_list = plugin->next;
00511             }
00512             else
00513             {
00514                 prev->next = plugin->next;
00515             }
00516 
00517             plugin->closefunc();
00518             plugins_dlclose(plugin->libptr);
00519             free(plugin);
00520             break;
00521         }
00522     }
00523 }
00524 
00527 void remove_plugins()
00528 {
00529     atrinik_plugin *plugin;
00530 
00531     if (!plugins_list)
00532     {
00533         return;
00534     }
00535 
00536     LOG(llevDebug, "Removing all plugins from memory.\n");
00537 
00538     for (plugin = plugins_list; plugin; )
00539     {
00540         atrinik_plugin *next = plugin->next;
00541 
00542         plugin->closefunc();
00543         plugins_dlclose(plugin->libptr);
00544         free(plugin);
00545         plugin = next;
00546     }
00547 
00548     plugins_list = NULL;
00549 }
00550 
00554 void map_event_obj_init(object *ob)
00555 {
00556     map_event *tmp;
00557 
00558     if (!ob->map)
00559     {
00560         LOG(llevBug, "Map event object not on map.\n");
00561         return;
00562     }
00563 
00564     tmp = malloc(sizeof(map_event));
00565     tmp->plugin = NULL;
00566     tmp->event = ob;
00567 
00568     tmp->next = ob->map->events;
00569     ob->map->events = tmp;
00570 }
00571 
00575 void map_event_free(map_event *tmp)
00576 {
00577     free(tmp);
00578 }
00579 
00583 void map_event_obj_deinit(object *ob)
00584 {
00585     map_event *tmp, *prev = NULL;
00586 
00587     if (!ob->map)
00588     {
00589         return;
00590     }
00591 
00592     for (tmp = ob->map->events; tmp; prev = tmp, tmp = tmp->next)
00593     {
00594         if (tmp->event == ob)
00595         {
00596             if (!prev)
00597             {
00598                 ob->map->events = tmp->next;
00599             }
00600             else
00601             {
00602                 prev->next = tmp->next;
00603             }
00604 
00605             map_event_free(tmp);
00606             break;
00607         }
00608     }
00609 }
00610 
00621 int trigger_map_event(int event_id, mapstruct *m, object *activator, object *other, object *other2, const char *text, int parm)
00622 {
00623     map_event *tmp;
00624 
00625     if (!m->events)
00626     {
00627         return 0;
00628     }
00629 
00630     for (tmp = m->events; tmp; tmp = tmp->next)
00631     {
00632         if (tmp->event->sub_type == event_id)
00633         {
00634             /* Load the event object's plugin as needed. */
00635             if (!tmp->plugin)
00636             {
00637                 tmp->plugin = find_plugin(tmp->event->name);
00638 
00639                 if (!tmp->plugin)
00640                 {
00641                     LOG(llevBug, "trigger_map_event(): Tried to trigger map event #%d, but could not find plugin '%s'.\n", event_id, tmp->event->name);
00642                     return 0;
00643                 }
00644             }
00645 
00646             return *(int *) (tmp->plugin->eventfunc)(0, PLUGIN_EVENT_MAP, event_id, activator, tmp->event, other, other2, tmp->event->race, tmp->event->slaying, text, parm);
00647         }
00648     }
00649 
00650     return 0;
00651 }
00652 
00659 void trigger_global_event(int event_type, void *parm1, void *parm2)
00660 {
00661     atrinik_plugin *plugin;
00662 
00663     if (!plugins_list)
00664     {
00665         return;
00666     }
00667 
00668     for (plugin = plugins_list; plugin; plugin = plugin->next)
00669     {
00670         if (plugin->gevent[event_type])
00671         {
00672             (plugin->eventfunc)(0, PLUGIN_EVENT_GLOBAL, event_type, parm1, parm2);
00673         }
00674     }
00675 }
00676 
00690 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)
00691 {
00692     object *event_obj;
00693     atrinik_plugin *plugin;
00694 
00695     if (me == NULL || !(me->event_flags & EVENT_FLAG(event_type)) || !plugins_list)
00696     {
00697         return 0;
00698     }
00699 
00700     if ((event_obj = get_event_object(me, event_type)) == NULL)
00701     {
00702         LOG(llevBug, "Object with event flag and no event object: %s\n", STRING_OBJ_NAME(me));
00703         me->event_flags &= ~(1 << event_type);
00704         return 0;
00705     }
00706 
00707     /* Ai event and we don't want this type of events. */
00708     if (event_type == EVENT_AI && !(event_obj->path_attuned & EVENT_FLAG(parm1)))
00709     {
00710         return 0;
00711     }
00712 
00713     if (event_obj->name && (plugin = find_plugin(event_obj->name)))
00714     {
00715         int returnvalue;
00716 #ifdef TIME_SCRIPTS
00717         struct timeval start, stop;
00718         uint64 start_u, stop_u;
00719 
00720         gettimeofday(&start, NULL);
00721 #endif
00722 
00723         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);
00724 
00725 #ifdef TIME_SCRIPTS
00726         gettimeofday(&stop, NULL);
00727         start_u = start.tv_sec * 1000000 + start.tv_usec;
00728         stop_u = stop.tv_sec * 1000000 + stop.tv_usec;
00729 
00730         LOG(llevDebug, "Running time: %2.6f seconds\n", (stop_u - start_u) / 1000000.0);
00731 #endif
00732         return returnvalue;
00733     }
00734     else
00735     {
00736         LOG(llevBug, "event object with unknown plugin: %s, plugin %s\n", STRING_OBJ_NAME(me), STRING_OBJ_NAME(event_obj));
00737         me->event_flags &= ~(1 << event_type);
00738     }
00739 
00740     return 0;
00741 }