fix: Buff FX not playing and general BuffComponent improvements (#1296)

* fix: Buff FX not playing

Fixes an issue where buff effects would not play at all.

Tested that frakjaw and maelstrom dagger now play their respective effects when you are effected by them

fix: buffs general improvements

add new arguments

* Remove duplicated code

* fix times and remove buff
This commit is contained in:
David Markowitz
2023-12-01 08:12:48 -08:00
committed by GitHub
parent 0b9dbaedbf
commit eca87c7257
6 changed files with 187 additions and 52 deletions

View File

@@ -11,9 +11,21 @@
#include "EntityManager.h"
#include "CDClientManager.h"
#include "CDSkillBehaviorTable.h"
#include "TeamManager.h"
std::unordered_map<int32_t, std::vector<BuffParameter>> BuffComponent::m_Cache{};
namespace {
std::map<std::string, std::string> BuffFx = {
{ "overtime", "OTB_" },
{ "max_health", "HEALTH_" },
{ "max_imagination", "IMAGINATION_" },
{ "max_armor", "ARMOR_" },
{ "speed", "SPEED_" },
{ "loot", "LOOT_" }
};
}
BuffComponent::BuffComponent(Entity* parent) : Component(parent) {
}
@@ -22,32 +34,38 @@ BuffComponent::~BuffComponent() {
void BuffComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
if (!bIsInitialUpdate) return;
if (m_Buffs.empty()) {
outBitStream->Write0();
} else {
outBitStream->Write1();
outBitStream->Write(!m_Buffs.empty());
if (!m_Buffs.empty()) {
outBitStream->Write<uint32_t>(m_Buffs.size());
for (const auto& buff : m_Buffs) {
outBitStream->Write<uint32_t>(buff.first);
outBitStream->Write0();
outBitStream->Write0();
outBitStream->Write0();
outBitStream->Write0();
outBitStream->Write0();
outBitStream->Write0();
outBitStream->Write0();
outBitStream->Write0();
outBitStream->Write0();
for (const auto& [id, buff] : m_Buffs) {
outBitStream->Write<uint32_t>(id);
outBitStream->Write(buff.time != 0.0f);
if (buff.time != 0.0f) outBitStream->Write(static_cast<uint32_t>(buff.time * 1000.0f));
outBitStream->Write(buff.cancelOnDeath);
outBitStream->Write(buff.cancelOnZone);
outBitStream->Write(buff.cancelOnDamaged);
outBitStream->Write(buff.cancelOnRemoveBuff);
outBitStream->Write(buff.cancelOnUi);
outBitStream->Write(buff.cancelOnLogout);
outBitStream->Write(buff.cancelOnUnequip);
outBitStream->Write0(); // Cancel on Damage Absorb Ran Out. Generally false from what I can tell
outBitStream->Write0();
outBitStream->Write0();
auto* team = TeamManager::Instance()->GetTeam(buff.source);
bool addedByTeammate = false;
if (team) {
addedByTeammate = std::count(team->members.begin(), team->members.end(), m_Parent->GetObjectID()) > 0;
}
outBitStream->Write<uint32_t>(0);
outBitStream->Write(addedByTeammate); // Added by teammate. If source is in the same team as the target, this is true. Otherwise, false.
outBitStream->Write(buff.applyOnTeammates);
if (addedByTeammate) outBitStream->Write(buff.source);
outBitStream->Write<uint32_t>(buff.refCount);
}
}
outBitStream->Write0();
outBitStream->Write0(); // something to do with immunity buffs?
}
void BuffComponent::Update(float deltaTime) {
@@ -83,17 +101,55 @@ void BuffComponent::Update(float deltaTime) {
}
}
const std::string& GetFxName(const std::string& buffname) {
const auto& toReturn = BuffFx[buffname];
if (toReturn.empty()) {
LOG_DEBUG("No fx name for %s", buffname.c_str());
}
return toReturn;
}
void BuffComponent::ApplyBuffFx(uint32_t buffId, const BuffParameter& buff) {
std::string fxToPlay;
const auto& buffName = GetFxName(buff.name);
if (buffName.empty()) return;
fxToPlay += std::to_string(buffId);
LOG_DEBUG("Playing %s %i", fxToPlay.c_str(), buff.effectId);
GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), buff.effectId, u"cast", fxToPlay, LWOOBJID_EMPTY, 1.07f, 1.0f, false);
}
void BuffComponent::RemoveBuffFx(uint32_t buffId, const BuffParameter& buff) {
std::string fxToPlay;
const auto& buffName = GetFxName(buff.name);
if (buffName.empty()) return;
fxToPlay += std::to_string(buffId);
LOG_DEBUG("Stopping %s", fxToPlay.c_str());
GameMessages::SendStopFXEffect(m_Parent, false, fxToPlay);
}
void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOOBJID source, bool addImmunity,
bool cancelOnDamaged, bool cancelOnDeath, bool cancelOnLogout, bool cancelOnRemoveBuff,
bool cancelOnUi, bool cancelOnUnequip, bool cancelOnZone) {
bool cancelOnUi, bool cancelOnUnequip, bool cancelOnZone, bool applyOnTeammates) {
// Prevent buffs from stacking.
if (HasBuff(id)) {
m_Buffs[id].refCount++;
m_Buffs[id].time = duration;
return;
}
auto* team = TeamManager::Instance()->GetTeam(source);
bool addedByTeammate = false;
if (team) {
addedByTeammate = std::count(team->members.begin(), team->members.end(), m_Parent->GetObjectID()) > 0;
}
GameMessages::SendAddBuff(const_cast<LWOOBJID&>(m_Parent->GetObjectID()), source, (uint32_t)id,
(uint32_t)duration * 1000, addImmunity, cancelOnDamaged, cancelOnDeath,
cancelOnLogout, cancelOnRemoveBuff, cancelOnUi, cancelOnUnequip, cancelOnZone);
cancelOnLogout, cancelOnRemoveBuff, cancelOnUi, cancelOnUnequip, cancelOnZone, addedByTeammate, applyOnTeammates);
float tick = 0;
float stacks = 0;
@@ -121,17 +177,43 @@ void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOO
buff.stacks = stacks;
buff.source = source;
buff.behaviorID = behaviorID;
buff.cancelOnDamaged = cancelOnDamaged;
buff.cancelOnDeath = cancelOnDeath;
buff.cancelOnLogout = cancelOnLogout;
buff.cancelOnRemoveBuff = cancelOnRemoveBuff;
buff.cancelOnUi = cancelOnUi;
buff.cancelOnUnequip = cancelOnUnequip;
buff.cancelOnZone = cancelOnZone;
buff.refCount = 1;
m_Buffs.emplace(id, buff);
auto* parent = GetParent();
if (!cancelOnDeath) return;
m_Parent->AddDieCallback([parent, id]() {
LOG_DEBUG("Removing buff %i because parent died", id);
if (!parent) return;
auto* buffComponent = parent->GetComponent<BuffComponent>();
if (buffComponent) buffComponent->RemoveBuff(id, false, false, true);
});
}
void BuffComponent::RemoveBuff(int32_t id, bool fromUnEquip, bool removeImmunity) {
void BuffComponent::RemoveBuff(int32_t id, bool fromUnEquip, bool removeImmunity, bool ignoreRefCount) {
const auto& iter = m_Buffs.find(id);
if (iter == m_Buffs.end()) {
return;
}
if (!ignoreRefCount && !iter->second.cancelOnRemoveBuff) {
iter->second.refCount--;
LOG_DEBUG("refCount for buff %i is now %i", id, iter->second.refCount);
if (iter->second.refCount > 0) {
return;
}
}
GameMessages::SendRemoveBuff(m_Parent, fromUnEquip, removeImmunity, id);
m_Buffs.erase(iter);
@@ -146,6 +228,7 @@ bool BuffComponent::HasBuff(int32_t id) {
void BuffComponent::ApplyBuffEffect(int32_t id) {
const auto& parameters = GetBuffParameters(id);
for (const auto& parameter : parameters) {
ApplyBuffFx(id, parameter);
if (parameter.name == "max_health") {
const auto maxHealth = parameter.value;
@@ -182,6 +265,7 @@ void BuffComponent::ApplyBuffEffect(int32_t id) {
void BuffComponent::RemoveBuffEffect(int32_t id) {
const auto& parameters = GetBuffParameters(id);
for (const auto& parameter : parameters) {
RemoveBuffFx(id, parameter);
if (parameter.name == "max_health") {
const auto maxHealth = parameter.value;
@@ -251,13 +335,25 @@ void BuffComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
auto* buffEntry = buffElement->FirstChildElement("b");
while (buffEntry != nullptr) {
while (buffEntry) {
int32_t id = buffEntry->IntAttribute("id");
float t = buffEntry->FloatAttribute("t");
float tk = buffEntry->FloatAttribute("tk");
float tt = buffEntry->FloatAttribute("tt");
int32_t s = buffEntry->FloatAttribute("s");
LWOOBJID sr = buffEntry->Int64Attribute("sr");
int32_t b = buffEntry->IntAttribute("b");
int32_t refCount = buffEntry->IntAttribute("refCount");
bool cancelOnDamaged = buffEntry->BoolAttribute("cancelOnDamaged");
bool cancelOnDeath = buffEntry->BoolAttribute("cancelOnDeath");
bool cancelOnLogout = buffEntry->BoolAttribute("cancelOnLogout");
bool cancelOnRemoveBuff = buffEntry->BoolAttribute("cancelOnRemoveBuff");
bool cancelOnUi = buffEntry->BoolAttribute("cancelOnUi");
bool cancelOnUnequip = buffEntry->BoolAttribute("cancelOnUnequip");
bool cancelOnZone = buffEntry->BoolAttribute("cancelOnZone");
bool applyOnTeammates = buffEntry->BoolAttribute("applyOnTeammates");
Buff buff;
buff.id = id;
@@ -266,6 +362,18 @@ void BuffComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
buff.stacks = s;
buff.source = sr;
buff.behaviorID = b;
buff.refCount = refCount;
buff.tickTime = tt;
buff.cancelOnDamaged = cancelOnDamaged;
buff.cancelOnDeath = cancelOnDeath;
buff.cancelOnLogout = cancelOnLogout;
buff.cancelOnRemoveBuff = cancelOnRemoveBuff;
buff.cancelOnUi = cancelOnUi;
buff.cancelOnUnequip = cancelOnUnequip;
buff.cancelOnZone = cancelOnZone;
buff.applyOnTeammates = applyOnTeammates;
m_Buffs.emplace(id, buff);
@@ -288,15 +396,27 @@ void BuffComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
buffElement->DeleteChildren();
}
for (const auto& buff : m_Buffs) {
for (const auto& [id, buff] : m_Buffs) {
auto* buffEntry = doc->NewElement("b");
if (buff.cancelOnZone || buff.cancelOnLogout) continue;
buffEntry->SetAttribute("id", buff.first);
buffEntry->SetAttribute("t", buff.second.time);
buffEntry->SetAttribute("tk", buff.second.tick);
buffEntry->SetAttribute("s", buff.second.stacks);
buffEntry->SetAttribute("sr", buff.second.source);
buffEntry->SetAttribute("b", buff.second.behaviorID);
buffEntry->SetAttribute("id", id);
buffEntry->SetAttribute("t", buff.time);
buffEntry->SetAttribute("tk", buff.tick);
buffEntry->SetAttribute("tt", buff.tickTime);
buffEntry->SetAttribute("s", buff.stacks);
buffEntry->SetAttribute("sr", buff.source);
buffEntry->SetAttribute("b", buff.behaviorID);
buffEntry->SetAttribute("refCount", buff.refCount);
buffEntry->SetAttribute("cancelOnDamaged", buff.cancelOnDamaged);
buffEntry->SetAttribute("cancelOnDeath", buff.cancelOnDeath);
buffEntry->SetAttribute("cancelOnLogout", buff.cancelOnLogout);
buffEntry->SetAttribute("cancelOnRemoveBuff", buff.cancelOnRemoveBuff);
buffEntry->SetAttribute("cancelOnUi", buff.cancelOnUi);
buffEntry->SetAttribute("cancelOnUnequip", buff.cancelOnUnequip);
buffEntry->SetAttribute("cancelOnZone", buff.cancelOnZone);
buffEntry->SetAttribute("applyOnTeammates", buff.applyOnTeammates);
buffElement->LinkEndChild(buffEntry);
}
@@ -309,8 +429,7 @@ const std::vector<BuffParameter>& BuffComponent::GetBuffParameters(int32_t buffI
return pair->second;
}
auto query = CDClientDatabase::CreatePreppedStmt(
"SELECT * FROM BuffParameters WHERE BuffID = ?;");
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM BuffParameters WHERE BuffID = ?;");
query.bind(1, (int)buffId);
auto result = query.execQuery();
@@ -321,11 +440,12 @@ const std::vector<BuffParameter>& BuffComponent::GetBuffParameters(int32_t buffI
BuffParameter param;
param.buffId = buffId;
param.name = result.getStringField(1);
param.value = result.getFloatField(2);
param.name = result.getStringField("ParameterName");
param.value = result.getFloatField("NumberValue");
param.effectId = result.getIntField("EffectID");
if (!result.fieldIsNull(3)) {
std::istringstream stream(result.getStringField(3));
std::istringstream stream(result.getStringField("StringValue"));
std::string token;
while (std::getline(stream, token, ',')) {