diff --git a/src/char/char.c b/src/char/char.c index 989136ab17..5781d2ce21 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -261,8 +261,6 @@ static DBData char_create_charstatus(DBKey key, va_list args) { return db_ptr2data(cp); } -int char_inventory_to_sql(const struct item items[], int max, int id); - int char_mmo_char_tosql(uint32 char_id, struct mmo_charstatus* p){ int i = 0; int count = 0; @@ -520,24 +518,35 @@ int char_mmo_char_tosql(uint32 char_id, struct mmo_charstatus* p){ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tableswitch) { StringBuf buf; SqlStmt* stmt; - int i,j; - const char* tablename; - const char* selectoption; + int i, j, offset = 0; + const char* tablename, *selectoption; struct item item; // temp storage variable bool* flag; // bit array for inventory matching bool found; int errors = 0; switch (tableswitch) { - case TABLE_CART: tablename = schema_config.cart_db; selectoption = "char_id"; break; - case TABLE_STORAGE: tablename = schema_config.storage_db; selectoption = "account_id"; break; - case TABLE_GUILD_STORAGE: tablename = schema_config.guild_storage_db; selectoption = "guild_id"; break; + case TABLE_INVENTORY: + tablename = schema_config.inventory_db; + selectoption = "char_id"; + break; + case TABLE_CART: + tablename = schema_config.cart_db; + selectoption = "char_id"; + break; + case TABLE_STORAGE: + tablename = schema_config.storage_db; + selectoption = "account_id"; + break; + case TABLE_GUILD_STORAGE: + tablename = schema_config.guild_storage_db; + selectoption = "guild_id"; + break; default: ShowError("Invalid table name!\n"); return 1; } - // The following code compares inventory with current database values // and performs modification/deletion/insertion only on relevant rows. // This approach is more complicated than a trivial delete&insert, but @@ -545,6 +554,10 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl StringBuf_Init(&buf); StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`"); + if (tableswitch == TABLE_INVENTORY) { + StringBuf_Printf(&buf, ", `favorite`"); + offset = 1; + } for( i = 0; i < MAX_SLOTS; ++i ) StringBuf_Printf(&buf, ", `card%d`", i); @@ -575,12 +588,14 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); SqlStmt_BindColumn(stmt, 8, SQLDT_UINT, &item.bound, 0, NULL, NULL); SqlStmt_BindColumn(stmt, 9, SQLDT_UINT64, &item.unique_id, 0, NULL, NULL); + if (tableswitch == TABLE_INVENTORY) + SqlStmt_BindColumn(stmt, 10, SQLDT_CHAR, &item.favorite, 0, NULL, NULL); for( i = 0; i < MAX_SLOTS; ++i ) - SqlStmt_BindColumn(stmt, 10+i, SQLDT_USHORT, &item.card[i], 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 10+offset+i, SQLDT_USHORT, &item.card[i], 0, NULL, NULL); for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) { - SqlStmt_BindColumn(stmt, 10+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].id, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 11+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].value, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 12+MAX_SLOTS+i*3, SQLDT_CHAR, &item.option[i].param, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 10+offset+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].id, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 11+offset+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].value, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 12+offset+MAX_SLOTS+i*3, SQLDT_CHAR, &item.option[i].param, 0, NULL, NULL); } // bit array indicating which inventory items have already been matched flag = (bool*) aCalloc(max, sizeof(bool)); @@ -614,7 +629,8 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl items[i].attribute == item.attribute && items[i].expire_time == item.expire_time && items[i].bound == item.bound && - items[i].unique_id == item.unique_id ) + items[i].unique_id == item.unique_id && + (tableswitch != TABLE_INVENTORY || items[i].favorite == item.favorite) ) ; //Do nothing. else { @@ -622,6 +638,8 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl StringBuf_Clear(&buf); StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `bound`='%d', `unique_id`='%"PRIu64"'", tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].bound, items[i].unique_id); + if (tableswitch == TABLE_INVENTORY) + StringBuf_Printf(&buf, ", `favorite`='%d'", items[i].favorite); for( j = 0; j < MAX_SLOTS; ++j ) StringBuf_Printf(&buf, ", `card%d`=%hu", j, items[i].card[j]); for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) { @@ -655,6 +673,8 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl StringBuf_Clear(&buf); StringBuf_Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`", tablename, selectoption); + if (tableswitch == TABLE_INVENTORY) + StringBuf_Printf(&buf, ", `favorite`"); for( j = 0; j < MAX_SLOTS; ++j ) StringBuf_Printf(&buf, ", `card%d`", j); for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) { @@ -679,6 +699,8 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl StringBuf_Printf(&buf, "('%d', '%hu', '%d', '%d', '%d', '%d', '%d', '%u', '%d', '%"PRIu64"'", id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].bound, items[i].unique_id); + if (tableswitch == TABLE_INVENTORY) + StringBuf_Printf(&buf, ", '%d'", items[i].favorite); for( j = 0; j < MAX_SLOTS; ++j ) StringBuf_Printf(&buf, ", '%hu'", items[i].card[j]); for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) { @@ -695,177 +717,7 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl errors++; } - ShowInfo("Saved %s data for %s: %d\n", (tableswitch == TABLE_CART ? "Cart" : (tableswitch == TABLE_STORAGE ? "Storage" : "Guild Storage") ), selectoption, id); - - StringBuf_Destroy(&buf); - aFree(flag); - - return errors; -} -/* pretty much a copy of memitemdata_to_sql except it handles inventory_db exclusively, - * - this is required because inventory db is the only one with the 'favorite' column. */ -int char_inventory_to_sql(const struct item items[], int max, int char_id) { - StringBuf buf; - SqlStmt* stmt; - int i, j; - struct item item; // temp storage variable - bool* flag; // bit array for inventory matching - bool found; - int errors = 0; - - - // The following code compares inventory with current database values - // and performs modification/deletion/insertion only on relevant rows. - // This approach is more complicated than a trivial delete&insert, but - // it significantly reduces cpu load on the database server. - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`"); - for( i = 0; i < MAX_SLOTS; ++i ) - StringBuf_Printf(&buf, ", `card%d`", i); - for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) { - StringBuf_Printf(&buf, ", `option_id%d`", i); - StringBuf_Printf(&buf, ", `option_val%d`", i); - StringBuf_Printf(&buf, ", `option_parm%d`", i); - } - StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d'", schema_config.inventory_db, char_id); - - stmt = SqlStmt_Malloc(sql_handle); - if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) || - SQL_ERROR == SqlStmt_Execute(stmt) ) - { - SqlStmt_ShowDebug(stmt); - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); - return 1; - } - - SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 1, SQLDT_USHORT, &item.nameid, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 3, SQLDT_UINT, &item.equip, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR, &item.favorite, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 9, SQLDT_CHAR, &item.bound, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 10,SQLDT_UINT64, &item.unique_id, 0, NULL, NULL); - for( i = 0; i < MAX_SLOTS; ++i ) - SqlStmt_BindColumn(stmt, 11+i, SQLDT_USHORT, &item.card[i], 0, NULL, NULL); - for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) { - SqlStmt_BindColumn(stmt, 11+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].id, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 12+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].value, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 13+MAX_SLOTS+i*3, SQLDT_CHAR, &item.option[i].param, 0, NULL, NULL); - } - - // bit array indicating which inventory items have already been matched - flag = (bool*) aCalloc(max, sizeof(bool)); - - while( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) { - found = false; - // search for the presence of the item in the char's inventory - for( i = 0; i < max; ++i ) { - // skip empty and already matched entries - if( items[i].nameid == 0 || flag[i] ) - continue; - - if( items[i].nameid == item.nameid - && items[i].card[0] == item.card[0] - && items[i].card[2] == item.card[2] - && items[i].card[3] == item.card[3] - ) { //They are the same item. - int k; - - ARR_FIND( 0, MAX_SLOTS, j, items[i].card[j] != item.card[j] ); - ARR_FIND( 0, MAX_ITEM_RDM_OPT, k, items[i].option[k].id != item.option[k].id || items[i].option[k].value != item.option[k].value || items[i].option[k].param != item.option[k].param ); - - if( j == MAX_SLOTS && - k == MAX_ITEM_RDM_OPT && - items[i].amount == item.amount && - items[i].equip == item.equip && - items[i].identify == item.identify && - items[i].refine == item.refine && - items[i].attribute == item.attribute && - items[i].expire_time == item.expire_time && - items[i].favorite == item.favorite && - items[i].bound == item.bound && - items[i].unique_id == item.unique_id ) - ; //Do nothing. - else { - // update all fields. - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `favorite`='%d', `bound`='%d', `unique_id`='%"PRIu64"'", - schema_config.inventory_db, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite, items[i].bound, items[i].unique_id); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", `card%d`=%hu", j, items[i].card[j]); - for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) { - StringBuf_Printf(&buf, ", `option_id%d`=%d", j, items[i].option[j].id); - StringBuf_Printf(&buf, ", `option_val%d`=%d", j, items[i].option[j].value); - StringBuf_Printf(&buf, ", `option_parm%d`=%d", j, items[i].option[j].param); - } - StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id); - - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) { - Sql_ShowDebug(sql_handle); - errors++; - } - } - - found = flag[i] = true; //Item dealt with, - break; //skip to next item in the db. - } - } - if( !found ) {// Item not present in inventory, remove it. - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `id`='%d' LIMIT 1", schema_config.inventory_db, item.id) ) { - Sql_ShowDebug(sql_handle); - errors++; - } - } - } - SqlStmt_Free(stmt); - - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`", schema_config.inventory_db); - for( i = 0; i < MAX_SLOTS; ++i ) - StringBuf_Printf(&buf, ", `card%d`", i); - for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) { - StringBuf_Printf(&buf, ", `option_id%d`", i); - StringBuf_Printf(&buf, ", `option_val%d`", i); - StringBuf_Printf(&buf, ", `option_parm%d`", i); - } - StringBuf_AppendStr(&buf, ") VALUES "); - - found = false; - // insert non-matched items into the db as new items - for( i = 0; i < max; ++i ) { - // skip empty and already matched entries - if( items[i].nameid == 0 || flag[i] ) - continue; - - if( found ) - StringBuf_AppendStr(&buf, ","); - else - found = true; - - StringBuf_Printf(&buf, "('%d', '%hu', '%d', '%d', '%d', '%d', '%d', '%u', '%d', '%d', '%"PRIu64"'", - char_id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite, items[i].bound, items[i].unique_id); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", '%hu'", items[i].card[j]); - for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) { - StringBuf_Printf(&buf, ", '%d'", items[i].option[j].id); - StringBuf_Printf(&buf, ", '%d'", items[i].option[j].value); - StringBuf_Printf(&buf, ", '%d'", items[i].option[j].param); - } - StringBuf_AppendStr(&buf, ")"); - } - - if( found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) { - Sql_ShowDebug(sql_handle); - errors++; - } - - ShowInfo("Saved Inventory data for char_id: %d.\n", char_id); + ShowInfo("Saved %s data for %s: %d\n", (tableswitch == TABLE_INVENTORY ? "Inventory" : (tableswitch == TABLE_CART ? "Cart" : (tableswitch == TABLE_STORAGE ? "Storage" : "Guild Storage"))), selectoption, id); StringBuf_Destroy(&buf); aFree(flag); diff --git a/src/char/char.h b/src/char/char.h index a0be0a60a2..4993fb0e30 100644 --- a/src/char/char.h +++ b/src/char/char.h @@ -257,7 +257,6 @@ int char_mmo_chars_fromsql(struct char_session_data* sd, uint8* buf); int char_delete_char_sql(uint32 char_id); int char_rename_char_sql(struct char_session_data *sd, uint32 char_id); int char_divorce_char_sql(int partner_id1, int partner_id2); -int char_inventory_to_sql(const struct item items[], int max, int char_id); int char_memitemdata_to_sql(const struct item items[], int max, int id, int tableswitch); void disconnect_player(uint32 account_id); diff --git a/src/char/int_storage.c b/src/char/int_storage.c index 0217ff3cce..efb88517b3 100644 --- a/src/char/int_storage.c +++ b/src/char/int_storage.c @@ -22,7 +22,7 @@ */ static int inventory_tosql(uint32 char_id, struct s_storage* p) { - return char_inventory_to_sql(p->u.items_inventory, MAX_INVENTORY, char_id); + return char_memitemdata_to_sql(p->u.items_inventory, MAX_INVENTORY, char_id, TABLE_INVENTORY); } /**