Jump to content
  • 0

skill_delunit() & map server crash


Squall

Question


  • Group:  Members
  • Topic Count:  6
  • Topics Per Day:  0.00
  • Content Count:  18
  • Reputation:   0
  • Joined:  05/25/14
  • Last Seen:  

map server crash randomly, look at my debug:

 

gJmcu6V.png

 

 

I think the problem in this skill_delunit() function, this function look like this in my source:

int skill_delunit (struct skill_unit* unit) {
	struct skill_unit_group *group;

	nullpo_ret(unit);
	if( !unit->alive )
		return 0;
	unit->alive=0;

	nullpo_ret(group=unit->group);

	if( group->state.song_dance&0x1 ) //Cancel dissonance effect.
		skill_dance_overlap(unit, 0);

	// invoke onout event
	if( !unit->range )
		map_foreachincell(skill_unit_effect,unit->bl.m,unit->bl.x,unit->bl.y,group->bl_flag,&unit->bl,gettick(),4);

	// perform ondelete actions
	switch (group->skill_id) {
		case HT_ANKLESNARE: {
				struct block_list* target = map_id2bl(group->val2);
				if( target )
					status_change_end(target, SC_ANKLE, INVALID_TIMER);
			}
			break;
		case WZ_ICEWALL:
			map_setgatcell(unit->bl.m,unit->bl.x,unit->bl.y,unit->val2);
			clif_changemapcell(0,unit->bl.m,unit->bl.x,unit->bl.y,unit->val2,ALL_SAMEMAP); // hack to avoid clientside cell bug
			skill_unitsetmapcell(unit,WZ_ICEWALL,group->skill_lv,CELL_ICEWALL,false);
			map[unit->bl.m].icewall_num--;
			break;
		case SA_LANDPROTECTOR:
			skill_unitsetmapcell(unit,SA_LANDPROTECTOR,group->skill_lv,CELL_LANDPROTECTOR,false);
			break;
		case HP_BASILICA:
			skill_unitsetmapcell(unit,HP_BASILICA,group->skill_lv,CELL_BASILICA,false);
			// Because of Basilica's range we need to specifically update the players inside when it's cancelled prematurely
			map_foreachincell(skill_unit_effect,unit->bl.m,unit->bl.x,unit->bl.y,group->bl_flag,&unit->bl,0,4);
			break;
		case RA_ELECTRICSHOCKER: {
				struct block_list* target = map_id2bl(group->val2);
				if( target )
					status_change_end(target, SC_ELECTRICSHOCKER, INVALID_TIMER);
			}
			break;
		case SC_MAELSTROM:
			skill_unitsetmapcell(unit,SC_MAELSTROM,group->skill_lv,CELL_MAELSTROM,false);
			break;
		case SC_MANHOLE: // Note : Removing the unit don't remove the status (official info)
			if( group->val2 ) { // Someone Traped
				struct status_change *tsc = status_get_sc( map_id2bl(group->val2));
				if( tsc && tsc->data[SC__MANHOLE] )
					tsc->data[SC__MANHOLE]->val4 = 0; // Remove the Unit ID
			}
			break;
	}

	clif_skill_delunit(unit);

	unit->group=NULL;
	map_delblock(&unit->bl); // don't free yet
	map_deliddb(&unit->bl);
	idb_remove(skillunit_db, unit->bl.id);
	if(--group->alive_count==0)
		skill_delunitgroup(group);

	return 0;
}

does have a solution or just switching the emulator to solve?

 

 

Link to comment
Share on other sites

8 answers to this question

Recommended Posts


  • Group:  Members
  • Topic Count:  6
  • Topics Per Day:  0.00
  • Content Count:  18
  • Reputation:   0
  • Joined:  05/25/14
  • Last Seen:  

//= rAthena Dev Team

//===== Current Version: =====================================

//= $Revision: 17421 $

//===== Last Updated: ========================================

//= $LastChangedDate: 2013-07-17 18:38:58 -0600 (mié, 17 jul 2013) $

Link to comment
Share on other sites


  • Group:  Developer
  • Topic Count:  34
  • Topics Per Day:  0.01
  • Content Count:  802
  • Reputation:   228
  • Joined:  01/30/13
  • Last Seen:  

You need to check skill_castend_pos2 (skill.c line 10895).

It doesn't even get to skill_delunit, it crashes before that because ud->skillunit does not exist and you still access an element from it.

That line that crashes for you no longer seems to exist in the sourcecode, so I can't help you further.

Link to comment
Share on other sites


  • Group:  Members
  • Topic Count:  6
  • Topics Per Day:  0.00
  • Content Count:  18
  • Reputation:   0
  • Joined:  05/25/14
  • Last Seen:  

