Procházet zdrojové kódy

* Changed how the Unique ID System saves and creates IDs for items. (Hercules dd49dbc)
- System is now enabled by default.
- All non-stackable items that previously existed will get unique IDs if items::item_check is enabled.
- Added 'getequipuniqueid' script command to get the unique ID of an equipment on a player.
- Don't forget to apply the SQL update!
* Renamed SQL update file that applied to logs.

aleos89 před 10 roky
rodič
revize
c0ed836e87

+ 9 - 1
doc/script_commands.txt

@@ -2540,7 +2540,15 @@ armor, but also don't want them to equip if after the check, you would do this:
 
 ---------------------------------------
 
-*getequipname(<equpment slot>)
+*getequipuniqueid(<equipment slot>)
+
+This function returns the unique ID (as a string) of the item equipped in the equipment slot 
+specified on the invoking character. If nothing is equipped there, it returns an empty string.
+See 'getequipid' for a full list of valid equipment slots.
+
+---------------------------------------
+
+*getequipname(<equipment slot>)
 
 Returns the jname of the item equipped in the specified equipment slot on the
 invoking character, or an empty string if nothing is equipped in that position.

+ 1 - 2
sql-files/main.sql

@@ -124,6 +124,7 @@ CREATE TABLE IF NOT EXISTS `char` (
   `moves` int(11) unsigned NOT NULL DEFAULT '0',
   `unban_time` int(11) unsigned NOT NULL default '0',
   `font` tinyint(3) unsigned NOT NULL default '0',
+  `uniqueitem_counter` bigint(20) NOT NULL,
   PRIMARY KEY  (`char_id`),
   UNIQUE KEY `name_key` (`name`),
   KEY `account_id` (`account_id`),
@@ -698,8 +699,6 @@ CREATE TABLE IF NOT EXISTS `interreg` (
   `value` varchar(20) NOT NULL,
    PRIMARY KEY (`varname`)
 ) ENGINE=InnoDB;
-INSERT INTO `interreg` (`varname`, `value`) VALUES
-('unique_id', '0');
 
 --
 -- Table structure for table `bonus_script`

+ 0 - 0
sql-files/upgrades/upgrade_20140713.sql → sql-files/upgrades/upgrade_20140713_log.sql


+ 1 - 0
sql-files/upgrades/upgrade_20140822.sql

@@ -0,0 +1 @@
+ALTER TABLE `char` ADD COLUMN `uniqueitem_counter` bigint(20) NOT NULL AFTER `font`;

+ 5 - 11
src/char/char.c

@@ -1,7 +1,6 @@
 // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
 // For more information, see LICENCE in the main folder
 
-
 #include <time.h>
 #include <signal.h>
 #include <stdarg.h>
@@ -335,7 +334,7 @@ int char_mmo_char_tosql(int char_id, struct mmo_charstatus* p){
 		(p->ele_id != cp->ele_id) || (p->shield != cp->shield) || (p->head_top != cp->head_top) ||
 		(p->head_mid != cp->head_mid) || (p->head_bottom != cp->head_bottom) || (p->delete_date != cp->delete_date) ||
 		(p->rename != cp->rename) || (p->robe != cp->robe) || (p->character_moves != cp->character_moves) ||
-		(p->unban_time != cp->unban_time) || (p->font != cp->font)
+		(p->unban_time != cp->unban_time) || (p->font != cp->font) || (p->uniqueitem_counter != cp->uniqueitem_counter)
 	)
 	{	//Save status
 		if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `base_level`='%d', `job_level`='%d',"
@@ -345,7 +344,7 @@ int char_mmo_char_tosql(int char_id, struct mmo_charstatus* p){
 			"`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d',`elemental_id`='%d',"
 			"`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d',"
 			"`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d',"
-			"`delete_date`='%lu',`robe`='%d',`moves`='%d',`font`='%u'"
+			"`delete_date`='%lu',`robe`='%d',`moves`='%d',`font`='%u',`uniqueitem_counter`='%u'"
 			" WHERE `account_id`='%d' AND `char_id` = '%d'",
 			schema_config.char_db, p->base_level, p->job_level,
 			p->base_exp, p->job_exp, p->zeny,
@@ -356,7 +355,7 @@ int char_mmo_char_tosql(int char_id, struct mmo_charstatus* p){
 			mapindex_id2name(p->last_point.map), p->last_point.x, p->last_point.y,
 			mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y, p->rename,
 			(unsigned long)p->delete_date, // FIXME: platform-dependent size
-			p->robe,p->character_moves,p->font,
+			p->robe,p->character_moves,p->font, p->uniqueitem_counter,
 			p->account_id, p->char_id) )
 		{
 			Sql_ShowDebug(sql_handle);
@@ -699,10 +698,7 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
 		for( j = 0; j < MAX_SLOTS; ++j )
 			StringBuf_Printf(&buf, ", '%hu'", items[i].card[j]);
 		StringBuf_AppendStr(&buf, ")");
-
-		updateLastUid(items[i].unique_id); // Unique Non Stackable Item ID
 	}
-	dbUpdateUid(sql_handle); // Unique Non Stackable Item ID
 
 	if( found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
 	{
@@ -840,10 +836,7 @@ int char_inventory_to_sql(const struct item items[], int max, int id) {
 		for( j = 0; j < MAX_SLOTS; ++j )
 			StringBuf_Printf(&buf, ", '%hu'", items[i].card[j]);
 		StringBuf_AppendStr(&buf, ")");
-
-		updateLastUid(items[i].unique_id);// Unique Non Stackable Item ID
 	}
-	dbUpdateUid(sql_handle);
 
 	if( found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) {
 		Sql_ShowDebug(sql_handle);
@@ -989,7 +982,7 @@ int char_mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_every
 		"`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`elemental_id`,`hair`,"
 		"`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`,"
 		"`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`, `moves`,"
-		"`unban_time`,`font`"
+		"`unban_time`,`font`,`uniqueitem_counter`"
 		" FROM `%s` WHERE `char_id`=? LIMIT 1", schema_config.char_db)
 	||	SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0)
 	||	SQL_ERROR == SqlStmt_Execute(stmt)
@@ -1048,6 +1041,7 @@ int char_mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_every
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 52, SQLDT_UINT32, &p->character_moves, 0, NULL, NULL)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 53, SQLDT_LONG,   &p->unban_time, 0, NULL, NULL)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 54, SQLDT_UCHAR,  &p->font, 0, NULL, NULL)
+	||  SQL_ERROR == SqlStmt_BindColumn(stmt, 55, SQLDT_UINT,   &p->uniqueitem_counter, 0, NULL, NULL)
 	)
 	{
 		SqlStmt_ShowDebug(stmt);

+ 0 - 4
src/char/int_auction.c

@@ -91,10 +91,6 @@ unsigned int auction_create(struct auction_data *auction)
 		StringBuf_Printf(&buf, ",'%hu'", auction->item.card[j]);
 	StringBuf_AppendStr(&buf, ")");
 
-	//Unique Non Stackable Item ID
-	updateLastUid(auction->item.unique_id);
-	dbUpdateUid(sql_handle);
-
 	stmt = SqlStmt_Malloc(sql_handle);
 	if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
 	||  SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH))

