浏览代码

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://svn.code.sf.net/p/rathena/svn/trunk@16485 54d463be-8e91-2dee-dedb-b68131a5f0ec
shennetsind 13 年之前
父节点
当前提交
dc62ddd164
共有 4 个文件被更改,包括 112 次插入62 次删除
  1. 12 11
      src/map/atcommand.c
  2. 6 5
      src/map/atcommand.h
  3. 10 15
      src/map/npc.c
  4. 84 31
      src/map/script.c

+ 12 - 11
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;

+ 6 - 5
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_ */

+ 10 - 15
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++];
 	}
 

+ 84 - 31
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;
 }