case GN_FIRE_EXPANSION: {
		int i;
		struct unit_data *ud = unit_bl2ud(src);

		if( !ud ) break;

		for( i = 0; i < MAX_SKILLUNITGROUP && ud->skillunit[i]; i ++ ) {
			if( ud->skillunit[i]->skill_id == GN_DEMONIC_FIRE &&
			   distance_xy(x, y, ud->skillunit[i]->unit->bl.x, ud->skillunit[i]->unit->bl.y) < 4 ) {
				switch( skill_lv ) {
					case 3:
						ud->skillunit[i]->unit_id = UNT_FIRE_EXPANSION_SMOKE_POWDER;
						clif_changetraplook(&ud->skillunit[i]->unit->bl, UNT_FIRE_EXPANSION_SMOKE_POWDER);
						break;
					case 4:
						ud->skillunit[i]->unit_id = UNT_FIRE_EXPANSION_TEAR_GAS;
						clif_changetraplook(&ud->skillunit[i]->unit->bl, UNT_FIRE_EXPANSION_TEAR_GAS);
						break;
					case 5:
						map_foreachinarea(skill_area_sub, src->m,
										  ud->skillunit[i]->unit->bl.x - 3, ud->skillunit[i]->unit->bl.y - 3,
										  ud->skillunit[i]->unit->bl.x + 3, ud->skillunit[i]->unit->bl.y + 3, BL_CHAR,
										  src, CR_ACIDDEMONSTRATION, sd ? pc_checkskill(sd, CR_ACIDDEMONSTRATION) : skill_lv, tick, flag|BCT_ENEMY|1|SD_LEVEL, skill_castend_damage_id);
						skill_delunit(ud->skillunit[i]->unit);
						break;
					default:
						ud->skillunit[i]->unit->val2 = skill_lv;
						ud->skillunit[i]->unit->group->val2 = skill_lv;
						break;
					}
				}
			}
		}
		break;

Line 10895: skill_delunit(ud->skillunit->unit);

 

 

Function skill_casend_pos2():

