From 629fbd735a2a09d865dda51f0d128fc90039ea5a Mon Sep 17 00:00:00 2001
From: shennetsind <ind@henn.et>
Date: Mon, 8 Jul 2013 22:40:21 -0300
Subject: For Bug #7494

Modified skill cool down storage (also interfaced the remaining 2 static ers)
http://hercules.ws/board/tracker/issue-7494-crash-crash-crash/

Signed-off-by: shennetsind <ind@henn.et>
---
 src/map/clif.c  |  13 +++---
 src/map/skill.c | 136 ++++++++++++++++++++++++++++++++++----------------------
 src/map/skill.h |  23 +++++++---
 3 files changed, 105 insertions(+), 67 deletions(-)

(limited to 'src')

diff --git a/src/map/clif.c b/src/map/clif.c
index 4233e86e8..f17766f50 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -17565,15 +17565,14 @@ void clif_skill_cooldown_list(int fd, struct skill_cd* cd) {
 #endif
 	
 	for( i = 0; i < cd->cursor; i++ ) {
-		if( cd->duration[i] < 1 ) continue;
+		if( cd->entry[i]->duration < 1 ) continue;
+		
+		WFIFOW(fd, 4 + (count*offset)) = cd->entry[i]->skill_id;
+		WFIFOL(fd, 6 + (count*offset)) = cd->entry[i]->duration;
 #if PACKETVER >= 20120604
-		WFIFOW(fd, 4  + (i*10)) = cd->nameid[i];
-		WFIFOL(fd, 6  + (i*10)) = cd->total[i];
-		WFIFOL(fd, 10 + (i*10)) = cd->duration[i];
-#else
-		WFIFOW(fd, 4 + (i*6)) = cd->nameid[i];
-		WFIFOL(fd, 6 + (i*6)) = cd->duration[i];
+		WFIFOL(fd, 10 + (count*offset)) = cd->entry[i]->duration;
 #endif
+
 		count++;
 	}
 	
diff --git a/src/map/skill.c b/src/map/skill.c
index caee534ba..5df3596da 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -58,8 +58,6 @@
 #if GD_SKILLRANGEMAX > 999
 	#error GD_SKILLRANGEMAX is greater than 999
 #endif
-static struct eri *skill_unit_ers = NULL; //For handling skill_unit's [Skotlex]
-static struct eri *skill_timer_ers = NULL; //For handling skill_timerskills [Skotlex]
 
 DBMap* skillunit_db = NULL; // int id -> struct skill_unit*
 
@@ -3290,7 +3288,7 @@ int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data) {
 		}
 	} while (0);
 	//Free skl now that it is no longer needed.
-	ers_free(skill_timer_ers, skl);
+	ers_free(skill->timer_ers, skl);
 	return 0;
 }
 
