Buff Component fixes

This commit is contained in:
David Markowitz 2023-06-26 01:49:56 -07:00
parent 06acd23cb7
commit d29287f9d9
2 changed files with 52 additions and 71 deletions

View File

@ -16,12 +16,10 @@ std::unordered_map<int32_t, std::vector<BuffParameter>> BuffComponent::m_Cache{}
void BuffComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { void BuffComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
if (!bIsInitialUpdate) return; if (!bIsInitialUpdate) return;
if (m_Buffs.empty()) {
outBitStream->Write0();
} else {
outBitStream->Write1();
outBitStream->Write<uint32_t>(m_Buffs.size());
outBitStream->Write(!m_Buffs.empty());
if (!m_Buffs.empty()) {
outBitStream->Write<uint32_t>(m_Buffs.size());
for (const auto& buff : m_Buffs) { for (const auto& buff : m_Buffs) {
outBitStream->Write<uint32_t>(buff.first); outBitStream->Write<uint32_t>(buff.first);
outBitStream->Write0(); outBitStream->Write0();
@ -41,7 +39,7 @@ void BuffComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUp
} }
} }
outBitStream->Write0(); outBitStream->Write0(); // immunities
} }
void BuffComponent::Update(float deltaTime) { void BuffComponent::Update(float deltaTime) {
@ -49,30 +47,28 @@ void BuffComponent::Update(float deltaTime) {
* Loop through all buffs and apply deltaTime to ther time. * Loop through all buffs and apply deltaTime to ther time.
* If they have expired, remove the buff and break. * If they have expired, remove the buff and break.
*/ */
for (auto& buff : m_Buffs) { for (auto& [buffId, buffInfo] : m_Buffs) {
// For damage buffs // For damage buffs
if (buff.second.tick != 0.0f && buff.second.stacks > 0) { if (buffInfo.tick != 0.0f && buffInfo.stacks > 0) {
buff.second.tickTime -= deltaTime; buffInfo.tickTime -= deltaTime;
if (buff.second.tickTime <= 0.0f) { if (buffInfo.tickTime <= 0.0f) {
buff.second.tickTime = buff.second.tick; buffInfo.tickTime = buffInfo.tick;
buff.second.stacks--; buffInfo.stacks--;
SkillComponent::HandleUnmanaged(buff.second.behaviorID, m_ParentEntity->GetObjectID(), buff.second.source); SkillComponent::HandleUnmanaged(buffInfo.behaviorID, m_ParentEntity->GetObjectID(), buffInfo.source);
} }
} }
// These are indefinate buffs, don't update them. // These are indefinate buffs, don't update them.
if (buff.second.time == 0.0f) { if (buffInfo.time == 0.0f) continue;
continue;
}
buff.second.time -= deltaTime; buffInfo.time -= deltaTime;
if (buff.second.time <= 0.0f) { if (buffInfo.time <= 0.0f) {
RemoveBuff(buff.first); RemoveBuff(buffId);
break; break; // Break because we modified or may modify the map.
} }
} }
} }
@ -81,9 +77,7 @@ void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOO
bool cancelOnDamaged, bool cancelOnDeath, bool cancelOnLogout, bool cancelOnRemoveBuff, bool cancelOnDamaged, bool cancelOnDeath, bool cancelOnLogout, bool cancelOnRemoveBuff,
bool cancelOnUi, bool cancelOnUnequip, bool cancelOnZone) { bool cancelOnUi, bool cancelOnUnequip, bool cancelOnZone) {
// Prevent buffs from stacking. // Prevent buffs from stacking.
if (HasBuff(id)) { if (HasBuff(id)) return;
return;
}
GameMessages::SendAddBuff(m_ParentEntity->GetObjectID(), source, (uint32_t)id, GameMessages::SendAddBuff(m_ParentEntity->GetObjectID(), source, (uint32_t)id,
(uint32_t)duration * 1000, addImmunity, cancelOnDamaged, cancelOnDeath, (uint32_t)duration * 1000, addImmunity, cancelOnDamaged, cancelOnDeath,
@ -94,14 +88,14 @@ void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOO
int32_t behaviorID = 0; int32_t behaviorID = 0;
const auto& parameters = GetBuffParameters(id); const auto& parameters = GetBuffParameters(id);
auto* skillBehaviorTable = CDClientManager::Instance().GetTable<CDSkillBehaviorTable>();
for (const auto& parameter : parameters) { for (const auto& parameter : parameters) {
if (parameter.name == "overtime") { if (parameter.name == "overtime") {
auto* behaviorTemplateTable = CDClientManager::Instance().GetTable<CDSkillBehaviorTable>();
behaviorID = behaviorTemplateTable->GetSkillByID(parameter.values[0]).behaviorID; behaviorID = skillBehaviorTable->GetSkillByID(parameter.values.skillId).behaviorID;
stacks = static_cast<int32_t>(parameter.values[1]); stacks = static_cast<int32_t>(parameter.values.stacks);
tick = parameter.values[2]; tick = parameter.values.tick;
const auto unknown2 = parameter.values[3]; // Always 0 const auto unknown2 = parameter.values.unknown2; // Always 0
} }
} }
@ -116,15 +110,13 @@ void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOO
buff.source = source; buff.source = source;
buff.behaviorID = behaviorID; buff.behaviorID = behaviorID;
m_Buffs.emplace(id, buff); m_Buffs.insert_or_assign(id, buff);
} }
void BuffComponent::RemoveBuff(int32_t id, bool fromUnEquip, bool removeImmunity) { void BuffComponent::RemoveBuff(int32_t id, bool fromUnEquip, bool removeImmunity) {
const auto& iter = m_Buffs.find(id); const auto& iter = m_Buffs.find(id);
if (iter == m_Buffs.end()) { if (iter == m_Buffs.end()) return;
return;
}
GameMessages::SendRemoveBuff(m_ParentEntity, fromUnEquip, removeImmunity, id); GameMessages::SendRemoveBuff(m_ParentEntity, fromUnEquip, removeImmunity, id);
@ -181,7 +173,7 @@ void BuffComponent::RemoveBuffEffect(int32_t id) {
auto* destroyable = this->GetParentEntity()->GetComponent<DestroyableComponent>(); auto* destroyable = this->GetParentEntity()->GetComponent<DestroyableComponent>();
if (destroyable == nullptr) return; if (!destroyable) return;
destroyable->SetMaxHealth(destroyable->GetMaxHealth() - maxHealth); destroyable->SetMaxHealth(destroyable->GetMaxHealth() - maxHealth);
} else if (parameter.name == "max_armor") { } else if (parameter.name == "max_armor") {
@ -189,7 +181,7 @@ void BuffComponent::RemoveBuffEffect(int32_t id) {
auto* destroyable = this->GetParentEntity()->GetComponent<DestroyableComponent>(); auto* destroyable = this->GetParentEntity()->GetComponent<DestroyableComponent>();
if (destroyable == nullptr) return; if (!destroyable) return;
destroyable->SetMaxArmor(destroyable->GetMaxArmor() - maxArmor); destroyable->SetMaxArmor(destroyable->GetMaxArmor() - maxArmor);
} else if (parameter.name == "max_imagination") { } else if (parameter.name == "max_imagination") {
@ -197,7 +189,7 @@ void BuffComponent::RemoveBuffEffect(int32_t id) {
auto* destroyable = this->GetParentEntity()->GetComponent<DestroyableComponent>(); auto* destroyable = this->GetParentEntity()->GetComponent<DestroyableComponent>();
if (destroyable == nullptr) return; if (!destroyable) return;
destroyable->SetMaxImagination(destroyable->GetMaxImagination() - maxImagination); destroyable->SetMaxImagination(destroyable->GetMaxImagination() - maxImagination);
} else if (parameter.name == "speed") { } else if (parameter.name == "speed") {
@ -210,27 +202,19 @@ void BuffComponent::RemoveBuffEffect(int32_t id) {
} }
void BuffComponent::RemoveAllBuffs() { void BuffComponent::RemoveAllBuffs() {
for (const auto& buff : m_Buffs) { for (const auto& [buffId, buffInfo] : m_Buffs) {
RemoveBuffEffect(buff.first); RemoveBuffEffect(buffId);
} }
m_Buffs.clear(); m_Buffs.clear();
} }
void BuffComponent::Reset() {
RemoveAllBuffs();
}
void BuffComponent::ReApplyBuffs() { void BuffComponent::ReApplyBuffs() {
for (const auto& buff : m_Buffs) { for (const auto& [buffId, buffInfo] : m_Buffs) {
ApplyBuffEffect(buff.first); ApplyBuffEffect(buffId);
} }
} }
Entity* BuffComponent::GetParentEntity() const {
return m_ParentEntity;
}
void BuffComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { void BuffComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
// Load buffs // Load buffs
auto* dest = doc->FirstChildElement("obj")->FirstChildElement("dest"); auto* dest = doc->FirstChildElement("obj")->FirstChildElement("dest");
@ -239,9 +223,7 @@ void BuffComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
auto* buffElement = dest->FirstChildElement("buff"); auto* buffElement = dest->FirstChildElement("buff");
// Old character, no buffs to load // Old character, no buffs to load
if (buffElement == nullptr) { if (buffElement) return;
return;
}
auto* buffEntry = buffElement->FirstChildElement("b"); auto* buffEntry = buffElement->FirstChildElement("b");
@ -299,12 +281,9 @@ void BuffComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
const std::vector<BuffParameter>& BuffComponent::GetBuffParameters(int32_t buffId) { const std::vector<BuffParameter>& BuffComponent::GetBuffParameters(int32_t buffId) {
const auto& pair = m_Cache.find(buffId); const auto& pair = m_Cache.find(buffId);
if (pair != m_Cache.end()) { if (pair != m_Cache.end()) return pair->second;
return pair->second;
}
auto query = CDClientDatabase::CreatePreppedStmt( auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM BuffParameters WHERE BuffID = ?;");
"SELECT * FROM BuffParameters WHERE BuffID = ?;");
query.bind(1, (int)buffId); query.bind(1, (int)buffId);
auto result = query.execQuery(); auto result = query.execQuery();
@ -319,17 +298,15 @@ const std::vector<BuffParameter>& BuffComponent::GetBuffParameters(int32_t buffI
param.value = result.getFloatField(2); param.value = result.getFloatField(2);
if (!result.fieldIsNull(3)) { if (!result.fieldIsNull(3)) {
std::istringstream stream(result.getStringField(3)); const auto parameterInfo = result.getStringField(3);
std::string token; const auto values = GeneralUtils::SplitString(parameterInfo, ',');
if (values.size() >= 4) {
while (std::getline(stream, token, ',')) { GeneralUtils::TryParse(values.at(0), param.values.skillId);
try { GeneralUtils::TryParse(values.at(1), param.values.stacks);
const auto value = std::stof(token); GeneralUtils::TryParse(values.at(2), param.values.tick);
GeneralUtils::TryParse(values.at(3), param.values.unknown2);
param.values.push_back(value); } else {
} catch (std::invalid_argument& exception) { Game::logger->Log("BuffComponent", "Failed to parse %s into parameter struct. Too few parameters to split on.", parameterInfo);
Game::logger->Log("BuffComponent", "Failed to parse value (%s): (%s)!", token.c_str(), exception.what());
}
} }
} }

View File

@ -15,10 +15,16 @@ class Entity;
* Extra information on effects to apply after applying a buff, for example whether to buff armor, imag or health and by how much * Extra information on effects to apply after applying a buff, for example whether to buff armor, imag or health and by how much
*/ */
struct BuffParameter { struct BuffParameter {
struct ParameterValues {
int32_t skillId = 0;
int32_t stacks = 0;
float tick = 0.0f;
int32_t unknown2 = 0;
};
int32_t buffId = 0; int32_t buffId = 0;
std::string name; std::string name;
float value = 0.0f; float value = 0.0f;
std::vector<float> values; ParameterValues values;
int32_t effectId = 0; int32_t effectId = 0;
}; };
@ -42,9 +48,7 @@ class BuffComponent final : public Component {
public: public:
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::BUFF; inline static const eReplicaComponentType ComponentType = eReplicaComponentType::BUFF;
explicit BuffComponent(Entity* parent) : Component(parent) { }; explicit BuffComponent(Entity* parent) : Component(parent) {};
Entity* GetParentEntity() const;
void LoadFromXml(tinyxml2::XMLDocument* doc) override; void LoadFromXml(tinyxml2::XMLDocument* doc) override;
@ -106,7 +110,7 @@ public:
/** /**
* Removes all buffs for the entity and reverses all of their effects * Removes all buffs for the entity and reverses all of their effects
*/ */
void Reset(); void Reset() { RemoveAllBuffs(); };
/** /**
* Applies all effects for all buffs, active or not, again * Applies all effects for all buffs, active or not, again