[Spells/Disciplines] Bulk Train / Scribe (#1640)

* Bulk scribe spells

* Add bulk disc training

* Remove bulk from non bulk method

* PR adjustments
This commit is contained in:
Chris Miles 2021-10-27 20:45:27 -05:00 committed by GitHub
parent 6e5bf4b941
commit 7230714cbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 157 additions and 75 deletions

View File

@ -63,6 +63,10 @@ extern volatile bool RunLoops;
#include "../common/expedition_lockout_timer.h" #include "../common/expedition_lockout_timer.h"
#include "cheat_manager.h" #include "cheat_manager.h"
#include "../common/repositories/character_spells_repository.h"
#include "../common/repositories/character_disciplines_repository.h"
extern QueryServ* QServ; extern QueryServ* QServ;
extern EntityList entity_list; extern EntityList entity_list;
extern Zone* zone; extern Zone* zone;
@ -10673,3 +10677,45 @@ void Client::SummonBaggedItems(uint32 bag_item_id, const std::vector<ServerLootI
SendItemPacket(EQ::invslot::slotCursor, summoned_bag, ItemPacketLimbo); SendItemPacket(EQ::invslot::slotCursor, summoned_bag, ItemPacketLimbo);
safe_delete(summoned_bag); safe_delete(summoned_bag);
} }
void Client::SaveSpells()
{
std::vector<CharacterSpellsRepository::CharacterSpells> character_spells = {};
for (int index = 0; index < EQ::spells::SPELLBOOK_SIZE; index++) {
if (IsValidSpell(m_pp.spell_book[index])) {
auto spell = CharacterSpellsRepository::NewEntity();
spell.id = CharacterID();
spell.slot_id = index;
spell.spell_id = m_pp.spell_book[index];
character_spells.emplace_back(spell);
}
}
CharacterSpellsRepository::DeleteWhere(database, fmt::format("id = {}", CharacterID()));
if (!character_spells.empty()) {
CharacterSpellsRepository::InsertMany(database, character_spells);
}
}
void Client::SaveDisciplines()
{
std::vector<CharacterDisciplinesRepository::CharacterDisciplines> character_discs = {};
for (int index = 0; index < MAX_PP_DISCIPLINES; index++) {
if (IsValidSpell(m_pp.disciplines.values[index])) {
auto discipline = CharacterDisciplinesRepository::NewEntity();
discipline.id = CharacterID();
discipline.slot_id = index;
discipline.disc_id = m_pp.disciplines.values[index];
character_discs.emplace_back(discipline);
}
}
CharacterDisciplinesRepository::DeleteWhere(database, fmt::format("id = {}", CharacterID()));
if (!character_discs.empty()) {
CharacterDisciplinesRepository::InsertMany(database, character_discs);
}
}

View File

@ -799,10 +799,15 @@ public:
std::vector<int> GetMemmedSpells(); std::vector<int> GetMemmedSpells();
std::vector<int> GetScribeableSpells(uint8 min_level = 1, uint8 max_level = 0); std::vector<int> GetScribeableSpells(uint8 min_level = 1, uint8 max_level = 0);
std::vector<int> GetScribedSpells(); std::vector<int> GetScribedSpells();
void ScribeSpell(uint16 spell_id, int slot, bool update_client = true); // defer save used when bulk saving
void UnscribeSpell(int slot, bool update_client = true); void ScribeSpell(uint16 spell_id, int slot, bool update_client = true, bool defer_save = false);
void SaveSpells();
void SaveDisciplines();
// defer save used when bulk saving
void UnscribeSpell(int slot, bool update_client = true, bool defer_save = false);
void UnscribeSpellAll(bool update_client = true); void UnscribeSpellAll(bool update_client = true);
void UntrainDisc(int slot, bool update_client = true); void UntrainDisc(int slot, bool update_client = true, bool defer_save = false);
void UntrainDiscAll(bool update_client = true); void UntrainDiscAll(bool update_client = true);
void UntrainDiscBySpellID(uint16 spell_id, bool update_client = true); void UntrainDiscBySpellID(uint16 spell_id, bool update_client = true);
bool SpellGlobalCheck(uint16 spell_id, uint32 char_id); bool SpellGlobalCheck(uint16 spell_id, uint32 char_id);

