diff --git a/src/bot/Brokk/brokk.cpp b/src/bot/Brokk/brokk.cpp index 6b997b8..90d18d1 100644 --- a/src/bot/Brokk/brokk.cpp +++ b/src/bot/Brokk/brokk.cpp @@ -256,6 +256,8 @@ int brokk_mmo_auth_delete_num(uint32 account_id) { std::vector skills_to_delete; std::vector items_to_delete; + ShowInfo("Processing Account %d ...\n", account_id); + // Check if the account exists if (!login_accounts->load_num(login_accounts, &acc, account_id)) { ShowNotice("Attempt to delete non-existent account (account_id: %d)\n", account_id); @@ -285,11 +287,12 @@ int brokk_mmo_auth_delete_num(uint32 account_id) { // First pass: Collect char_ids to delete based on config CharakterDBIterator* iter_chars = charakters->iterator(charakters); // Create the iterator + char_ids_to_delete.clear(); while (iter_chars->next(iter_chars, &charakter)) { //ShowDebug("Charakter %s scanned\n", charakter.name); if (charakter.account_id == account_id) { - //ShowInfo("Charakter %s marked for deletion\n", charakter.name); + //ShowDebug("Charakter %s marked for deletion\n", charakter.name); char_ids_to_delete.push_back(charakter.char_id); } } @@ -297,7 +300,7 @@ int brokk_mmo_auth_delete_num(uint32 account_id) { // Second pass: Delete the collected charakters for (const auto& char_id : char_ids_to_delete) { - ShowInfo("Deleting charakter with ID %d.\n", char_id); + ShowInfo("Deleting character with ID %d.\n", char_id); if (!charakters->remove(charakters, char_id)) { ShowError("Failed to delete charakter (char_id: %s)\n", char_id); continue; // Deletion failed @@ -306,6 +309,7 @@ int brokk_mmo_auth_delete_num(uint32 account_id) { // Step 3B: Attempt to delete skills of the char (if any) // First pass: Collect skill_ids to delete based on config SkillDBIterator* iter_skills = skills->iterator(skills, char_id); // Create the iterator + skills_to_delete.clear(); while (iter_skills->next(iter_skills, char_id, &skill)) { std::string id_str = convert_skill_id_to_str(skill.skill_id); //ShowDebug("Skill %s found. Schedule for deletion...\n", id_str.c_str()); @@ -316,47 +320,58 @@ int brokk_mmo_auth_delete_num(uint32 account_id) { // Second pass: Delete the collected skills int skill_count = 0; for (const auto& skill_entry : skills_to_delete) { - //ShowInfo("Deleting skill with ID %d.\n", char_id); + //ShowDebug("Deleting skill with ID %d.\n", char_id); if (!skills->remove(skills, char_id, skill_entry.skill_id)) { ShowError("Failed to delete skill (skill_id: %s)\n", skill_entry.skill_id); continue; // Deletion failed } else { - //ShowNotice("Deleting of skill %s from char_id %d was successful\n", convert_skill_id_to_str(skill_entry.skill_id), char_id); + //ShowDebug("Deleting of skill %s from char_id %d was successful\n", convert_skill_id_to_str(skill_entry.skill_id), char_id); skill_count++; } } - ShowNotice("Skill cleanup for char_id %d completed. %d skills cleaned.\n", char_id, skill_count); - - ShowDebug("Marco\n"); //TODO Prüfn warum hier iterator keine validen items wirft + ShowStatus("Skill cleanup for char_id %d completed. %d skills cleaned.\n", char_id, skill_count); // Step 3C: Attempt to delete inventory of the char (if any) - // First pass: Collect inv_item_ids to delete based on config + // First pass: Collect inv_item_ids to delete based on config + InventoryDBIterator* iter_inventory = inventory->iterator(inventory, char_id); // Create the iterator - ShowDebug("Polo1\n"); - while (iter_inventory->next(iter_inventory, char_id, &item)) { - ShowDebug("Polo iter loop\n"); - std::string id_str = convert_item_id_to_name(item.item_id); - ShowDebug("Item %s found. Schedule for deletion...\n", id_str.c_str()); + items_to_delete.clear(); + + while (iter_inventory->next(iter_inventory, &item)) { + //std::string id_str = convert_item_id_to_name(item.item_id); + //ShowDebug("Item id %d found. Schedule for deletion...\n", item.item_id); items_to_delete.push_back(item); } iter_inventory->destroy(iter_inventory); // Destroy the iterator after use - ShowDebug("Polo2\n"); + //ShowDebug("Item-Scan completed.\n"); + bot_item_bundle bundle; + bundle.items = items_to_delete; + //dump_item_bundle(bundle); + // Second pass: Delete the collected items + int item_count = 0; for (const auto& inv_item_entry : items_to_delete) { - ShowInfo("Deleting item with ID %d.\n", inv_item_entry.inventory_id); + //ShowInfo("Attempting to delete item with inventory ID %u and item id %u.\n", inv_item_entry.inventory_id, inv_item_entry.item_id); + if (!inventory->remove(inventory, char_id, inv_item_entry.inventory_id)) { - ShowError("Failed to delete item (item_id: %s)\n", inv_item_entry.item_id); - continue; // Deletion failed - } - else { - ShowNotice("Deleting of item %s from char_id %d was successful\n", convert_item_id_to_aegisname(inv_item_entry.item_id), char_id); + ShowError("Failed to delete item (item_id: %u, char_id: %u)\n", inv_item_entry.item_id, char_id); + continue; // Log failure but continue with next item } + + // Verify deletion + //std::string aegisname = convert_item_id_to_aegisname(inv_item_entry.item_id); + //ShowDebug("Successfully deleted item %s (item_id: %u) from char_id: %u\n", aegisname.c_str(), inv_item_entry.item_id, char_id); + item_count++; } - ShowDebug("Polo3\n"); + ShowStatus("Item cleanup for char_id %d completed. %d items cleaned.\n", char_id, item_count); + + + ShowStatus("Character cleanup for char_id %d completed.\n", char_id); + } - ShowNotice("Bot account deletion completed (account: %s, id: %d)\n\n", acc.userid, acc.account_id); + ShowInfo("Bot account cleanup completed (account: %s, id: %d)\n\n", acc.userid, acc.account_id); return 0; // Success } @@ -772,12 +787,12 @@ int brokk_apply_item_loadout(bot_item_bundle& item_bundle, int& char_id) { } // Log success single item std::string aegisname = convert_item_id_to_aegisname(item.item_id); - ShowNotice("Item %s added to character char_id: %d)\n", aegisname.c_str(), item.char_id); + //ShowNotice("Item %s added to character char_id: %d)\n", aegisname.c_str(), item.char_id); item_count++; } // Log success - ShowStatus("Successfully added %d Items to characters inventory (name: %s, char_id: %d)\n", item_count, char_name.c_str(), char_id); + //ShowDebug("Successfully added %d Items to characters inventory (name: %s, char_id: %d)\n", item_count, char_name.c_str(), char_id); return -1; // Success } @@ -952,7 +967,7 @@ bool BrokkServer::initialize(int argc, char* argv[]) { if (!brokk_mmo_auth_new(userid, pass.c_str(), sex, true)) { ShowError("Failed to create bot account (userid: %s)\n", userid); continue; // Skip to the next bot account - } + } // Iterate over each character for this bot account // Retrieve the account ID for the newly created account (assuming your function updates a global or accessible database) @@ -964,6 +979,7 @@ bool BrokkServer::initialize(int argc, char* argv[]) { uint32 account_id = acc.account_id; // Iterate over each character for this bot account + ShowStatus("Bot account: %s (ID: %u) created.\n", userid_str.c_str(), account_id); if (bot.contains("characters")) { const auto& json_characters = bot["characters"]; @@ -994,17 +1010,19 @@ bool BrokkServer::initialize(int argc, char* argv[]) { // Step2: build data of character new_char.account_id = account_id; new_char.char_id = -1; - ShowInfo("Preparing build data for bot character %s ...\n", char_name.c_str()); + ShowStatus("Applied character meta data for bot char %s .\n", char_name.c_str()); + prepare_character_build_data(new_char, json_character, bot_job_db); + ShowStatus("Applied build data for bot character %s .\n", char_name.c_str()); // Step3: appearance of character - ShowInfo("Preparing appearance of bot character %s ...\n", char_name.c_str()); prepare_character_appearance_data(new_char, json_character); + ShowStatus("Applied appearance data for bot character %s .\n", char_name.c_str()); // Step4: location data of character - ShowInfo("Preparing location data for bot character %s ...\n", char_name.c_str()); prepare_character_location_data(new_char, json_character); - + ShowStatus("Applied location data for bot character %s .\n", char_name.c_str()); + // All char table related data is collected and can be saved to allow further steps (skills/items/equip) int new_char_id = 0; try { @@ -1024,11 +1042,12 @@ bool BrokkServer::initialize(int argc, char* argv[]) { ShowError("Character creation for '%s 'failed: %s\n",new_char.name, e.what()); continue; } + ShowStatus("DB entry for bot character %s created.\n", char_name.c_str()); // Step5: Skills // Prepare skills inside a skill bundle ShowInfo("Preparing skill data of bot character %s ...\n", char_name.c_str()); - bot_skill_bundle skill_bundle{}; + bot_skill_bundle skill_bundle{}; prepare_skill_bundle(skill_bundle, new_char_id, json_character); validate_skill_bundle(skill_bundle, job_id_str.c_str()); @@ -1045,79 +1064,35 @@ bool BrokkServer::initialize(int argc, char* argv[]) { continue; } - // ShowNotice("Skills successfully teached to character (name: %s, char_id: %d, sex: %c)\n", new_char.name, new_char.char_id, new_char.sex); + ShowStatus("Teached %d skills to bot character %s .\n", skill_bundle.skills.size(), char_name.c_str()); // Step6: Items // Prepare items inside a item bundle ShowInfo("Preparing inventory data for bot character %s ...\n", char_name.c_str()); - bot_item_bundle item_bundle{}; + bot_item_bundle item_bundle{}; prepare_item_bundle(item_bundle, new_char_id, json_character); // All inventory table related data is collected and can be saved try { - /* Lock-out while in debug + if (!brokk_apply_item_loadout(item_bundle, new_char_id)) { ShowError("Failed to create inventory entry for: %s\n", new_char.name); continue; - }*/ + } } catch (const std::exception& e) { ShowError("skill creation for '%s 'failed: %s\n", new_char.name, e.what()); continue; } - ShowStatus("Items successfully handed out to character (name: %s, char_id: %d, sex: %c)\n", new_char.name, new_char.char_id, new_char.sex); - + ShowStatus("%d Items successfully handed out to character (name: %s, char_id: %d, sex: %c)\n", item_bundle.items.size(), new_char.name, new_char.char_id, new_char.sex); + //Step5: Equipment //ShowInfo("Preparing equipment for bot character %s ...\n", char_name.c_str()); ShowStatus("Bot-Character creation and administration completed (name: %s, char_id: %d, sex: %c)\n\n", new_char.name, new_char.char_id, new_char.sex); - /***** - * Validating/Applying skill build - ***** - // DEBUG: check skill plausibility - const auto& skill_bundle = character["skills"]; - ShowDebug("Skill bundle: %s\n", skill_bundle.dump(4).c_str()); // Ensure `skill_bundle` is structured as expected - - for (const auto& skill : skill_bundle.items()) { - ShowDebug("Skill: %s", skill.key().c_str()); - std::unordered_map required_skill; - //skill >> required_skill; - std::string skill_str = skill.key(); - int skill_id = convert_skill_str_to_id(skill_str.c_str()); - if (skill_id < 0) { // Assuming negative IDs are invalid - ShowError("Invalid skill ID for skill string: %s\n", skill_str.c_str()); - continue; // Skip this iteration - } - - std::unordered_map parsed_skill_bundle; - for (const auto& skill : skill_bundle.items()) { - uint16 skill_id = convert_skill_str_to_id(skill.key().c_str()); - uint16 level = skill.value(); // Assuming the value represents the skill level - parsed_skill_bundle[skill_id] = level; - } - - bool skill_plausible = check_skill_requirements(start_job, skill_id, parsed_skill_bundle); - if (skill_plausible) { - ShowDebug("all requirements met for skill %s \n", skill.key()); - } - else { - ShowDebug("some requirements not met for skill %s , Cancel creation process?\n", skill.key()); - continue; - } - }*/ - - // Create the character for this account - // TODO rebuild to: - // if (!brokk_create_character(new_char, skill_build_data, item_data, equip_data true)) - /* - if (!brokk_create_character(account_id, char_name.c_str(), slot, base_level, job_level, str, agi, vit, int_, dex, luk, hair_style, hair_color, start_job, sex, true)) - { - ShowError("Failed to create charakter (char_name: %s)\n", char_name); - continue; // Skip to the next charakter - }*/ } } @@ -1125,8 +1100,11 @@ bool BrokkServer::initialize(int argc, char* argv[]) { ShowError("No 'characters' array found for bot (userid: %s)\n", userid); } + ShowStatus("Bot account: %s (ID: %u) creation completed.\n\n", userid_str.c_str(), account_id); + } - + ShowStatus("Bot account creation process completed.\n"); + // Other initialization logic //setup_periodic_cleanup_timer(); // Set up the cleanup timer diff --git a/src/bot/Brokk/helper_inventory.cpp b/src/bot/Brokk/helper_inventory.cpp index 13d4bfd..e4ba2ad 100644 --- a/src/bot/Brokk/helper_inventory.cpp +++ b/src/bot/Brokk/helper_inventory.cpp @@ -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; - inventory_id = atoi(data); uint32 skill_id; - + uint32 inventory_id = atoi(data); + item->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{}; diff --git a/src/bot/Brokk/helper_inventory.hpp b/src/bot/Brokk/helper_inventory.hpp index dba6aff..0ac93c6 100644 --- a/src/bot/Brokk/helper_inventory.hpp +++ b/src/bot/Brokk/helper_inventory.hpp @@ -105,7 +105,7 @@ struct InventoryDBIterator { /// @param self Iterator /// @param item InvItem data /// @return true if successful - bool (*next)(InventoryDBIterator* self, const uint32 char_id, struct bot_inv_item* item); + bool (*next)(InventoryDBIterator* self, struct bot_inv_item* item); }; @@ -180,9 +180,9 @@ struct InventoryDB { }; void set_bot_inv_item_defaults(bot_inv_item& item); -int convert_item_aegisname_to_id(const char* aegisname); -std::string convert_item_id_to_name(int item_id); -std::string convert_item_id_to_aegisname(int item_id); +uint32 convert_item_aegisname_to_id(const char* aegisname); +std::string convert_item_id_to_name(uint32 item_id); +std::string convert_item_id_to_aegisname(uint32 item_id); struct bot_item { uint32 item_id; @@ -196,4 +196,5 @@ struct bot_item_bundle { }; void prepare_item_bundle(bot_item_bundle& bundle, uint32 char_id, const nlohmann::json& character); +void dump_item_bundle(const bot_item_bundle& item_bundle); #endif /* HELPER_INVENTORY_HPP */ diff --git a/src/bot/Brokk/helper_skills.cpp b/src/bot/Brokk/helper_skills.cpp index d00af05..3db51c7 100644 --- a/src/bot/Brokk/helper_skills.cpp +++ b/src/bot/Brokk/helper_skills.cpp @@ -854,23 +854,6 @@ void BotSkillTreeDatabase::loadingFinished() { TypesafeYamlDatabase::loadingFinished(); } -std::unordered_map parse_skill_bundle(const nlohmann::json& skill_bundle) { - std::unordered_map parsed_skill_bundle; - - for (const auto& skill : skill_bundle.items()) { - uint16 skill_id = convert_skill_str_to_id(skill.key().c_str()); - if (skill_id < 0) { - ShowError("Invalid skill ID for skill string: %s\n", skill.key().c_str()); - continue; // Skip invalid skills - } - - uint16 level = skill.value(); // Assuming the value represents the skill level - parsed_skill_bundle[skill_id] = level; - } - - return parsed_skill_bundle; -} - void dump_skill_bundle(const bot_skill_bundle& skill_bundle) { ShowDebug("Dumping skill bundle contents...\n"); if (skill_bundle.skills.empty()) { @@ -947,7 +930,7 @@ void validate_skill_bundle(bot_skill_bundle& skill_bundle, const char* job_id) { // Update the skill bundle with valid skills skill_bundle.skills = std::move(valid_skills); - ShowStatus("Skill bundle validation completed for job ID: %s.\n", job_id); + //ShowStatus("Skill bundle validation completed for job ID: %s.\n", job_id); } void prepare_skill_bundle(bot_skill_bundle& bundle, uint32 char_id, const nlohmann::json& character) {