@@ -3310,7 +3308,7 @@ int skill_addtimerskill (struct block_list *src, unsigned int tick, int target,
 	ARR_FIND( 0, MAX_SKILLTIMERSKILL, i, ud->skilltimerskill[i] == 0 );
 	if( i == MAX_SKILLTIMERSKILL ) return 1;
 
-	ud->skilltimerskill[i] = ers_alloc(skill_timer_ers, struct skill_timerskill);
+	ud->skilltimerskill[i] = ers_alloc(skill->timer_ers, struct skill_timerskill);
 	ud->skilltimerskill[i]->timer = iTimer->add_timer(tick, skill->timerskill, src->id, i);
 	ud->skilltimerskill[i]->src_id = src->id;
 	ud->skilltimerskill[i]->target_id = target;
@@ -3338,7 +3336,7 @@ int skill_cleartimerskill (struct block_list *src)
 	for(i=0;i<MAX_SKILLTIMERSKILL;i++) {
 		if(ud->skilltimerskill[i]) {
 			iTimer->delete_timer(ud->skilltimerskill[i]->timer, skill->timerskill);
-			ers_free(skill_timer_ers, ud->skilltimerskill[i]);
+			ers_free(skill->timer_ers, ud->skilltimerskill[i]);
 			ud->skilltimerskill[i]=NULL;
 		}
 	}
@@ -15268,7 +15266,7 @@ struct skill_unit_group* skill_initunitgroup (struct block_list* src, int count,
 		i = MAX_SKILLUNITGROUP-1;
 	}
 
-	group             = ers_alloc(skill_unit_ers, struct skill_unit_group);
+	group             = ers_alloc(skill->unit_ers, struct skill_unit_group);
 	group->src_id     = src->id;
 	group->party_id   = iStatus->get_party_id(src);
 	group->guild_id   = iStatus->get_guild_id(src);
@@ -15426,7 +15424,7 @@ int skill_delunitgroup(struct skill_unit_group *group, const char* file, int lin
 	if( i < MAX_SKILLUNITGROUP ) {
 		ud->skillunit[i] = ud->skillunit[j];
 		ud->skillunit[j] = NULL;
-		ers_free(skill_unit_ers, group);
+		ers_free(skill->unit_ers, group);
 	} else
 		ShowError("skill_delunitgroup: Group not found! (src_id: %d skill_id: %d)\n", group->src_id, group->skill_id);
 
@@ -16969,34 +16967,35 @@ int skill_blockpc_end(int tid, unsigned int tick, int id, intptr_t data) {
 	if (sd->blockskill[data] != (0x1|(tid&0xFE))) return 0;
 
 	if( ( cd = idb_get(skill->cd_db,sd->status.char_id) ) ) {
-		int i,cursor;
-		ARR_FIND( 0, cd->cursor+1, cursor, cd->skidx[cursor] == data );
-		cd->duration[cursor] = 0;
-#if PACKETVER >= 20120604
-		cd->total[cursor] = 0;
-#endif
-		cd->skidx[cursor] = 0;
-		cd->nameid[cursor] = 0;
-		cd->started[cursor] = 0;
-		// compact the cool down list
-		for( i = 0, cursor = 0; i < cd->cursor; i++ ) {
-			if( cd->duration[i] == 0 )
-				continue;
-			if( cursor != i ) {
-				cd->duration[cursor] = cd->duration[i];
-#if PACKETVER >= 20120604
-				cd->total[cursor] = cd->total[i];
-#endif
-				cd->skidx[cursor] = cd->skidx[i];
-				cd->nameid[cursor] = cd->nameid[i];
-				cd->started[cursor] = cd->started[i];
+		int i;
+		
+		for( i = 0; i < cd->cursor; i++ ) {
+			if( cd->entry[i]->skidx == data )
+				break;
+		}
+		
+		if( i == cd->cursor ) {
+			ShowError("skill_blockpc_end: '%s' : no data found for '%d'\n",sd->status.name,data);
+		} else {
+			int cursor = 0;
+			
+			ers_free(skill->cd_entry_ers, cd->entry[i]);
+			
+			cd->entry[i] = NULL;
+			
+			for( i = 0, cursor = 0; i < cd->cursor; i++ ) {
+				if( !cd->entry[i] )
+					continue;
+				if( cursor != i )
+					cd->entry[cursor] = cd->entry[i];
+				cursor++;
+			}
+			
+			if( (cd->cursor = cursor) == 0 ) {
+				idb_remove(skill->cd_db,sd->status.char_id);
+				ers_free(skill->cd_ers, cd);
 			}
-			cursor++;
 		}
-		if( cursor == 0 )
-			idb_remove(skill->cd_db,sd->status.char_id);
-		else
-			cd->cursor = cursor;
 	}
 
 	sd->blockskill[data] = 0;
@@ -17012,7 +17011,6 @@ int skill_blockpc_end(int tid, unsigned int tick, int id, intptr_t data) {
  * @return  0 if successful, -1 otherwise
  */
 int skill_blockpc_start_(struct map_session_data *sd, uint16 skill_id, int tick, bool load) {
-	struct skill_cd* cd = NULL;
 	uint16 idx = skill->get_index(skill_id);
 
 	nullpo_retr (-1, sd);
@@ -17029,20 +17027,38 @@ int skill_blockpc_start_(struct map_session_data *sd, uint16 skill_id, int tick,
 		clif->skill_cooldown(sd, skill_id, tick);
 
 	if( !load ) {// not being loaded initially so ensure the skill delay is recorded
-		if( !(cd = idb_get(skill->cd_db,sd->status.char_id)) ) {// create a new skill cooldown object for map storage
-			CREATE( cd, struct skill_cd, 1 );
+		struct skill_cd* cd = NULL;
+		int i;
+		
+		if( !(cd = idb_get(skill->cd_db,sd->status.char_id)) ) {// create a new skill cooldown object for map storage			
+			cd = ers_alloc(skill->cd_ers, struct skill_cd);
+			
+			cd->cursor = 0;
+			memset(cd->entry, 0, sizeof(cd->entry));
+			
 			idb_put( skill->cd_db, sd->status.char_id, cd );
 		}
 
-		// record the skill duration in the database map
-		cd->duration[cd->cursor] = tick;
+		for(i = 0; i < MAX_SKILL_TREE; i++) {
+			if( !cd->entry[i] )
+				break;
+		}
+		
+		if( i == MAX_SKILL_TREE ) {
+			ShowError("skill_blockpc_start: '%s' got over '%d' skill cooldowns, no room to save!\n",sd->status.name,MAX_SKILL_TREE);
+		} else {
+			cd->entry[i] = ers_alloc(skill->cd_entry_ers,struct skill_cd_entry);
+			
+			cd->entry[i]->duration = tick;
 #if PACKETVER >= 20120604
-		cd->total[cd->cursor] = tick;
+			cd->entry[i]->total = tick;
 #endif
-		cd->skidx[cd->cursor] = idx;
-		cd->nameid[cd->cursor] = skill_id;
-		cd->started[cd->cursor] = iTimer->gettick();
-		cd->cursor++;
+			cd->entry[i]->skidx = idx;
+			cd->entry[i]->skill_id = skill_id;
+			cd->entry[i]->started = iTimer->gettick();
+			
+			cd->cursor++;
+		}				
 	}
 
 	sd->blockskill[idx] = 0x1|(0xFE&iTimer->add_timer(iTimer->gettick()+tick,skill->blockpc_end,sd->bl.id,idx));
@@ -17553,7 +17569,7 @@ void skill_cooldown_save(struct map_session_data * sd) {
 		
 	// process each individual cooldown associated with the character
 	for( i = 0; i < cd->cursor; i++ ) {
-		cd->duration[i] = DIFF_TICK(cd->started[i]+cd->duration[i],now);
+		cd->entry[i]->duration = DIFF_TICK(cd->entry[i]->started+cd->entry[i]->duration,now);
 	}
 }
 	
@@ -17579,9 +17595,9 @@ void skill_cooldown_load(struct map_session_data * sd) {
 	
 	// process each individual cooldown associated with the character
 	for( i = 0; i < cd->cursor; i++ ) {
-		cd->started[i] = now;
+		cd->entry[i]->started = now;
 		// block the skill from usage but ensure it is not recorded (load = true)
-		skill->blockpc_start( sd, cd->nameid[i], cd->duration[i], true );
+		skill->blockpc_start( sd, cd->entry[i]->skill_id, cd->entry[i]->duration, true );
 	}
 }
 
@@ -18053,11 +18069,17 @@ int do_init_skill (void) {
 
 	group_db = idb_alloc(DB_OPT_BASE);
 	skillunit_db = idb_alloc(DB_OPT_BASE);
-	skill->cd_db = idb_alloc(DB_OPT_RELEASE_DATA);
+	skill->cd_db = idb_alloc(DB_OPT_BASE);
 	skillusave_db = idb_alloc(DB_OPT_RELEASE_DATA);
-	skill_unit_ers = ers_new(sizeof(struct skill_unit_group),"skill.c::skill_unit_ers",ERS_OPT_NONE);
-	skill_timer_ers  = ers_new(sizeof(struct skill_timerskill),"skill.c::skill_timer_ers",ERS_OPT_NONE);
+	
+	skill->unit_ers = ers_new(sizeof(struct skill_unit_group),"skill.c::skill_unit_ers",ERS_OPT_NONE);
+	skill->timer_ers  = ers_new(sizeof(struct skill_timerskill),"skill.c::skill_timer_ers",ERS_OPT_NONE);
+	skill->cd_ers = ers_new(sizeof(struct skill_cd),"skill.c::skill_cd_ers",ERS_OPT_CLEAR);
+	skill->cd_entry_ers = ers_new(sizeof(struct skill_cd_entry),"skill.c::skill_cd_entry_ers",ERS_OPT_CLEAR);
 
+	ers_chunk_size(skill->cd_ers, 25);
+	ers_chunk_size(skill->cd_entry_ers, 100);
+	
 	iTimer->add_timer_func_list(skill->unit_timer,"skill_unit_timer");
 	iTimer->add_timer_func_list(skill->castend_id,"skill_castend_id");
 	iTimer->add_timer_func_list(skill->castend_pos,"skill_castend_pos");
@@ -18069,15 +18091,18 @@ int do_init_skill (void) {
 	return 0;
 }
 
-int do_final_skill(void)
-{
+int do_final_skill(void) {
+	
 	db_destroy(skilldb_name2id);
 	db_destroy(group_db);
 	db_destroy(skillunit_db);
 	db_destroy(skill->cd_db);
 	db_destroy(skillusave_db);
-	ers_destroy(skill_unit_ers);
-	ers_destroy(skill_timer_ers);
+	
+	ers_destroy(skill->unit_ers);
+	ers_destroy(skill->timer_ers);
+	ers_destroy(skill->cd_ers);
+	ers_destroy(skill->cd_entry_ers);
 	return 0;
 }
 /* initialize the interface */
@@ -18089,6 +18114,11 @@ void skill_defaults(void) {
 	skill->read_db = skill_readdb;
 	/* */
 	skill->cd_db = NULL;
+	/* */
+	skill->unit_ers = NULL;
+	skill->timer_ers = NULL;
+	skill->cd_ers = NULL;
+	skill->cd_entry_ers = NULL;
 	/* accesssors */
 	skill->get_index = skill_get_index;
 	skill->get_type = skill_get_type;
diff --git a/src/map/skill.h b/src/map/skill.h
index 35cb36809..1ca5f235a 100644
--- a/src/map/skill.h
+++ b/src/map/skill.h
@@ -1713,6 +1713,16 @@ struct s_skill_magicmushroom_db {
 };
 extern struct s_skill_magicmushroom_db skill_magicmushroom_db[MAX_SKILL_MAGICMUSHROOM_DB];
 
+struct skill_cd_entry {
+	int duration;//milliseconds
+#if PACKETVER >= 20120604
+	int total;
+#endif
+	short skidx;//the skill index entries belong to
+	unsigned int started;
+	uint16 skill_id;//skill id
+};
+
 /**
  * Skill Cool Down Delay Saving
  * Struct skill_cd is not a member of struct map_session_data
@@ -1720,13 +1730,7 @@ extern struct s_skill_magicmushroom_db skill_magicmushroom_db[MAX_SKILL_MAGICMUS
  * All cooldowns are reset when server is restarted.
  **/
 struct skill_cd {
-	int duration[MAX_SKILL_TREE];//milliseconds
-#if PACKETVER >= 20120604
-	int total[MAX_SKILL_TREE];
-#endif
-	short skidx[MAX_SKILL_TREE];//the skill index entries belong to
-	short nameid[MAX_SKILL_TREE];//skill id
-	unsigned int started[MAX_SKILL_TREE];
+	struct skill_cd_entry *entry[MAX_SKILL_TREE];
 	unsigned char cursor;
 };
 
@@ -1747,6 +1751,11 @@ struct skill_interface {
 	void (*read_db) (void);
 	/* */
 	DBMap* cd_db; // char_id -> struct skill_cd
+	/* */
+	struct eri *unit_ers; //For handling skill_unit's [Skotlex]
+	struct eri *timer_ers; //For handling skill_timerskills [Skotlex]
+	struct eri *cd_ers; // ERS Storage for skill cool down managers [Ind/Hercules]
+	struct eri *cd_entry_ers; // ERS Storage for skill cool down entries [Ind/Hercules]
 	/* accesssors */
 	int	(*get_index) ( uint16 skill_id );
 	int	(*get_type) ( uint16 skill_id );
-- 
cgit v1.2.3-70-g09d2