View File

@ -7928,7 +7928,7 @@ void command_scribespells(Client *c, const Seperator *sep)
} }
if (!IsDiscipline(spell_id_) && !t->HasSpellScribed(spell_id)) { // isn't a discipline & we don't already have it scribed if (!IsDiscipline(spell_id_) && !t->HasSpellScribed(spell_id)) { // isn't a discipline & we don't already have it scribed
t->ScribeSpell(spell_id_, book_slot); t->ScribeSpell(spell_id_, book_slot, true, true);
++count; ++count;
} }
@ -7940,14 +7940,18 @@ void command_scribespells(Client *c, const Seperator *sep)
if (count > 0) { if (count > 0) {
t->Message(Chat::White, "Successfully scribed %i spells.", count); t->Message(Chat::White, "Successfully scribed %i spells.", count);
if (t != c) if (t != c) {
c->Message(Chat::White, "Successfully scribed %i spells for %s.", count, t->GetName()); c->Message(Chat::White, "Successfully scribed %i spells for %s.", count, t->GetName());
} }
t->SaveSpells();
}
else { else {
t->Message(Chat::White, "No spells scribed."); t->Message(Chat::White, "No spells scribed.");
if (t != c) if (t != c) {
c->Message(Chat::White, "No spells scribed for %s.", t->GetName()); c->Message(Chat::White, "No spells scribed for %s.", t->GetName());
} }
}
} }
void command_scribespell(Client *c, const Seperator *sep) { void command_scribespell(Client *c, const Seperator *sep) {
@ -8058,6 +8062,7 @@ void command_untraindiscs(Client *c, const Seperator *sep) {
t = c->GetTarget()->CastToClient(); t = c->GetTarget()->CastToClient();
t->UntrainDiscAll(); t->UntrainDiscAll();
t->Message(Chat::Yellow, "All disciplines removed.");
} }
void command_wpinfo(Client *c, const Seperator *sep) void command_wpinfo(Client *c, const Seperator *sep)
@ -10999,7 +11004,6 @@ void command_traindisc(Client *c, const Seperator *sep)
} }
else if (t->GetPP().disciplines.values[r] == 0) { else if (t->GetPP().disciplines.values[r] == 0) {
t->GetPP().disciplines.values[r] = spell_id_; t->GetPP().disciplines.values[r] = spell_id_;
database.SaveCharacterDisc(t->CharacterID(), r, spell_id_);
change = true; change = true;
t->Message(Chat::White, "You have learned a new discipline!"); t->Message(Chat::White, "You have learned a new discipline!");
++count; // success counter ++count; // success counter
@ -11011,18 +11015,23 @@ void command_traindisc(Client *c, const Seperator *sep)
} }
} }
if (change) if (change) {
t->SendDisciplineUpdate(); t->SendDisciplineUpdate();
t->SaveDisciplines();
}
if (count > 0) { if (count > 0) {
t->Message(Chat::White, "Successfully trained %u disciplines.", count); t->Message(Chat::White, "Successfully trained %u disciplines.", count);
if (t != c) if (t != c) {
c->Message(Chat::White, "Successfully trained %u disciplines for %s.", count, t->GetName()); c->Message(Chat::White, "Successfully trained %u disciplines for %s.", count, t->GetName());
} else { }
}
else {
t->Message(Chat::White, "No disciplines trained."); t->Message(Chat::White, "No disciplines trained.");
if (t != c) if (t != c) {
c->Message(Chat::White, "No disciplines trained for %s.", t->GetName()); c->Message(Chat::White, "No disciplines trained for %s.", t->GetName());
} }
}
} }
void command_setgraveyard(Client *c, const Seperator *sep) void command_setgraveyard(Client *c, const Seperator *sep)

View File