int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, uint16 skill_lv, unsigned int tick, int flag)
{
	struct map_session_data* sd;
	struct status_change* sc;
	struct status_change_entry *sce;
	struct skill_unit_group* sg;
	enum sc_type type;
	int i;

	//if(skill_lv <= 0) return 0;
	if(skill_id > 0 && !skill_lv) return 0;	// celest

	nullpo_ret(src);

	if(status_isdead(src))
		return 0;

	sd = BL_CAST(BL_PC, src);

	sc = status_get_sc(src);
	type = status_skill2sc(skill_id);
	sce = (sc && type != -1)?sc->data[type]:NULL;

	switch (skill_id) { //Skill effect.
		case WZ_METEOR:
		case MO_BODYRELOCATION:
		case CR_CULTIVATION:
		case HW_GANBANTEIN:
		case LG_EARTHDRIVE:
			break; //Effect is displayed on respective switch case.
		default:
			if(skill_get_inf(skill_id)&INF_SELF_SKILL)
				clif_skill_nodamage(src,src,skill_id,skill_lv,1);
			else
				clif_skill_poseffect(src,skill_id,skill_lv,x,y,tick);
	}

	// SC_MAGICPOWER needs to switch states before any damage is actually dealt
	skill_toggle_magicpower(src, skill_id);

	switch(skill_id)
	{
	case PR_BENEDICTIO:
		skill_area_temp[1] = src->id;
		i = skill_get_splash(skill_id, skill_lv);
		map_foreachinarea(skill_area_sub,
			src->m, x-i, y-i, x+i, y+i, BL_PC,
			src, skill_id, skill_lv, tick, flag|BCT_ALL|1,
			skill_castend_nodamage_id);
		map_foreachinarea(skill_area_sub,
			src->m, x-i, y-i, x+i, y+i, BL_CHAR,
			src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1,
			skill_castend_damage_id);
		break;

	case BS_HAMMERFALL:
		i = skill_get_splash(skill_id, skill_lv);
		map_foreachinarea (skill_area_sub,
			src->m, x-i, y-i, x+i, y+i, BL_CHAR,
			src, skill_id, skill_lv, tick, flag|BCT_ENEMY|2,
			skill_castend_nodamage_id);
		break;

	case HT_DETECTING:
		i = skill_get_splash(skill_id, skill_lv);
		map_foreachinarea( status_change_timer_sub,
			src->m, x-i, y-i, x+i,y+i,BL_CHAR,
			src,NULL,SC_SIGHT,tick);
		if(battle_config.traps_setting&1)
		map_foreachinarea( skill_reveal_trap,
			src->m, x-i, y-i, x+i,y+i,BL_SKILL);
		break;

	case SR_RIDEINLIGHTNING:
		i = skill_get_splash(skill_id, skill_lv);
		map_foreachinarea(skill_area_sub, src->m, x-i, y-i, x+i, y+i, BL_CHAR,
			src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill_castend_damage_id);
		break;

	case SA_VOLCANO:
	case SA_DELUGE:
	case SA_VIOLENTGALE:
	{	//Does not consumes if the skill is already active. [Skotlex]
		struct skill_unit_group *sg;
		if ((sg= skill_locate_element_field(src)) != NULL && ( sg->skill_id == SA_VOLCANO || sg->skill_id == SA_DELUGE || sg->skill_id == SA_VIOLENTGALE ))
		{
			if (sg->limit - DIFF_TICK(gettick(), sg->tick) > 0)
			{
				skill_unitsetting(src,skill_id,skill_lv,x,y,0);
				return 0; // not to consume items
			}
			else
				sg->limit = 0; //Disable it.
		}
		skill_unitsetting(src,skill_id,skill_lv,x,y,0);
		break;
	}
	case MG_SAFETYWALL:
	case MG_FIREWALL:
	case MG_THUNDERSTORM:

	case AL_PNEUMA:
	case WZ_ICEWALL:
	case WZ_FIREPILLAR:
	case WZ_QUAGMIRE:
	case WZ_VERMILION:
	case WZ_STORMGUST:
	case WZ_HEAVENDRIVE:
	case PR_SANCTUARY:
	case PR_MAGNUS:
	case CR_GRANDCROSS:
	case NPC_GRANDDARKNESS:
	case HT_SKIDTRAP:
	case MA_SKIDTRAP:
	case HT_LANDMINE:
	case MA_LANDMINE:
	case HT_ANKLESNARE:
	case HT_SHOCKWAVE:
	case HT_SANDMAN:
	case MA_SANDMAN:
	case HT_FLASHER:
	case HT_FREEZINGTRAP:
	case MA_FREEZINGTRAP:
	case HT_BLASTMINE:
	case HT_CLAYMORETRAP:
	case AS_VENOMDUST:
	case AM_DEMONSTRATION:
	case PF_FOGWALL:
	case PF_SPIDERWEB:
	case HT_TALKIEBOX:
	case WE_CALLPARTNER:
	case WE_CALLPARENT:
	case WE_CALLBABY:
	case AC_SHOWER:	//Ground-placed skill implementation.
	case MA_SHOWER:
	case SA_LANDPROTECTOR:
	case BD_LULLABY:
	case BD_RICHMANKIM:
	case BD_ETERNALCHAOS:
	case BD_DRUMBATTLEFIELD:
	case BD_RINGNIBELUNGEN:
	case BD_ROKISWEIL:
	case BD_INTOABYSS:
	case BD_SIEGFRIED:
	case BA_DISSONANCE:
	case BA_POEMBRAGI:
	case BA_WHISTLE:
	case BA_ASSASSINCROSS:
	case BA_APPLEIDUN:
	case DC_UGLYDANCE:
	case DC_HUMMING:
	case DC_DONTFORGETME:
	case DC_FORTUNEKISS:
	case DC_SERVICEFORYOU:
	case CG_MOONLIT:
	case GS_DESPERADO:
	case NJ_KAENSIN:
	case NJ_BAKUENRYU:
	case NJ_SUITON:
	case NJ_HYOUSYOURAKU:
	case NJ_RAIGEKISAI:
	case NJ_KAMAITACHI:
#ifdef RENEWAL
	case NJ_HUUMA:
#endif
	case NPC_EVILLAND:
	case RA_ELECTRICSHOCKER:
	case RA_CLUSTERBOMB:
	case RA_MAGENTATRAP:
	case RA_COBALTTRAP:
	case RA_MAIZETRAP:
	case RA_VERDURETRAP:
	case RA_FIRINGTRAP:
	case RA_ICEBOUNDTRAP:
	case SC_MANHOLE:
	case SC_DIMENSIONDOOR:
	case SC_CHAOSPANIC:
	case SC_MAELSTROM:
	case SC_BLOODYLUST:
	case WM_REVERBERATION:
	case WM_SEVERE_RAINSTORM:
	case WM_POEMOFNETHERWORLD:
	case SO_PSYCHIC_WAVE:
	case SO_VACUUM_EXTREME:
	case GN_WALLOFTHORN:
	case GN_THORNS_TRAP:
	case GN_DEMONIC_FIRE:
	case GN_HELLS_PLANT:
	case SO_EARTHGRAVE:
	case SO_DIAMONDDUST:
	case SO_FIRE_INSIGNIA:
	case SO_WATER_INSIGNIA:
	case SO_WIND_INSIGNIA:
	case SO_EARTH_INSIGNIA:
	case KO_HUUMARANKA:
	case KO_MUCHANAGE:
	case KO_BAKURETSU:
	case KO_ZENKAI:
	case MH_LAVA_SLIDE:
	case MH_VOLCANIC_ASH:
	case MH_POISON_MIST:
	case MH_STEINWAND:
	case MH_XENO_SLASHER:
		flag|=1;//Set flag to 1 to prevent deleting ammo (it will be deleted on group-delete).
	case GS_GROUNDDRIFT: //Ammo should be deleted right away.
		skill_unitsetting(src,skill_id,skill_lv,x,y,0);
		break;
	case RG_GRAFFITI:			/* Graffiti [Valaris] */
		skill_clear_unitgroup(src);
		skill_unitsetting(src,skill_id,skill_lv,x,y,0);
		flag|=1;
		break;
	case HP_BASILICA:
		if( sc->data[SC_BASILICA] ) {
			status_change_end(src, SC_BASILICA, INVALID_TIMER); // Cancel Basilica and return so requirement isn't consumed again
			return 0;
		} else { // Create Basilica. Start SC on caster. Unit timer start SC on others.
			if( map_getcell(src->m, x, y, CELL_CHKLANDPROTECTOR) ) {
				clif_skill_fail(sd,skill_id,USESKILL_FAIL,0);
				return 0;
			}
			skill_clear_unitgroup(src);
			if( skill_unitsetting(src,skill_id,skill_lv,x,y,0) )
				sc_start4(src,src,type,100,skill_lv,0,0,src->id,skill_get_time(skill_id,skill_lv));
			flag|=1;
		}
		break;
	case CG_HERMODE:
		skill_clear_unitgroup(src);
		if ((sg = skill_unitsetting(src,skill_id,skill_lv,x,y,0)))
			sc_start4(src,src,SC_DANCING,100,
				skill_id,0,skill_lv,sg->group_id,skill_get_time(skill_id,skill_lv));
		flag|=1;
		break;
	case RG_CLEANER: // [Valaris]
		i = skill_get_splash(skill_id, skill_lv);
		map_foreachinarea(skill_graffitiremover,src->m,x-i,y-i,x+i,y+i,BL_SKILL);
		break;

	case SO_WARMER:
		flag|= 8;
	case SO_CLOUD_KILL:
		skill_unitsetting(src,skill_id,skill_lv,x,y,0);
		break;

	case WZ_METEOR: {
			int area = skill_get_splash(skill_id, skill_lv);
			short tmpx = 0, tmpy = 0, x1 = 0, y1 = 0;

			for( i = 0; i < 2 + (skill_lv>>1); i++ ) {
				// Creates a random Cell in the Splash Area
				tmpx = x - area + rnd()%(area * 2 + 1);
				tmpy = y - area + rnd()%(area * 2 + 1);

				if( i == 0 && path_search_long(NULL, src->m, src->x, src->y, tmpx, tmpy, CELL_CHKWALL) )
					clif_skill_poseffect(src,skill_id,skill_lv,tmpx,tmpy,tick);

				if( i > 0 )
					skill_addtimerskill(src,tick+i*1000,0,tmpx,tmpy,skill_id,skill_lv,(x1<<16)|y1,0);

				x1 = tmpx;
				y1 = tmpy;
			}

			skill_addtimerskill(src,tick+i*1000,0,tmpx,tmpy,skill_id,skill_lv,-1,0);
		}
		break;

	case AL_WARP:
		if(sd)
		{
			clif_skill_warppoint(sd, skill_id, skill_lv, sd->status.save_point.map,
				(skill_lv >= 2) ? sd->status.memo_point[0].map : 0,
				(skill_lv >= 3) ? sd->status.memo_point[1].map : 0,
				(skill_lv >= 4) ? sd->status.memo_point[2].map : 0
			);
		}
		if( sc && sc->data[SC_CURSEDCIRCLE_ATKER] ) //Should only remove after the skill has been casted.
			status_change_end(src,SC_CURSEDCIRCLE_ATKER,INVALID_TIMER);
		return 0; // not to consume item.

	case MO_BODYRELOCATION:
		if (unit_movepos(src, x, y, 1, 1)) {
#if PACKETVER >= 20111005
			clif_snap(src, src->x, src->y);
#else
			clif_skill_poseffect(src,skill_id,skill_lv,src->x,src->y,tick);
#endif
			if (sd)
				skill_blockpc_start (sd, MO_EXTREMITYFIST, 2000);
		}
		break;
	case NJ_SHADOWJUMP:
		if( !map_flag_gvg(src->m) && !map[src->m].flag.battleground ) { //You don't move on GVG grounds.
			unit_movepos(src, x, y, 1, 0);
			clif_slide(src,x,y);
		}
		status_change_end(src, SC_HIDING, INVALID_TIMER);
		break;
	case AM_SPHEREMINE:
	case AM_CANNIBALIZE:
		{
			int summons[5] = { 1589, 1579, 1575, 1555, 1590 };
			//int summons[5] = { 1020, 1068, 1118, 1500, 1368 };
			int class_ = skill_id==AM_SPHEREMINE?1142:summons[skill_lv-1];
			int ai = (skill_id == AM_SPHEREMINE) ? AI_SPHERE : AI_FLORA;
			struct mob_data *md;

			// Correct info, don't change any of this! [celest]
			md = mob_once_spawn_sub(src, src->m, x, y, status_get_name(src), class_, "", SZ_SMALL, ai);
			if (md) {
				md->master_id = src->id;
				md->special_state.ai = (enum mob_ai)ai;
				if( md->deletetimer != INVALID_TIMER )
					delete_timer(md->deletetimer, mob_timer_delete);
				md->deletetimer = add_timer (gettick() + skill_get_time(skill_id,skill_lv), mob_timer_delete, md->bl.id, 0);
				mob_spawn (md); //Now it is ready for spawning.
			}
		}
		break;

	// Slim Pitcher [Celest]
	case CR_SLIMPITCHER:
		if (sd) {
		int i = 0, j = 0;
		struct skill_condition require = skill_get_requirement(sd, skill_id, skill_lv);
		i = skill_lv%11 - 1;
		j = pc_search_inventory(sd, require.itemid[i]);
		if (j < 0 || require.itemid[i] <= 0 || sd->inventory_data[j] == NULL || sd->status.inventory[j].amount < require.amount[i])
			{
				clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
				return 1;
			}
			potion_flag = 1;
			potion_hp = 0;
			potion_sp = 0;
			run_script(sd->inventory_data[j]->script,0,sd->bl.id,0);
			potion_flag = 0;
			//Apply skill bonuses
			i = pc_checkskill(sd,CR_SLIMPITCHER)*10
				+ pc_checkskill(sd,AM_POTIONPITCHER)*10
				+ pc_checkskill(sd,AM_LEARNINGPOTION)*5
				+ pc_skillheal_bonus(sd, skill_id);

			potion_hp = potion_hp * (100+i)/100;
			potion_sp = potion_sp * (100+i)/100;

			if(potion_hp > 0 || potion_sp > 0) {
				i = skill_get_splash(skill_id, skill_lv);
				map_foreachinarea(skill_area_sub,
					src->m,x-i,y-i,x+i,y+i,BL_CHAR,
					src,skill_id,skill_lv,tick,flag|BCT_PARTY|BCT_GUILD|1,
					skill_castend_nodamage_id);
			}
		} else {
			int i = skill_get_itemid(skill_id, skill_lv);
			struct item_data *item;
			item = itemdb_search(i);
			potion_flag = 1;
			potion_hp = 0;
			potion_sp = 0;
			run_script(item->script,0,src->id,0);
			potion_flag = 0;
			i = skill_get_max(CR_SLIMPITCHER)*10;

			potion_hp = potion_hp * (100+i)/100;
			potion_sp = potion_sp * (100+i)/100;

			if(potion_hp > 0 || potion_sp > 0) {
				i = skill_get_splash(skill_id, skill_lv);
				map_foreachinarea(skill_area_sub,
					src->m,x-i,y-i,x+i,y+i,BL_CHAR,
					src,skill_id,skill_lv,tick,flag|BCT_PARTY|BCT_GUILD|1,
						skill_castend_nodamage_id);
			}
		}
		break;

	case HW_GANBANTEIN:
		if (rnd()%100 < 80) {
			int dummy = 1;
			clif_skill_poseffect(src,skill_id,skill_lv,x,y,tick);
			i = skill_get_splash(skill_id, skill_lv);
			map_foreachinarea(skill_cell_overlap, src->m, x-i, y-i, x+i, y+i, BL_SKILL, HW_GANBANTEIN, &dummy, src);
		} else {
			if (sd) clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
			return 1;
		}
		break;

	case HW_GRAVITATION:
		if ((sg = skill_unitsetting(src,skill_id,skill_lv,x,y,0)))
			sc_start4(src,src,type,100,skill_lv,0,BCT_SELF,sg->group_id,skill_get_time(skill_id,skill_lv));
		flag|=1;
		break;

	// Plant Cultivation [Celest]
	case CR_CULTIVATION:
		if (sd) {
			if( map_count_oncell(src->m,x,y,BL_CHAR) > 0 )
			{
				clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
				return 1;
			}
			clif_skill_poseffect(src,skill_id,skill_lv,x,y,tick);
			if (rnd()%100 < 50) {
				clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
			} else {
				TBL_MOB* md = mob_once_spawn_sub(src, src->m, x, y, "--ja--",(skill_lv < 2 ? 1084+rnd()%2 : 1078+rnd()%6),"", SZ_SMALL, AI_NONE);
				int i;
				if (!md) break;
				if ((i = skill_get_time(skill_id, skill_lv)) > 0)
				{
					if( md->deletetimer != INVALID_TIMER )
						delete_timer(md->deletetimer, mob_timer_delete);
					md->deletetimer = add_timer (tick + i, mob_timer_delete, md->bl.id, 0);
				}
				mob_spawn (md);
			}
		}
		break;

	case SG_SUN_WARM:
	case SG_MOON_WARM:
	case SG_STAR_WARM:
		skill_clear_unitgroup(src);
		if ((sg = skill_unitsetting(src,skill_id,skill_lv,src->x,src->y,0)))
			sc_start4(src,src,type,100,skill_lv,0,0,sg->group_id,skill_get_time(skill_id,skill_lv));
		flag|=1;
		break;

	case PA_GOSPEL:
		if (sce && sce->val4 == BCT_SELF)
		{
			status_change_end(src, SC_GOSPEL, INVALID_TIMER);
			return 0;
		}
		else
		{
			sg = skill_unitsetting(src,skill_id,skill_lv,src->x,src->y,0);
			if (!sg) break;
			if (sce)
				status_change_end(src, type, INVALID_TIMER); //Was under someone else's Gospel. [Skotlex]
			sc_start4(src,src,type,100,skill_lv,0,sg->group_id,BCT_SELF,skill_get_time(skill_id,skill_lv));
			clif_skill_poseffect(src, skill_id, skill_lv, 0, 0, tick); // PA_GOSPEL music packet
		}
		break;
	case NJ_TATAMIGAESHI:
		if (skill_unitsetting(src,skill_id,skill_lv,src->x,src->y,0))
			sc_start(src,src,type,100,skill_lv,skill_get_time2(skill_id,skill_lv));
		break;

	case AM_RESURRECTHOMUN:	//[orn]
		if (sd)
		{
			if (!merc_resurrect_homunculus(sd, 20*skill_lv, x, y))
			{
				clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
				break;
			}
		}
		break;

	case RK_WINDCUTTER:
		clif_skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6);
	case NC_COLDSLOWER:
	case NC_ARMSCANNON:
	case RK_DRAGONBREATH:
		i = skill_get_splash(skill_id,skill_lv);
		map_foreachinarea(skill_area_sub,src->m,x-i,y-i,x+i,y+i,splash_target(src),
			src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id);
		break;

	case SO_ARRULLO:
		i = skill_get_splash(skill_id,skill_lv);
		map_foreachinarea(skill_area_sub,src->m,x-i,y-i,x+i,y+i,splash_target(src),
			src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill_castend_nodamage_id);
		break;
	/**
	 * Guilotine Cross
	 **/
	case GC_POISONSMOKE:
		if( !(sc && sc->data[SC_POISONINGWEAPON]) ) {
			if( sd )
				clif_skill_fail(sd,skill_id,USESKILL_FAIL_GC_POISONINGWEAPON,0);
			return 0;
		}
		clif_skill_damage(src,src,tick,status_get_amotion(src),0,-30000,1,skill_id,skill_lv,6);
		skill_unitsetting(src, skill_id, skill_lv, x, y, flag);
		//status_change_end(src,SC_POISONINGWEAPON,INVALID_TIMER); // 08/31/2011 - When using poison smoke, you no longer lose the poisoning weapon effect.
		break;
	/**
	 * Arch Bishop
	 **/
	case AB_EPICLESIS:
		if( (sg = skill_unitsetting(src, skill_id, skill_lv, x, y, 0)) ) {
			i = sg->unit->range;
			map_foreachinarea(skill_area_sub, src->m, x - i, y - i, x + i, y + i, BL_CHAR, src, ALL_RESURRECTION, 1, tick, flag|BCT_NOENEMY|1,skill_castend_nodamage_id);
		}
		break;
	/**
	 * Warlock
	 **/
	case WL_COMET:
		if( sc ) {
			sc->comet_x = x;
			sc->comet_y = y;
		}
		i = skill_get_splash(skill_id,skill_lv);
		map_foreachinarea(skill_area_sub,src->m,x-i,y-i,x+i,y+i,splash_target(src),src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id);
		break;

	case WL_EARTHSTRAIN:
		{
			int i, wave = skill_lv + 4, dir = map_calc_dir(src,x,y);
			int sx = x = src->x, sy = y = src->y; // Store first caster's location to avoid glitch on unit setting

			for( i = 1; i <= wave; i++ )
			{
				switch( dir ){
					case 0: case 1: case 7: sy = y + i; break;
					case 3: case 4: case 5: sy = y - i; break;
					case 2: sx = x - i; break;
					case 6: sx = x + i; break;
				}
				skill_addtimerskill(src,gettick() + (150 * i),0,sx,sy,skill_id,skill_lv,dir,flag&2);
			}
		}
		break;
	/**
	 * Ranger
	 **/
	case RA_DETONATOR:
		i = skill_get_splash(skill_id, skill_lv);
		map_foreachinarea(skill_detonator, src->m, x-i, y-i, x+i, y+i, BL_SKILL, src);
		clif_skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6);
		break;
	/**
	 * Mechanic
	 **/
	case NC_NEUTRALBARRIER:
	case NC_STEALTHFIELD:
		if( (sc->data[SC_NEUTRALBARRIER_MASTER] && skill_id == NC_NEUTRALBARRIER) || (sc->data[SC_STEALTHFIELD_MASTER] && skill_id == NC_STEALTHFIELD) ) {
			skill_clear_unitgroup(src);
			return 0;
		}
		skill_clear_unitgroup(src); // To remove previous skills - cannot used combined
		if( (sg = skill_unitsetting(src,skill_id,skill_lv,src->x,src->y,0)) != NULL ) {
			sc_start2(src,src,skill_id == NC_NEUTRALBARRIER ? SC_NEUTRALBARRIER_MASTER : SC_STEALTHFIELD_MASTER,100,skill_lv,sg->group_id,skill_get_time(skill_id,skill_lv));
			if( sd ) pc_overheat(sd,1);
		}
		break;

	case NC_SILVERSNIPER:
		{
			int class_ = 2042;
			struct mob_data *md;

			md = mob_once_spawn_sub(src, src->m, x, y, status_get_name(src), class_, "", SZ_SMALL, AI_NONE);
			if( md )
			{
				md->master_id = src->id;
				md->special_state.ai = AI_FAW;
				if( md->deletetimer != INVALID_TIMER )
					delete_timer(md->deletetimer, mob_timer_delete);
				md->deletetimer = add_timer (gettick() + skill_get_time(skill_id, skill_lv), mob_timer_delete, md->bl.id, 0);
				mob_spawn( md );
			}
		}
		break;

	case NC_MAGICDECOY:
		if( sd ) clif_magicdecoy_list(sd,skill_lv,x,y);
		break;

	case SC_FEINTBOMB:
		clif_skill_nodamage(src,src,skill_id,skill_lv,1);
		skill_unitsetting(src,skill_id,skill_lv,x,y,0); // Set bomb on current Position
		if( skill_blown(src,src,6,unit_getdir(src),0) )
			skill_castend_nodamage_id(src,src,TF_HIDING,1,tick,0);
		break;

	case LG_OVERBRAND:
		skill_overbrand(src, skill_id, skill_lv, x, y, tick, flag);
		break;

	case LG_BANDING:
		if( sc && sc->data[SC_BANDING] )
			status_change_end(src,SC_BANDING,INVALID_TIMER);
		else if( (sg = skill_unitsetting(src,skill_id,skill_lv,src->x,src->y,0)) != NULL ) {
			sc_start4(src,src,SC_BANDING,100,skill_lv,0,0,sg->group_id,skill_get_time(skill_id,skill_lv));
			if( sd ) pc_banding(sd,skill_lv);
		}
		clif_skill_nodamage(src,src,skill_id,skill_lv,1);
		break;

	case LG_RAYOFGENESIS:
		if( status_charge(src,status_get_max_hp(src)*3*skill_lv / 100,0) ) {
			i = skill_get_splash(skill_id,skill_lv);
			map_foreachinarea(skill_area_sub,src->m,x-i,y-i,x+i,y+i,splash_target(src),
				src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id);
		} else if( sd )
			clif_skill_fail(sd,skill_id,USESKILL_FAIL,0);
		break;

	case WM_DOMINION_IMPULSE:
		i = skill_get_splash(skill_id, skill_lv);
		map_foreachinarea( skill_ative_reverberation,
			src->m, x-i, y-i, x+i,y+i,BL_SKILL);
		break;

	case WM_GREAT_ECHO:
		flag|=1; // Should counsume 1 item per skill usage.
		map_foreachinrange(skill_area_sub, src, skill_get_splash(skill_id,skill_lv),splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY, skill_castend_damage_id);
		break;
	case GN_CRAZYWEED: {
			int area = skill_get_splash(GN_CRAZYWEED_ATK, skill_lv);
			short x1 = 0, y1 = 0;

			for( i = 0; i < 3 + (skill_lv/2); i++ ) {
				x1 = x - area + rnd()%(area * 2 + 1);
				y1 = y - area + rnd()%(area * 2 + 1);
				skill_addtimerskill(src,tick+i*150,0,x1,y1,GN_CRAZYWEED_ATK,skill_lv,-1,0);
			}
		}
		break;
	case GN_FIRE_EXPANSION: {
		int i;
		struct unit_data *ud = unit_bl2ud(src);

		if( !ud ) break;

		for( i = 0; i < MAX_SKILLUNITGROUP && ud->skillunit[i]; i ++ ) {
			if( ud->skillunit[i]->skill_id == GN_DEMONIC_FIRE &&
			   distance_xy(x, y, ud->skillunit[i]->unit->bl.x, ud->skillunit[i]->unit->bl.y) < 4 ) {
				switch( skill_lv ) {
					case 3:
						ud->skillunit[i]->unit_id = UNT_FIRE_EXPANSION_SMOKE_POWDER;
						clif_changetraplook(&ud->skillunit[i]->unit->bl, UNT_FIRE_EXPANSION_SMOKE_POWDER);
						break;
					case 4:
						ud->skillunit[i]->unit_id = UNT_FIRE_EXPANSION_TEAR_GAS;
						clif_changetraplook(&ud->skillunit[i]->unit->bl, UNT_FIRE_EXPANSION_TEAR_GAS);
						break;
					case 5:
						map_foreachinarea(skill_area_sub, src->m,
										  ud->skillunit[i]->unit->bl.x - 3, ud->skillunit[i]->unit->bl.y - 3,
										  ud->skillunit[i]->unit->bl.x + 3, ud->skillunit[i]->unit->bl.y + 3, BL_CHAR,
										  src, CR_ACIDDEMONSTRATION, sd ? pc_checkskill(sd, CR_ACIDDEMONSTRATION) : skill_lv, tick, flag|BCT_ENEMY|1|SD_LEVEL, skill_castend_damage_id);
						skill_delunit(ud->skillunit[i]->unit);
						break;
					default:
						ud->skillunit[i]->unit->val2 = skill_lv;
						ud->skillunit[i]->unit->group->val2 = skill_lv;
						break;
					}
				}
			}
		}
		break;

	case SO_FIREWALK:
	case SO_ELECTRICWALK:
		if( sc && sc->data[type] )
			status_change_end(src,type,INVALID_TIMER);
		clif_skill_nodamage(src, src ,skill_id, skill_lv,
			sc_start2(src,src, type, 100, skill_id, skill_lv, skill_get_time(skill_id, skill_lv)));
		break;

	case KO_MAKIBISHI:
		for( i = 0; i < (skill_lv+2); i++ ) {
			x = src->x - 1 + rnd()%3;
			y = src->y - 1 + rnd()%3;
			skill_unitsetting(src,skill_id,skill_lv,x,y,0);
		}
		break;

	default:
		ShowWarning("skill_castend_pos2: Unknown skill used:%d\n",skill_id);
		return 1;
	}

	if( sc && sc->data[SC_CURSEDCIRCLE_ATKER] ) //Should only remove after the skill has been casted.
		status_change_end(src,SC_CURSEDCIRCLE_ATKER,INVALID_TIMER);

	if( sd )
	{// ensure that the skill last-cast tick is recorded
		sd->canskill_tick = gettick();

		if( sd->state.arrow_atk && !(flag&1) )
		{// consume arrow if this is a ground skill
			battle_consume_ammo(sd, skill_id, skill_lv);
		}

		// perform skill requirement consumption
		skill_consume_requirement(sd,skill_id,skill_lv,2);
	}

	return 0;
}