+ 0 - 4
src/char/int_mail.c

@@ -119,10 +119,6 @@ int mail_savemessage(struct mail_message* msg)
 		StringBuf_Printf(&buf, ", '%hu'", msg->item.card[j]);
 	StringBuf_AppendStr(&buf, ")");
 
-	//Unique Non Stackable Item ID
-	updateLastUid(msg->item.unique_id);
-	dbUpdateUid(sql_handle);
-
 	// prepare and execute query
 	stmt = SqlStmt_Malloc(sql_handle);
 	if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))

+ 0 - 1
src/char/int_storage.h

@@ -14,7 +14,6 @@ int inter_guild_storage_delete(int guild_id);
 
 int inter_storage_parse_frommap(int fd);
 
-//Exported for use in the TXT-SQL converter.
 int storage_fromsql(int account_id, struct storage_data* p);
 int storage_tosql(int account_id,struct storage_data *p);
 int guild_storage_tosql(int guild_id, struct guild_storage *p);

+ 0 - 19
src/char/inter.c

@@ -1168,23 +1168,4 @@ int inter_parse_frommap(int fd)
 	return 1;
 }
 
-uint64 inter_chk_lastuid(int8 flag, uint64 value){
-	static uint64 last_updt_uid = 0;
-	static int8 update = 0;
-	if(flag)
-	{
-		if(last_updt_uid < value){
-			last_updt_uid = value;
-			update = 1;
-		}
-
-		return 0;
-	}else if(update)
-	{
-		update = 0;
-		return last_updt_uid;
-	}
-	return 0;
-}
-
 

+ 0 - 14
src/char/inter.h

@@ -25,18 +25,4 @@ extern Sql* lsql_handle;
 
 int inter_accreg_tosql(int account_id, int char_id, struct accreg *reg, int type);
 
-uint64 inter_chk_lastuid(int8 flag, uint64 value);
-#ifdef NSI_UNIQUE_ID
-	#define updateLastUid(val_) inter_chk_lastuid(1, val_)
-	#define dbUpdateUid(handler_)\
-	{ \
-		uint64 unique_id_ = inter_chk_lastuid(0, 0); \
-		if (unique_id_ && SQL_ERROR == Sql_Query(handler_, "UPDATE `interreg` SET `value`='%"PRIu64"' WHERE `varname`='unique_id'", unique_id_)) \
-				Sql_ShowDebug(handler_);\
-	}
-#else
-	#define dbUpdateUid(handler_)
-	#define updateLastUid(val_)
-#endif
-
 #endif /* _INTER_SQL_H_ */

