diff --git a/common/repositories/base/base_character_buffs_repository.h b/common/repositories/base/base_character_buffs_repository.h index e4de463a3..4b3124c29 100644 --- a/common/repositories/base/base_character_buffs_repository.h +++ b/common/repositories/base/base_character_buffs_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_BUFFS_REPOSITORY_H @@ -16,6 +16,7 @@ #include "../../strings.h" #include + class BaseCharacterBuffsRepository { public: struct CharacterBuffs { @@ -168,8 +169,9 @@ public: { auto results = db.QueryDatabase( fmt::format( - "{} WHERE id = {} LIMIT 1", + "{} WHERE {} = {} LIMIT 1", BaseSelect(), + PrimaryKey(), character_buffs_id ) ); @@ -478,6 +480,94 @@ 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 CharacterBuffs &e + ) + { + std::vector v; + + v.push_back(std::to_string(e.character_id)); + v.push_back(std::to_string(e.slot_id)); + v.push_back(std::to_string(e.spell_id)); + v.push_back(std::to_string(e.caster_level)); + v.push_back("'" + Strings::Escape(e.caster_name) + "'"); + v.push_back(std::to_string(e.ticsremaining)); + v.push_back(std::to_string(e.counters)); + v.push_back(std::to_string(e.numhits)); + v.push_back(std::to_string(e.melee_rune)); + v.push_back(std::to_string(e.magic_rune)); + v.push_back(std::to_string(e.persistent)); + v.push_back(std::to_string(e.dot_rune)); + v.push_back(std::to_string(e.caston_x)); + v.push_back(std::to_string(e.caston_y)); + v.push_back(std::to_string(e.caston_z)); + v.push_back(std::to_string(e.ExtraDIChance)); + v.push_back(std::to_string(e.instrument_mod)); + + 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.character_id)); + v.push_back(std::to_string(e.slot_id)); + v.push_back(std::to_string(e.spell_id)); + v.push_back(std::to_string(e.caster_level)); + v.push_back("'" + Strings::Escape(e.caster_name) + "'"); + v.push_back(std::to_string(e.ticsremaining)); + v.push_back(std::to_string(e.counters)); + v.push_back(std::to_string(e.numhits)); + v.push_back(std::to_string(e.melee_rune)); + v.push_back(std::to_string(e.magic_rune)); + v.push_back(std::to_string(e.persistent)); + v.push_back(std::to_string(e.dot_rune)); + v.push_back(std::to_string(e.caston_x)); + v.push_back(std::to_string(e.caston_y)); + v.push_back(std::to_string(e.caston_z)); + v.push_back(std::to_string(e.ExtraDIChance)); + v.push_back(std::to_string(e.instrument_mod)); + + 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_BUFFS_REPOSITORY_H diff --git a/zone/entity.cpp b/zone/entity.cpp index a2412f63c..cabe9d31c 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -1814,14 +1814,14 @@ void EntityList::DuelMessage(Mob *winner, Mob *loser, bool flee) } } -Client *EntityList::GetClientByName(const char *checkname) +Client *EntityList::GetClientByName(const char* name) { - auto it = client_list.begin(); - while (it != client_list.end()) { - if (strcasecmp(it->second->GetName(), checkname) == 0) - return it->second; - ++it; + for (const auto& e : client_list) { + if (e.second && Strings::EqualFold(e.second->GetName(), name)) { + return e.second; + } } + return nullptr; } diff --git a/zone/entity.h b/zone/entity.h index 20a368298..1638dd40d 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -171,7 +171,7 @@ public: return it->second; return nullptr; } - Client *GetClientByName(const char *name); + Client *GetClientByName(const char* name); Client *GetClientByAccID(uint32 accid); inline Client *GetClientByID(uint16 id) { diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 0f44a02fa..81c81d45e 100755 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -2930,160 +2930,150 @@ void ZoneDatabase::UpdateAltCurrencyValue(uint32 char_id, uint32 currency_id, ui } -void ZoneDatabase::SaveBuffs(Client *client) { +void ZoneDatabase::SaveBuffs(Client *client) +{ + CharacterBuffsRepository::DeleteWhere( + database, + fmt::format( + "`character_id` = {}", + client->CharacterID() + ) + ); - // delete the character buffs - CharacterBuffsRepository::DeleteWhere(database, fmt::format("character_id = {}", client->CharacterID())); + auto buffs = client->GetBuffs(); + const int max_buff_slots = client->GetMaxBuffSlots(); - // get the character buffs - uint32 buff_count = client->GetMaxBuffSlots(); - Buffs_Struct *buffs = client->GetBuffs(); + std::vector v; - // character buffs struct - auto b = CharacterBuffsRepository::NewEntity(); + auto e = CharacterBuffsRepository::NewEntity(); - // vector of character buffs - std::vector character_buffs = {}; + uint32 character_buff_count = 0; - // count the number of buffs that are valid - int character_buff_count = 0; - for (int index = 0; index < buff_count; index++) { - if (!IsValidSpell(buffs[index].spellid)) { + for (int slot_id = 0; slot_id < max_buff_slots; slot_id++) { + if (!IsValidSpell(buffs[slot_id].spellid)) { continue; } + character_buff_count++; } - // allocate memory for the character buffs - character_buffs.reserve(character_buff_count); + v.reserve(character_buff_count); - for (int index = 0; index < buff_count; index++) { - if (!IsValidSpell(buffs[index].spellid)) { + for (int slot_id = 0; slot_id < max_buff_slots; slot_id++) { + if (!IsValidSpell(buffs[slot_id].spellid)) { continue; } - // fill in the buff struct - b.character_id = client->CharacterID(); - b.slot_id = index; - b.spell_id = buffs[index].spellid; - b.caster_level = buffs[index].casterlevel; - b.caster_name = buffs[index].caster_name; - b.ticsremaining = buffs[index].ticsremaining; - b.counters = buffs[index].counters; - b.numhits = buffs[index].hit_number; - b.melee_rune = buffs[index].melee_rune; - b.magic_rune = buffs[index].magic_rune; - b.persistent = buffs[index].persistant_buff; - b.dot_rune = buffs[index].dot_rune; - b.caston_x = buffs[index].caston_x; - b.caston_y = buffs[index].caston_y; - b.caston_z = buffs[index].caston_z; - b.ExtraDIChance = buffs[index].ExtraDIChance; - b.instrument_mod = buffs[index].instrument_mod; + e.character_id = client->CharacterID(); + e.slot_id = slot_id; + e.spell_id = buffs[slot_id].spellid; + e.caster_level = buffs[slot_id].casterlevel; + e.caster_name = buffs[slot_id].caster_name; + e.ticsremaining = buffs[slot_id].ticsremaining; + e.counters = buffs[slot_id].counters; + e.numhits = buffs[slot_id].hit_number; + e.melee_rune = buffs[slot_id].melee_rune; + e.magic_rune = buffs[slot_id].magic_rune; + e.persistent = buffs[slot_id].persistant_buff; + e.dot_rune = buffs[slot_id].dot_rune; + e.caston_x = buffs[slot_id].caston_x; + e.caston_y = buffs[slot_id].caston_y; + e.caston_z = buffs[slot_id].caston_z; + e.ExtraDIChance = buffs[slot_id].ExtraDIChance; + e.instrument_mod = buffs[slot_id].instrument_mod; - // add the buff to the vector - character_buffs.emplace_back(b); + v.emplace_back(e); } - // insert the buffs into the database - if (!character_buffs.empty()) { - CharacterBuffsRepository::InsertMany(database, character_buffs); + if (!v.empty()) { + CharacterBuffsRepository::ReplaceMany(database, v); } } void ZoneDatabase::LoadBuffs(Client *client) { + auto buffs = client->GetBuffs(); + int max_buff_slots = client->GetMaxBuffSlots(); - Buffs_Struct *buffs = client->GetBuffs(); - uint32 max_slots = client->GetMaxBuffSlots(); + for (int slot_id = 0; slot_id < max_buff_slots; ++slot_id) { + buffs[slot_id].spellid = SPELL_UNKNOWN; + } - for (int index = 0; index < max_slots; ++index) - buffs[index].spellid = SPELL_UNKNOWN; + const auto& l = CharacterBuffsRepository::GetWhere( + *this, + fmt::format( + "`character_id` = {}", + client->CharacterID() + ) + ); - std::string query = StringFormat("SELECT spell_id, slot_id, caster_level, caster_name, ticsremaining, " - "counters, numhits, melee_rune, magic_rune, persistent, dot_rune, " - "caston_x, caston_y, caston_z, ExtraDIChance, instrument_mod " - "FROM `character_buffs` WHERE `character_id` = '%u'", - client->CharacterID()); - auto results = QueryDatabase(query); - if (!results.Success()) { + if (l.empty()) { return; } - for (auto& row = results.begin(); row != results.end(); ++row) { - uint32 slot_id = Strings::ToUnsignedInt(row[1]); - if (slot_id >= client->GetMaxBuffSlots()) + for (const auto& e : l) { + if (e.slot_id >= max_buff_slots) { continue; - - uint32 spell_id = Strings::ToUnsignedInt(row[0]); - if (!IsValidSpell(spell_id)) - continue; - - Client *caster = entity_list.GetClientByName(row[3]); - uint32 caster_level = Strings::ToInt(row[2]); - int32 ticsremaining = Strings::ToInt(row[4]); - uint32 counters = Strings::ToUnsignedInt(row[5]); - uint32 hit_number = Strings::ToUnsignedInt(row[6]); - uint32 melee_rune = Strings::ToUnsignedInt(row[7]); - uint32 magic_rune = Strings::ToUnsignedInt(row[8]); - uint8 persistent = Strings::ToUnsignedInt(row[9]); - uint32 dot_rune = Strings::ToUnsignedInt(row[10]); - int32 caston_x = Strings::ToUnsignedInt(row[11]); - int32 caston_y = Strings::ToUnsignedInt(row[12]); - int32 caston_z = Strings::ToUnsignedInt(row[13]); - int32 ExtraDIChance = Strings::ToUnsignedInt(row[14]); - uint32 instrument_mod = Strings::ToUnsignedInt(row[15]); - - buffs[slot_id].spellid = spell_id; - buffs[slot_id].casterlevel = caster_level; - - if (caster) { - buffs[slot_id].casterid = caster->GetID(); - strcpy(buffs[slot_id].caster_name, caster->GetName()); - buffs[slot_id].client = true; - } else { - buffs[slot_id].casterid = 0; - strcpy(buffs[slot_id].caster_name, ""); - buffs[slot_id].client = false; } - buffs[slot_id].ticsremaining = ticsremaining; - buffs[slot_id].counters = counters; - buffs[slot_id].hit_number = hit_number; - buffs[slot_id].melee_rune = melee_rune; - buffs[slot_id].magic_rune = magic_rune; - buffs[slot_id].persistant_buff = persistent ? true : false; - buffs[slot_id].dot_rune = dot_rune; - buffs[slot_id].caston_x = caston_x; - buffs[slot_id].caston_y = caston_y; - buffs[slot_id].caston_z = caston_z; - buffs[slot_id].ExtraDIChance = ExtraDIChance; - buffs[slot_id].RootBreakChance = 0; - buffs[slot_id].virus_spread_time = 0; - buffs[slot_id].UpdateClient = false; - buffs[slot_id].instrument_mod = instrument_mod; + if (!IsValidSpell(e.spell_id)) { + continue; + } + + Client* c = entity_list.GetClientByName(e.caster_name.c_str()); + + buffs[e.slot_id].spellid = e.spell_id; + buffs[e.slot_id].casterlevel = e.caster_level; + + if (c) { + buffs[e.slot_id].casterid = c->GetID(); + buffs[e.slot_id].client = true; + + strncpy(buffs[e.slot_id].caster_name, c->GetName(), 64); + } else { + buffs[e.slot_id].casterid = 0; + buffs[e.slot_id].client = false; + + strncpy(buffs[e.slot_id].caster_name, "", 64); + } + + buffs[e.slot_id].ticsremaining = e.ticsremaining; + buffs[e.slot_id].counters = e.counters; + buffs[e.slot_id].hit_number = e.numhits; + buffs[e.slot_id].melee_rune = e.melee_rune; + buffs[e.slot_id].magic_rune = e.magic_rune; + buffs[e.slot_id].persistant_buff = e.persistent ? true : false; + buffs[e.slot_id].dot_rune = e.dot_rune; + buffs[e.slot_id].caston_x = e.caston_x; + buffs[e.slot_id].caston_y = e.caston_y; + buffs[e.slot_id].caston_z = e.caston_z; + buffs[e.slot_id].ExtraDIChance = e.ExtraDIChance; + buffs[e.slot_id].RootBreakChance = 0; + buffs[e.slot_id].virus_spread_time = 0; + buffs[e.slot_id].UpdateClient = false; + buffs[e.slot_id].instrument_mod = e.instrument_mod; } // We load up to the most our client supports - max_slots = EQ::spells::StaticLookup(client->ClientVersion())->LongBuffs; - for (int index = 0; index < max_slots; ++index) { - if (!IsValidSpell(buffs[index].spellid)) + max_buff_slots = EQ::spells::StaticLookup(client->ClientVersion())->LongBuffs; + + for (int slot_id = 0; slot_id < max_buff_slots; ++slot_id) { + if (!IsValidSpell(buffs[slot_id].spellid)) { continue; + } - for (int effectIndex = 0; effectIndex < EFFECT_COUNT; ++effectIndex) { + if (IsEffectInSpell(buffs[slot_id].spellid, SE_Charm)) { + buffs[slot_id].spellid = SPELL_UNKNOWN; + break; + } - if (spells[buffs[index].spellid].effect_id[effectIndex] == SE_Charm) { - buffs[index].spellid = SPELL_UNKNOWN; + if (IsEffectInSpell(buffs[slot_id].spellid, SE_Illusion)) { + if (buffs[slot_id].persistant_buff) { break; } - if (spells[buffs[index].spellid].effect_id[effectIndex] == SE_Illusion) { - if (buffs[index].persistant_buff) - break; - - buffs[index].spellid = SPELL_UNKNOWN; - break; - } + buffs[slot_id].spellid = SPELL_UNKNOWN; + break; } } }