@ -619,13 +619,14 @@ bool Client::MemorizeSpellFromItem(uint32 item_id) {
return false; return false;
} }
for(int index = 0; index < EQ::spells::SPELLBOOK_SIZE; index++) { for (int index = 0; index < EQ::spells::SPELLBOOK_SIZE; index++) {
if (!HasSpellScribed(spell_id)) { if (!HasSpellScribed(spell_id)) {
auto next_slot = GetNextAvailableSpellBookSlot(); auto next_slot = GetNextAvailableSpellBookSlot();
if (next_slot != -1) { if (next_slot != -1) {
ScribeSpell(spell_id, next_slot); ScribeSpell(spell_id, next_slot);
return true; return true;
} else { }
else {
Message( Message(
Chat::Red, Chat::Red,
"Unable to scribe spell %s (%i) to spellbook: no more spell book slots available.", "Unable to scribe spell %s (%i) to spellbook: no more spell book slots available.",
@ -635,12 +636,14 @@ bool Client::MemorizeSpellFromItem(uint32 item_id) {
SummonItem(item_id); SummonItem(item_id);
return false; return false;
} }
} else { }
else {
Message(Chat::Red, "You already know this spell."); Message(Chat::Red, "You already know this spell.");
SummonItem(item_id); SummonItem(item_id);
return false; return false;
} }
} }
Message(Chat::Red, "You have learned too many spells and can learn no more."); Message(Chat::Red, "You have learned too many spells and can learn no more.");
return false; return false;
} }

View File

@ -1130,7 +1130,8 @@ uint16 QuestManager::scribespells(uint8 max_level, uint8 min_level) {
if (initiator->HasSpellScribed(spell_id)) if (initiator->HasSpellScribed(spell_id))
continue; continue;
initiator->ScribeSpell(spell_id, book_slot); // defer saving per spell and bulk save at the end
initiator->ScribeSpell(spell_id, book_slot, true, true);
book_slot = initiator->GetNextAvailableSpellBookSlot(book_slot); book_slot = initiator->GetNextAvailableSpellBookSlot(book_slot);
spells_learned++; spells_learned++;
} }
@ -1139,6 +1140,9 @@ uint16 QuestManager::scribespells(uint8 max_level, uint8 min_level) {
if (spells_learned > 0) { if (spells_learned > 0) {
std::string spell_message = (spells_learned == 1 ? "a new spell" : fmt::format("{} new spells", spells_learned)); std::string spell_message = (spells_learned == 1 ? "a new spell" : fmt::format("{} new spells", spells_learned));
initiator->Message(Chat::White, fmt::format("You have learned {}!", spell_message).c_str()); initiator->Message(Chat::White, fmt::format("You have learned {}!", spell_message).c_str());
// bulk insert spells
initiator->SaveSpells();
} }
return spells_learned; return spells_learned;
} }

View File

