From efbc04ac76d287712b55644364a4793d19c25b52 Mon Sep 17 00:00:00 2001 From: Piotr HaƂaczkiewicz Date: Sat, 13 Jul 2013 13:01:47 +0200 Subject: Fixed crash when unloading NPC (bug #7517) Follow-up to 6e0da189207134c8d57ecca48f397bc592dcc1ad Bug report: http://hercules.ws/board/tracker/issue-7517-yet-another-map-server-cr/ Duplicate events are now skipped instead of overwriting existing ones. --- src/map/npc.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/map/npc.c b/src/map/npc.c index 673c4f7bd..77c101f14 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -74,7 +74,7 @@ int npc_get_new_npc_id(void) { } static DBMap* ev_db; // const char* event_name -> struct event_data* -static DBMap* ev_label_db; // const char* label_name (without leading "::") -> struct linkdb_node* (key: struct npc_data*; data: struct event_data*) +static DBMap* ev_label_db; // const char* label_name (without leading "::") -> struct linkdb_node** (key: struct npc_data*; data: struct event_data*) static DBMap* npcname_db; // const char* npc_name -> struct npc_data* struct event_data { @@ -314,6 +314,17 @@ int npc_event_dequeue(struct map_session_data* sd) return 1; } +/** + * @see DBCreateData + */ +static DBData npc_event_export_create(DBKey key, va_list args) +{ + struct linkdb_node** head_ptr; + CREATE(head_ptr, struct linkdb_node*, 1); + *head_ptr = NULL; + return DB->ptr2data(head_ptr); +} + /*========================================== * exports a npc event label * called from npc_parse_script @@ -324,18 +335,18 @@ static int npc_event_export(struct npc_data *nd, int i) int pos = nd->u.scr.label_list[i].pos; if ((lname[0] == 'O' || lname[0] == 'o') && (lname[1] == 'N' || lname[1] == 'n')) { struct event_data *ev; - struct linkdb_node *label_linkdb = NULL; + struct linkdb_node **label_linkdb = NULL; char buf[EVENT_NAME_LENGTH]; snprintf(buf, ARRAYLENGTH(buf), "%s::%s", nd->exname, lname); + if (strdb_exists(ev_db, buf)) // There was already another event of the same name? + return 1; // generate the data and insert it CREATE(ev, struct event_data, 1); ev->nd = nd; ev->pos = pos; - if (strdb_put(ev_db, buf, ev)) // There was already another event of the same name? - return 1; - label_linkdb = strdb_get(ev_label_db, lname); - linkdb_insert(&label_linkdb, nd, ev); // it changes head to the new node so... - strdb_put(ev_label_db, lname, label_linkdb); // ...we need to update db to point to new head + strdb_put(ev_db, buf, ev); + label_linkdb = strdb_ensure(ev_label_db, lname, npc_event_export_create); + linkdb_insert(label_linkdb, nd, ev); } return 0; } @@ -391,12 +402,12 @@ int npc_event_do(const char* name) int npc_event_doall_id(const char* name, int rid) { int c = 0; - struct linkdb_node *label_linkdb = strdb_get(ev_label_db, name); + struct linkdb_node **label_linkdb = strdb_get(ev_label_db, name); if (label_linkdb == NULL) return 0; - linkdb_foreach(&label_linkdb, npc_event_doall_sub, &c, name, rid); + linkdb_foreach(label_linkdb, npc_event_doall_sub, &c, name, rid); return c; } @@ -1770,10 +1781,10 @@ static int npc_unload_ev(DBKey key, DBData *data, va_list ap) */ static int npc_unload_ev_label(DBKey key, DBData *data, va_list ap) { - struct linkdb_node* label_linkdb = DB->data2ptr(data); + struct linkdb_node **label_linkdb = DB->data2ptr(data); struct npc_data* nd = va_arg(ap, struct npc_data *); - linkdb_erase(&label_linkdb, nd); + linkdb_erase(label_linkdb, nd); return 0; } @@ -3750,8 +3761,8 @@ static int npc_path_db_clear_sub(DBKey key, DBData *data, va_list args) */ static int ev_label_db_clear_sub(DBKey key, DBData *data, va_list args) { - struct linkdb_node *label_linkdb = DB->data2ptr(data); - linkdb_final(&label_linkdb); // linked data (struct event_data*) is freed when clearing ev_db + struct linkdb_node **label_linkdb = DB->data2ptr(data); + linkdb_final(label_linkdb); // linked data (struct event_data*) is freed when clearing ev_db return 0; } @@ -3963,7 +3974,7 @@ int do_init_npc(void) npc_viewdb2[i - MAX_NPC_CLASS2_START].class_ = i; ev_db = stridb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, EVENT_NAME_LENGTH); - ev_label_db = stridb_alloc(DB_OPT_DUP_KEY, NAME_LENGTH); // data is linkdb and is fully released in ev_label_db_clear_sub + ev_label_db = stridb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, NAME_LENGTH); npcname_db = strdb_alloc(DB_OPT_BASE, NAME_LENGTH); npc_path_db = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, 0); -- cgit v1.2.3-70-g09d2