I get the impression that this only occurs with the skills that are used in the ground...

 

 

But will not have a way to skip this error so no more server crash?

Edited by Squall
Link to comment
Share on other sites


  • Group:  Developer
  • Topic Count:  34
  • Topics Per Day:  0.01
  • Content Count:  802
  • Reputation:   228
  • Joined:  01/30/13
  • Last Seen:  

Well in this case, the crash seems to always occur when someone is casting GN_FIRE_EXPANSION at level 5.

But I honestly don't see what's wrong in it. It accesses ud->skillunit->unit before and doesn't crash then so why would it crash when unit_delunit is called?

Wait... maybe the "skill_castend_damage_id" deletes the unit already in some cases?

You could try:

if(ud && ud->skillunit[i] && ud->skillunit[i]->unit)
  skill_delunit(ud->skillunit[i]->unit);
break;
Link to comment
Share on other sites


  • Group:  Members
  • Topic Count:  6
  • Topics Per Day:  0.00
  • Content Count:  18
  • Reputation:   0
  • Joined:  05/25/14
  • Last Seen:  

Thanks, I'll try.


This info appears randomly, so my suspicion about skill_delunit () be the source of problems ..

 

J1wgMRl.png


int skill_delunit (struct skill_unit* unit) {
	struct skill_unit_group *group;

	nullpo_ret(unit);
	if( !unit->alive )
		return 0;
	unit->alive=0;

	nullpo_ret(group=unit->group);

	if( group->state.song_dance&0x1 ) //Cancel dissonance effect.
		skill_dance_overlap(unit, 0);

	// invoke onout event
	if( !unit->range )
		map_foreachincell(skill_unit_effect,unit->bl.m,unit->bl.x,unit->bl.y,group->bl_flag,&unit->bl,gettick(),4);

	// perform ondelete actions
	switch (group->skill_id) {
		case HT_ANKLESNARE: {
				struct block_list* target = map_id2bl(group->val2);
				if( target )
					status_change_end(target, SC_ANKLE, INVALID_TIMER);
			}
			break;
		case WZ_ICEWALL:
			map_setgatcell(unit->bl.m,unit->bl.x,unit->bl.y,unit->val2);
			clif_changemapcell(0,unit->bl.m,unit->bl.x,unit->bl.y,unit->val2,ALL_SAMEMAP); // hack to avoid clientside cell bug
			skill_unitsetmapcell(unit,WZ_ICEWALL,group->skill_lv,CELL_ICEWALL,false);
			map[unit->bl.m].icewall_num--;
			break;
		case SA_LANDPROTECTOR:
			skill_unitsetmapcell(unit,SA_LANDPROTECTOR,group->skill_lv,CELL_LANDPROTECTOR,false);
			break;
		case HP_BASILICA:
			skill_unitsetmapcell(unit,HP_BASILICA,group->skill_lv,CELL_BASILICA,false);
			// Because of Basilica's range we need to specifically update the players inside when it's cancelled prematurely
			map_foreachincell(skill_unit_effect,unit->bl.m,unit->bl.x,unit->bl.y,group->bl_flag,&unit->bl,0,4);
			break;
		case RA_ELECTRICSHOCKER: {
				struct block_list* target = map_id2bl(group->val2);
				if( target )
					status_change_end(target, SC_ELECTRICSHOCKER, INVALID_TIMER);
			}
			break;
		case SC_MAELSTROM:
			skill_unitsetmapcell(unit,SC_MAELSTROM,group->skill_lv,CELL_MAELSTROM,false);
			break;
		case SC_MANHOLE: // Note : Removing the unit don't remove the status (official info)
			if( group->val2 ) { // Someone Traped
				struct status_change *tsc = status_get_sc( map_id2bl(group->val2));
				if( tsc && tsc->data[SC__MANHOLE] )
					tsc->data[SC__MANHOLE]->val4 = 0; // Remove the Unit ID
			}
			break;
	}

	clif_skill_delunit(unit);

	unit->group=NULL;
	map_delblock(&unit->bl); // don't free yet
	map_deliddb(&unit->bl);
	idb_remove(skillunit_db, unit->bl.id);
	if(--group->alive_count==0)
		skill_delunitgroup(group);

	return 0;
}

 

