mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-31 13:16:39 +00:00
Adding buff infrastructure to handle legacy and modern buff semantics
This commit is contained in:
@@ -139,7 +139,7 @@ void MapOpcodes()
|
||||
ConnectedOpcodes[OP_BlockedBuffs] = &Client::Handle_OP_BlockedBuffs;
|
||||
ConnectedOpcodes[OP_BoardBoat] = &Client::Handle_OP_BoardBoat;
|
||||
ConnectedOpcodes[OP_BookButton] = &Client::Handle_OP_BookButton;
|
||||
ConnectedOpcodes[OP_Buff] = &Client::Handle_OP_Buff;
|
||||
ConnectedOpcodes[OP_BuffDefinition] = &Client::Handle_OP_BuffDefinition;
|
||||
ConnectedOpcodes[OP_BuffRemoveRequest] = &Client::Handle_OP_BuffRemoveRequest;
|
||||
ConnectedOpcodes[OP_Bug] = &Client::Handle_OP_Bug;
|
||||
ConnectedOpcodes[OP_Camp] = &Client::Handle_OP_Camp;
|
||||
@@ -4163,14 +4163,14 @@ void Client::Handle_OP_BookButton(const EQApplicationPacket* app)
|
||||
QueuePacket(&outapp);
|
||||
}
|
||||
|
||||
void Client::Handle_OP_Buff(const EQApplicationPacket *app)
|
||||
void Client::Handle_OP_BuffDefinition(const EQApplicationPacket *app)
|
||||
{
|
||||
/*
|
||||
Note: if invisibility is on client, this will force it to drop.
|
||||
*/
|
||||
if (app->size != sizeof(SpellBuffPacket_Struct))
|
||||
{
|
||||
LogError("Size mismatch in OP_Buff. expected [{}] got [{}]", sizeof(SpellBuffPacket_Struct), app->size);
|
||||
LogError("Size mismatch in OP_BuffDefinition. expected [{}] got [{}]", sizeof(SpellBuffPacket_Struct), app->size);
|
||||
DumpPacket(app);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
void Handle_OP_BlockedBuffs(const EQApplicationPacket *app);
|
||||
void Handle_OP_BoardBoat(const EQApplicationPacket *app);
|
||||
void Handle_OP_BookButton(const EQApplicationPacket *app);
|
||||
void Handle_OP_Buff(const EQApplicationPacket *app);
|
||||
void Handle_OP_BuffDefinition(const EQApplicationPacket *app);
|
||||
void Handle_OP_BuffRemoveRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_Bug(const EQApplicationPacket *app);
|
||||
void Handle_OP_Camp(const EQApplicationPacket *app);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "common/emu_versions.h"
|
||||
#include "common/patches/client_version.h"
|
||||
#include "common/patches/IBuff.h"
|
||||
#include "common/patches/IMessage.h"
|
||||
|
||||
#include "zone/client.h"
|
||||
@@ -97,10 +98,88 @@ static auto QueueCloseClients(
|
||||
};
|
||||
}
|
||||
|
||||
template <typename Fun, typename Obj, typename... Args>
|
||||
static void FastQueuePacket(Client* c, Fun fun, Obj* obj, Args&&... args)
|
||||
{
|
||||
static_assert(std::is_member_function_pointer_v<Fun>);
|
||||
EQApplicationPacket* app = std::invoke(fun, obj, std::forward<Args>(args)...);
|
||||
if (app != nullptr) {
|
||||
c->FastQueuePacket(&app); // FastQueuePacket inherits the lifetime management of the packet, do not delete or it will be double free
|
||||
}
|
||||
}
|
||||
|
||||
static auto QueueClientsByTarget(Mob* sender, bool iSendToSender, Mob* SkipThisMob, bool ackreq, bool HoTT,
|
||||
uint32 ClientVersionBits, bool inspect_buffs, bool clear_target_window)
|
||||
{
|
||||
return [=]<typename Fun, typename Obj, typename... Args>(Fun fun,
|
||||
std::function<Obj*(const Client*)> component_getter, Args&&... args) {
|
||||
static_assert(std::is_member_function_pointer_v<Fun>, "Function is required to be a member function");
|
||||
std::unordered_map<EQ::versions::ClientVersion, EQApplicationPacket*> build_packets;
|
||||
std::unordered_map<uint16, Client*> client_list = entity_list.GetClientList();
|
||||
|
||||
for (auto [_, c] : client_list) {
|
||||
if (c != SkipThisMob && (iSendToSender || c != sender)) {
|
||||
Mob* Target = c->GetTarget();
|
||||
if (Target != nullptr) {
|
||||
// if (Target == sender || (iSendToSender && c == sender) || (HoTT && Target->GetTarget() == sender)) {
|
||||
// // the client has the sender targeted, so check if we send the packet
|
||||
// EQApplicationPacket* app = std::invoke(fun, component_getter(c), std::forward<Args>(args)...);
|
||||
// }
|
||||
Mob* TargetsTarget = Target->GetTarget();
|
||||
bool Send = iSendToSender && c == sender;
|
||||
if (c != sender) {
|
||||
if (Target == sender) {
|
||||
if (inspect_buffs) { // if inspect_buffs is true we're sending a mob's buffs to those with the LAA
|
||||
Send = clear_target_window;
|
||||
if (c->GetGM() || RuleB(Spells, AlwaysSendTargetsBuffs)) {
|
||||
if (c->GetGM()) {
|
||||
if (!c->EntityVariableExists(SEE_BUFFS_FLAG)) {
|
||||
c->Message(Chat::White,
|
||||
"Your GM flag allows you to always see your targets' buffs.");
|
||||
c->SetEntityVariable(SEE_BUFFS_FLAG, "1");
|
||||
}
|
||||
}
|
||||
|
||||
Send = !clear_target_window;
|
||||
} else if (c->IsRaidGrouped()) {
|
||||
Raid* raid = c->GetRaid();
|
||||
if (raid) {
|
||||
uint32 gid = raid->GetGroup(c);
|
||||
if (gid < MAX_RAID_GROUPS && raid->GroupCount(gid) >= 3) {
|
||||
if (raid->GetLeadershipAA(groupAAInspectBuffs, gid))
|
||||
Send = !clear_target_window;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Group* group = c->GetGroup();
|
||||
if (group && group->GroupCount() >= 3) {
|
||||
if (group->GetLeadershipAA(groupAAInspectBuffs)) {
|
||||
Send = !clear_target_window;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Send = true;
|
||||
}
|
||||
} else if (HoTT && TargetsTarget == sender) {
|
||||
Send = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Send && (c->ClientVersionBit() & ClientVersionBits)) {
|
||||
EQApplicationPacket* app = std::invoke(fun, component_getter(c), std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace ClientPatch
|
||||
|
||||
// Helpers for the Message interface to send message packets
|
||||
namespace Message {
|
||||
|
||||
static std::function GetComponent = [](const Client* c) -> IMessage* {
|
||||
return GetMessageComponent(c->GetClientVersion()).get();
|
||||
};
|
||||
@@ -152,3 +231,22 @@ inline void InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id
|
||||
}
|
||||
|
||||
} // namespace Message
|
||||
|
||||
// helper functions to handle sending buffs
|
||||
namespace Buff {
|
||||
|
||||
static std::function GetComponent = [](const Client* c) -> IBuff* {
|
||||
return GetBuffComponent(c->GetClientVersion()).get();
|
||||
};
|
||||
|
||||
inline void SendLegacyBuffsPacket(Client* c, Mob* sender, int32 timer, bool for_target = true, bool clear_buffs = false)
|
||||
{
|
||||
ClientPatch::FastQueuePacket(c, &IBuff::MakeLegacyBuffsPacket, GetComponent(c), sender, timer, for_target, clear_buffs);
|
||||
}
|
||||
|
||||
inline void SendLegacyBuffsPacketToClients(Client* c, bool for_target = true, bool clear_buffs = false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
} // namespace Buff
|
||||
|
||||
+2
-2
@@ -223,9 +223,9 @@ namespace Journal {
|
||||
|
||||
//this is our internal representation of the BUFF struct, can put whatever we want in it
|
||||
struct Buffs_Struct {
|
||||
uint16 spellid;
|
||||
int32 spellid;
|
||||
uint8 casterlevel;
|
||||
uint16 casterid; // Maybe change this to a pointer sometime, but gotta make sure it's 0'd when it no longer points to anything
|
||||
uint32 casterid; // Maybe change this to a pointer sometime, but gotta make sure it's 0'd when it no longer points to anything
|
||||
char caster_name[64];
|
||||
int32 ticsremaining;
|
||||
uint32 counters;
|
||||
|
||||
+8
-4
@@ -530,7 +530,8 @@ luabind::scope lua_register_packet_opcodes() {
|
||||
luabind::value("Camp", static_cast<int>(OP_Camp)),
|
||||
luabind::value("YellForHelp", static_cast<int>(OP_YellForHelp)),
|
||||
luabind::value("SafePoint", static_cast<int>(OP_SafePoint)),
|
||||
luabind::value("Buff", static_cast<int>(OP_Buff)),
|
||||
luabind::value("Buff", static_cast<int>(OP_BuffDefinition)),
|
||||
luabind::value("BuffDefinition", static_cast<int>(OP_BuffDefinition)),
|
||||
luabind::value("ColoredText", static_cast<int>(OP_ColoredText)),
|
||||
luabind::value("SpecialMesg", static_cast<int>(OP_SpecialMesg)),
|
||||
luabind::value("Consent", static_cast<int>(OP_Consent)),
|
||||
@@ -798,7 +799,8 @@ luabind::scope lua_register_packet_opcodes() {
|
||||
luabind::value("CancelTask", static_cast<int>(OP_CancelTask)),
|
||||
luabind::value("TaskHistoryRequest", static_cast<int>(OP_TaskHistoryRequest)),
|
||||
luabind::value("TaskHistoryReply", static_cast<int>(OP_TaskHistoryReply)),
|
||||
luabind::value("PetBuffWindow", static_cast<int>(OP_PetBuffWindow)),
|
||||
luabind::value("PetBuffWindow", static_cast<int>(OP_RefreshPetBuffs)),
|
||||
luabind::value("RefreshPetBuffs", static_cast<int>(OP_RefreshPetBuffs)),
|
||||
luabind::value("RaidJoin", static_cast<int>(OP_RaidJoin)),
|
||||
luabind::value("Translocate", static_cast<int>(OP_Translocate)),
|
||||
luabind::value("Sacrifice", static_cast<int>(OP_Sacrifice)),
|
||||
@@ -858,7 +860,8 @@ luabind::scope lua_register_packet_opcodes() {
|
||||
luabind::value("GroupRoles", static_cast<int>(OP_GroupRoles)),
|
||||
luabind::value("SendFindableNPCs", static_cast<int>(OP_SendFindableNPCs)),
|
||||
luabind::value("HideCorpse", static_cast<int>(OP_HideCorpse)),
|
||||
luabind::value("TargetBuffs", static_cast<int>(OP_TargetBuffs)),
|
||||
luabind::value("TargetBuffs", static_cast<int>(OP_RefreshTargetBuffs)),
|
||||
luabind::value("RefreshTargetBuffs", static_cast<int>(OP_RefreshTargetBuffs)),
|
||||
luabind::value("TradeBusy", static_cast<int>(OP_TradeBusy)),
|
||||
luabind::value("GuildUpdate", static_cast<int>(OP_GuildUpdate)),
|
||||
luabind::value("CameraEffect", static_cast<int>(OP_CameraEffect)),
|
||||
@@ -882,7 +885,8 @@ luabind::scope lua_register_packet_opcodes() {
|
||||
luabind::value("DzCompass", static_cast<int>(OP_DzCompass)),
|
||||
luabind::value("DzChooseZone", static_cast<int>(OP_DzChooseZone)),
|
||||
luabind::value("DzChooseZoneReply", static_cast<int>(OP_DzChooseZoneReply)),
|
||||
luabind::value("BuffCreate", static_cast<int>(OP_BuffCreate)),
|
||||
luabind::value("BuffCreate", static_cast<int>(OP_RefreshBuffs)),
|
||||
luabind::value("RefreshBuffs", static_cast<int>(OP_RefreshBuffs)),
|
||||
luabind::value("GuildStatus", static_cast<int>(OP_GuildStatus)),
|
||||
luabind::value("BuffRemoveRequest", static_cast<int>(OP_BuffRemoveRequest)),
|
||||
luabind::value("CorpseDrag", static_cast<int>(OP_CorpseDrag)),
|
||||
|
||||
+6
-6
@@ -5834,7 +5834,7 @@ void Client::MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message)
|
||||
{
|
||||
EQApplicationPacket* outapp = nullptr;
|
||||
|
||||
outapp = new EQApplicationPacket(OP_Buff, sizeof(SpellBuffPacket_Struct));
|
||||
outapp = new EQApplicationPacket(OP_BuffDefinition, sizeof(SpellBuffPacket_Struct));
|
||||
SpellBuffPacket_Struct* sbf = (SpellBuffPacket_Struct*) outapp->pBuffer;
|
||||
|
||||
sbf->entityid = GetID();
|
||||
@@ -6530,7 +6530,7 @@ int Mob::GetCasterLevel(uint16 spell_id) {
|
||||
void Client::SendBuffDurationPacket(Buffs_Struct &buff, int slot)
|
||||
{
|
||||
EQApplicationPacket* outapp = nullptr;
|
||||
outapp = new EQApplicationPacket(OP_Buff, sizeof(SpellBuffPacket_Struct));
|
||||
outapp = new EQApplicationPacket(OP_BuffDefinition, sizeof(SpellBuffPacket_Struct));
|
||||
SpellBuffPacket_Struct* sbf = (SpellBuffPacket_Struct*) outapp->pBuffer;
|
||||
|
||||
sbf->entityid = GetID();
|
||||
@@ -6566,7 +6566,7 @@ void Client::SendBuffNumHitPacket(Buffs_Struct &buff, int slot)
|
||||
if (ClientVersion() < EQ::versions::ClientVersion::UF)
|
||||
return;
|
||||
EQApplicationPacket *outapp = nullptr;
|
||||
outapp = new EQApplicationPacket(OP_BuffCreate, sizeof(BuffIcon_Struct) + sizeof(BuffIconEntry_Struct));
|
||||
outapp = new EQApplicationPacket(OP_RefreshBuffs, sizeof(BuffIcon_Struct) + sizeof(BuffIconEntry_Struct));
|
||||
BuffIcon_Struct *bi = (BuffIcon_Struct *)outapp->pBuffer;
|
||||
bi->entity_id = GetID();
|
||||
bi->count = 1;
|
||||
@@ -6591,7 +6591,7 @@ void Mob::SendPetBuffsToClient()
|
||||
|
||||
int PetBuffCount = 0;
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_PetBuffWindow, sizeof(PetBuff_Struct));
|
||||
auto outapp = new EQApplicationPacket(OP_RefreshPetBuffs, sizeof(PetBuff_Struct));
|
||||
PetBuff_Struct* pbs=(PetBuff_Struct*)outapp->pBuffer;
|
||||
memset(outapp->pBuffer,0,outapp->size);
|
||||
pbs->petid=GetID();
|
||||
@@ -6651,10 +6651,10 @@ EQApplicationPacket *Mob::MakeBuffsPacket(bool for_target, bool clear_buffs)
|
||||
|
||||
//Create it for a targeting window, else create it for a create buff packet.
|
||||
if(for_target) {
|
||||
outapp = new EQApplicationPacket(OP_TargetBuffs, sizeof(BuffIcon_Struct) + sizeof(BuffIconEntry_Struct) * count);
|
||||
outapp = new EQApplicationPacket(OP_RefreshTargetBuffs, sizeof(BuffIcon_Struct) + sizeof(BuffIconEntry_Struct) * count);
|
||||
}
|
||||
else {
|
||||
outapp = new EQApplicationPacket(OP_BuffCreate, sizeof(BuffIcon_Struct) + sizeof(BuffIconEntry_Struct) * count);
|
||||
outapp = new EQApplicationPacket(OP_RefreshBuffs, sizeof(BuffIcon_Struct) + sizeof(BuffIconEntry_Struct) * count);
|
||||
}
|
||||
BuffIcon_Struct *buff = (BuffIcon_Struct*)outapp->pBuffer;
|
||||
buff->entity_id = GetID();
|
||||
|
||||
Reference in New Issue
Block a user