Pārlūkot izejas kodu

Speed up item and mob information commands (#7084)

* Fixes #7081.
* Small refactor of the atcommands: iteminfo, mobinfo, whodrops, and idsearch.
* Item information gathering is now sped up.
* Refactored itemdb_searchname_array to store results in a std::map so that the data is sorted by ID automatically.
* Cleanups across the board to remove extra calls for itemdb_exists().
Thanks to @voyfmyuh, @CairoLee, and @Lemongrass3110!
Aleos 2 gadi atpakaļ
vecāks
revīzija
8038e71322

+ 22 - 0
src/common/utilities.hpp

@@ -83,6 +83,19 @@ namespace rathena {
 				return defaultValue;
 				return defaultValue;
 		}
 		}
 
 
+		/**
+		 * Resize a map.
+		 * @param map: Map to resize
+		 * @param size: Size to set map to
+		 */
+		template <typename K, typename V, typename S> void map_resize(std::map<K, V> &map, S size) {
+			auto it = map.begin();
+
+			std::advance(it, size);
+
+			map.erase(it, map.end());
+		}
+
 		/**
 		/**
 		 * Find a key-value pair and return the key value as a reference
 		 * Find a key-value pair and return the key value as a reference
 		 * @param map: Unordered Map to search through
 		 * @param map: Unordered Map to search through
@@ -129,6 +142,15 @@ namespace rathena {
 				return defaultValue;
 				return defaultValue;
 		}
 		}
 
 
+		/**
+		 * Resize an unordered map.
+		 * @param map: Unordered map to resize
+		 * @param size: Size to set unordered map to
+		 */
+		template <typename K, typename V, typename S> void umap_resize(std::unordered_map<K, V> &map, S size) {
+			map.erase(std::advance(map.begin(), map.min(size, map.size())), map.end());
+		}
+
 		/**
 		/**
 		 * Get a random value from the given unordered map
 		 * Get a random value from the given unordered map
 		 * @param map: Unordered Map to search through
 		 * @param map: Unordered Map to search through

+ 86 - 47
src/map/atcommand.cpp

@@ -3911,28 +3911,33 @@ ACMD_FUNC(mapexit)
  *------------------------------------------*/
  *------------------------------------------*/
 ACMD_FUNC(idsearch)
 ACMD_FUNC(idsearch)
 {
 {
-	char item_name[100];
-	uint16 i, match;
-	struct item_data *item_array[MAX_SEARCH];
 	nullpo_retr(-1, sd);
 	nullpo_retr(-1, sd);
 
 
+	char item_name[100];
+
 	memset(item_name, '\0', sizeof(item_name));
 	memset(item_name, '\0', sizeof(item_name));
-	memset(atcmd_output, '\0', sizeof(atcmd_output));
 
 
 	if (!message || !*message || sscanf(message, "%99s", item_name) < 0) {
 	if (!message || !*message || sscanf(message, "%99s", item_name) < 0) {
 		clif_displaymessage(fd, msg_txt(sd,1031)); // Please enter part of an item name (usage: @idsearch <part_of_item_name>).
 		clif_displaymessage(fd, msg_txt(sd,1031)); // Please enter part of an item name (usage: @idsearch <part_of_item_name>).
 		return -1;
 		return -1;
 	}
 	}
 
 
+	memset(atcmd_output, '\0', sizeof(atcmd_output));
+
 	sprintf(atcmd_output, msg_txt(sd,77), item_name); // The reference result of '%s' (name: id):
 	sprintf(atcmd_output, msg_txt(sd,77), item_name); // The reference result of '%s' (name: id):
 	clif_displaymessage(fd, atcmd_output);
 	clif_displaymessage(fd, atcmd_output);
-	match = itemdb_searchname_array(item_array, MAX_SEARCH, item_name);
+
+	std::map<t_itemid, std::shared_ptr<item_data>> item_array = {};
+	uint16 match = itemdb_searchname_array(item_array, MAX_SEARCH, item_name);
+
 	if (match == MAX_SEARCH) {
 	if (match == MAX_SEARCH) {
 		sprintf(atcmd_output, msg_txt(sd,269), MAX_SEARCH); // Displaying first %d matches
 		sprintf(atcmd_output, msg_txt(sd,269), MAX_SEARCH); // Displaying first %d matches
 		clif_displaymessage(fd, atcmd_output);
 		clif_displaymessage(fd, atcmd_output);
 	}
 	}
-	for(i = 0; i < match; i++) {
-		sprintf(atcmd_output, msg_txt(sd,78), item_array[i]->ename.c_str(), item_array[i]->nameid); // %s: %u
+	for(const auto &result : item_array) {
+		std::shared_ptr<item_data> id = result.second;
+
+		sprintf(atcmd_output, msg_txt(sd,78), id->ename.c_str(), id->nameid); // %s: %u
 		clif_displaymessage(fd, atcmd_output);
 		clif_displaymessage(fd, atcmd_output);
 	}
 	}
 	sprintf(atcmd_output, msg_txt(sd,79), match); // It is %d affair above.
 	sprintf(atcmd_output, msg_txt(sd,79), match); // It is %d affair above.
@@ -5840,7 +5845,6 @@ ACMD_FUNC(dropall)
 {
 {
 	int8 type = -1;
 	int8 type = -1;
 	uint16 i, count = 0, count2 = 0;
 	uint16 i, count = 0, count2 = 0;
-	struct item_data *item_data = NULL;
 
 
 	nullpo_retr(-1, sd);
 	nullpo_retr(-1, sd);
 	
 	
@@ -5857,14 +5861,16 @@ ACMD_FUNC(dropall)
 
 
 	for( i = 0; i < MAX_INVENTORY; i++ ) {
 	for( i = 0; i < MAX_INVENTORY; i++ ) {
 		if( sd->inventory.u.items_inventory[i].amount ) {
 		if( sd->inventory.u.items_inventory[i].amount ) {
-			if( (item_data = itemdb_exists(sd->inventory.u.items_inventory[i].nameid)) == NULL ) {
+			std::shared_ptr<item_data> id = item_db.find(sd->inventory.u.items_inventory[i].nameid);
+
+			if( id == nullptr ) {
 				ShowDebug("Non-existant item %d on dropall list (account_id: %d, char_id: %d)\n", sd->inventory.u.items_inventory[i].nameid, sd->status.account_id, sd->status.char_id);
 				ShowDebug("Non-existant item %d on dropall list (account_id: %d, char_id: %d)\n", sd->inventory.u.items_inventory[i].nameid, sd->status.account_id, sd->status.char_id);
 				continue;
 				continue;
 			}
 			}
 			if( !pc_candrop(sd,&sd->inventory.u.items_inventory[i]) )
 			if( !pc_candrop(sd,&sd->inventory.u.items_inventory[i]) )
 				continue;
 				continue;
 
 
-			if( type == -1 || type == (uint8)item_data->type ) {
+			if( type == -1 || type == (uint8)id->type ) {
 				if( sd->inventory.u.items_inventory[i].equip != 0 )
 				if( sd->inventory.u.items_inventory[i].equip != 0 )
 					pc_unequipitem(sd, i, 3);
 					pc_unequipitem(sd, i, 3);
 				if( itemdb_ishatched_egg( &sd->inventory.u.items_inventory[i] ) ){
 				if( itemdb_ishatched_egg( &sd->inventory.u.items_inventory[i] ) ){
@@ -7612,9 +7618,8 @@ ACMD_FUNC(mobinfo)
 	unsigned char mrace[RC_ALL][11] = { "Formless", "Undead", "Beast", "Plant", "Insect", "Fish", "Demon", "Demi-Human", "Angel", "Dragon", "Player" };
 	unsigned char mrace[RC_ALL][11] = { "Formless", "Undead", "Beast", "Plant", "Insect", "Fish", "Demon", "Demi-Human", "Angel", "Dragon", "Player" };
 	unsigned char melement[ELE_ALL][8] = { "Neutral", "Water", "Earth", "Fire", "Wind", "Poison", "Holy", "Dark", "Ghost", "Undead" };
 	unsigned char melement[ELE_ALL][8] = { "Neutral", "Water", "Earth", "Fire", "Wind", "Poison", "Holy", "Dark", "Ghost", "Undead" };
 	char atcmd_output2[CHAT_SIZE_MAX];
 	char atcmd_output2[CHAT_SIZE_MAX];
-	struct item_data *item_data;
 	uint16 mob_ids[MAX_SEARCH], count;
 	uint16 mob_ids[MAX_SEARCH], count;
-	int i, k;
+	uint16 i;
 
 
 	memset(atcmd_output, '\0', sizeof(atcmd_output));
 	memset(atcmd_output, '\0', sizeof(atcmd_output));
 	memset(atcmd_output2, '\0', sizeof(atcmd_output2));
 	memset(atcmd_output2, '\0', sizeof(atcmd_output2));
@@ -7625,7 +7630,7 @@ ACMD_FUNC(mobinfo)
 	}
 	}
 
 
 	// If monster identifier/name argument is a name
 	// If monster identifier/name argument is a name
-	if ((i = mobdb_checkid(atoi(message))))
+	if ((i = mobdb_checkid(strtoul(message, nullptr, 10))))
 	{
 	{
 		mob_ids[0] = i;
 		mob_ids[0] = i;
 		count = 1;
 		count = 1;
@@ -7642,7 +7647,7 @@ ACMD_FUNC(mobinfo)
 		clif_displaymessage(fd, atcmd_output);
 		clif_displaymessage(fd, atcmd_output);
 		count = MAX_SEARCH;
 		count = MAX_SEARCH;
 	}
 	}
-	for (k = 0; k < count; k++) {
+	for (uint16 k = 0; k < count; k++) {
 		std::shared_ptr<s_mob_db> mob = mob_db.find(mob_ids[k]);
 		std::shared_ptr<s_mob_db> mob = mob_db.find(mob_ids[k]);
 
 
 		if (mob == nullptr)
 		if (mob == nullptr)
@@ -7697,15 +7702,21 @@ ACMD_FUNC(mobinfo)
 #endif
 #endif
 
 
 		for (i = 0; i < MAX_MOB_DROP_TOTAL; i++) {
 		for (i = 0; i < MAX_MOB_DROP_TOTAL; i++) {
-			if (mob->dropitem[i].nameid == 0 || mob->dropitem[i].rate < 1 || (item_data = itemdb_exists(mob->dropitem[i].nameid)) == NULL)
+
+			if (mob->dropitem[i].nameid == 0 || mob->dropitem[i].rate < 1)
+				continue;
+
+			std::shared_ptr<item_data> id = item_db.find(mob->dropitem[i].nameid);
+
+			if (id == nullptr)
 				continue;
 				continue;
 
 
 			int droprate = mob_getdroprate( &sd->bl, mob, mob->dropitem[i].rate, drop_modifier );
 			int droprate = mob_getdroprate( &sd->bl, mob, mob->dropitem[i].rate, drop_modifier );
 
 
-			if (item_data->slots)
-				sprintf(atcmd_output2, " - %s[%d]  %02.02f%%", item_data->ename.c_str(), item_data->slots, (float)droprate / 100);
+			if (id->slots)
+				sprintf(atcmd_output2, " - %s[%d]  %02.02f%%", id->ename.c_str(), id->slots, (float)droprate / 100);
 			else
 			else
-				sprintf(atcmd_output2, " - %s  %02.02f%%", item_data->ename.c_str(), (float)droprate / 100);
+				sprintf(atcmd_output2, " - %s  %02.02f%%", id->ename.c_str(), (float)droprate / 100);
 			strcat(atcmd_output, atcmd_output2);
 			strcat(atcmd_output, atcmd_output2);
 			if (++j % 3 == 0) {
 			if (++j % 3 == 0) {
 				clif_displaymessage(fd, atcmd_output);
 				clif_displaymessage(fd, atcmd_output);
@@ -7725,8 +7736,15 @@ ACMD_FUNC(mobinfo)
 			mvpremain = 100.0; //Remaining drop chance for official mvp drop mode
 			mvpremain = 100.0; //Remaining drop chance for official mvp drop mode
 			j = 0;
 			j = 0;
 			for (i = 0; i < MAX_MVP_DROP_TOTAL; i++) {
 			for (i = 0; i < MAX_MVP_DROP_TOTAL; i++) {
-				if (mob->mvpitem[i].nameid == 0 || (item_data = itemdb_exists(mob->mvpitem[i].nameid)) == NULL)
+
+				if (mob->mvpitem[i].nameid == 0)
+					continue;
+
+				std::shared_ptr<item_data> id = item_db.find(mob->mvpitem[i].nameid);
+
+				if (id == nullptr)
 					continue;
 					continue;
+
 				//Because if there are 3 MVP drops at 50%, the first has a chance of 50%, the second 25% and the third 12.5%
 				//Because if there are 3 MVP drops at 50%, the first has a chance of 50%, the second 25% and the third 12.5%
 				mvppercent = (float)mob->mvpitem[i].rate * mvpremain / 10000.0f;
 				mvppercent = (float)mob->mvpitem[i].rate * mvpremain / 10000.0f;
 				if(battle_config.item_drop_mvp_mode == 0) {
 				if(battle_config.item_drop_mvp_mode == 0) {
@@ -7735,15 +7753,15 @@ ACMD_FUNC(mobinfo)
 				if (mvppercent > 0) {
 				if (mvppercent > 0) {
 					j++;
 					j++;
 					if (j == 1) {
 					if (j == 1) {
-						if (item_data->slots)
-							sprintf(atcmd_output2, " %s[%d]  %02.02f%%", item_data->ename.c_str(), item_data->slots, mvppercent);
+						if (id->slots)
+							sprintf(atcmd_output2, " %s[%d]  %02.02f%%", id->ename.c_str(), id->slots, mvppercent);
 						else
 						else
-							sprintf(atcmd_output2, " %s  %02.02f%%", item_data->ename.c_str(), mvppercent);
+							sprintf(atcmd_output2, " %s  %02.02f%%", id->ename.c_str(), mvppercent);
 					} else {
 					} else {
-						if (item_data->slots)
-							sprintf(atcmd_output2, " - %s[%d]  %02.02f%%", item_data->ename.c_str(), item_data->slots, mvppercent);
+						if (id->slots)
+							sprintf(atcmd_output2, " - %s[%d]  %02.02f%%", id->ename.c_str(), id->slots, mvppercent);
 						else
 						else
-							sprintf(atcmd_output2, " - %s  %02.02f%%", item_data->ename.c_str(), mvppercent);
+							sprintf(atcmd_output2, " - %s  %02.02f%%", id->ename.c_str(), mvppercent);
 					}
 					}
 					strcat(atcmd_output, atcmd_output2);
 					strcat(atcmd_output, atcmd_output2);
 				}
 				}
@@ -8149,15 +8167,21 @@ ACMD_FUNC(homshuffle)
  *------------------------------------------*/
  *------------------------------------------*/
 ACMD_FUNC(iteminfo)
 ACMD_FUNC(iteminfo)
 {
 {
-	struct item_data *item_array[MAX_SEARCH];
-	uint16 i, count = 1;
-
 	if (!message || !*message) {
 	if (!message || !*message) {
 		clif_displaymessage(fd, msg_txt(sd,1276)); // Please enter an item name/ID (usage: @ii/@iteminfo <item name/ID>).
 		clif_displaymessage(fd, msg_txt(sd,1276)); // Please enter an item name/ID (usage: @ii/@iteminfo <item name/ID>).
 		return -1;
 		return -1;
 	}
 	}
-	if ((item_array[0] = itemdb_exists(strtoul(message, nullptr, 10))) == nullptr)
+
+	std::map<t_itemid, std::shared_ptr<item_data>> item_array = {};
+	uint16 count = 1;
+	t_itemid itemid = strtoul(message, nullptr, 10);
+
+	if (itemid == 0) // Entered a string
 		count = itemdb_searchname_array(item_array, MAX_SEARCH, message);
 		count = itemdb_searchname_array(item_array, MAX_SEARCH, message);
+	else {
+		if ((item_array[0] = item_db.find(itemid)) == nullptr)
+			count = 0;
+	}
 
 
 	if (!count) {
 	if (!count) {
 		clif_displaymessage(fd, msg_txt(sd,19));	// Invalid item ID or name.
 		clif_displaymessage(fd, msg_txt(sd,19));	// Invalid item ID or name.
@@ -8168,8 +8192,9 @@ ACMD_FUNC(iteminfo)
 		sprintf(atcmd_output, msg_txt(sd,269), MAX_SEARCH); // Displaying first %d matches
 		sprintf(atcmd_output, msg_txt(sd,269), MAX_SEARCH); // Displaying first %d matches
 		clif_displaymessage(fd, atcmd_output);
 		clif_displaymessage(fd, atcmd_output);
 	}
 	}
-	for (i = 0; i < count; i++) {
-		struct item_data * item_data = item_array[i];
+	for (const auto &result : item_array) {
+		std::shared_ptr<item_data> item_data = result.second;
+
 		sprintf(atcmd_output, msg_txt(sd,1277), // Item: '%s'/'%s'[%d] (%u) Type: %s | Extra Effect: %s
 		sprintf(atcmd_output, msg_txt(sd,1277), // Item: '%s'/'%s'[%d] (%u) Type: %s | Extra Effect: %s
 			item_data->name.c_str(),item_data->ename.c_str(),item_data->slots,item_data->nameid,
 			item_data->name.c_str(),item_data->ename.c_str(),item_data->slots,item_data->nameid,
 			(item_data->type != IT_AMMO) ? itemdb_typename((enum item_types)item_data->type) : itemdb_typename_ammo((e_ammo_type)item_data->subtype),
 			(item_data->type != IT_AMMO) ? itemdb_typename((enum item_types)item_data->type) : itemdb_typename_ammo((e_ammo_type)item_data->subtype),
@@ -8200,15 +8225,21 @@ ACMD_FUNC(iteminfo)
  *------------------------------------------*/
  *------------------------------------------*/
 ACMD_FUNC(whodrops)
 ACMD_FUNC(whodrops)
 {
 {
-	struct item_data *item_data, *item_array[MAX_SEARCH];
-	uint16 i, j, count = 1;
-
 	if (!message || !*message) {
 	if (!message || !*message) {
 		clif_displaymessage(fd, msg_txt(sd,1284)); // Please enter item name/ID (usage: @whodrops <item name/ID>).
 		clif_displaymessage(fd, msg_txt(sd,1284)); // Please enter item name/ID (usage: @whodrops <item name/ID>).
 		return -1;
 		return -1;
 	}
 	}
-	if ((item_array[0] = itemdb_exists(strtoul(message, nullptr, 10))) == nullptr)
+
+	std::map<t_itemid, std::shared_ptr<item_data>> item_array = {};
+	uint16 count = 1;
+	t_itemid itemid = strtoul(message, nullptr, 10);
+
+	if (itemid == 0) // Entered a string
 		count = itemdb_searchname_array(item_array, MAX_SEARCH, message);
 		count = itemdb_searchname_array(item_array, MAX_SEARCH, message);
+	else {
+		if ((item_array[0] = item_db.find(itemid)) == nullptr)
+			count = 0;
+	}
 
 
 	if (!count) {
 	if (!count) {
 		clif_displaymessage(fd, msg_txt(sd,19));	// Invalid item ID or name.
 		clif_displaymessage(fd, msg_txt(sd,19));	// Invalid item ID or name.
@@ -8219,22 +8250,23 @@ ACMD_FUNC(whodrops)
 		sprintf(atcmd_output, msg_txt(sd,269), MAX_SEARCH); // Displaying first %d matches
 		sprintf(atcmd_output, msg_txt(sd,269), MAX_SEARCH); // Displaying first %d matches
 		clif_displaymessage(fd, atcmd_output);
 		clif_displaymessage(fd, atcmd_output);
 	}
 	}
-	for (i = 0; i < count; i++) {
-		item_data = item_array[i];
-		sprintf(atcmd_output, msg_txt(sd,1285), item_data->ename.c_str(), item_data->slots, item_data->nameid); // Item: '%s'[%d] (ID:%u)
+	for (const auto &result : item_array) {
+		std::shared_ptr<item_data> id = result.second;
+
+		sprintf(atcmd_output, msg_txt(sd,1285), id->ename.c_str(), id->slots, id->nameid); // Item: '%s'[%d] (ID:%u)
 		clif_displaymessage(fd, atcmd_output);
 		clif_displaymessage(fd, atcmd_output);
 
 
-		if (item_data->mob[0].chance == 0) {
+		if (id->mob[0].chance == 0) {
 			strcpy(atcmd_output, msg_txt(sd,1286)); //  - Item is not dropped by mobs.
 			strcpy(atcmd_output, msg_txt(sd,1286)); //  - Item is not dropped by mobs.
 			clif_displaymessage(fd, atcmd_output);
 			clif_displaymessage(fd, atcmd_output);
 		} else {
 		} else {
 			sprintf(atcmd_output, msg_txt(sd,1287), MAX_SEARCH); //  - Common mobs with highest drop chance (only max %d are listed):
 			sprintf(atcmd_output, msg_txt(sd,1287), MAX_SEARCH); //  - Common mobs with highest drop chance (only max %d are listed):
 			clif_displaymessage(fd, atcmd_output);
 			clif_displaymessage(fd, atcmd_output);
 
 
-			for (j=0; j < MAX_SEARCH && item_data->mob[j].chance > 0; j++)
+			for (uint16 j=0; j < MAX_SEARCH && id->mob[j].chance > 0; j++)
 			{
 			{
-				int dropchance = item_data->mob[j].chance;
-				std::shared_ptr<s_mob_db> mob = mob_db.find(item_data->mob[j].id);
+				int dropchance = id->mob[j].chance;
+				std::shared_ptr<s_mob_db> mob = mob_db.find(id->mob[j].id);
 				if(!mob) continue;
 				if(!mob) continue;
 
 
 #ifdef RENEWAL_DROP
 #ifdef RENEWAL_DROP
@@ -8246,7 +8278,7 @@ ACMD_FUNC(whodrops)
 #endif
 #endif
 				if (pc_isvip(sd)) // Display item rate increase for VIP
 				if (pc_isvip(sd)) // Display item rate increase for VIP
 					dropchance += (dropchance * battle_config.vip_drop_increase) / 100;
 					dropchance += (dropchance * battle_config.vip_drop_increase) / 100;
-				sprintf(atcmd_output, "- %s (%d): %02.02f%%", mob->jname.c_str(), item_data->mob[j].id, dropchance/100.);
+				sprintf(atcmd_output, "- %s (%d): %02.02f%%", mob->jname.c_str(), id->mob[j].id, dropchance/100.);
 				clif_displaymessage(fd, atcmd_output);
 				clif_displaymessage(fd, atcmd_output);
 			}
 			}
 		}
 		}
@@ -9198,9 +9230,13 @@ ACMD_FUNC(itemlist)
 	counter = 0; // total items found
 	counter = 0; // total items found
 	for( i = 0; i < size; ++i ) {
 	for( i = 0; i < size; ++i ) {
 		const struct item* it = &items[i];
 		const struct item* it = &items[i];
-		struct item_data* itd;
 
 
-		if( it->nameid == 0 || (itd = itemdb_exists(it->nameid)) == NULL )
+		if( it->nameid == 0  )
+			continue;
+
+		std::shared_ptr<item_data> itd = item_db.find(it->nameid);
+
+		if (itd == nullptr)
 			continue;
 			continue;
 
 
 		counter += it->amount;
 		counter += it->amount;
@@ -9302,9 +9338,12 @@ ACMD_FUNC(itemlist)
 			int counter2 = 0;
 			int counter2 = 0;
 
 
 			for( j = 0; j < itd->slots; ++j ) {
 			for( j = 0; j < itd->slots; ++j ) {
-				struct item_data* card;
+				if( it->card[j] == 0 )
+					continue;
+
+				std::shared_ptr<item_data> card = item_db.find(it->card[j]);
 
 
-				if( it->card[j] == 0 || (card = itemdb_exists(it->card[j])) == NULL )
+				if (card == nullptr)
 					continue;
 					continue;
 
 
 				counter2++;
 				counter2++;

+ 3 - 4
src/map/buyingstore.cpp

@@ -162,11 +162,10 @@ int8 buyingstore_create( struct map_session_data* sd, int zenylimit, unsigned ch
 	// check item list
 	// check item list
 	for( i = 0; i < count; i++ ){
 	for( i = 0; i < count; i++ ){
 		const struct PACKET_CZ_REQ_OPEN_BUYING_STORE_sub *item = &itemlist[i];
 		const struct PACKET_CZ_REQ_OPEN_BUYING_STORE_sub *item = &itemlist[i];
-
-		struct item_data* id = itemdb_exists( item->itemId );
+		std::shared_ptr<item_data> id = item_db.find(item->itemId);
 
 
 		// invalid input
 		// invalid input
-		if( id == NULL || item->amount == 0 ){	
+		if( id == nullptr || item->amount == 0 ){	
 			break;
 			break;
 		}
 		}
 
 
@@ -176,7 +175,7 @@ int8 buyingstore_create( struct map_session_data* sd, int zenylimit, unsigned ch
 		}
 		}
 
 
 		// restrictions: allowed and no character-bound items
 		// restrictions: allowed and no character-bound items
-		if( !id->flag.buyingstore || !itemdb_cantrade_sub( id, pc_get_group_level( sd ), pc_get_group_level( sd ) ) ){ 
+		if( !id->flag.buyingstore || !itemdb_cantrade_sub( id.get(), pc_get_group_level( sd ), pc_get_group_level( sd ) ) ){ 
 			break;
 			break;
 		}
 		}
 
 

+ 2 - 2
src/map/cashshop.cpp

@@ -471,7 +471,6 @@ bool cashshop_buylist( struct map_session_data* sd, uint32 kafrapoints, int n, s
 	uint32 totalcash = 0;
 	uint32 totalcash = 0;
 	uint32 totalweight = 0;
 	uint32 totalweight = 0;
 	int i,new_;
 	int i,new_;
-	item_data *id;
 
 
 	if( sd == NULL || item_list == NULL || !cash_shop_defined){
 	if( sd == NULL || item_list == NULL || !cash_shop_defined){
 		clif_cashshop_result( sd, 0, CASHSHOP_RESULT_ERROR_UNKNOWN );
 		clif_cashshop_result( sd, 0, CASHSHOP_RESULT_ERROR_UNKNOWN );
@@ -502,7 +501,8 @@ bool cashshop_buylist( struct map_session_data* sd, uint32 kafrapoints, int n, s
 		}
 		}
 
 
 		nameid = item_list[i].itemId = cash_shop_items[tab].item[j]->nameid; //item_avail replacement
 		nameid = item_list[i].itemId = cash_shop_items[tab].item[j]->nameid; //item_avail replacement
-		id = itemdb_exists(nameid);
+
+		std::shared_ptr<item_data> id = item_db.find(nameid);
 
 
 		if( !id ){
 		if( !id ){
 			clif_cashshop_result( sd, nameid, CASHSHOP_RESULT_ERROR_UNKONWN_ITEM );
 			clif_cashshop_result( sd, nameid, CASHSHOP_RESULT_ERROR_UNKONWN_ITEM );

+ 22 - 19
src/map/clif.cpp

@@ -2193,10 +2193,10 @@ void clif_buylist( struct map_session_data *sd, struct npc_data *nd ){
 		p->items[count].itemType = itemtype( nd->u.shop.shop_item[i].nameid );
 		p->items[count].itemType = itemtype( nd->u.shop.shop_item[i].nameid );
 		p->items[count].itemId = client_nameid( nd->u.shop.shop_item[i].nameid );
 		p->items[count].itemId = client_nameid( nd->u.shop.shop_item[i].nameid );
 #if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103
 #if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103
-		struct item_data* id = itemdb_exists( nd->u.shop.shop_item[i].nameid );
+		std::shared_ptr<item_data> id = item_db.find(nd->u.shop.shop_item[i].nameid);
 
 
 		p->items[count].viewSprite = id->look;
 		p->items[count].viewSprite = id->look;
-		p->items[count].location = pc_equippoint_sub( sd, id );
+		p->items[count].location = pc_equippoint_sub( sd, id.get() );
 #endif
 #endif
 		count++;
 		count++;
 	}
 	}
@@ -2279,7 +2279,7 @@ void clif_npc_market_open(struct map_session_data *sd, struct npc_data *nd) {
 			continue;
 			continue;
 		}
 		}
 
 
-		struct item_data *id = itemdb_exists( item->nameid );
+		std::shared_ptr<item_data> id = item_db.find(item->nameid);
 
 
 		if( !id ){
 		if( !id ){
 			continue;
 			continue;
@@ -2296,7 +2296,7 @@ void clif_npc_market_open(struct map_session_data *sd, struct npc_data *nd) {
 		p->list[count].qty = item->qty;
 		p->list[count].qty = item->qty;
 		p->list[count].weight = id->weight;
 		p->list[count].weight = id->weight;
 #if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103
 #if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103
-		p->list[count].location = pc_equippoint_sub( sd, id );
+		p->list[count].location = pc_equippoint_sub( sd, id.get() );
 #endif
 #endif
 		count++;
 		count++;
 	}
 	}
@@ -16215,7 +16215,6 @@ void clif_Mail_read( struct map_session_data *sd, int mail_id ){
 	} else {
 	} else {
 		struct mail_message *msg = &sd->mail.inbox.msg[i];
 		struct mail_message *msg = &sd->mail.inbox.msg[i];
 		struct item *item;
 		struct item *item;
-		struct item_data *data;
 		int msg_len = strlen(msg->body);
 		int msg_len = strlen(msg->body);
 
 
 		if( msg_len == 0 ) {
 		if( msg_len == 0 ) {
@@ -16273,7 +16272,9 @@ void clif_Mail_read( struct map_session_data *sd, int mail_id ){
 		for( int j = 0; j < MAIL_MAX_ITEM; j++ ){
 		for( int j = 0; j < MAIL_MAX_ITEM; j++ ){
 			item = &msg->item[j];
 			item = &msg->item[j];
 
 
-			if( item->nameid > 0 && item->amount > 0 && ( data = itemdb_exists( item->nameid ) ) != NULL ){
+			std::shared_ptr<item_data> data = item_db.find(item->nameid);
+
+			if( item->nameid > 0 && item->amount > 0 && data != nullptr ){
 				struct PACKET_ZC_ACK_READ_RODEX_SUB* mailitem = (struct PACKET_ZC_ACK_READ_RODEX_SUB*)WBUFP( p, p->PacketLength );
 				struct PACKET_ZC_ACK_READ_RODEX_SUB* mailitem = (struct PACKET_ZC_ACK_READ_RODEX_SUB*)WBUFP( p, p->PacketLength );
 
 
 				mailitem->ITID = client_nameid( item->nameid );
 				mailitem->ITID = client_nameid( item->nameid );
@@ -16282,7 +16283,7 @@ void clif_Mail_read( struct map_session_data *sd, int mail_id ){
 				mailitem->IsIdentified = item->identify ? 1 : 0;
 				mailitem->IsIdentified = item->identify ? 1 : 0;
 				mailitem->IsDamaged = item->attribute ? 1 : 0;
 				mailitem->IsDamaged = item->attribute ? 1 : 0;
 				mailitem->refiningLevel = item->refine;
 				mailitem->refiningLevel = item->refine;
-				mailitem->location = pc_equippoint_sub( sd, data );
+				mailitem->location = pc_equippoint_sub( sd, data.get() );
 				mailitem->viewSprite = data->look;
 				mailitem->viewSprite = data->look;
 				mailitem->bindOnEquip = item->bound ? 2 : data->flag.bindOnEquip ? 1 : 0;
 				mailitem->bindOnEquip = item->bound ? 2 : data->flag.bindOnEquip ? 1 : 0;
 				clif_addcards( &mailitem->slot, item );
 				clif_addcards( &mailitem->slot, item );
@@ -16476,9 +16477,9 @@ void clif_parse_Mail_getattach( int fd, struct map_session_data *sd ){
 			struct item* item = &msg->item[i];
 			struct item* item = &msg->item[i];
 
 
 			if( item->nameid > 0 && item->amount > 0 ){
 			if( item->nameid > 0 && item->amount > 0 ){
-				struct item_data *data;
+				std::shared_ptr<item_data> data = item_db.find(item->nameid);
 
 
-				if((data = itemdb_exists(item->nameid)) == NULL)
+				if(data == nullptr)
 					continue;
 					continue;
 
 
 				switch( pc_checkadditem(sd, item->nameid, item->amount) ){
 				switch( pc_checkadditem(sd, item->nameid, item->amount) ){
@@ -16845,7 +16846,6 @@ void clif_parse_Auction_setitem(int fd, struct map_session_data *sd){
 	struct s_packet_db* info = &packet_db[RFIFOW(fd,0)];
 	struct s_packet_db* info = &packet_db[RFIFOW(fd,0)];
 	int idx = RFIFOW(fd,info->pos[0]) - 2;
 	int idx = RFIFOW(fd,info->pos[0]) - 2;
 	int amount = RFIFOL(fd,info->pos[1]); // Always 1
 	int amount = RFIFOL(fd,info->pos[1]); // Always 1
-	struct item_data *item;
 
 
 	if( !battle_config.feature_auction )
 	if( !battle_config.feature_auction )
 		return;
 		return;
@@ -16863,7 +16863,9 @@ void clif_parse_Auction_setitem(int fd, struct map_session_data *sd){
 		return;
 		return;
 	}
 	}
 
 
-	if( (item = itemdb_exists(sd->inventory.u.items_inventory[idx].nameid)) != NULL && !(item->type == IT_ARMOR || item->type == IT_PETARMOR || item->type == IT_WEAPON || item->type == IT_CARD || item->type == IT_ETC || item->type == IT_SHADOWGEAR) )
+	std::shared_ptr<item_data> id = item_db.find(sd->inventory.u.items_inventory[idx].nameid);
+
+	if( id != nullptr && !(id->type == IT_ARMOR || id->type == IT_PETARMOR || id->type == IT_WEAPON || id->type == IT_CARD || id->type == IT_ETC || id->type == IT_SHADOWGEAR) )
 	{ // Consumable or pets are not allowed
 	{ // Consumable or pets are not allowed
 		clif_Auction_setitem(sd->fd, idx, true);
 		clif_Auction_setitem(sd->fd, idx, true);
 		return;
 		return;
@@ -16925,7 +16927,6 @@ void clif_Auction_close(int fd, unsigned char flag)
 void clif_parse_Auction_register(int fd, struct map_session_data *sd)
 void clif_parse_Auction_register(int fd, struct map_session_data *sd)
 {
 {
 	struct auction_data auction;
 	struct auction_data auction;
-	struct item_data *item;
 	struct s_packet_db* info = &packet_db[RFIFOW(fd,0)];
 	struct s_packet_db* info = &packet_db[RFIFOW(fd,0)];
 
 
 	if( !battle_config.feature_auction )
 	if( !battle_config.feature_auction )
@@ -16980,14 +16981,16 @@ void clif_parse_Auction_register(int fd, struct map_session_data *sd)
 		return;
 		return;
 	}
 	}
 
 
-	if( (item = itemdb_exists(sd->inventory.u.items_inventory[sd->auction.index].nameid)) == NULL )
+	std::shared_ptr<item_data> id = item_db.find(sd->inventory.u.items_inventory[sd->auction.index].nameid);
+
+	if( id == nullptr )
 	{ // Just in case
 	{ // Just in case
 		clif_Auction_message(fd, 2); // The auction has been canceled
 		clif_Auction_message(fd, 2); // The auction has been canceled
 		return;
 		return;
 	}
 	}
 
 
-	safestrncpy(auction.item_name, item->ename.c_str(), sizeof(auction.item_name));
-	auction.type = item->type;
+	safestrncpy(auction.item_name, id->ename.c_str(), sizeof(auction.item_name));
+	auction.type = id->type;
 	memcpy(&auction.item, &sd->inventory.u.items_inventory[sd->auction.index], sizeof(struct item));
 	memcpy(&auction.item, &sd->inventory.u.items_inventory[sd->auction.index], sizeof(struct item));
 	auction.item.amount = 1;
 	auction.item.amount = 1;
 	auction.timestamp = 0;
 	auction.timestamp = 0;
@@ -22788,7 +22791,7 @@ void clif_barter_open( struct map_session_data& sd, struct npc_data& nd ){
 	int16 count = 0;
 	int16 count = 0;
 	for( const auto& itemPair : barter->items ){
 	for( const auto& itemPair : barter->items ){
 		struct PACKET_ZC_NPC_BARTER_MARKET_ITEMINFO_sub* item = &p->list[count];
 		struct PACKET_ZC_NPC_BARTER_MARKET_ITEMINFO_sub* item = &p->list[count];
-		struct item_data* id = itemdb_exists( itemPair.second->nameid );
+		std::shared_ptr<item_data> id = item_db.find(itemPair.second->nameid);
 
 
 		item->nameid = client_nameid( id->nameid );
 		item->nameid = client_nameid( id->nameid );
 		item->type = itemtype( id->nameid );
 		item->type = itemtype( id->nameid );
@@ -22801,7 +22804,7 @@ void clif_barter_open( struct map_session_data& sd, struct npc_data& nd ){
 		item->index = itemPair.second->index;
 		item->index = itemPair.second->index;
 #if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103
 #if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103
 		item->viewSprite = id->look;
 		item->viewSprite = id->look;
-		item->location = pc_equippoint_sub( &sd, id );
+		item->location = pc_equippoint_sub( &sd, id.get() );
 #endif
 #endif
 
 
 		// Use a loop if someone did not start with index 0
 		// Use a loop if someone did not start with index 0
@@ -22938,7 +22941,7 @@ void clif_barter_extended_open( struct map_session_data& sd, struct npc_data& nd
 	for( const auto& itemPair : barter->items ){
 	for( const auto& itemPair : barter->items ){
 		// Needs dynamic calculation, because of variable currencies
 		// Needs dynamic calculation, because of variable currencies
 		struct PACKET_ZC_NPC_EXPANDED_BARTER_MARKET_ITEMINFO_sub* item = (struct PACKET_ZC_NPC_EXPANDED_BARTER_MARKET_ITEMINFO_sub*)( ( (uint8*)p ) + p->packetLength );
 		struct PACKET_ZC_NPC_EXPANDED_BARTER_MARKET_ITEMINFO_sub* item = (struct PACKET_ZC_NPC_EXPANDED_BARTER_MARKET_ITEMINFO_sub*)( ( (uint8*)p ) + p->packetLength );
-		struct item_data* id = itemdb_exists( itemPair.second->nameid );
+		std::shared_ptr<item_data> id = item_db.find(itemPair.second->nameid);
 
 
 		item->nameid = client_nameid( id->nameid );
 		item->nameid = client_nameid( id->nameid );
 		item->type = itemtype( id->nameid );
 		item->type = itemtype( id->nameid );
@@ -22952,7 +22955,7 @@ void clif_barter_extended_open( struct map_session_data& sd, struct npc_data& nd
 		item->zeny = itemPair.second->price;
 		item->zeny = itemPair.second->price;
 #if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103
 #if PACKETVER_MAIN_NUM >= 20210203 || PACKETVER_RE_NUM >= 20211103
 		item->viewSprite = id->look;
 		item->viewSprite = id->look;
-		item->location = pc_equippoint_sub( &sd, id );
+		item->location = pc_equippoint_sub( &sd, id.get() );
 #endif
 #endif
 		
 		
 		p->packetLength += (int16)( sizeof( *item ) - sizeof( item->currencies ) );
 		p->packetLength += (int16)( sizeof( *item ) - sizeof( item->currencies ) );

+ 19 - 20
src/map/itemdb.cpp

@@ -4,7 +4,6 @@
 #include "itemdb.hpp"
 #include "itemdb.hpp"
 
 
 #include <iostream>
 #include <iostream>
-#include <map>
 #include <stdlib.h>
 #include <stdlib.h>
 
 
 #include "../common/nullpo.hpp"
 #include "../common/nullpo.hpp"
@@ -1670,22 +1669,21 @@ LaphineUpgradeDatabase laphine_upgrade_db;
  * @param str
  * @param str
  * @return Number of matches item
  * @return Number of matches item
  *------------------------------------------*/
  *------------------------------------------*/
-uint16 itemdb_searchname_array(struct item_data** data, uint16 size, const char *str)
+uint16 itemdb_searchname_array(std::map<t_itemid, std::shared_ptr<item_data>> &data, uint16 size, const char *str)
 {
 {
-	uint16 count = 0;
-	const auto &item_list = item_db.getCache();
+	for (const auto &item : item_db) {
+		std::shared_ptr<item_data> id = item.second;
 
 
-	for (const auto &item : item_list) {
-		if (item == nullptr)
+		if (id == nullptr)
 			continue;
 			continue;
-		if (count < size) {
-			if (stristr(item->name.c_str(), str) != nullptr || stristr(item->ename.c_str(), str) != nullptr || strcmpi(item->ename.c_str(), str) == 0)
-				data[count++] = item.get();
-		} else
-			break;
+		if (stristr(id->name.c_str(), str) != nullptr || stristr(id->ename.c_str(), str) != nullptr || strcmpi(id->ename.c_str(), str) == 0)
+			data[id->nameid] = id;
 	}
 	}
 
 
-	return count;
+	if (data.size() > size)
+		util::map_resize(data, size);
+
+	return static_cast<uint16>(data.size());
 }
 }
 
 
 std::shared_ptr<s_item_group_entry> get_random_itemsubgroup(std::shared_ptr<s_item_group_random> random) {
 std::shared_ptr<s_item_group_entry> get_random_itemsubgroup(std::shared_ptr<s_item_group_random> random) {
@@ -1844,10 +1842,8 @@ uint8 ItemGroupDatabase::pc_get_itemgroup(uint16 group_id, bool identify, map_se
 * @param nameid
 * @param nameid
 * @return *item_data if item is exist, or NULL if not
 * @return *item_data if item is exist, or NULL if not
 */
 */
-struct item_data* itemdb_exists(t_itemid nameid) {
-	std::shared_ptr<item_data> item = item_db.find(nameid);
-
-	return item ? item.get() : nullptr;
+std::shared_ptr<item_data> itemdb_exists(t_itemid nameid) {
+	return item_db.find(nameid);
 }
 }
 
 
 /// Returns name type of ammunition [Cydh]
 /// Returns name type of ammunition [Cydh]
@@ -2366,12 +2362,13 @@ void ItemGroupDatabase::loadingFinished() {
 static bool itemdb_read_noequip(char* str[], int columns, int current) {
 static bool itemdb_read_noequip(char* str[], int columns, int current) {
 	t_itemid nameid;
 	t_itemid nameid;
 	int flag;
 	int flag;
-	struct item_data *id;
 
 
 	nameid = strtoul(str[0], nullptr, 10);
 	nameid = strtoul(str[0], nullptr, 10);
 	flag = atoi(str[1]);
 	flag = atoi(str[1]);
 
 
-	if( ( id = itemdb_exists(nameid) ) == NULL )
+	std::shared_ptr<item_data> id = item_db.find(nameid);
+
+	if( id == nullptr )
 	{
 	{
 		ShowWarning("itemdb_read_noequip: Invalid item id %u.\n", nameid);
 		ShowWarning("itemdb_read_noequip: Invalid item id %u.\n", nameid);
 		return false;
 		return false;
@@ -2530,8 +2527,10 @@ void ComboDatabase::loadingFinished() {
 	// Populate item_data to refer to the combo
 	// Populate item_data to refer to the combo
 	for (const auto &combo : *this) {
 	for (const auto &combo : *this) {
 		for (const auto &itm : combo.second->nameid) {
 		for (const auto &itm : combo.second->nameid) {
-			item_data *it = itemdb_exists(itm);
-			it->combos.push_back(combo.second);
+			std::shared_ptr<item_data> it = item_db.find(itm);
+
+			if (it != nullptr)
+				it->combos.push_back(combo.second);
 		}
 		}
 	}
 	}
 
 

+ 2 - 2
src/map/itemdb.hpp

@@ -1385,9 +1385,9 @@ public:
 
 
 extern LaphineUpgradeDatabase laphine_upgrade_db;
 extern LaphineUpgradeDatabase laphine_upgrade_db;
 
 
-uint16 itemdb_searchname_array(struct item_data** data, uint16 size, const char *str);
+uint16 itemdb_searchname_array(std::map<t_itemid, std::shared_ptr<item_data>> &data, uint16 size, const char *str);
 struct item_data* itemdb_search(t_itemid nameid);
 struct item_data* itemdb_search(t_itemid nameid);
-struct item_data* itemdb_exists(t_itemid nameid);
+std::shared_ptr<item_data> itemdb_exists(t_itemid nameid);
 #define itemdb_name(n) itemdb_search(n)->name.c_str()
 #define itemdb_name(n) itemdb_search(n)->name.c_str()
 #define itemdb_ename(n) itemdb_search(n)->ename.c_str()
 #define itemdb_ename(n) itemdb_search(n)->ename.c_str()
 #define itemdb_type(n) itemdb_search(n)->type
 #define itemdb_type(n) itemdb_search(n)->type

+ 2 - 2
src/map/log.cpp

@@ -144,9 +144,9 @@ static char log_feedingtype2char(e_log_feeding_type type) {
 static bool should_log_item(t_itemid nameid, int amount, int refine)
 static bool should_log_item(t_itemid nameid, int amount, int refine)
 {
 {
 	int filter = log_config.filter;
 	int filter = log_config.filter;
-	struct item_data* id;
+	std::shared_ptr<item_data> id = item_db.find(nameid);
 
 
-	if( ( id = itemdb_exists(nameid) ) == NULL )
+	if( id == nullptr )
 		return false;
 		return false;
 
 
 	if( ( filter&LOG_FILTER_ALL ) ||
 	if( ( filter&LOG_FILTER_ALL ) ||

+ 10 - 5
src/map/mob.cpp

@@ -313,7 +313,7 @@ std::shared_ptr<s_mob_db> mobdb_search_aegisname( const char* str ){
 }
 }
 
 
 /*==========================================
 /*==========================================
- * Founds up to N matches. Returns number of matches [Skotlex]
+ * Searches up to N matches. Returns number of matches [Skotlex]
  *------------------------------------------*/
  *------------------------------------------*/
 uint16 mobdb_searchname_array_(const char *str, uint16 * out, uint16 size, bool full_cmp)
 uint16 mobdb_searchname_array_(const char *str, uint16 * out, uint16 size, bool full_cmp)
 {
 {
@@ -2787,7 +2787,6 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 	{ // Item Drop
 	{ // Item Drop
 		struct item_drop_list *dlist = ers_alloc(item_drop_list_ers, struct item_drop_list);
 		struct item_drop_list *dlist = ers_alloc(item_drop_list_ers, struct item_drop_list);
 		struct item_drop *ditem;
 		struct item_drop *ditem;
-		struct item_data* it = NULL;
 		int drop_rate, drop_modifier = 100;
 		int drop_rate, drop_modifier = 100;
 
 
 #ifdef RENEWAL_DROP
 #ifdef RENEWAL_DROP
@@ -2804,7 +2803,10 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 		for (i = 0; i < MAX_MOB_DROP_TOTAL; i++) {
 		for (i = 0; i < MAX_MOB_DROP_TOTAL; i++) {
 			if (md->db->dropitem[i].nameid == 0)
 			if (md->db->dropitem[i].nameid == 0)
 				continue;
 				continue;
-			if ( !(it = itemdb_exists(md->db->dropitem[i].nameid)) )
+
+			std::shared_ptr<item_data> it = item_db.find(md->db->dropitem[i].nameid);
+
+			if ( it == nullptr )
 				continue;
 				continue;
 			
 			
 			drop_rate = mob_getdroprate(src, md->db, md->db->dropitem[i].rate, drop_modifier);
 			drop_rate = mob_getdroprate(src, md->db, md->db->dropitem[i].rate, drop_modifier);
@@ -2966,9 +2968,12 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 #endif
 #endif
 
 
 			for(i = 0; i < MAX_MVP_DROP_TOTAL; i++) {
 			for(i = 0; i < MAX_MVP_DROP_TOTAL; i++) {
-				struct item_data *i_data;
+				if(mdrop[i].nameid == 0)
+					continue;
+
+				std::shared_ptr<item_data> i_data = item_db.find(mdrop[i].nameid);
 
 
-				if(mdrop[i].nameid == 0 || !(i_data = itemdb_exists(mdrop[i].nameid)))
+				if (i_data == nullptr)
 					continue;
 					continue;
 
 
 				temp = mdrop[i].rate;
 				temp = mdrop[i].rate;

+ 22 - 21
src/map/npc.cpp

@@ -2343,7 +2343,7 @@ static enum e_CASHSHOP_ACK npc_cashshop_process_payment(struct npc_data *nd, int
 			break;
 			break;
 		case NPCTYPE_ITEMSHOP:
 		case NPCTYPE_ITEMSHOP:
 			{
 			{
-				struct item_data *id = itemdb_exists(nd->u.shop.itemshop_nameid);
+				std::shared_ptr<item_data> id = item_db.find(nd->u.shop.itemshop_nameid);
 				int delete_amount = price, i;
 				int delete_amount = price, i;
 
 
 				if (!id) { // Item Data is checked at script parsing but in case of item_db reload, check again.
 				if (!id) { // Item Data is checked at script parsing but in case of item_db reload, check again.
@@ -2418,7 +2418,6 @@ int npc_cashshop_buylist( struct map_session_data *sd, int points, std::vector<s
 	t_itemid nameid;
 	t_itemid nameid;
 	struct npc_data *nd = (struct npc_data *)map_id2bl(sd->npc_shopid);
 	struct npc_data *nd = (struct npc_data *)map_id2bl(sd->npc_shopid);
 	enum e_CASHSHOP_ACK res;
 	enum e_CASHSHOP_ACK res;
-	item_data *id;
 
 
 	if( !nd || ( nd->subtype != NPCTYPE_CASHSHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP ) )
 	if( !nd || ( nd->subtype != NPCTYPE_CASHSHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP ) )
 		return ERROR_TYPE_NPC;
 		return ERROR_TYPE_NPC;
@@ -2434,7 +2433,8 @@ int npc_cashshop_buylist( struct map_session_data *sd, int points, std::vector<s
 	{
 	{
 		nameid = item_list[i].nameid;
 		nameid = item_list[i].nameid;
 		amount = item_list[i].qty;
 		amount = item_list[i].qty;
-		id = itemdb_exists(nameid);
+
+		std::shared_ptr<item_data> id = item_db.find(nameid);
 
 
 		if( !id || amount <= 0 )
 		if( !id || amount <= 0 )
 			return ERROR_TYPE_ITEM_ID;
 			return ERROR_TYPE_ITEM_ID;
@@ -2445,7 +2445,7 @@ int npc_cashshop_buylist( struct map_session_data *sd, int points, std::vector<s
 
 
 		nameid = item_list[i].nameid = nd->u.shop.shop_item[j].nameid; //item_avail replacement
 		nameid = item_list[i].nameid = nd->u.shop.shop_item[j].nameid; //item_avail replacement
 
 
-		if( !itemdb_isstackable2(id) && amount > 1 )
+		if( !itemdb_isstackable2(id.get()) && amount > 1 )
 		{
 		{
 			ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of nonstackable item %u!\n", sd->status.name, sd->status.account_id, sd->status.char_id, amount, nameid);
 			ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of nonstackable item %u!\n", sd->status.name, sd->status.account_id, sd->status.char_id, amount, nameid);
 			amount = item_list[i].qty = 1;
 			amount = item_list[i].qty = 1;
@@ -2529,7 +2529,7 @@ void npc_shop_currency_type(struct map_session_data *sd, struct npc_data *nd, in
 		case NPCTYPE_ITEMSHOP:
 		case NPCTYPE_ITEMSHOP:
 		{
 		{
 			int total = 0, i;
 			int total = 0, i;
-			struct item_data *id = itemdb_exists(nd->u.shop.itemshop_nameid);
+			std::shared_ptr<item_data> id = item_db.find(nd->u.shop.itemshop_nameid);
 
 
 			if (id) { // Item Data is checked at script parsing but in case of item_db reload, check again.
 			if (id) { // Item Data is checked at script parsing but in case of item_db reload, check again.
 				if (display) {
 				if (display) {
@@ -2576,7 +2576,6 @@ void npc_shop_currency_type(struct map_session_data *sd, struct npc_data *nd, in
 int npc_cashshop_buy(struct map_session_data *sd, t_itemid nameid, int amount, int points)
 int npc_cashshop_buy(struct map_session_data *sd, t_itemid nameid, int amount, int points)
 {
 {
 	struct npc_data *nd = (struct npc_data *)map_id2bl(sd->npc_shopid);
 	struct npc_data *nd = (struct npc_data *)map_id2bl(sd->npc_shopid);
-	struct item_data *item;
 	int i, price, w;
 	int i, price, w;
 	enum e_CASHSHOP_ACK res;
 	enum e_CASHSHOP_ACK res;
 
 
@@ -2592,7 +2591,9 @@ int npc_cashshop_buy(struct map_session_data *sd, t_itemid nameid, int amount, i
 	if( sd->state.trading )
 	if( sd->state.trading )
 		return ERROR_TYPE_EXCHANGE;
 		return ERROR_TYPE_EXCHANGE;
 
 
-	if( (item = itemdb_exists(nameid)) == NULL )
+	std::shared_ptr<item_data> id = item_db.find(nameid);
+
+	if( id == nullptr )
 		return ERROR_TYPE_ITEM_ID; // Invalid Item
 		return ERROR_TYPE_ITEM_ID; // Invalid Item
 
 
 	ARR_FIND(0, nd->u.shop.count, i, nd->u.shop.shop_item[i].nameid == nameid || itemdb_viewid(nd->u.shop.shop_item[i].nameid) == nameid);
 	ARR_FIND(0, nd->u.shop.count, i, nd->u.shop.shop_item[i].nameid == nameid || itemdb_viewid(nd->u.shop.shop_item[i].nameid) == nameid);
@@ -2603,7 +2604,7 @@ int npc_cashshop_buy(struct map_session_data *sd, t_itemid nameid, int amount, i
 
 
 	nameid = nd->u.shop.shop_item[i].nameid; //item_avail replacement
 	nameid = nd->u.shop.shop_item[i].nameid; //item_avail replacement
 
 
-	if(!itemdb_isstackable2(item) && amount > 1)
+	if(!itemdb_isstackable2(id.get()) && amount > 1)
 	{
 	{
 		ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of nonstackable item %u!\n",
 		ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of nonstackable item %u!\n",
 			sd->status.name, sd->status.account_id, sd->status.char_id, amount, nameid);
 			sd->status.name, sd->status.account_id, sd->status.char_id, amount, nameid);
@@ -2613,20 +2614,20 @@ int npc_cashshop_buy(struct map_session_data *sd, t_itemid nameid, int amount, i
 	switch( pc_checkadditem(sd, nameid, amount) )
 	switch( pc_checkadditem(sd, nameid, amount) )
 	{
 	{
 		case CHKADDITEM_NEW:
 		case CHKADDITEM_NEW:
-			if( pc_inventoryblank(sd) < item->inventorySlotNeeded(amount) )
+			if( pc_inventoryblank(sd) < id->inventorySlotNeeded(amount) )
 				return ERROR_TYPE_INVENTORY_WEIGHT;
 				return ERROR_TYPE_INVENTORY_WEIGHT;
 			break;
 			break;
 		case CHKADDITEM_OVERAMOUNT:
 		case CHKADDITEM_OVERAMOUNT:
 			return ERROR_TYPE_INVENTORY_WEIGHT;
 			return ERROR_TYPE_INVENTORY_WEIGHT;
 	}
 	}
 
 
-	w = item->weight * amount;
+	w = id->weight * amount;
 	if( w + sd->weight > sd->max_weight )
 	if( w + sd->weight > sd->max_weight )
 		return ERROR_TYPE_INVENTORY_WEIGHT;
 		return ERROR_TYPE_INVENTORY_WEIGHT;
 
 
 	if( (double)nd->u.shop.shop_item[i].value * amount > INT_MAX )
 	if( (double)nd->u.shop.shop_item[i].value * amount > INT_MAX )
 	{
 	{
-		ShowWarning("npc_cashshop_buy: Item '%s' (%u) price overflow attempt!\n", item->name.c_str(), nameid);
+		ShowWarning("npc_cashshop_buy: Item '%s' (%u) price overflow attempt!\n", id->name.c_str(), nameid);
 		ShowDebug("(NPC:'%s' (%s,%d,%d), player:'%s' (%d/%d), value:%d, amount:%d)\n",
 		ShowDebug("(NPC:'%s' (%s,%d,%d), player:'%s' (%d/%d), value:%d, amount:%d)\n",
 					nd->exname, map_mapid2mapname(nd->bl.m), nd->bl.x, nd->bl.y, sd->status.name, sd->status.account_id, sd->status.char_id, nd->u.shop.shop_item[i].value, amount);
 					nd->exname, map_mapid2mapname(nd->bl.m), nd->bl.x, nd->bl.y, sd->status.name, sd->status.account_id, sd->status.char_id, nd->u.shop.shop_item[i].value, amount);
 		return ERROR_TYPE_ITEM_ID;
 		return ERROR_TYPE_ITEM_ID;
@@ -2647,7 +2648,7 @@ int npc_cashshop_buy(struct map_session_data *sd, t_itemid nameid, int amount, i
 		item_tmp.nameid = nameid;
 		item_tmp.nameid = nameid;
 		item_tmp.identify = 1;
 		item_tmp.identify = 1;
 
 
-		if (item->flag.guid)
+		if (id->flag.guid)
 			get_amt = 1;
 			get_amt = 1;
 
 
 		for (int j = 0; j < amount; j += get_amt)
 		for (int j = 0; j < amount; j += get_amt)
@@ -2722,7 +2723,6 @@ e_purchase_result npc_buylist( struct map_session_data* sd, std::vector<s_npc_bu
 		t_itemid nameid;
 		t_itemid nameid;
 		unsigned short amount;
 		unsigned short amount;
 		int value;
 		int value;
-		item_data *id;
 
 
 		// find this entry in the shop's sell list
 		// find this entry in the shop's sell list
 		ARR_FIND( 0, nd->u.shop.count, j,
 		ARR_FIND( 0, nd->u.shop.count, j,
@@ -2744,12 +2744,13 @@ e_purchase_result npc_buylist( struct map_session_data* sd, std::vector<s_npc_bu
 		amount = item_list[i].qty;
 		amount = item_list[i].qty;
 		nameid = item_list[i].nameid = shop[j].nameid; //item_avail replacement
 		nameid = item_list[i].nameid = shop[j].nameid; //item_avail replacement
 		value = shop[j].value;
 		value = shop[j].value;
-		id = itemdb_exists(nameid);
+
+		std::shared_ptr<item_data> id = item_db.find(nameid);
 
 
 		if( !id )
 		if( !id )
 			return e_purchase_result::PURCHASE_FAIL_COUNT; // item no longer in itemdb
 			return e_purchase_result::PURCHASE_FAIL_COUNT; // item no longer in itemdb
 
 
-		if( !itemdb_isstackable2(id) && amount > 1 ) { //Exploit? You can't buy more than 1 of equipment types o.O
+		if( !itemdb_isstackable2(id.get()) && amount > 1 ) { //Exploit? You can't buy more than 1 of equipment types o.O
 			ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of nonstackable item %u!\n",
 			ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of nonstackable item %u!\n",
 				sd->status.name, sd->status.account_id, sd->status.char_id, amount, nameid);
 				sd->status.name, sd->status.account_id, sd->status.char_id, amount, nameid);
 			amount = item_list[i].qty = 1;
 			amount = item_list[i].qty = 1;
@@ -3046,7 +3047,7 @@ e_purchase_result npc_barter_purchase( struct map_session_data& sd, std::shared_
 	uint32 requiredItems[MAX_INVENTORY] = { 0 };
 	uint32 requiredItems[MAX_INVENTORY] = { 0 };
 
 
 	for( s_barter_purchase& purchase : purchases ){
 	for( s_barter_purchase& purchase : purchases ){
-		purchase.data = itemdb_exists( purchase.item->nameid );
+		purchase.data = item_db.find( purchase.item->nameid ).get();
 
 
 		if( purchase.data == nullptr ){
 		if( purchase.data == nullptr ){
 			return e_purchase_result::PURCHASE_FAIL_EXCHANGE_FAILED;
 			return e_purchase_result::PURCHASE_FAIL_EXCHANGE_FAILED;
@@ -3071,14 +3072,13 @@ e_purchase_result npc_barter_purchase( struct map_session_data& sd, std::shared_
 
 
 		for( const auto& requirementPair : purchase.item->requirements ){
 		for( const auto& requirementPair : purchase.item->requirements ){
 			std::shared_ptr<s_npc_barter_requirement> requirement = requirementPair.second;
 			std::shared_ptr<s_npc_barter_requirement> requirement = requirementPair.second;
-
-			item_data* id = itemdb_exists( requirement->nameid );
+			std::shared_ptr<item_data> id = item_db.find(requirement->nameid);
 
 
 			if( id == nullptr ){
 			if( id == nullptr ){
 				return e_purchase_result::PURCHASE_FAIL_EXCHANGE_FAILED;
 				return e_purchase_result::PURCHASE_FAIL_EXCHANGE_FAILED;
 			}
 			}
 
 
-			if( itemdb_isstackable2( id ) ){
+			if( itemdb_isstackable2( id.get() ) ){
 				int j;
 				int j;
 
 
 				for( j = 0; j < MAX_INVENTORY; j++ ){
 				for( j = 0; j < MAX_INVENTORY; j++ ){
@@ -3985,7 +3985,6 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const
 		t_itemid nameid2;
 		t_itemid nameid2;
 		int32 qty = -1;
 		int32 qty = -1;
 		int value;
 		int value;
-		struct item_data* id;
 		bool skip = false;
 		bool skip = false;
 
 
 		if( p == NULL )
 		if( p == NULL )
@@ -4010,7 +4009,9 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const
 		if (skip)
 		if (skip)
 			break;
 			break;
 
 
-		if( (id = itemdb_exists(nameid2)) == NULL ) {
+		std::shared_ptr<item_data> id = item_db.find(nameid2);
+
+		if( id == nullptr ) {
 			ShowWarning("npc_parse_shop: Invalid sell item in file '%s', line '%d' (id '%u').\n", filepath, strline(buffer,start-buffer), nameid2);
 			ShowWarning("npc_parse_shop: Invalid sell item in file '%s', line '%d' (id '%u').\n", filepath, strline(buffer,start-buffer), nameid2);
 			p = strchr(p+1,',');
 			p = strchr(p+1,',');
 			continue;
 			continue;

+ 27 - 22
src/map/pc.cpp

@@ -6138,17 +6138,17 @@ int pc_show_steal(struct block_list *bl,va_list ap)
 {
 {
 	struct map_session_data *sd;
 	struct map_session_data *sd;
 	t_itemid itemid;
 	t_itemid itemid;
-
-	struct item_data *item=NULL;
 	char output[100];
 	char output[100];
 
 
 	sd=va_arg(ap,struct map_session_data *);
 	sd=va_arg(ap,struct map_session_data *);
 	itemid=va_arg(ap,int);
 	itemid=va_arg(ap,int);
 
 
-	if((item=itemdb_exists(itemid))==NULL)
+	std::shared_ptr<item_data> id = item_db.find(itemid);
+
+	if(id == nullptr)
 		sprintf(output,"%s stole an Unknown Item (id: %u).",sd->status.name, itemid);
 		sprintf(output,"%s stole an Unknown Item (id: %u).",sd->status.name, itemid);
 	else
 	else
-		sprintf(output,"%s stole %s.",sd->status.name,item->ename.c_str());
+		sprintf(output,"%s stole %s.",sd->status.name,id->ename.c_str());
 	clif_displaymessage( ((struct map_session_data *)bl)->fd, output);
 	clif_displaymessage( ((struct map_session_data *)bl)->fd, output);
 
 
 	return 0;
 	return 0;
@@ -11314,15 +11314,15 @@ int pc_load_combo(struct map_session_data *sd) {
 			ret += pc_checkcombo(sd, id);
 			ret += pc_checkcombo(sd, id);
 
 
 		if (!itemdb_isspecial(sd->inventory.u.items_inventory[idx].card[0])) {
 		if (!itemdb_isspecial(sd->inventory.u.items_inventory[idx].card[0])) {
-			item_data *data;
-
 			for (uint8 j = 0; j < MAX_SLOTS; j++) {
 			for (uint8 j = 0; j < MAX_SLOTS; j++) {
 				if (!sd->inventory.u.items_inventory[idx].card[j])
 				if (!sd->inventory.u.items_inventory[idx].card[j])
 					continue;
 					continue;
 
 
-				if ((data = itemdb_exists(sd->inventory.u.items_inventory[idx].card[j])) != nullptr) {
+				std::shared_ptr<item_data> data = item_db.find(sd->inventory.u.items_inventory[idx].card[j]);
+
+				if (data != nullptr) {
 					if (!data->combos.empty())
 					if (!data->combos.empty())
-						ret += pc_checkcombo(sd, data);
+						ret += pc_checkcombo(sd, data.get());
 				}
 				}
 			}
 			}
 		}
 		}
@@ -11415,7 +11415,7 @@ bool pc_equipitem(struct map_session_data *sd,short n,int req_pos,bool equipswit
 			if (!sd->inventory.u.items_inventory[n].card[i])
 			if (!sd->inventory.u.items_inventory[n].card[i])
 				continue;
 				continue;
 
 
-			struct item_data *card_data = itemdb_exists(sd->inventory.u.items_inventory[n].card[i]);
+			std::shared_ptr<item_data> card_data = item_db.find(sd->inventory.u.items_inventory[n].card[i]);
 
 
 			if (card_data) {
 			if (card_data) {
 				int card_pos = card_data->equip;
 				int card_pos = card_data->equip;
@@ -11560,13 +11560,14 @@ bool pc_equipitem(struct map_session_data *sd,short n,int req_pos,bool equipswit
 		; // No cards
 		; // No cards
 	else {
 	else {
 		for (i = 0; i < MAX_SLOTS; i++) {
 		for (i = 0; i < MAX_SLOTS; i++) {
-			item_data *data;
-
 			if (!sd->inventory.u.items_inventory[n].card[i])
 			if (!sd->inventory.u.items_inventory[n].card[i])
 				continue;
 				continue;
-			if ((data = itemdb_exists(sd->inventory.u.items_inventory[n].card[i])) != nullptr) {
+
+			std::shared_ptr<item_data> data = item_db.find(sd->inventory.u.items_inventory[n].card[i]);
+
+			if (data != nullptr) {
 				if (!data->combos.empty())
 				if (!data->combos.empty())
-					pc_checkcombo(sd, data);
+					pc_checkcombo(sd, data.get());
 			}
 			}
 		}
 		}
 	}
 	}
@@ -11584,11 +11585,13 @@ bool pc_equipitem(struct map_session_data *sd,short n,int req_pos,bool equipswit
 			; //No cards
 			; //No cards
 		else {
 		else {
 			for( i = 0; i < MAX_SLOTS; i++ ) {
 			for( i = 0; i < MAX_SLOTS; i++ ) {
-				struct item_data *data;
 				if (!sd->inventory.u.items_inventory[n].card[i])
 				if (!sd->inventory.u.items_inventory[n].card[i])
 					continue;
 					continue;
-				if ( ( data = itemdb_exists(sd->inventory.u.items_inventory[n].card[i]) ) != NULL ) {
-					if (data->equip_script && (pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT) || !itemdb_isNoEquip(data,sd->bl.m)))
+
+				std::shared_ptr<item_data> data = item_db.find(sd->inventory.u.items_inventory[n].card[i]);
+
+				if ( data != nullptr ) {
+					if (data->equip_script && (pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT) || !itemdb_isNoEquip(data.get(), sd->bl.m)))
 						run_script(data->equip_script,0,sd->bl.id,fake_nd->bl.id);
 						run_script(data->equip_script,0,sd->bl.id,fake_nd->bl.id);
 				}
 				}
 			}
 			}
@@ -11645,13 +11648,14 @@ static void pc_unequipitem_sub(struct map_session_data *sd, int n, int flag) {
 			; // No cards
 			; // No cards
 		else {
 		else {
 			for (i = 0; i < MAX_SLOTS; i++) {
 			for (i = 0; i < MAX_SLOTS; i++) {
-				item_data *data;
-
 				if (!sd->inventory.u.items_inventory[n].card[i])
 				if (!sd->inventory.u.items_inventory[n].card[i])
 					continue;
 					continue;
-				if ((data = itemdb_exists(sd->inventory.u.items_inventory[n].card[i])) != nullptr) {
+
+				std::shared_ptr<item_data> data = item_db.find(sd->inventory.u.items_inventory[n].card[i]);
+
+				if (data != nullptr) {
 					if (!data->combos.empty()) {
 					if (!data->combos.empty()) {
-						if (pc_removecombo(sd, data))
+						if (pc_removecombo(sd, data.get()))
 							status_calc = true;
 							status_calc = true;
 					}
 					}
 				}
 				}
@@ -11675,11 +11679,12 @@ static void pc_unequipitem_sub(struct map_session_data *sd, int n, int flag) {
 			; //No cards
 			; //No cards
 		else {
 		else {
 			for (i = 0; i < MAX_SLOTS; i++) {
 			for (i = 0; i < MAX_SLOTS; i++) {
-				struct item_data *data;
 				if (!sd->inventory.u.items_inventory[n].card[i])
 				if (!sd->inventory.u.items_inventory[n].card[i])
 					continue;
 					continue;
 
 
-				if ((data = itemdb_exists(sd->inventory.u.items_inventory[n].card[i])) != NULL) {
+				std::shared_ptr<item_data> data = item_db.find(sd->inventory.u.items_inventory[n].card[i]);
+
+				if (data != nullptr) {
 					if (data->unequip_script)
 					if (data->unequip_script)
 						run_script(data->unequip_script, 0, sd->bl.id, fake_nd->bl.id);
 						run_script(data->unequip_script, 0, sd->bl.id, fake_nd->bl.id);
 				}
 				}

+ 22 - 27
src/map/script.cpp

@@ -14215,13 +14215,10 @@ BUILDIN_FUNC(getitemname)
  *------------------------------------------*/
  *------------------------------------------*/
 BUILDIN_FUNC(getitemslots)
 BUILDIN_FUNC(getitemslots)
 {
 {
-	struct item_data *i_data;
-
 	t_itemid item_id=script_getnum(st,2);
 	t_itemid item_id=script_getnum(st,2);
+	std::shared_ptr<item_data> i_data = item_db.find(item_id);
 
 
-	i_data = itemdb_exists(item_id);
-
-	if (i_data)
+	if (i_data != nullptr)
 		script_pushint(st,i_data->slots);
 		script_pushint(st,i_data->slots);
 	else
 	else
 		script_pushint(st,-1);
 		script_pushint(st,-1);
@@ -16311,18 +16308,19 @@ BUILDIN_FUNC(unequip) {
  **/
  **/
 BUILDIN_FUNC(equip) {
 BUILDIN_FUNC(equip) {
 	TBL_PC *sd;
 	TBL_PC *sd;
-	struct item_data *item_data;
 
 
 	if (!script_charid2sd(3,sd))
 	if (!script_charid2sd(3,sd))
 		return SCRIPT_CMD_FAILURE;
 		return SCRIPT_CMD_FAILURE;
 
 
 	t_itemid nameid = script_getnum(st,2);
 	t_itemid nameid = script_getnum(st,2);
-	if ((item_data = itemdb_exists(nameid))) {
+	std::shared_ptr<item_data> id = item_db.find(nameid);
+
+	if (id == nullptr) {
 		int i;
 		int i;
 
 
 		ARR_FIND( 0, MAX_INVENTORY, i, sd->inventory.u.items_inventory[i].nameid == nameid );
 		ARR_FIND( 0, MAX_INVENTORY, i, sd->inventory.u.items_inventory[i].nameid == nameid );
 		if (i < MAX_INVENTORY) {
 		if (i < MAX_INVENTORY) {
-			pc_equipitem(sd,i,item_data->equip);
+			pc_equipitem(sd,i,id->equip);
 			script_pushint(st,1);
 			script_pushint(st,1);
 			return SCRIPT_CMD_SUCCESS;
 			return SCRIPT_CMD_SUCCESS;
 		}
 		}
@@ -16335,24 +16333,23 @@ BUILDIN_FUNC(equip) {
 
 
 BUILDIN_FUNC(autoequip)
 BUILDIN_FUNC(autoequip)
 {
 {
-	int flag;
-	struct item_data *item_data;
 	t_itemid nameid=script_getnum(st,2);
 	t_itemid nameid=script_getnum(st,2);
-	flag=script_getnum(st,3);
+	int flag=script_getnum(st,3);
+	std::shared_ptr<item_data> id = item_db.find(nameid);
 
 
-	if( ( item_data = itemdb_exists(nameid) ) == NULL )
+	if( id == nullptr )
 	{
 	{
 		ShowError("buildin_autoequip: Invalid item '%u'.\n", nameid);
 		ShowError("buildin_autoequip: Invalid item '%u'.\n", nameid);
 		return SCRIPT_CMD_FAILURE;
 		return SCRIPT_CMD_FAILURE;
 	}
 	}
 
 
-	if( !itemdb_isequip2(item_data) )
+	if( !itemdb_isequip2(id.get()) )
 	{
 	{
 		ShowError("buildin_autoequip: Item '%u' cannot be equipped.\n", nameid);
 		ShowError("buildin_autoequip: Item '%u' cannot be equipped.\n", nameid);
 		return SCRIPT_CMD_FAILURE;
 		return SCRIPT_CMD_FAILURE;
 	}
 	}
 
 
-	item_data->flag.autoequip = flag>0?1:0;
+	id->flag.autoequip = flag>0?1:0;
 	return SCRIPT_CMD_SUCCESS;
 	return SCRIPT_CMD_SUCCESS;
 }
 }
 
 
@@ -17784,14 +17781,14 @@ BUILDIN_FUNC(setitemscript)
 {
 {
 	int n = 0;
 	int n = 0;
 	const char *script;
 	const char *script;
-	struct item_data *i_data;
 	struct script_code **dstscript;
 	struct script_code **dstscript;
 
 
 	t_itemid item_id = script_getnum(st,2);
 	t_itemid item_id = script_getnum(st,2);
 	script = script_getstr(st,3);
 	script = script_getstr(st,3);
 	if( script_hasdata(st,4) )
 	if( script_hasdata(st,4) )
 		n=script_getnum(st,4);
 		n=script_getnum(st,4);
-	i_data = itemdb_exists(item_id);
+
+	std::shared_ptr<item_data> i_data = item_db.find(item_id);
 
 
 	if (!i_data || script==NULL || ( script[0] && script[0]!='{' )) {
 	if (!i_data || script==NULL || ( script[0] && script[0]!='{' )) {
 		script_pushint(st,0);
 		script_pushint(st,0);
@@ -17845,7 +17842,7 @@ BUILDIN_FUNC(addmonsterdrop)
 	}
 	}
 
 
 	t_itemid item_id = script_getnum(st, 3);
 	t_itemid item_id = script_getnum(st, 3);
-	item_data *itm = itemdb_exists(item_id);
+	std::shared_ptr<item_data> itm = item_db.find(item_id);
 
 
 	if (itm == nullptr) {
 	if (itm == nullptr) {
 		ShowError("addmonsterdrop: Nonexistant item %u requested.\n", item_id);
 		ShowError("addmonsterdrop: Nonexistant item %u requested.\n", item_id);
@@ -18085,7 +18082,7 @@ BUILDIN_FUNC(searchitem)
 {
 {
 	struct script_data* data = script_getdata(st, 2);
 	struct script_data* data = script_getdata(st, 2);
 	const char *itemname = script_getstr(st,3);
 	const char *itemname = script_getstr(st,3);
-	struct item_data *items[MAX_SEARCH];
+	std::map<t_itemid, std::shared_ptr<item_data>> items;
 	int count;
 	int count;
 
 
 	char* name;
 	char* name;
@@ -18094,10 +18091,10 @@ BUILDIN_FUNC(searchitem)
 	int32 i;
 	int32 i;
 	TBL_PC* sd = NULL;
 	TBL_PC* sd = NULL;
 
 
-	if ((items[0] = itemdb_exists(atoi(itemname))))
+	if ((items[0] = item_db.find(strtoul(itemname, nullptr, 10))))
 		count = 1;
 		count = 1;
 	else
 	else
-		count = itemdb_searchname_array(items, ARRAYLENGTH(items), itemname);
+		count = itemdb_searchname_array(items, MAX_SEARCH, itemname);
 
 
 	if (!count) {
 	if (!count) {
 		script_pushint(st, 0);
 		script_pushint(st, 0);
@@ -25208,15 +25205,15 @@ BUILDIN_FUNC(mail){
 		}
 		}
 
 
 		for( i = 0; i < num_items && start < end; i++, start++ ){
 		for( i = 0; i < num_items && start < end; i++, start++ ){
-			struct item_data *item = itemdb_exists(msg.item[i].nameid);
+			std::shared_ptr<item_data> itm = item_db.find(msg.item[i].nameid);
 
 
 			msg.item[i].amount = (short)get_val2_num( st, reference_uid( id, start ), reference_getref( data ) );
 			msg.item[i].amount = (short)get_val2_num( st, reference_uid( id, start ), reference_getref( data ) );
 
 
 			if( msg.item[i].amount <= 0 ){
 			if( msg.item[i].amount <= 0 ){
 				ShowError( "buildin_mail: amount %d for item %u is invalid.\n", msg.item[i].amount, msg.item[i].nameid );
 				ShowError( "buildin_mail: amount %d for item %u is invalid.\n", msg.item[i].amount, msg.item[i].nameid );
 				return SCRIPT_CMD_FAILURE;
 				return SCRIPT_CMD_FAILURE;
-			}else if( itemdb_isstackable2(item) ){
-				uint16 max = item->stack.amount > 0 ? item->stack.amount : MAX_AMOUNT;
+			}else if( itemdb_isstackable2(itm.get()) ){
+				uint16 max = itm->stack.amount > 0 ? itm->stack.amount : MAX_AMOUNT;
 
 
 				if( msg.item[i].amount > max ){
 				if( msg.item[i].amount > max ){
 					ShowWarning( "buildin_mail: amount %d for item %u is exceeding the maximum of %d. Capping...\n", msg.item[i].amount, msg.item[i].nameid, max );
 					ShowWarning( "buildin_mail: amount %d for item %u is exceeding the maximum of %d. Capping...\n", msg.item[i].amount, msg.item[i].nameid, max );
@@ -25242,11 +25239,11 @@ BUILDIN_FUNC(mail){
 		}
 		}
 
 
 		for (i = 0; i < num_items && start < end; i++, start++) {
 		for (i = 0; i < num_items && start < end; i++, start++) {
-			struct item_data* item = itemdb_exists(msg.item[i].nameid);
+			std::shared_ptr<item_data> itm = item_db.find(msg.item[i].nameid);
 
 
 			msg.item[i].refine = (char)get_val2_num( st, reference_uid( id, start ), reference_getref( data ) );
 			msg.item[i].refine = (char)get_val2_num( st, reference_uid( id, start ), reference_getref( data ) );
 
 
-			if (!item->flag.no_refine && (item->type == IT_WEAPON || item->type == IT_ARMOR || item->type == IT_SHADOWGEAR)) {
+			if (!itm->flag.no_refine && (itm->type == IT_WEAPON || itm->type == IT_ARMOR || itm->type == IT_SHADOWGEAR)) {
 				if (msg.item[i].refine > MAX_REFINE)
 				if (msg.item[i].refine > MAX_REFINE)
 					msg.item[i].refine = MAX_REFINE;
 					msg.item[i].refine = MAX_REFINE;
 			}
 			}
@@ -25268,8 +25265,6 @@ BUILDIN_FUNC(mail){
 		}
 		}
 
 
 		for( i = 0; i < num_items && start < end; i++, start++ ){
 		for( i = 0; i < num_items && start < end; i++, start++ ){
-			struct item_data *item = itemdb_exists(msg.item[i].nameid);
-
 			msg.item[i].bound = (char)get_val2_num( st, reference_uid( id, start ), reference_getref( data ) );
 			msg.item[i].bound = (char)get_val2_num( st, reference_uid( id, start ), reference_getref( data ) );
 
 
 			if( msg.item[i].bound < BOUND_NONE || msg.item[i].bound >= BOUND_MAX ){
 			if( msg.item[i].bound < BOUND_NONE || msg.item[i].bound >= BOUND_MAX ){

+ 1 - 1
src/map/skill.cpp

@@ -24051,7 +24051,7 @@ void SkillDatabase::loadingFinished(){
 		ShowError( "There are more skills defined in the skill database (%d) than the MAX_SKILL (%d) define. Please increase it and recompile.\n", this->skill_num, MAX_SKILL );
 		ShowError( "There are more skills defined in the skill database (%d) than the MAX_SKILL (%d) define. Please increase it and recompile.\n", this->skill_num, MAX_SKILL );
 	}
 	}
 
 
-	TypesafeYamlDatabase::loadingFinished();
+	TypesafeCachedYamlDatabase::loadingFinished();
 }
 }
 
 
 /**
 /**

+ 10 - 8
src/map/status.cpp

@@ -3790,10 +3790,10 @@ int status_calc_pc_sub(struct map_session_data* sd, uint8 opt)
 
 
 			// Check combo items
 			// Check combo items
 			while (j < item_combo->nameid.size()) {
 			while (j < item_combo->nameid.size()) {
-				item_data *id = itemdb_exists(item_combo->nameid[j]);
+				std::shared_ptr<item_data> id = item_db.find(item_combo->nameid[j]);
 
 
 				// Don't run the script if at least one of combo's pair has restriction
 				// Don't run the script if at least one of combo's pair has restriction
-				if (id && !pc_has_permission(sd, PC_PERM_USE_ALL_EQUIPMENT) && itemdb_isNoEquip(id, sd->bl.m)) {
+				if (id && !pc_has_permission(sd, PC_PERM_USE_ALL_EQUIPMENT) && itemdb_isNoEquip(id.get(), sd->bl.m)) {
 					no_run = true;
 					no_run = true;
 					break;
 					break;
 				}
 				}
@@ -3830,7 +3830,6 @@ int status_calc_pc_sub(struct map_session_data* sd, uint8 opt)
 
 
 		if (sd->inventory_data[index]) {
 		if (sd->inventory_data[index]) {
 			int j;
 			int j;
-			struct item_data *data;
 
 
 			// Card script execution.
 			// Card script execution.
 			if (itemdb_isspecial(sd->inventory.u.items_inventory[index].card[0]))
 			if (itemdb_isspecial(sd->inventory.u.items_inventory[index].card[0]))
@@ -3840,17 +3839,19 @@ int status_calc_pc_sub(struct map_session_data* sd, uint8 opt)
 				current_equip_card_id= c;
 				current_equip_card_id= c;
 				if(!c)
 				if(!c)
 					continue;
 					continue;
-				data = itemdb_exists(c);
+
+				std::shared_ptr<item_data> data = item_db.find(c);
+
 				if(!data)
 				if(!data)
 					continue;
 					continue;
-				if (opt&SCO_FIRST && data->equip_script && (pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT) || !itemdb_isNoEquip(data,sd->bl.m))) {// Execute equip-script on login
+				if (opt&SCO_FIRST && data->equip_script && (pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT) || !itemdb_isNoEquip(data.get(), sd->bl.m))) {// Execute equip-script on login
 					run_script(data->equip_script,0,sd->bl.id,0);
 					run_script(data->equip_script,0,sd->bl.id,0);
 					if (!calculating)
 					if (!calculating)
 						return 1;
 						return 1;
 				}
 				}
 				if(!data->script)
 				if(!data->script)
 					continue;
 					continue;
-				if(!pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT) && itemdb_isNoEquip(data,sd->bl.m)) // Card restriction checks.
+				if(!pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT) && itemdb_isNoEquip(data.get(), sd->bl.m)) // Card restriction checks.
 					continue;
 					continue;
 				if(i == EQI_HAND_L && sd->inventory.u.items_inventory[index].equip == EQP_HAND_L) { // Left hand status.
 				if(i == EQI_HAND_L && sd->inventory.u.items_inventory[index].equip == EQP_HAND_L) { // Left hand status.
 					sd->state.lr_flag = 1;
 					sd->state.lr_flag = 1;
@@ -3907,7 +3908,8 @@ int status_calc_pc_sub(struct map_session_data* sd, uint8 opt)
 	}
 	}
 
 
 	if (sc->count && sc->data[SC_ITEMSCRIPT]) {
 	if (sc->count && sc->data[SC_ITEMSCRIPT]) {
-		struct item_data *data = itemdb_exists(sc->data[SC_ITEMSCRIPT]->val1);
+		std::shared_ptr<item_data> data = item_db.find(sc->data[SC_ITEMSCRIPT]->val1);
+
 		if (data && data->script)
 		if (data && data->script)
 			run_script(data->script, 0, sd->bl.id, 0);
 			run_script(data->script, 0, sd->bl.id, 0);
 	}
 	}
@@ -15555,7 +15557,7 @@ void StatusDatabase::loadingFinished(){
 		}
 		}
 	}
 	}
 
 
-	TypesafeYamlDatabase::loadingFinished();
+	TypesafeCachedYamlDatabase::loadingFinished();
 }
 }
 
 
 StatusDatabase status_db;
 StatusDatabase status_db;

+ 5 - 4
src/map/storage.cpp

@@ -794,19 +794,20 @@ bool storage_guild_additem(struct map_session_data* sd, struct s_storage* stor,
  * @return True : success, False : fail
  * @return True : success, False : fail
  */
  */
 bool storage_guild_additem2(struct s_storage* stor, struct item* item, int amount) {
 bool storage_guild_additem2(struct s_storage* stor, struct item* item, int amount) {
-	struct item_data *id;
 	int i;
 	int i;
 
 
 	nullpo_ret(stor);
 	nullpo_ret(stor);
 	nullpo_ret(item);
 	nullpo_ret(item);
 
 
-	if (item->nameid == 0 || amount <= 0 || !(id = itemdb_exists(item->nameid)))
+	if (item->nameid == 0 || amount <= 0)
 		return false;
 		return false;
 
 
-	if (item->expire_time)
+	std::shared_ptr<item_data> id = item_db.find(item->nameid);
+
+	if (id == nullptr || item->expire_time)
 		return false;
 		return false;
 
 
-	if (itemdb_isstackable2(id)) { // Stackable
+	if (itemdb_isstackable2(id.get())) { // Stackable
 		for (i = 0; i < stor->max_amount; i++) {
 		for (i = 0; i < stor->max_amount; i++) {
 			if (compare_item(&stor->u.items_guild[i], item)) {
 			if (compare_item(&stor->u.items_guild[i], item)) {
 				// Set the amount, make it fit with max amount
 				// Set the amount, make it fit with max amount