Line 15895 is: nullpo_ret(unit);

Link to comment
Share on other sites


  • Group:  Developer
  • Topic Count:  34
  • Topics Per Day:  0.01
  • Content Count:  802
  • Reputation:   228
  • Joined:  01/30/13
  • Last Seen:  

Yeah, though that just means it tries to delete a unit that was already deleted. Which is not too critical as long as we don't forget to check for it anywhere it's used (that's why I suggested my update in the code). Does it no longer crash now?

Link to comment
Share on other sites


  • Group:  Members
  • Topic Count:  6
  • Topics Per Day:  0.00
  • Content Count:  18
  • Reputation:   0
  • Joined:  05/25/14
  • Last Seen:  

Crash again...

 

0PhtOnx.png

int skill_detonator(struct block_list *bl, va_list ap)
{
	struct skill_unit *unit=NULL;
	struct block_list *src;
	int unit_id;

	nullpo_ret(bl);
	nullpo_ret(ap);
	src = va_arg(ap,struct block_list *);

	if( bl->type != BL_SKILL || (unit = (struct skill_unit *)bl) == NULL || !unit->group )
		return 0;
	if( unit->group->src_id != src->id )
		return 0;

	unit_id = unit->group->unit_id;
	switch( unit_id )
	{ //List of Hunter and Ranger Traps that can be detonate.
		case UNT_BLASTMINE:
		case UNT_SANDMAN:
		case UNT_CLAYMORETRAP:
		case UNT_TALKIEBOX:
		case UNT_CLUSTERBOMB:
		case UNT_FIRINGTRAP:
		case UNT_ICEBOUNDTRAP:
			if( unit_id == UNT_TALKIEBOX )
			{
				clif_talkiebox(bl,unit->group->valstr);
				unit->group->val2 = -1;
			}
			else
				map_foreachinrange(skill_trap_splash,bl,skill_get_splash(unit->group->skill_id,unit->group->skill_lv),unit->group->bl_flag,bl,unit->group->tick);

			clif_changetraplook(bl,unit_id == UNT_FIRINGTRAP ? UNT_DUMMYSKILL : UNT_USED_TRAPS);
			unit->group->unit_id = UNT_USED_TRAPS;
			unit->group->limit = DIFF_TICK(gettick(),unit->group->tick) +
				(unit_id == UNT_TALKIEBOX ? 5000 : (unit_id == UNT_CLUSTERBOMB || unit_id == UNT_ICEBOUNDTRAP? 2500 : 1500) );
			break;
	}
	return 0;
}

Line 15519: clif_changetraplook(bl,unit_id == UNT_FIRINGTRAP ? UNT_DUMMYSKILL : UNT_USED_TRAPS);

 

 

 

 

My map server not online for 1 day, always appears a different crash. Is it better to give up?

Edited by Squall
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...