@ -5314,40 +5314,47 @@ int Client::MemmedCount() {
} }
void Client::ScribeSpell(uint16 spell_id, int slot, bool update_client) void Client::ScribeSpell(uint16 spell_id, int slot, bool update_client, bool defer_save)
{ {
if(slot >= EQ::spells::SPELLBOOK_SIZE || slot < 0) if (slot >= EQ::spells::SPELLBOOK_SIZE || slot < 0) {
return; return;
}
if(update_client) if (update_client) {
{ if (m_pp.spell_book[slot] != 0xFFFFFFFF) {
if(m_pp.spell_book[slot] != 0xFFFFFFFF) UnscribeSpell(slot, update_client, defer_save);
UnscribeSpell(slot, update_client); }
} }
m_pp.spell_book[slot] = spell_id; m_pp.spell_book[slot] = spell_id;
// defer save if we're bulk saving elsewhere
if (!defer_save) {
database.SaveCharacterSpell(this->CharacterID(), spell_id, slot); database.SaveCharacterSpell(this->CharacterID(), spell_id, slot);
}
LogSpells("Spell [{}] scribed into spell book slot [{}]", spell_id, slot); LogSpells("Spell [{}] scribed into spell book slot [{}]", spell_id, slot);
if(update_client) if (update_client) {
{
MemorizeSpell(slot, spell_id, memSpellScribing); MemorizeSpell(slot, spell_id, memSpellScribing);
} }
} }
void Client::UnscribeSpell(int slot, bool update_client) void Client::UnscribeSpell(int slot, bool update_client, bool defer_save)
{ {
if(slot >= EQ::spells::SPELLBOOK_SIZE || slot < 0) if (slot >= EQ::spells::SPELLBOOK_SIZE || slot < 0) {
return; return;
}
LogSpells("Spell [{}] erased from spell book slot [{}]", m_pp.spell_book[slot], slot); LogSpells("Spell [{}] erased from spell book slot [{}]", m_pp.spell_book[slot], slot);
m_pp.spell_book[slot] = 0xFFFFFFFF; m_pp.spell_book[slot] = 0xFFFFFFFF;
if (!defer_save) {
database.DeleteCharacterSpell(this->CharacterID(), m_pp.spell_book[slot], slot); database.DeleteCharacterSpell(this->CharacterID(), m_pp.spell_book[slot], slot);
if(update_client && slot < EQ::spells::DynamicLookup(ClientVersion(), GetGM())->SpellbookSize) }
{
if (update_client && slot < EQ::spells::DynamicLookup(ClientVersion(), GetGM())->SpellbookSize) {
auto outapp = new EQApplicationPacket(OP_DeleteSpell, sizeof(DeleteSpell_Struct)); auto outapp = new EQApplicationPacket(OP_DeleteSpell, sizeof(DeleteSpell_Struct));
DeleteSpell_Struct* del = (DeleteSpell_Struct*)outapp->pBuffer; DeleteSpell_Struct *del = (DeleteSpell_Struct *) outapp->pBuffer;
del->spell_slot = slot; del->spell_slot = slot;
del->success = 1; del->success = 1;
QueuePacket(outapp); QueuePacket(outapp);
@ -5357,37 +5364,44 @@ void Client::UnscribeSpell(int slot, bool update_client)
void Client::UnscribeSpellAll(bool update_client) void Client::UnscribeSpellAll(bool update_client)
{ {
for(int i = 0; i < EQ::spells::SPELLBOOK_SIZE; i++) for (int i = 0; i < EQ::spells::SPELLBOOK_SIZE; i++) {
{ if (m_pp.spell_book[i] != 0xFFFFFFFF) {
if(m_pp.spell_book[i] != 0xFFFFFFFF) UnscribeSpell(i, update_client, true);
UnscribeSpell(i, update_client);
} }
}
// bulk save at end (this will only delete)
SaveSpells();
} }
void Client::UntrainDisc(int slot, bool update_client) void Client::UntrainDisc(int slot, bool update_client, bool defer_save)
{ {
if(slot >= MAX_PP_DISCIPLINES || slot < 0) if (slot >= MAX_PP_DISCIPLINES || slot < 0) {
return; return;
}
LogSpells("Discipline [{}] untrained from slot [{}]", m_pp.disciplines.values[slot], slot); LogSpells("Discipline [{}] untrained from slot [{}]", m_pp.disciplines.values[slot], slot);
m_pp.disciplines.values[slot] = 0; m_pp.disciplines.values[slot] = 0;
database.DeleteCharacterDisc(this->CharacterID(), slot);
if(update_client) if (!defer_save) {
{ database.DeleteCharacterDisc(this->CharacterID(), slot);
}
if (update_client) {
SendDisciplineUpdate(); SendDisciplineUpdate();
} }
} }
void Client::UntrainDiscAll(bool update_client) void Client::UntrainDiscAll(bool update_client)
{ {
int i; for (int i = 0; i < MAX_PP_DISCIPLINES; i++) {
if (m_pp.disciplines.values[i] != 0) {
for(i = 0; i < MAX_PP_DISCIPLINES; i++) UntrainDisc(i, update_client, true);
{
if(m_pp.disciplines.values[i] != 0)
UntrainDisc(i, update_client);
} }
}
// bulk delete / save
SaveDisciplines();
} }
void Client::UntrainDiscBySpellID(uint16 spell_id, bool update_client) void Client::UntrainDiscBySpellID(uint16 spell_id, bool update_client)
@ -6244,3 +6258,4 @@ bool Client::IsLinkedSpellReuseTimerReady(uint32 timer_id)
} }