diff --git a/common/repositories/base/base_character_item_recast_repository.h b/common/repositories/base/base_character_item_recast_repository.h index 929705ff8..1784a3b30 100644 --- a/common/repositories/base/base_character_item_recast_repository.h +++ b/common/repositories/base/base_character_item_recast_repository.h @@ -6,7 +6,7 @@ * Any modifications to base repositories are to be made by the generator only * * @generator ./utils/scripts/generators/repository-generator.pl - * @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories + * @docs https://docs.eqemu.io/developer/repositories */ #ifndef EQEMU_BASE_CHARACTER_ITEM_RECAST_REPOSITORY_H @@ -16,11 +16,12 @@ #include "../../strings.h" #include + class BaseCharacterItemRecastRepository { public: struct CharacterItemRecast { uint32_t id; - uint16_t recast_type; + uint32_t recast_type; uint32_t timestamp; }; @@ -112,8 +113,9 @@ public: { auto results = db.QueryDatabase( fmt::format( - "{} WHERE id = {} LIMIT 1", + "{} WHERE {} = {} LIMIT 1", BaseSelect(), + PrimaryKey(), character_item_recast_id ) ); @@ -123,7 +125,7 @@ public: CharacterItemRecast e{}; e.id = static_cast(strtoul(row[0], nullptr, 10)); - e.recast_type = static_cast(strtoul(row[1], nullptr, 10)); + e.recast_type = static_cast(strtoul(row[1], nullptr, 10)); e.timestamp = static_cast(strtoul(row[2], nullptr, 10)); return e; @@ -251,7 +253,7 @@ public: CharacterItemRecast e{}; e.id = static_cast(strtoul(row[0], nullptr, 10)); - e.recast_type = static_cast(strtoul(row[1], nullptr, 10)); + e.recast_type = static_cast(strtoul(row[1], nullptr, 10)); e.timestamp = static_cast(strtoul(row[2], nullptr, 10)); all_entries.push_back(e); @@ -278,7 +280,7 @@ public: CharacterItemRecast e{}; e.id = static_cast(strtoul(row[0], nullptr, 10)); - e.recast_type = static_cast(strtoul(row[1], nullptr, 10)); + e.recast_type = static_cast(strtoul(row[1], nullptr, 10)); e.timestamp = static_cast(strtoul(row[2], nullptr, 10)); all_entries.push_back(e); @@ -338,6 +340,66 @@ public: return (results.Success() && results.begin()[0] ? strtoll(results.begin()[0], nullptr, 10) : 0); } + static std::string BaseReplace() + { + return fmt::format( + "REPLACE INTO {} ({}) ", + TableName(), + ColumnsRaw() + ); + } + + static int ReplaceOne( + Database& db, + const CharacterItemRecast &e + ) + { + std::vector v; + + v.push_back(std::to_string(e.id)); + v.push_back(std::to_string(e.recast_type)); + v.push_back(std::to_string(e.timestamp)); + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES ({})", + BaseReplace(), + Strings::Implode(",", v) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } + + static int ReplaceMany( + Database& db, + const std::vector &entries + ) + { + std::vector insert_chunks; + + for (auto &e: entries) { + std::vector v; + + v.push_back(std::to_string(e.id)); + v.push_back(std::to_string(e.recast_type)); + v.push_back(std::to_string(e.timestamp)); + + insert_chunks.push_back("(" + Strings::Implode(",", v) + ")"); + } + + std::vector v; + + auto results = db.QueryDatabase( + fmt::format( + "{} VALUES {}", + BaseReplace(), + Strings::Implode(",", insert_chunks) + ) + ); + + return (results.Success() ? results.RowsAffected() : 0); + } }; #endif //EQEMU_BASE_CHARACTER_ITEM_RECAST_REPOSITORY_H diff --git a/common/shareddb.cpp b/common/shareddb.cpp index d75081945..ebf07027f 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -44,6 +44,7 @@ #include "repositories/starting_items_repository.h" #include "path_manager.h" #include "repositories/loottable_repository.h" +#include "repositories/character_item_recast_repository.h" namespace ItemField { @@ -882,34 +883,49 @@ bool SharedDatabase::GetInventory(uint32 account_id, char *name, EQ::InventoryPr std::map SharedDatabase::GetItemRecastTimestamps(uint32 char_id) { std::map timers; - const std::string query = StringFormat("SELECT recast_type,timestamp FROM character_item_recast WHERE id=%u", char_id); - auto results = QueryDatabase(query); - if (!results.Success() || results.RowCount() == 0) - return timers; - for (auto& row = results.begin(); row != results.end(); ++row) - timers[Strings::ToUnsignedInt(row[0])] = Strings::ToUnsignedInt(row[1]); - return timers; // RVO or move assigned + const auto& l = CharacterItemRecastRepository::GetWhere( + *this, + fmt::format( + "`id` = {}", + char_id + ) + ); + + if (l.empty()) { + return timers; + } + + for (const auto& e : l) { + timers[e.recast_type] = e.timestamp; + } + + return timers; } uint32 SharedDatabase::GetItemRecastTimestamp(uint32 char_id, uint32 recast_type) { - const std::string query = StringFormat("SELECT timestamp FROM character_item_recast WHERE id=%u AND recast_type=%u", - char_id, recast_type); - auto results = QueryDatabase(query); - if (!results.Success() || results.RowCount() == 0) - return 0; + const auto& l = CharacterItemRecastRepository::GetWhere( + *this, + fmt::format( + "`id` = {} AND `recast_type` = {}", + char_id, + recast_type + ) + ); - auto& row = results.begin(); - return Strings::ToUnsignedInt(row[0]); + return l.empty() ? 0 : l[0].timestamp; } void SharedDatabase::ClearOldRecastTimestamps(uint32 char_id) { - // This actually isn't strictly live-like. Live your recast timestamps are forever - const std::string query = - StringFormat("DELETE FROM character_item_recast WHERE id = %u and timestamp < UNIX_TIMESTAMP()", char_id); - QueryDatabase(query); + CharacterItemRecastRepository::DeleteWhere( + *this, + fmt::format( + "`id` = {} AND `timestamp` < UNIX_TIMESTAMP()", + char_id + ) + ); } void SharedDatabase::GetItemsCount(int32 &item_count, uint32 &max_id) diff --git a/zone/spells.cpp b/zone/spells.cpp index dd867b2a2..4b5564973 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -6504,10 +6504,13 @@ void Client::SendItemRecastTimer(int32 recast_type, uint32 recast_delay, bool in if (recast_delay) { auto outapp = new EQApplicationPacket(OP_ItemRecastDelay, sizeof(ItemRecastDelay_Struct)); - ItemRecastDelay_Struct *ird = (ItemRecastDelay_Struct *)outapp->pBuffer; - ird->recast_delay = recast_delay; - ird->recast_type = static_cast(recast_type); + + auto ird = (ItemRecastDelay_Struct *) outapp->pBuffer; + + ird->recast_delay = recast_delay; + ird->recast_type = static_cast(recast_type); ird->ignore_casting_requirement = in_ignore_casting_requirement; //True allows reset of item cast timers + QueuePacket(outapp); safe_delete(outapp); } @@ -6515,150 +6518,157 @@ void Client::SendItemRecastTimer(int32 recast_type, uint32 recast_delay, bool in void Client::SetItemRecastTimer(int32 spell_id, uint32 inventory_slot) { - EQ::ItemInstance *item = CastToClient()->GetInv().GetItem(inventory_slot); - - int recast_delay = 0; - int recast_type = 0; - bool from_augment = false; - int item_casting = 0; + auto item = CastToClient()->GetInv().GetItem(inventory_slot); if (!item) { return; } - item_casting = item->GetItem()->ID; - //Check primary item. - if (item->GetItem()->RecastDelay > 0) { + uint32 recast_delay = 0; + int recast_type = 0; + uint32 item_id = item->GetItem()->ID; + bool from_augment = false; + + if (item->GetItem()->RecastDelay > 0) { // Check item recast_type = item->GetItem()->RecastType; recast_delay = item->GetItem()->RecastDelay; - } - //Check augmenent - else{ + } else { // Check augments for (int r = EQ::invaug::SOCKET_BEGIN; r <= EQ::invaug::SOCKET_END; r++) { - const EQ::ItemInstance* aug_i = item->GetAugment(r); + const auto aug = item->GetAugment(r); - if (!aug_i) { - continue; - } - const EQ::ItemData* aug = aug_i->GetItem(); if (!aug) { continue; } - if (aug->Click.Effect == spell_id) { - recast_delay = aug_i->GetItem()->RecastDelay; - recast_type = aug_i->GetItem()->RecastType; + const auto aug_data = aug->GetItem(); + if (!aug_data) { + continue; + } + + if (aug_data->Click.Effect == spell_id) { + recast_delay = aug->GetItem()->RecastDelay; + recast_type = aug->GetItem()->RecastType; from_augment = true; - item_casting = aug_i->GetItem()->ID; + item_id = aug->GetItem()->ID; break; } } } + //must use SPA 415 with focus (SPA 310) to reduce item recast int reduction = GetFocusEffect(focusReduceRecastTime, spell_id); if (reduction) { recast_delay -= reduction; } - recast_delay = std::max(recast_delay, 0); + recast_delay = std::max(recast_delay, static_cast(0)); if (recast_delay > 0) { - if (recast_type != RECAST_TYPE_UNLINKED_ITEM) { - GetPTimers().Start((pTimerItemStart + recast_type), static_cast(recast_delay)); + GetPTimers().Start((pTimerItemStart + recast_type), recast_delay); database.UpdateItemRecast( CharacterID(), recast_type, GetPTimers().Get(pTimerItemStart + recast_type)->GetReadyTimestamp() ); } else if (recast_type == RECAST_TYPE_UNLINKED_ITEM) { - GetPTimers().Start((pTimerNegativeItemReuse * item_casting), static_cast(recast_delay)); + GetPTimers().Start((pTimerNegativeItemReuse * item_id), recast_delay); database.UpdateItemRecast( CharacterID(), - item_casting, - GetPTimers().Get(pTimerNegativeItemReuse * item_casting)->GetReadyTimestamp() + item_id, + GetPTimers().Get(pTimerNegativeItemReuse * item_id)->GetReadyTimestamp() ); } if (!from_augment) { - SendItemRecastTimer(recast_type, static_cast(recast_delay)); + SendItemRecastTimer(recast_type, recast_delay); } } } void Client::DeleteItemRecastTimer(uint32 item_id) { - const auto* d = database.GetItem(item_id); + const auto item = database.GetItem(item_id); - if (!d) { - return; - } + if (!item) { + return; + } - const auto recast_type = d->RecastType != RECAST_TYPE_UNLINKED_ITEM ? d->RecastType : item_id; - const int timer_id = d->RecastType != RECAST_TYPE_UNLINKED_ITEM ? (pTimerItemStart + recast_type) : (pTimerNegativeItemReuse * item_id); + const auto recast_type = ( + item->RecastType != RECAST_TYPE_UNLINKED_ITEM ? + item->RecastType : + item_id + ); - database.DeleteItemRecast(CharacterID(), recast_type); - GetPTimers().Clear(&database, timer_id); + const int timer_id = ( + item->RecastType != RECAST_TYPE_UNLINKED_ITEM ? + (pTimerItemStart + recast_type) : + (pTimerNegativeItemReuse * item_id) + ); - if (recast_type != RECAST_TYPE_UNLINKED_ITEM) { - SendItemRecastTimer(recast_type, 1, true); - } + database.DeleteItemRecast(CharacterID(), recast_type); + GetPTimers().Clear(&database, timer_id); + + if (recast_type != RECAST_TYPE_UNLINKED_ITEM) { + SendItemRecastTimer(recast_type, 1, true); + } } bool Client::HasItemRecastTimer(int32 spell_id, uint32 inventory_slot) { - EQ::ItemInstance *item = CastToClient()->GetInv().GetItem(inventory_slot); + auto item = CastToClient()->GetInv().GetItem(inventory_slot); - int recast_delay = 0; - int recast_type = 0; - int item_id = 0; - bool from_augment = false; - - if (!item) { + if (!item || !item->GetItem()) { return false; } - if (!item->GetItem()) { - return false; - } + uint32 recast_delay = 0; + int recast_type = 0; + uint32 item_id = 0; + bool from_augment = false; - //Check primary item. - if (item->GetItem()->RecastDelay > 0) { - recast_type = item->GetItem()->RecastType; + if (item->GetItem()->RecastDelay > 0) { // Check item + recast_type = item->GetItem()->RecastType; recast_delay = item->GetItem()->RecastDelay; - item_id = item->GetItem()->ID; - } - //Check augmenent - else { + item_id = item->GetItem()->ID; + } else { // Check augments for (int r = EQ::invaug::SOCKET_BEGIN; r <= EQ::invaug::SOCKET_END; r++) { - const EQ::ItemInstance* aug_i = item->GetAugment(r); + const auto aug = item->GetAugment(r); - if (!aug_i) { - continue; - } - const EQ::ItemData* aug = aug_i->GetItem(); if (!aug) { continue; } - if (aug->Click.Effect == spell_id) { - if (aug_i->GetItem() && aug_i->GetItem()->RecastDelay > 0) { - recast_delay = aug_i->GetItem()->RecastDelay; - recast_type = aug_i->GetItem()->RecastType; - item_id = aug_i->GetItem()->ID; + const auto aug_data = aug->GetItem(); + if (!aug_data) { + continue; + } + + if (aug_data->Click.Effect == spell_id) { + if (aug->GetItem() && aug->GetItem()->RecastDelay > 0) { + recast_delay = aug->GetItem()->RecastDelay; + recast_type = aug->GetItem()->RecastType; + item_id = aug->GetItem()->ID; } + break; } } } - //do not check if item has no recast delay. + if (!recast_delay) { return false; } - //if time is not expired, then it exists and therefore we have a recast on this item. - if (recast_type != RECAST_TYPE_UNLINKED_ITEM && !CastToClient()->GetPTimers().Expired(&database, (pTimerItemStart + recast_type), false)) { + + if ( + recast_type != RECAST_TYPE_UNLINKED_ITEM && + !CastToClient()->GetPTimers().Expired(&database, (pTimerItemStart + recast_type), false) + ) { return true; - } else if (recast_type == RECAST_TYPE_UNLINKED_ITEM && !CastToClient()->GetPTimers().Expired(&database, (pTimerNegativeItemReuse * item_id), false)) { + } else if ( + recast_type == RECAST_TYPE_UNLINKED_ITEM && + !CastToClient()->GetPTimers().Expired(&database, (pTimerNegativeItemReuse * item_id), false) + ) { return true; } diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 96c3dc955..2acbee8f1 100755 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -35,6 +35,7 @@ #include "../common/repositories/character_alternate_abilities_repository.h" #include "../common/repositories/character_auras_repository.h" #include "../common/repositories/character_alt_currency_repository.h" +#include "../common/repositories/character_item_recast_repository.h" #include #include @@ -3279,23 +3280,26 @@ void ZoneDatabase::RemoveTempFactions(Client *client) { void ZoneDatabase::UpdateItemRecast(uint32 character_id, uint32 recast_type, uint32 timestamp) { - const auto query = fmt::format( - "REPLACE INTO character_item_recast (id, recast_type, timestamp) VALUES ({}, {}, {})", - character_id, - recast_type, - timestamp + CharacterItemRecastRepository::ReplaceOne( + *this, + CharacterItemRecastRepository::CharacterItemRecast{ + .id = character_id, + .recast_type = recast_type, + .timestamp = timestamp, + } ); - QueryDatabase(query); } void ZoneDatabase::DeleteItemRecast(uint32 character_id, uint32 recast_type) { - const auto query = fmt::format( - "DELETE FROM character_item_recast WHERE id = {} AND recast_type = {}", - character_id, - recast_type + CharacterItemRecastRepository::DeleteWhere( + *this, + fmt::format( + "`id` = {} AND `recast_type` = {}", + character_id, + recast_type + ) ); - QueryDatabase(query); } void ZoneDatabase::LoadPetInfo(Client *client)