@ -56,8 +56,8 @@ typedef struct InventoryDB_SQL {
typedef struct InventoryDBIterator_SQL {
InventoryDBIterator vtable ; // public interface
InventoryDB_SQL * db ;
int char_id ;
int last_inv_item_id ;
uint32 char_id ;
uint32 last_inv_item_id ;
} InventoryDBIterator_SQL ;
/// internal functions
@ -71,7 +71,7 @@ static bool bot_inv_item_db_sql_remove(InventoryDB* self, const uint32 char_id,
static bool bot_inv_item_db_sql_load_num ( InventoryDB * self , struct bot_inv_item * item ) ;
static InventoryDBIterator * bot_inv_item_db_sql_iterator ( InventoryDB * self , const uint32 char_id ) ;
static void bot_inv_item_db_sql_iter_destroy ( InventoryDBIterator * self ) ;
static bool bot_inv_item_db_sql_iter_next ( InventoryDBIterator * self , const uint32 char_id , struct bot_inv_item * item ) ;
static bool bot_inv_item_db_sql_iter_next ( InventoryDBIterator * self , struct bot_inv_item * item ) ;
static bool bot_inv_item_db_fromsql ( InventoryDB_SQL * db , struct bot_inv_item * item ) ;
static bool bot_inv_item_db_tosql ( InventoryDB_SQL * db , const struct bot_inv_item * item , bool is_new ) ;
@ -286,7 +286,7 @@ static bool bot_inv_item_db_sql_create(InventoryDB* self, struct bot_inv_item* i
* @ param char_id : id of char , the item belongs to
* @ param inventory_id : if of item to delete
* @ return true if successful , false if something has failed
*/
static bool bot_inv_item_db_sql_remove ( InventoryDB * self , const uint32 char_id , const uint32 inventory_id ) {
InventoryDB_SQL * db = ( InventoryDB_SQL * ) self ;
Sql * sql_handle = db - > bot_inventory ;
@ -302,8 +302,66 @@ static bool bot_inv_item_db_sql_remove(InventoryDB* self, const uint32 char_id,
result & = ( SQL_SUCCESS = = Sql_QueryStr ( sql_handle , ( result = = true ) ? " COMMIT " : " ROLLBACK " ) ) ;
return result ;
}
} */
static bool bot_inv_item_db_sql_remove ( InventoryDB * self , const uint32 char_id , const uint32 inventory_id ) {
InventoryDB_SQL * db = ( InventoryDB_SQL * ) self ;
Sql * sql_handle = db - > bot_inventory ;
bool result = false ;
// Start the transaction
//ShowDebug("Starting transaction for char_id: %u, inventory_id: %u\n", char_id, inventory_id);
if ( SQL_SUCCESS ! = Sql_QueryStr ( sql_handle , " START TRANSACTION " ) ) {
Sql_ShowDebug ( sql_handle ) ;
ShowError ( " Failed to start transaction for char_id: %u, inventory_id: %u \n " , char_id , inventory_id ) ;
return false ;
}
// Attempt to delete the item
//ShowDebug("Attempting to delete item with char_id: %u, inventory_id: %u\n", char_id, inventory_id);
if ( SQL_SUCCESS ! = Sql_Query ( sql_handle ,
" DELETE FROM `%s` WHERE `char_id` = %u AND `id` = %u " ,
db - > inventory_db , char_id , inventory_id ) )
{
Sql_ShowDebug ( sql_handle ) ;
ShowError ( " Failed to delete item with char_id: %u, inventory_id: %u \n " , char_id , inventory_id ) ;
result = false ;
}
else {
result = true ;
//ShowDebug("Item deletion query executed successfully for char_id: %u, inventory_id: %u\n", char_id, inventory_id);
}
// Commit or rollback based on the result
//ShowDebug("%s transaction for char_id: %u, inventory_id: %u\n", result ? "Committing" : "Rolling back", char_id, inventory_id);
if ( SQL_SUCCESS ! = Sql_QueryStr ( sql_handle , result ? " COMMIT " : " ROLLBACK " ) ) {
Sql_ShowDebug ( sql_handle ) ;
ShowError ( " %s transaction failed for char_id: %u, inventory_id: %u \n " , result ? " Commit " : " Rollback " , char_id , inventory_id ) ;
result = false ;
}
// Validate the deletion
if ( result ) {
//ShowDebug("Validating deletion of item_id: %u\n", inventory_id);
if ( SQL_SUCCESS ! = Sql_Query ( sql_handle ,
" SELECT `id` FROM `%s` WHERE `id` = %u " ,
db - > inventory_db , inventory_id ) )
{
Sql_ShowDebug ( sql_handle ) ;
ShowError ( " Failed to validate deletion of item_id: %u \n " , inventory_id ) ;
result = false ;
}
else if ( SQL_SUCCESS = = Sql_NextRow ( sql_handle ) ) {
ShowError ( " Item with id: %u still exists after deletion attempt. \n " , inventory_id ) ;
result = false ;
}
else {
//ShowDebug("Item with id: %u successfully deleted.\n", inventory_id);
}
}
Sql_FreeResult ( sql_handle ) ;
return result ;
}
/**
* Retrieve data from db and store it in the provided data structure .
* Filled data structure is done by delegation to bot_inv_item_db_fromsql .
@ -318,12 +376,31 @@ static bool bot_inv_item_db_sql_load_num(InventoryDB* self, struct bot_inv_item*
return bot_inv_item_db_fromsql ( db , item ) ;
}
void dump_item_bundle ( const bot_item_bundle & item_bundle ) {
ShowDebug ( " Dumping item bundle contents... \n " ) ;
if ( item_bundle . items . empty ( ) ) {
ShowDebug ( " Item bundle is empty. \n " ) ;
return ;
}
for ( const auto & item : item_bundle . items ) {
ShowDebug ( " Character ID: %u \n " , item . char_id ) ;
ShowDebug ( " Inventory ID: %u \n " , item . inventory_id ) ;
ShowDebug ( " Item ID: %u \n " , item . item_id ) ;
std : : string item_name = convert_item_id_to_aegisname ( item . item_id ) ;
ShowDebug ( " Item Name: %s \n " , item_name . c_str ( ) ) ;
ShowDebug ( " Amount: %u \n " , item . amount ) ;
ShowDebug ( " Equip Slot: %u \n " , item . equip ) ;
}
ShowDebug ( " End of item bundle dump. \n " ) ;
}
/**
* Create a new forward iterator .
* @ param self : pointer to db iterator
* @ return a new db iterator
*/
static InventoryDBIterator * bot_inv_item_db_sql_iterator ( InventoryDB * self , const uint32 char_id ) {
InventoryDB_SQL * db = ( InventoryDB_SQL * ) self ;
InventoryDBIterator_SQL * iter = ( InventoryDBIterator_SQL * ) aCalloc ( 1 , sizeof ( InventoryDBIterator_SQL ) ) ;
@ -337,6 +414,38 @@ static InventoryDBIterator* bot_inv_item_db_sql_iterator(InventoryDB* self, cons
iter - > char_id = char_id ;
iter - > last_inv_item_id = - 1 ;
return & iter - > vtable ;
} */
static InventoryDBIterator * bot_inv_item_db_sql_iterator ( InventoryDB * self , const uint32 char_id ) {
InventoryDB_SQL * db = ( InventoryDB_SQL * ) self ;
if ( ! db ) {
ShowError ( " InventoryDB_SQL is null. \n " ) ;
return nullptr ;
}
InventoryDBIterator_SQL * iter = ( InventoryDBIterator_SQL * ) aCalloc ( 1 , sizeof ( InventoryDBIterator_SQL ) ) ;
if ( ! iter ) {
ShowError ( " Failed to allocate memory for InventoryDBIterator_SQL. \n " ) ;
return nullptr ;
}
// Initialize vtable
iter - > vtable . destroy = & bot_inv_item_db_sql_iter_destroy ;
iter - > vtable . next = & bot_inv_item_db_sql_iter_next ;
// Initialize fields
iter - > db = db ;
iter - > char_id = char_id ;
iter - > last_inv_item_id = 0 ;
if ( ! db - > bot_inventory ) {
ShowError ( " SQL handle is not initialized. \n " ) ;
aFree ( iter ) ;
return nullptr ;
}
return & iter - > vtable ;
}
@ -352,11 +461,10 @@ static void bot_inv_item_db_sql_iter_destroy(InventoryDBIterator* self) {
/**
* Fetches the next inv item entry in the database .
* @ param self : pointer to db iterator
* @ param char_id : char_id of the bot the items belong to
* @ param inventory_id : id of the inventory table the item belongs to
* @ return true if next inventory entry found and filled , false if something has failed
*/
static bool bot_inv_item_db_sql_iter_next ( InventoryDBIterator * self , const uint32 char_id , struct bot_inv_item * item ) {
static bool bot_inv_item_db_sql_iter_next ( InventoryDBIterator * self , struct bot_inv_item * item ) {
InventoryDBIterator_SQL * iter = ( InventoryDBIterator_SQL * ) self ;
InventoryDB_SQL * db = iter - > db ;
Sql * sql_handle = db - > bot_inventory ;
@ -374,9 +482,9 @@ static bool bot_inv_item_db_sql_iter_next(InventoryDBIterator* self, const uint3
SQL_SUCCESS = = Sql_GetData ( sql_handle , 0 , & data , nullptr ) & &
data ! = nullptr )
{ // get item data
uint32 inventory_id ;
i nventory_id = atoi ( data ) ; uint32 skill _id;
uint32 inventory_id = atoi ( data ) ;
i tem- > inventory_id = inventory _id;
if ( bot_inv_item_db_fromsql ( db , item ) )
{
iter - > last_inv_item_id = inventory_id ;
@ -384,6 +492,59 @@ static bool bot_inv_item_db_sql_iter_next(InventoryDBIterator* self, const uint3
return true ;
}
}
Sql_FreeResult ( sql_handle ) ;
return false ;
} */
static bool bot_inv_item_db_sql_iter_next ( InventoryDBIterator * self , struct bot_inv_item * item ) {
InventoryDBIterator_SQL * iter = ( InventoryDBIterator_SQL * ) self ;
InventoryDB_SQL * db = iter - > db ;
Sql * sql_handle = db - > bot_inventory ;
char * data ;
// Debugging: Check inputs
//ShowDebug("Fetching next item for char_id: %u, last_inv_item_id: %u\n", iter->char_id, iter->last_inv_item_id);
// Build and execute query
char query [ 256 ] ;
snprintf ( query , sizeof ( query ) ,
" SELECT `id` FROM `%s` WHERE `char_id` = %u AND `id` > %u ORDER BY `id` ASC LIMIT 1 " ,
db - > inventory_db , iter - > char_id , iter - > last_inv_item_id ) ;
//ShowDebug("Executing SQL Query: %s\n", query);
if ( SQL_ERROR = = Sql_Query ( sql_handle , query ) ) {
Sql_ShowDebug ( sql_handle ) ;
return false ;
}
// Process the next row
if ( SQL_SUCCESS = = Sql_NextRow ( sql_handle ) & &
SQL_SUCCESS = = Sql_GetData ( sql_handle , 0 , & data , nullptr ) & &
data ! = nullptr )
{
uint32 inventory_id = atoi ( data ) ;
if ( inventory_id = = 0 ) {
ShowError ( " Invalid inventory_id retrieved: %s \n " , data ) ;
Sql_FreeResult ( sql_handle ) ;
return false ;
}
item - > inventory_id = inventory_id ;
//ShowDebug("Retrieved inventory_id: %u\n", inventory_id);
// Load item details
if ( bot_inv_item_db_fromsql ( db , item ) ) {
iter - > last_inv_item_id = inventory_id ;
Sql_FreeResult ( sql_handle ) ;
return true ;
}
else {
ShowError ( " Failed to load item data for inventory_id: %u \n " , inventory_id ) ;
}
}
else {
//ShowDebug("No more items found for char_id: %u\n", iter->char_id);
}
Sql_FreeResult ( sql_handle ) ;
return false ;
}
@ -395,7 +556,7 @@ static bool bot_inv_item_db_sql_iter_next(InventoryDBIterator* self, const uint3
* @ param char_id : id of character , item belong to
* @ param item_id : id of item to take data from
* @ return true if successful , false if something has failed
*/
static bool bot_inv_item_db_fromsql ( InventoryDB_SQL * db , struct bot_inv_item * item ) {
Sql * sql_handle = db - > bot_inventory ;
char * data ;
@ -403,11 +564,11 @@ static bool bot_inv_item_db_fromsql(InventoryDB_SQL* db, struct bot_inv_item* it
// retrieve login entry for the specified account
if ( SQL_ERROR = = Sql_Query ( sql_handle ,
# ifdef VIP_ENABLE
" SELECT `id`, `char_id`, `nameid`, `amount`, `equip`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `enchantgrade` FROM `%s` WHERE ` char_id` = %d AND ` id` = %d" ,
" SELECT `id`, `char_id`, `nameid`, `amount`, `equip`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `enchantgrade` FROM `%s` WHERE ` id` = %d" ,
# else
" SELECT `id`, `char_id`, `nameid`, `amount`, `equip`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `enchantgrade` FROM `%s` WHERE ` char_id` = %d AND ` id` = %d" ,
" SELECT `id`, `char_id`, `nameid`, `amount`, `equip`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `enchantgrade` FROM `%s` WHERE ` id` = %d" ,
# endif
db - > inventory_db , item - > char_id, item - > inventory_id )
db - > inventory_db , item - > inventory_id )
) {
Sql_ShowDebug ( sql_handle ) ;
return false ;
@ -459,6 +620,73 @@ static bool bot_inv_item_db_fromsql(InventoryDB_SQL* db, struct bot_inv_item* it
item - > option_parm4 = 0 ;
item - > option_val4 = 0 ;
return true ;
} */
static bool bot_inv_item_db_fromsql ( InventoryDB_SQL * db , struct bot_inv_item * item ) {
Sql * sql_handle = db - > bot_inventory ;
char * data ;
// Execute the query
if ( SQL_ERROR = = Sql_Query ( sql_handle ,
" SELECT `id`, `char_id`, `nameid`, `amount`, `equip`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `enchantgrade` "
" FROM `%s` WHERE `id` = %d " ,
db - > inventory_db , item - > inventory_id ) )
{
Sql_ShowDebug ( sql_handle ) ;
ShowError ( " SQL query failed for inventory ID: %d \n " , item - > inventory_id ) ;
return false ;
}
// Retrieve the next row
if ( SQL_SUCCESS ! = Sql_NextRow ( sql_handle ) ) {
ShowWarning ( " No inventory data found for ID: %d \n " , item - > inventory_id ) ;
Sql_FreeResult ( sql_handle ) ;
return false ;
}
// Parse data
auto parse_column = [ & ] ( int column_index , auto & target_field ) - > bool {
if ( SQL_SUCCESS ! = Sql_GetData ( sql_handle , column_index , & data , nullptr ) | | data = = nullptr ) {
ShowError ( " Failed to retrieve column %d for inventory ID: %d \n " , column_index , item - > inventory_id ) ;
return false ;
}
target_field = atoi ( data ) ;
return true ;
} ;
if ( ! parse_column ( 0 , item - > inventory_id ) | |
! parse_column ( 1 , item - > char_id ) | |
! parse_column ( 2 , item - > item_id ) | |
! parse_column ( 3 , item - > amount ) | |
! parse_column ( 4 , item - > equip ) | |
! parse_column ( 5 , item - > refine ) | |
! parse_column ( 6 , item - > attribute ) | |
! parse_column ( 7 , item - > card0 ) | |
! parse_column ( 8 , item - > card1 ) | |
! parse_column ( 9 , item - > card2 ) | |
! parse_column ( 10 , item - > card3 ) | |
! parse_column ( 11 , item - > enchantgrade ) )
{
Sql_FreeResult ( sql_handle ) ;
return false ;
}
Sql_FreeResult ( sql_handle ) ;
// Set default values
item - > identify = 1 ; // Identified
item - > expire_time = 0 ; // No expiration
item - > favorite = 0 ;
item - > bound = 0 ;
item - > unique_id = 0 ;
item - > equip_switch = 0 ;
item - > option_id0 = item - > option_parm0 = item - > option_val0 = 0 ;
item - > option_id1 = item - > option_parm1 = item - > option_val1 = 0 ;
item - > option_id2 = item - > option_parm2 = item - > option_val2 = 0 ;
item - > option_id3 = item - > option_parm3 = item - > option_val3 = 0 ;
item - > option_id4 = item - > option_parm4 = item - > option_val4 = 0 ;
return true ;
}
@ -522,11 +750,11 @@ static bool bot_inv_item_db_tosql(InventoryDB_SQL* db, const struct bot_inv_item
// Per default, amount of an allready existing item is updated here but currently (01/25) no valid usecase is defined yet
if ( SQL_SUCCESS ! = SqlStmt_Prepare ( stmt ,
# ifdef VIP_ENABLE
" UPDATE `%s` SET `amount`=? WHERE ` char_id` = '%d' AND ` id` = '%d'" ,
" UPDATE `%s` SET `amount`=? WHERE ` id` = '%d'" ,
# else
" UPDATE `%s` SET `amount`=? WHERE ` char_id` = '%d' AND ` id` = '%d'" ,
" UPDATE `%s` SET `amount`=? WHERE ` id` = '%d'" ,
# endif
db - > inventory_db , item - > char_id, item - > inventory_id)
db - > inventory_db , item - > inventory_id)
| | SQL_SUCCESS ! = SqlStmt_BindParam ( stmt , 0 , SQLDT_UINT32 , ( void * ) item - > amount , sizeof ( item - > amount ) )
# ifdef VIP_ENABLE
# endif
@ -598,7 +826,7 @@ void set_bot_inv_item_defaults(bot_inv_item& item) {
item . enchantgrade = 0 ;
}
int convert_item_aegisname_to_id ( const char * aegisname )
uint32 convert_item_aegisname_to_id ( const char * aegisname )
{
// Open the mapping JSON file
std : : ifstream bot_itemdb_aegisname_to_id_file ( " conf/bot_helper_jsons/itemdb_converter_aegisname_to_id.json " ) ;
@ -628,31 +856,40 @@ int convert_item_aegisname_to_id(const char* aegisname)
return 0 ;
}
const int item_id = json_itemdb_aegisname_to_id [ aegisname ] ;
const uint32 item_id = json_itemdb_aegisname_to_id [ aegisname ] ;
//ShowStatus("aegisname found for Item_id %d\n",item_id);
return item_id ;
}
std : : string convert_item_id_to_name ( int item_id )
{
std : : string convert_item_id_to_name ( uint32 item_id )
{
// Open the mapping JSON file
std : : ifstream bot_itemdb_item_id_to_name_file ( " conf/bot_helper_jsons/itemdb_converter_id_to_name.json " ) ;
if ( ! bot_itemdb_item_id_to_name_file . is_open ( ) ) {
ShowError ( " Failed to open itemdb_converter_id_to_name.json \n " ) ;
return " UNKNOWN " ;
}
// Parse the JSON file
json json_itemdb_id_to_name ;
try {
bot_itemdb_item_id_to_name_file > > json_itemdb_id_to_name ;
//bot_itemdb_item_id_to_name_file >> json_itemdb_id_to_name;
json test_json = json : : parse ( bot_itemdb_item_id_to_name_file ) ;
//ShowDebug("Test parse successful: %s\n", test_json.dump().c_str());
}
catch ( json : : parse_error & e ) {
ShowError ( " Error parsing itemdb_converter_id_to_name.json: %s \n " , e . what ( ) ) ;
return " UNKNOWN " ;
catch ( const json : : parse_error & e ) {
ShowError ( " JSON parse error: %s \n " , e . what ( ) ) ;
}
catch ( const std : : exception & e ) {
ShowError ( " General exception: %s \n " , e . what ( ) ) ;
}
catch ( . . . ) {
ShowError ( " Unknown error occurred during JSON parsing. \n " ) ;
}
// Close file after done with it
bot_itemdb_item_id_to_name_file . close ( ) ;
//ShowStatus("Mapping item_id to item_name...\n");
@ -661,7 +898,7 @@ std::string convert_item_id_to_name(int item_id)
//ShowStatus("id=%s\n", id_str.c_str());
if ( ! json_itemdb_id_to_name . contains ( id_str ) ) {
// Error: item_id is not inside json file
ShowWarning ( " Item_id \" %d \" was not found inside the itemdb. Skipped... " , item_id ) ;
ShowWarning ( " Item_id \" %d \" was not found inside the itemdb. Skipped... \n " , item_id ) ;
return " UNKNOWN " ;
}
@ -672,41 +909,38 @@ std::string convert_item_id_to_name(int item_id)
}
std : : string convert_item_id_to_aegisname ( int item_id )
{
// Open the mapping JSON file
std : : ifstream bot_itemdb_item_id_to_aegisname_file ( " conf/bot_helper_jsons/itemdb_converter_id_to_aegisname.json " ) ;
if ( ! bot_itemdb_item_id_to_aegisname_file . is_open ( ) ) {
ShowError ( " Failed to open itemdb_converter_id_to_aegisname.json \n " ) ;
return " UNKNOWN " ;
}
std : : string convert_item_id_to_aegisname ( uint32 item_id ) {
static json json_itemdb_id_to_aegisname ;
static bool id_to_aegisname_is_loaded = false ;
// Parse the JSON file
json json_itemdb_id_to_aegisname ;
try {
bot_itemdb_item_id_to_aegisname_file > > json_itemdb_id_to_aegisname ;
}
catch ( json : : parse_error & e ) {
ShowError ( " Error parsing itemdb_converter_id_to_name.json: %s \n " , e . what ( ) ) ;
return " UNKNOWN " ;
// Load the JSON file only once
if ( ! id_to_aegisname_is_loaded ) {
std : : ifstream bot_itemdb_item_id_to_aegisname_file ( " conf/bot_helper_jsons/itemdb_converter_id_to_aegisname.json " ) ;
if ( ! bot_itemdb_item_id_to_aegisname_file . is_open ( ) ) {
ShowError ( " Failed to open itemdb_converter_id_to_aegisname.json \n " ) ;
return " UNKNOWN " ;
}
try {
bot_itemdb_item_id_to_aegisname_file > > json_itemdb_id_to_aegisname ;
id_to_aegisname_is_loaded = true ;
}
catch ( json : : parse_error & e ) {
ShowError ( " Error parsing itemdb_converter_id_to_aegisname.json: %s \n " , e . what ( ) ) ;
return " UNKNOWN " ;
}
bot_itemdb_item_id_to_aegisname_file . close ( ) ;
}
// Close file after done with it
bot_itemdb_item_id_to_aegisname_file . close ( ) ;
//ShowStatus("Mapping item_id to item aegisname...\n");
// Lookup the item ID in the JSON data
std : : string id_str = std : : to_string ( item_id ) ;
//ShowStatus("id=%s\n", id_str.c_str());
if ( ! json_itemdb_id_to_aegisname . contains ( id_str ) ) {
// Error: item_id is not inside json file
ShowWarning ( " Item_id \" %d \" was not found inside the itemdb. Skipped... " , item_id ) ;
ShowWarning ( " Item_id \" %u \" was not found inside the itemdb. Skipped... " , item_id ) ;
return " UNKNOWN " ;
}
std : : string item_name = json_itemdb_id_to_aegisname [ id_str ] ;
//ShowStatus("Entry found. Item Name: %s\n", item_name.c_str());
return item_name ;
return json_itemdb_id_to_aegisname [ id_str ] ;
}
/*
@ -735,12 +969,7 @@ void prepare_item_bundle(bot_item_bundle& bundle, uint32 char_id, const nlohmann
ShowWarning ( " Item ID (Aegisname) %s is Invalid. Skipping... \n " , item_name . c_str ( ) ) ;
continue ; // Skip invalid item
}
// Retrieve ingame name of the item
std : : string ingame_name = convert_item_id_to_name ( item_id ) ;
if ( ingame_name = = " UNKNOWN " ) { // invalid ingame name
ShowWarning ( " Item id %d is Invalid. Skipping... \n " , item_id ) ;
continue ; // Skip invalid item id
}
// Add the item to the item bundle
bot_inv_item new_item { } ;
@ -800,13 +1029,6 @@ void prepare_item_bundle(bot_item_bundle& bundle, uint32 char_id, const nlohmann
continue ; // Skip invalid items
}
// Retrieve ingame name of the item
std : : string ingame_name = convert_item_id_to_name ( item_id ) ;
if ( ingame_name = = " UNKNOWN " ) { // invalid ingame name
ShowWarning ( " Item id %d is Invalid. Skipping... \n " , item_id ) ;
continue ; // Skip invalid item id
}
// Add the item to the item bundle
bot_inv_item new_item { } ;