summaryrefslogtreecommitdiff
path: root/src/map
diff options
context:
space:
mode:
authorPiotr HaƂaczkiewicz <piotr.halaczkiewicz@gmail.com>2013-07-13 13:01:47 +0200
committerPiotr HaƂaczkiewicz <piotr.halaczkiewicz@gmail.com>2013-07-13 13:01:47 +0200
commitefbc04ac76d287712b55644364a4793d19c25b52 (patch)
tree12e6a358bb025e25044db93238c068e7e27e2d98 /src/map
parent902a6580985435f0889da7ec4d81d8fefa36aaf9 (diff)
downloadhercules-efbc04ac76d287712b55644364a4793d19c25b52.tar.gz
hercules-efbc04ac76d287712b55644364a4793d19c25b52.tar.bz2
hercules-efbc04ac76d287712b55644364a4793d19c25b52.tar.xz
hercules-efbc04ac76d287712b55644364a4793d19c25b52.zip
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.
Diffstat (limited to 'src/map')
-rw-r--r--src/map/npc.c39
1 files 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);