From 98e833dc83ad9f0642bdbf6b90b239704292f15f Mon Sep 17 00:00:00 2001 From: shennetsind Date: Mon, 23 Jul 2012 19:26:50 +0000 Subject: Follow up r16471 improved overall feature performance by making the bind list a pointer array, this also allows the system to have a unlimited amount of atcommand bind instances. also fixed a memory leak that'd be caused when npc_do_atcmd_event fails (e.g. when target npc is manually reloaded) git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@16485 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/map/atcommand.c | 23 ++++++----- src/map/atcommand.h | 11 ++--- src/map/npc.c | 25 +++++------- src/map/script.c | 115 ++++++++++++++++++++++++++++++++++++++-------------- 4 files changed, 112 insertions(+), 62 deletions(-) (limited to 'src') diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 15f75d55a..6eeb5ec9f 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -57,6 +57,8 @@ typedef struct AtCommandInfo AtCommandInfo; typedef struct AliasInfo AliasInfo; +int atcmd_binding_count = 0; + struct AtCommandInfo { char command[ATCOMMAND_LENGTH]; AtCommandFunc func; @@ -86,14 +88,15 @@ static const char* atcommand_checkalias(const char *aliasname); // @help static void atcommand_get_suggestions(struct map_session_data* sd, const char *name, bool atcommand); // @help // @commands (script-based) -struct Atcmd_Binding* get_atcommandbind_byname(const char* name) -{ +struct atcmd_binding_data* get_atcommandbind_byname(const char* name) { int i = 0; + if( *name == atcommand_symbol || *name == charcommand_symbol ) name++; // for backwards compatibility - ARR_FIND( 0, ARRAYLENGTH(atcmd_binding), i, strcmp(atcmd_binding[i].command, name) == 0 ); - return ( i < ARRAYLENGTH(atcmd_binding) ) ? &atcmd_binding[i] : NULL; - return NULL; + + ARR_FIND( 0, atcmd_binding_count, i, strcmp(atcmd_binding[i]->command, name) == 0 ); + + return ( i < atcmd_binding_count ) ? atcmd_binding[i] : NULL; } //----------------------------------------------------------- @@ -8998,9 +9001,6 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message TBL_PC * ssd = NULL; //sd for target AtCommandInfo * info; - // @commands (script based) - Atcmd_Binding * binding; - nullpo_retr(false, sd); //Shouldn't happen @@ -9079,11 +9079,12 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message params[0] = '\0'; // @commands (script based) - if(type == 1) { + if(type == 1 && atcmd_binding_count > 0) { + struct atcmd_binding_data * binding; + // Check if the command initiated is a character command if (*message == charcommand_symbol && - (ssd = map_nick2sd(charname)) == NULL && (ssd = map_nick2sd(charname2)) == NULL ) - { + (ssd = map_nick2sd(charname)) == NULL && (ssd = map_nick2sd(charname2)) == NULL ) { sprintf(output, "%s failed. Player not found.", command); clif_displaymessage(fd, output); return true; diff --git a/src/map/atcommand.h b/src/map/atcommand.h index 9bc844664..8affa4c26 100644 --- a/src/map/atcommand.h +++ b/src/map/atcommand.h @@ -34,17 +34,18 @@ const char* msg_txt(int msg_number); int msg_config_read(const char* cfgName); void do_final_msg(void); -#define MAX_ATCMD_BINDINGS 100 +extern int atcmd_binding_count; // @commands (script based) -typedef struct Atcmd_Binding { +struct atcmd_binding_data { char command[50]; char npc_event[50]; int level; int level2; -} Atcmd_Binding; +}; -struct Atcmd_Binding atcmd_binding[MAX_ATCMD_BINDINGS]; -struct Atcmd_Binding* get_atcommandbind_byname(const char* name); +struct atcmd_binding_data** atcmd_binding; + +struct atcmd_binding_data* get_atcommandbind_byname(const char* name); #endif /* _ATCOMMAND_H_ */ diff --git a/src/map/npc.c b/src/map/npc.c index d629ac1b3..4faa54e24 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -2758,22 +2758,18 @@ int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const c struct script_state *st; int i = 0, j = 0, k = 0; char *temp; - temp = (char*)aMalloc(strlen(message) + 1); nullpo_ret(sd); - if( ev == NULL || (nd = ev->nd) == NULL ) - { + if( ev == NULL || (nd = ev->nd) == NULL ) { ShowError("npc_event: event not found [%s]\n", eventname); return 0; } - if( sd->npc_id != 0 ) - { // Enqueue the event trigger. + if( sd->npc_id != 0 ) { // Enqueue the event trigger. int i; ARR_FIND( 0, MAX_EVENTQUEUE, i, sd->eventqueue[i][0] == '\0' ); - if( i < MAX_EVENTQUEUE ) - { + if( i < MAX_EVENTQUEUE ) { safestrncpy(sd->eventqueue[i],eventname,50); //Event enqueued. return 0; } @@ -2782,8 +2778,7 @@ int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const c return 1; } - if( ev->nd->sc.option&OPTION_INVISIBLE ) - { // Disabled npc, shouldn't trigger event. + if( ev->nd->sc.option&OPTION_INVISIBLE ) { // Disabled npc, shouldn't trigger event. npc_event_dequeue(sd); return 2; } @@ -2794,16 +2789,16 @@ int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const c // split atcmd parameters based on spaces i = 0; j = 0; - while( message[i] != '\0' ) - { - if( message[i] == ' ' && k < 127 ) - { + + temp = (char*)aMalloc(strlen(message) + 1); + + while( message[i] != '\0' ) { + if( message[i] == ' ' && k < 127 ) { temp[j] = '\0'; setd_sub(st, NULL, ".@atcmd_parameters$", k++, (void *)temp, NULL); j = 0; ++i; - } - else + } else temp[j++] = message[i++]; } diff --git a/src/map/script.c b/src/map/script.c index 9521f2d54..6de233732 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -3956,14 +3956,14 @@ void script_setarray_pc(struct map_session_data* sd, const char* varname, uint8 /*========================================== * I—¹ *------------------------------------------*/ -int do_final_script() -{ +int do_final_script() { + int i; #ifdef DEBUG_HASH if (battle_config.etc_log) { FILE *fp = fopen("hash_dump.txt","wt"); if(fp) { - int i,count[SCRIPT_HASH_SIZE]; + int count[SCRIPT_HASH_SIZE]; int count2[SCRIPT_HASH_SIZE]; // number of buckets with a certain number of items int n=0; int min=INT_MAX,max=0,zero=0; @@ -4033,6 +4033,13 @@ int do_final_script() if (str_buf) aFree(str_buf); + for( i = 0; i < atcmd_binding_count; i++ ) { + aFree(atcmd_binding[i]); + } + + if( atcmd_binding_count != 0 ) + aFree(atcmd_binding); + return 0; } /*========================================== @@ -4050,12 +4057,20 @@ int do_init_script() } int script_reload() { + int i; userfunc_db->clear(userfunc_db, db_script_free_code_sub); db_clear(scriptlabel_db); // @commands (script based) // Clear bindings - memset(atcmd_binding,0,sizeof(atcmd_binding)); + for( i = 0; i < atcmd_binding_count; i++ ) { + aFree(atcmd_binding[i]); + } + + if( atcmd_binding_count != 0 ) + aFree(atcmd_binding); + + atcmd_binding_count = 0; if(sleep_db) { struct linkdb_node *n = (struct linkdb_node *)sleep_db; @@ -16355,52 +16370,90 @@ BUILDIN_FUNC(freeloop) { /** * @commands (script based) **/ -BUILDIN_FUNC(bindatcmd) -{ +BUILDIN_FUNC(bindatcmd) { const char* atcmd; const char* eventName; - int i = 0, level = 0, level2 = 0; - + int i, level = 0, level2 = 0; + bool create = false; + atcmd = script_getstr(st,2); eventName = script_getstr(st,3); + if( *atcmd == atcommand_symbol || *atcmd == charcommand_symbol ) + atcmd++; + if( script_hasdata(st,4) ) level = script_getnum(st,4); if( script_hasdata(st,5) ) level2 = script_getnum(st,5); - // check if event is already binded - ARR_FIND(0, MAX_ATCMD_BINDINGS, i, strcmp(atcmd_binding[i].command,atcmd) == 0); - if( i < MAX_ATCMD_BINDINGS ) - { - safestrncpy(atcmd_binding[i].npc_event, eventName, 50); - atcmd_binding[i].level = level; - atcmd_binding[i].level2 = level2; + if( atcmd_binding_count == 0 ) { + CREATE(atcmd_binding,struct atcmd_binding_data*,1); + + create = true; + } else { + ARR_FIND(0, atcmd_binding_count, i, strcmp(atcmd_binding[i]->command,atcmd) == 0); + if( i < atcmd_binding_count ) {/* update existent entry */ + safestrncpy(atcmd_binding[i]->npc_event, eventName, 50); + atcmd_binding[i]->level = level; + atcmd_binding[i]->level2 = level2; + } else + create = true; } - else - { // make new binding - ARR_FIND(0, MAX_ATCMD_BINDINGS, i, atcmd_binding[i].command[0] == '\0'); - if( i < MAX_ATCMD_BINDINGS ) - { - safestrncpy(atcmd_binding[i].command, atcmd, 50); - safestrncpy(atcmd_binding[i].npc_event, eventName, 50); - atcmd_binding[i].level = level; - atcmd_binding[i].level2 = level2; - } + + if( create ) { + i = atcmd_binding_count; + + if( atcmd_binding_count++ != 0 ) + RECREATE(atcmd_binding,struct atcmd_binding_data*,atcmd_binding_count); + + CREATE(atcmd_binding[i],struct atcmd_binding_data,1); + + safestrncpy(atcmd_binding[i]->command, atcmd, 50); + safestrncpy(atcmd_binding[i]->npc_event, eventName, 50); + atcmd_binding[i]->level = level; + atcmd_binding[i]->level2 = level2; } - + return 0; } -BUILDIN_FUNC(unbindatcmd) -{ +BUILDIN_FUNC(unbindatcmd) { const char* atcmd; int i = 0; atcmd = script_getstr(st, 2); - ARR_FIND(0, MAX_ATCMD_BINDINGS, i, strcmp(atcmd_binding[i].command, atcmd) == 0); - if( i < MAX_ATCMD_BINDINGS ) - memset(&atcmd_binding[i],0,sizeof(atcmd_binding[0])); + if( *atcmd == atcommand_symbol || *atcmd == charcommand_symbol ) + atcmd++; + + if( atcmd_binding_count == 0 ) { + script_pushint(st, 0); + return 0; + } + + ARR_FIND(0, atcmd_binding_count, i, strcmp(atcmd_binding[i]->command, atcmd) == 0); + if( i < atcmd_binding_count ) { + int cursor = 0; + aFree(atcmd_binding[i]); + atcmd_binding[i] = NULL; + /* compact the list now that we freed a slot somewhere */ + for( i = 0, cursor = 0; i < atcmd_binding_count; i++ ) { + if( atcmd_binding[i] == NULL ) + continue; + + if( cursor != i ) { + memmove(&atcmd_binding[cursor], &atcmd_binding[i], sizeof(struct atcmd_binding_data*)); + } + + cursor++; + } + if( (atcmd_binding_count = cursor) == 0 ) + aFree(atcmd_binding); + + script_pushint(st, 1); + } else + script_pushint(st, 0);/* not found */ + return 0; } -- cgit v1.2.3-70-g09d2