+ 2 - 0
src/common/mmo.h

@@ -420,6 +420,8 @@ struct mmo_charstatus {
 	unsigned char font;
 
 	bool cashshop_sent; // Whether the player has received the CashShop list
+
+	uint32 uniqueitem_counter;
 };
 
 typedef enum mail_status {

+ 0 - 4
src/config/core.h

@@ -48,10 +48,6 @@
 /// - but is not the official behaviour.
 //#define CIRCULAR_AREA
 
-/// Uncomment to enable Non Stackable items unique ID
-/// By enabling it, the system will create an unique id for each new non stackable item created
-//#define NSI_UNIQUE_ID
-
 /// Comment to disable Guild/Party Bound item system
 /// By default, we recover/remove Guild/Party Bound items automatically
 #define BOUND_ITEMS

+ 6 - 46
src/map/itemdb.c

@@ -1430,52 +1430,13 @@ static int itemdb_read_sqldb(void) {
 	return 0;
 }
 
-/** Unique item ID function
-* Only one operation by once
-* @param flag
-* 0 return new id
-* 1 set new value, checked with current value
-* 2 set new value bypassing anything
-* 3/other
-* @param value
-* @return last value
-*------------------------------------------*/
-uint64 itemdb_unique_id(int8 flag, int64 value) {
-	static uint64 item_uid = 0;
-
-	if(flag)
-	{
-		if(flag == 1)
-		{	if(item_uid < value)
-				return (item_uid = value);
-		}else if(flag == 2)
-			return (item_uid = value);
-
-		return item_uid;
-	}
-
-	return ++item_uid;
-}
-
 /**
-* Load Unique ID for Item
-*/
-static void itemdb_uid_load(void){
-
-	char * uid;
-	if (SQL_ERROR == Sql_Query(mmysql_handle, "SELECT `value` FROM `interreg` WHERE `varname`='unique_id'"))
-		Sql_ShowDebug(mmysql_handle);
-
-	if( SQL_SUCCESS != Sql_NextRow(mmysql_handle) )
-	{
-		ShowError("itemdb_uid_load: Unable to fetch unique_id data\n");
-		Sql_FreeResult(mmysql_handle);
-		return;
-	}
-
-	Sql_GetData(mmysql_handle, 0, &uid, NULL);
-	itemdb_unique_id(1, (uint64)strtoull(uid, NULL, 10));
-	Sql_FreeResult(mmysql_handle);
+ * Unique item ID function
+ * @param sd : Player
+ * @return unique_id
+ */
+uint64 itemdb_unique_id(struct map_session_data *sd) {
+	return ((uint64)sd->status.char_id << 32) | sd->status.uniqueitem_counter++;
 }
 
 /** Check if the item is restricted by item_noequip.txt
@@ -1542,7 +1503,6 @@ static void itemdb_read(void) {
 		aFree(dbsubpath1);
 		aFree(dbsubpath2);
 	}
-	itemdb_uid_load();
 }
 
 /*==========================================

+ 1 - 1
src/map/itemdb.h

@@ -479,7 +479,7 @@ bool itemdb_isequip2(struct item_data *id);
 char itemdb_isidentified(unsigned short nameid);
 bool itemdb_isstackable2(struct item_data *id);
 #define itemdb_isstackable(nameid) itemdb_isstackable2(itemdb_search(nameid))
-uint64 itemdb_unique_id(int8 flag, int64 value); // Unique Item ID
+uint64 itemdb_unique_id(struct map_session_data *sd); // Unique Item ID
 bool itemdb_isNoEquip(struct item_data *id, uint16 m);
 
 struct item_combo *itemdb_combo_exists(unsigned short combo_id);

+ 19 - 6
src/map/pc.c

@@ -4308,10 +4308,8 @@ char pc_additem(struct map_session_data *sd,struct item *item,int amount,e_log_p
 		sd->last_addeditem_index = i;
 		clif_additem(sd,i,amount,0);
 	}
-#ifdef NSI_UNIQUE_ID
 	if( !itemdb_isstackable2(id) && !item->unique_id )
-		sd->status.inventory[i].unique_id = itemdb_unique_id(0,0);
-#endif
+		sd->status.inventory[i].unique_id = itemdb_unique_id(sd);
 	log_pick_pc(sd, log_type, amount, &sd->status.inventory[i]);
 
 	sd->weight += w;
@@ -9518,12 +9516,17 @@ void pc_check_available_item(struct map_session_data *sd) {
 		for( i = 0; i < MAX_INVENTORY; i++ ) {
 			it = sd->status.inventory[i].nameid;
 
-			if( it && !itemdb_available(it) ) {
+			if (!it)
+				continue;
+			if (!itemdb_available(it)) {
 				sprintf(output, msg_txt(sd, 709), it); // Item %hu has been removed from your inventory.
 				clif_displaymessage(sd->fd, output);
 				ShowWarning("Removed invalid/disabled item id %hu from inventory (amount=%d, char_id=%d).\n", it, sd->status.inventory[i].amount, sd->status.char_id);
 				pc_delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_OTHER);
+				continue;
 			}
+			if (!sd->status.inventory[i].unique_id && !itemdb_isstackable(it))
+				sd->status.inventory[i].unique_id = itemdb_unique_id(sd);
 		}
 	}
 
@@ -9531,12 +9534,17 @@ void pc_check_available_item(struct map_session_data *sd) {
 		for( i = 0; i < MAX_CART; i++ ) {
 			it = sd->status.cart[i].nameid;
 
-			if( it && !itemdb_available(it) ) {
+			if (!it)
+				continue;
+			if (!itemdb_available(it)) {
 				sprintf(output, msg_txt(sd, 710), it); // Item %hu has been removed from your cart.
 				clif_displaymessage(sd->fd, output);
 				ShowWarning("Removed invalid/disabled item id %hu from cart (amount=%d, char_id=%d).\n", it, sd->status.cart[i].amount, sd->status.char_id);
 				pc_cart_delitem(sd, i, sd->status.cart[i].amount, 0, LOG_TYPE_OTHER);
+				continue;
 			}
+			if (!sd->status.cart[i].unique_id && !itemdb_isstackable(it))
+				sd->status.cart[i].unique_id = itemdb_unique_id(sd);
 		}
 	}
 
@@ -9544,12 +9552,17 @@ void pc_check_available_item(struct map_session_data *sd) {
 		for( i = 0; i < sd->storage_size; i++ ) {
 			it = sd->status.storage.items[i].nameid;
 
-			if( it && !itemdb_available(it) ) {
+			if (!it)
+				continue;
+			if (!itemdb_available(it)) {
 				sprintf(output, msg_txt(sd, 711), it); // Item %hu has been removed from your storage.
 				clif_displaymessage(sd->fd, output);
 				ShowWarning("Removed invalid/disabled item id %hu from storage (amount=%d, char_id=%d).\n", it, sd->status.storage.items[i].amount, sd->status.char_id);
 				storage_delitem(sd, i, sd->status.storage.items[i].amount);
+				continue;
 			}
+			if (!sd->status.storage.items[i].unique_id && !itemdb_isstackable(it))
+				sd->status.storage.items[i].unique_id = itemdb_unique_id(sd);
  		}
 	}
 }

+ 41 - 0
src/map/script.c

@@ -7793,6 +7793,46 @@ BUILDIN_FUNC(getequipid)
 	return SCRIPT_CMD_SUCCESS;
 }
 
+/*==========================================
+ * GetEquipUniqueID(Pos);     Pos: 1-14
+ *------------------------------------------*/
+BUILDIN_FUNC(getequipuniqueid)
+{
+	int i, num;
+	TBL_PC* sd;
+	struct item* item;
+
+	sd = script_rid2sd(st);
+	if (sd == NULL)
+		return 0;
+
+	num = script_getnum(st,2) - 1;
+	if (num < 0 || num >= ARRAYLENGTH(equip)) {
+		script_pushconststr(st, "");
+		return 0;
+	}
+
+	// get inventory position of item
+	i = pc_checkequip(sd,equip[num]);
+	if (i < 0) {
+		script_pushconststr(st, "");
+		return 0;
+	}
+
+	item = &sd->status.inventory[i];
+	if (item != 0) {
+		char buf[256];
+
+		memset(buf, 0, sizeof(buf));
+		snprintf(buf, sizeof(buf)-1, "%llu", (unsigned long long)item->unique_id);
+
+		script_pushstr(st, buf);
+	} else
+		script_pushconststr(st, "");
+
+	return SCRIPT_CMD_SUCCESS;
+}
+
 /*==========================================
  * Get the equipement name at pos
  * return item jname or ""
@@ -19108,6 +19148,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(strcharinfo,"i"),
 	BUILDIN_DEF(strnpcinfo,"i"),
 	BUILDIN_DEF(getequipid,"i"),
+	BUILDIN_DEF(getequipuniqueid,"i"),
 	BUILDIN_DEF(getequipname,"i"),
 	BUILDIN_DEF(getbrokenid,"i"), // [Valaris]
 	BUILDIN_DEF(repair,"i"), // [Valaris]