diff --git a/common/repositories/inventory_snapshots_repository.h b/common/repositories/inventory_snapshots_repository.h index 487adc37d..6acf9ea8d 100644 --- a/common/repositories/inventory_snapshots_repository.h +++ b/common/repositories/inventory_snapshots_repository.h @@ -167,27 +167,51 @@ public: } } - static void TransformToInv(InventorySnapshots &out, const InventoryRepository::Inventory &in, uint32 time_index) + static void DivergeCharacterInvSnapshotFromInventory( + Database &db, + uint32 character_id, + uint32 timestamp, + std::list> &compare_list) { - out.character_id = in.character_id; - out.item_id = in.item_id; - out.item_unique_id = in.item_unique_id; - out.augment_one = in.augment_one; - out.augment_two = in.augment_two; - out.augment_three = in.augment_three; - out.augment_four = in.augment_four; - out.augment_five = in.augment_five; - out.augment_six = in.augment_six; - out.charges = in.charges; - out.color = in.color; - out.custom_data = in.custom_data; - out.instnodrop = in.instnodrop; - out.ornament_hero_model = in.ornament_hero_model; - out.ornament_icon = in.ornament_icon; - out.ornament_idfile = in.ornament_idfile; - out.guid = in.guid; - out.slot_id = in.slot_id; - out.time_index = time_index; + const std::string &query = fmt::format( + "SELECT slot_id, item_id FROM `inventory_snapshots` " + "WHERE `time_index` = '{0}' AND `character_id` = '{1}' AND `slot_id` NOT IN (" + "SELECT a.`slot_id` FROM `inventory_snapshots` a JOIN `inventory` b USING (`slot_id`, `item_id`) " + "WHERE a.`time_index` = '{0}' AND a.`character_id` = '{1}' AND b.`character_id` = '{1}')", + timestamp, + character_id + ); + auto results = db.QueryDatabase(query); + + if (!results.Success()) { + return; + } + + for (auto row: results) { + compare_list.emplace_back(std::pair(Strings::ToInt(row[0]), Strings::ToUnsignedInt(row[1]))); + } + } + + static void DivergeCharacterInventoryFromInvSnapshot( + Database &db, uint32 character_id, uint32 timestamp, std::list> &compare_list) + { + const std::string &query = fmt::format( + "SELECT `slot_id`, `item_id` FROM `inventory` WHERE " + "`character_id` = '{0}' AND `slot_id` NOT IN (" + "SELECT a.`slot_id` FROM `inventory` a JOIN `inventory_snapshots` b USING (`slot_id`, `item_id`) " + "WHERE b.`time_index` = '{1}' AND b.`character_id` = '{0}' AND a.`character_id` = '{0}')", + character_id, + timestamp + ); + + auto results = db.QueryDatabase(query); + if (!results.Success()) { + return; + } + + for (auto row: results) { + compare_list.emplace_back(std::pair(Strings::ToInt(row[0]), Strings::ToUnsignedInt(row[1]))); + } } static bool SaveCharacterInvSnapshot(Database &db, uint32 character_id) @@ -196,23 +220,104 @@ public: std::vector queue{}; auto inventory = InventoryRepository::GetWhere(db, fmt::format("`character_id` = '{}'", character_id)); + if (inventory.empty()) { + LogError("Character ID [{}] inventory is empty. Snapshot not created", character_id); + return false; + } for (auto const &i: inventory) { - auto snapshot = NewEntity(); - TransformToInv(snapshot, i, time_index); + auto snapshot = NewEntity(); + snapshot.character_id = i.character_id; + snapshot.item_id = i.item_id; + snapshot.item_unique_id = i.item_unique_id; + snapshot.augment_one = i.augment_one; + snapshot.augment_two = i.augment_two; + snapshot.augment_three = i.augment_three; + snapshot.augment_four = i.augment_four; + snapshot.augment_five = i.augment_five; + snapshot.augment_six = i.augment_six; + snapshot.charges = i.charges; + snapshot.color = i.color; + snapshot.custom_data = i.custom_data; + snapshot.instnodrop = i.instnodrop; + snapshot.ornament_hero_model = i.ornament_hero_model; + snapshot.ornament_icon = i.ornament_icon; + snapshot.ornament_idfile = i.ornament_idfile; + snapshot.guid = i.guid; + snapshot.slot_id = i.slot_id; + snapshot.time_index = time_index; queue.push_back(snapshot); } - if (!queue.empty()) { - InsertMany(db, queue); - LogInventory("Created inventory snapshot for [{}] with ([{}]) items", character_id, queue.size()); - return true; + if (queue.empty()) { + LogError("Character ID [{}] inventory is empty. Snapshot not created", character_id); + return false; } - LogInventory("Failed to created inventory snapshot for [{}]", character_id); - return false; + if (!InsertMany(db, queue)) { + LogError("Failed to created inventory snapshot for [{}]", character_id); + return false; + } + + LogInventory("Created inventory snapshot for [{}] with ([{}]) items", character_id, queue.size()); + return true; } + static bool RestoreCharacterInvSnapshot(Database &db, uint32 character_id, uint32 timestamp) + { + InventoryRepository::DeleteWhere(db, fmt::format("`character_id` = '{}'", character_id)); + + auto snapshot = GetWhere(db, fmt::format("`character_id` = '{}' AND `time_index` = '{}'", character_id, timestamp)); + if (snapshot.empty()) { + LogError("The snapshot requested could not be found. Restore failed for character id [{}] @ [{}] failed", + character_id, + timestamp + ); + return false; + } + + std::vector queue{}; + for (auto const &i: snapshot) { + auto inventory_entry = InventoryRepository::NewEntity(); + inventory_entry.character_id = i.character_id; + inventory_entry.item_id = i.item_id; + inventory_entry.item_unique_id = i.item_unique_id; + inventory_entry.augment_one = i.augment_one; + inventory_entry.augment_two = i.augment_two; + inventory_entry.augment_three = i.augment_three; + inventory_entry.augment_four = i.augment_four; + inventory_entry.augment_five = i.augment_five; + inventory_entry.augment_six = i.augment_six; + inventory_entry.charges = i.charges; + inventory_entry.color = i.color; + inventory_entry.custom_data = i.custom_data; + inventory_entry.instnodrop = i.instnodrop; + inventory_entry.ornament_hero_model = i.ornament_hero_model; + inventory_entry.ornament_icon = i.ornament_icon; + inventory_entry.ornament_idfile = i.ornament_idfile; + inventory_entry.guid = i.guid; + inventory_entry.slot_id = i.slot_id; + queue.push_back(inventory_entry); + } + + if (queue.empty()) { + LogError("The snapshot is empty. Restore failed for character id [{}] @ [{}] failed", character_id, timestamp); + return false; + } + + if (!InventoryRepository::InsertMany(db, queue)) { + LogError("A database error occurred. Restore failed for character id [{}] @ [{}] failed", character_id, timestamp); + return false; + } + + LogInventory( + "Restore complete for character id [{}] with snapshot @ [{}] with [{}] entries", + character_id, + timestamp, + queue.size() + ); + return true; + } }; #endif //EQEMU_INVENTORY_SNAPSHOTS_REPOSITORY_H diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 56ccaee42..4df6e956d 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1350,89 +1350,14 @@ void ZoneDatabase::ParseCharacterInvSnapshot(uint32 character_id, uint32 timesta InventorySnapshotsRepository::ParseCharacterInvSnapshot(*this, character_id, timestamp, parse_list); } -void ZoneDatabase::DivergeCharacterInvSnapshotFromInventory(uint32 character_id, uint32 timestamp, std::list> &compare_list) { - std::string query = StringFormat( - "SELECT" - " slot_id," - " item_id " - "FROM" - " `inventory_snapshots` " - "WHERE" - " `time_index` = %u " - "AND" - " `character_id` = %u " - "AND" - " `slot_id` NOT IN " - "(" - "SELECT" - " a.`slot_id` " - "FROM" - " `inventory_snapshots` a " - "JOIN" - " `inventory` b " - "USING" - " (`slot_id`, `item_id`) " - "WHERE" - " a.`time_index` = %u " - "AND" - " a.`character_id` = %u " - "AND" - " b.`character_id` = %u" - ")", - timestamp, - character_id, - timestamp, - character_id, - character_id - ); - auto results = QueryDatabase(query); - - if (!results.Success()) - return; - - for (auto row : results) - compare_list.emplace_back(std::pair(Strings::ToInt(row[0]), Strings::ToUnsignedInt(row[1]))); +void ZoneDatabase::DivergeCharacterInvSnapshotFromInventory(uint32 character_id, uint32 timestamp, std::list> &compare_list) +{ + InventorySnapshotsRepository::DivergeCharacterInvSnapshotFromInventory(*this, character_id, timestamp, compare_list); } -void ZoneDatabase::DivergeCharacterInventoryFromInvSnapshot(uint32 character_id, uint32 timestamp, std::list> &compare_list) { - std::string query = StringFormat( - "SELECT" - " `slot_id`," - " `item_id` " - "FROM" - " `inventory` " - "WHERE" - " `character_id` = %u " - "AND" - " `slot_id` NOT IN " - "(" - "SELECT" - " a.`slot_id` " - "FROM" - " `inventory` a " - "JOIN" - " `inventory_snapshots` b " - "USING" - " (`slot_id`, `item_id`) " - "WHERE" - " b.`time_index` = %u " - "AND" - " b.`character_id` = %u " - "AND" - " a.`character_id` = %u" - ")", - character_id, - timestamp, - character_id, - character_id - ); - auto results = QueryDatabase(query); - - if (!results.Success()) - return; - - for (auto row : results) - compare_list.emplace_back(std::pair(Strings::ToInt(row[0]), Strings::ToUnsignedInt(row[1]))); +void ZoneDatabase::DivergeCharacterInventoryFromInvSnapshot(uint32 character_id, uint32 timestamp, std::list> &compare_list) +{ + InventorySnapshotsRepository::DivergeCharacterInventoryFromInvSnapshot(*this, character_id, timestamp, compare_list); } bool ZoneDatabase::RestoreCharacterInvSnapshot(uint32 character_id, uint32 timestamp) { @@ -1443,73 +1368,7 @@ bool ZoneDatabase::RestoreCharacterInvSnapshot(uint32 character_id, uint32 times return false; } - std::string query = StringFormat( - "DELETE " - "FROM" - " `inventory` " - "WHERE" - " `character_id` = %u", - character_id - ); - auto results = database.QueryDatabase(query); - if (!results.Success()) - return false; - - query = StringFormat( - "INSERT " - "INTO" - " `inventory` " - "(`character_id`," - " `slot_id`," - " `item_id`," - " `charges`," - " `color`," - " `augment_one`," - " `augment_two`," - " `augment_three`," - " `augment_four`," - " `augment_five`," - " `augment_six`," - " `instnodrop`," - " `custom_data`," - " `ornament_icon`," - " `ornament_idfile`," - " `ornament_hero_model`," - " `guid` " - ") " - "SELECT" - " `charid`," - " `slotid`," - " `itemid`," - " `charges`," - " `color`," - " `augslot1`," - " `augslot2`," - " `augslot3`," - " `augslot4`," - " `augslot5`," - " `augslot6`," - " `instnodrop`," - " `custom_data`," - " `ornamenticon`," - " `ornamentidfile`," - " `ornament_hero_model`, " - " `guid` " - "FROM" - " `inventory_snapshots` " - "WHERE" - " `charid` = %u " - "AND" - " `time_index` = %u", - character_id, - timestamp - ); - results = database.QueryDatabase(query); - - LogInventory("[{}] snapshot for [{}] @ [{}]", - (results.Success() ? "restored" : "failed to restore"), character_id, timestamp); - - return results.Success(); + return InventorySnapshotsRepository::RestoreCharacterInvSnapshot(database, character_id, timestamp); } const NPCType *ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load /*= false*/)