Forráskód Böngészése

Remove spawn info when unloading npc files (#8686)

Fixes #8685

Co-authored-by: Aleos <aleos89@users.noreply.github.com>
Co-authored-by: Lemongrass3110 <lemongrass@kstp.at>
Singe Horizontal 6 hónapja
szülő
commit
97ec3b5b8b
4 módosított fájl, 85 hozzáadás és 0 törlés
  1. 1 0
      src/map/map.hpp
  2. 1 0
      src/map/mob.hpp
  3. 82 0
      src/map/npc.cpp
  4. 1 0
      src/map/npc.hpp

+ 1 - 0
src/map/map.hpp

@@ -471,6 +471,7 @@ struct spawn_data {
 		uint32 boss : 1; //0: Non-boss monster | 1: Boss monster
 	} state;
 	char name[NAME_LENGTH], eventname[EVENT_NAME_LENGTH]; //Name/event
+	char filepath[256];
 };
 
 struct flooritem_data {

+ 1 - 0
src/map/mob.hpp

@@ -316,6 +316,7 @@ private:
 };
 
 extern MapDropDatabase map_drop_db;
+extern std::unordered_map<uint16, std::vector<spawn_info>> mob_spawn_data;
 
 struct mob_data {
 	struct block_list bl;

+ 82 - 0
src/map/npc.cpp

@@ -5350,6 +5350,9 @@ static const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const c
 		return strchr(start,'\n');// skip and continue
 	}
 
+	// Store filepath for possible unloading
+	strcpy( mob.filepath, filepath );
+
 	//Update mob spawn lookup database
 	struct spawn_info spawn = { mapdata->index, mob.num };
 	mob_add_spawn(mob_id, spawn);
@@ -6124,6 +6127,10 @@ bool npc_unloadfile( const char* path ) {
 
 	dbi_destroy(iter);
 
+	if(npc_remove_mob_spawns( path )){
+		found = true;
+	}
+
 	if( found ) /* refresh event cache */
 		npc_read_event_script();
 
@@ -6132,6 +6139,81 @@ bool npc_unloadfile( const char* path ) {
 	return found;
 }
 
+bool npc_remove_mob_spawns(const char* path) {
+	int32 spawn_count = {};
+	int32 unit_count = {};
+
+	auto remove_spawn_info = [&]( spawn_data& spawn, uint16 qty ){
+		auto it = mob_spawn_data.find( spawn.id );
+
+		if( it != mob_spawn_data.end() ){
+			uint16 mapindex = map_id2index( spawn.m );
+
+			it->second.erase( std::remove_if( it->second.begin(), it->second.end(), [&]( spawn_info& spawninfo ){
+				if( spawninfo.mapindex == mapindex ){
+					spawninfo.qty -= qty;
+					spawn_count += qty;
+					return spawninfo.qty == 0;
+				}
+
+				return false;
+			} ), it->second.end() );
+		}
+	};
+
+	// Remove spawned mobs
+	s_mapiterator* iter = mapit_geteachmob();
+
+	for( block_list* bl = mapit_first( iter ); mapit_exists( iter ); bl = mapit_next( iter ) ){
+		mob_data* md = reinterpret_cast<mob_data*>( bl );
+
+		if( md->spawn != nullptr && !strcmp( md->spawn->filepath, path ) ){
+			if( !battle_config.dynamic_mobs )
+				remove_spawn_info( *md->spawn, 1 );
+			unit_free( bl, CLR_OUTSIGHT );
+			unit_count++;
+		}
+	}
+
+	mapit_free(iter);
+
+	//dynamic mobs cleaning
+	if (battle_config.dynamic_mobs) {
+		for (int32 i = 0; i < map_num; i++) {
+			map_data* mapdata = map_getmapdata(i);
+
+			for (int16 j = 0; j < MAX_MOB_LIST_PER_MAP; j++) {
+				spawn_data* mob = mapdata->moblist[j];
+
+				if (mob != nullptr && !strcmp(mob->filepath, path)) {
+					npc_cache_mob -= mob->num;
+					remove_spawn_info( *mob, mob->num );
+
+					aFree(mapdata->moblist[j]);
+					mapdata->moblist[j] = nullptr;
+
+					if (mapdata->mob_delete_timer != INVALID_TIMER) {
+						delete_timer(mapdata->mob_delete_timer, map_removemobs_timer);
+						mapdata->mob_delete_timer = INVALID_TIMER;
+					}
+				}
+			}
+		}
+	}
+
+	// Sort spawns by spawn quantity
+	for( auto& pair : mob_spawn_data ){
+		std::sort( pair.second.begin(), pair.second.end(), []( const spawn_info& a, const spawn_info& b ) -> bool{
+			return a.qty > b.qty;
+		} );
+	}
+
+	if(spawn_count > 0 || unit_count > 0)
+		ShowInfo("%d mobs and %d spawns were removed.\n",unit_count,spawn_count);
+
+	return spawn_count > 0 || unit_count > 0;
+}
+
 void do_clear_npc(void) {
 	db_clear(npcname_db);
 	db_clear(ev_db);

+ 1 - 0
src/map/npc.hpp

@@ -1664,5 +1664,6 @@ void npc_market_delfromsql_(const char *exname, t_itemid nameid, bool clear);
 int npc_do_atcmd_event(map_session_data* sd, const char* command, const char* message, const char* eventname);
 
 bool npc_unloadfile( const char* path );
+bool npc_remove_mob_spawns(const char* path);
 
 #endif /* NPC_HPP */