diff --git a/zone/client.cpp b/zone/client.cpp index 732258bfd..d9e04ba7b 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -66,6 +66,8 @@ #include #include +#include "patch/client_version.h" + extern QueryServ* QServ; extern EntityList entity_list; extern Zone* zone; @@ -3809,7 +3811,11 @@ void Client::MessageString(uint32 type, uint32 string_id, uint32 distance) if (GetFilter(FilterSpellCrits) == FilterHide && type == Chat::SpellCrit) return; - m_messageComponent->Simple(this, type, string_id, distance); + if (distance > 0) + ZoneClient::ClientPatch::QueueCloseClients(this, false, distance)( + &ZoneClient::Message::IMessage::Simple, type, string_id); + else + ZoneClient::ClientPatch::QueuePacket(this, &ZoneClient::Message::IMessage::Simple, type, string_id); } // @@ -3837,9 +3843,16 @@ void Client::MessageString(uint32 type, uint32 string_id, const char* message1, if (type == Chat::Emote) type = 4; - m_messageComponent->Formatted(this, type, string_id, - message1, message2, message3, message4, message5, - message6, message7, message8, message9, distance); + if (distance > 0) + ZoneClient::ClientPatch::QueueCloseClients(this, false, distance)( + &ZoneClient::Message::IMessage::Formatted, type, string_id, + message1, message2, message3, message4, message5, + message6, message7, message8, message9); + else + ZoneClient::ClientPatch::QueuePacket( + this, &ZoneClient::Message::IMessage::Formatted, type, string_id, + message1, message2, message3, message4, message5, + message6, message7, message8, message9); } void Client::MessageString(const CZClientMessageString_Struct* msg) diff --git a/zone/patch/client_version.h b/zone/patch/client_version.h index 428853154..c78ababbd 100644 --- a/zone/patch/client_version.h +++ b/zone/patch/client_version.h @@ -23,9 +23,11 @@ public: template static void QueuePacket(Client* c, Fun fun, Args&&... args) { static_assert(std::is_member_function_pointer_v); - EQApplicationPacket* app = std::invoke(fun, c->GetMessageComponent().get(), c, std::forward(args)...); - c->QueuePacket(app); - safe_delete(app); + EQApplicationPacket* app = std::invoke(fun, c->GetMessageComponent().get(), std::forward(args)...); + if (app != nullptr) { + c->QueuePacket(app); + delete app; + } } // packet generator queue functions @@ -39,13 +41,15 @@ public: if (!ignore_sender || ent != sender) { auto [packet, _] = build_packets.try_emplace( ent->ClientVersion(), - std::invoke(fun, GetMessageComponent(ent->ClientVersion()).get(), sender, std::forward(args)...)); - ent->QueuePacket(packet->second, ackreq, Client::CLIENT_CONNECTED); + std::invoke(fun, GetMessageComponent(ent->ClientVersion()).get(), std::forward(args)...)); + if (packet->second != nullptr) + ent->QueuePacket(packet->second, ackreq, Client::CLIENT_CONNECTED); } } for (auto [_, packet] : build_packets) - safe_delete(packet); + if (packet != nullptr) + delete packet; }; } @@ -77,16 +81,18 @@ public: ) { auto [packet, _] = build_packets.try_emplace( client->ClientVersion(), - std::invoke(fun, GetMessageComponent(client->ClientVersion()).get(), sender, + std::invoke(fun, GetMessageComponent(client->ClientVersion()).get(), std::forward(args)...)); - client->QueuePacket(packet->second, is_ack_required, Client::CLIENT_CONNECTED); + if (packet->second != nullptr) + client->QueuePacket(packet->second, is_ack_required, Client::CLIENT_CONNECTED); } } } } for (auto [_, packet] : build_packets) - safe_delete(packet); + if (packet != nullptr) + delete packet;; } }; } diff --git a/zone/patch/components/message/IMessage.h b/zone/patch/components/message/IMessage.h index e7f8bb8e3..f42e2c59a 100644 --- a/zone/patch/components/message/IMessage.h +++ b/zone/patch/components/message/IMessage.h @@ -32,29 +32,21 @@ public: constexpr IMessage() {} constexpr virtual ~IMessage() {} - virtual void Simple(Client* c, uint32_t color, uint32_t id, uint32_t distance = 0) const = 0; - - virtual void Formatted(Client* c, uint32_t color, uint32_t id, - const char* a1 = nullptr, const char* a2 = nullptr, const char* a3 = nullptr, - const char* a4 = nullptr, const char* a5 = nullptr, const char* a6 = nullptr, - const char* a7 = nullptr, const char* a8 = nullptr, const char* a9 = nullptr, - uint32_t distance = 0) const = 0; + // these two are the basic string message packets + virtual EQApplicationPacket* Simple(uint32_t color, uint32_t id) const = 0; + virtual EQApplicationPacket* Formatted(uint32_t color, uint32_t id, + const char* a1 = nullptr, const char* a2 = nullptr, const char* a3 = nullptr, + const char* a4 = nullptr, const char* a5 = nullptr, const char* a6 = nullptr, + const char* a7 = nullptr, const char* a8 = nullptr, const char* a9 = nullptr) const = 0; // These aren't technically messages, but they use the same format and are similar enough to include here - virtual EQApplicationPacket* InterruptSpell(Client* c, uint32_t message, uint32_t spawn_id, uint32_t spell_id, + virtual EQApplicationPacket* InterruptSpell(uint32_t message, uint32_t spawn_id, uint32_t spell_id, const char* spell_name_override = "") const = 0; - virtual EQApplicationPacket* InterruptSpellOther(Mob* m, uint32_t message, uint32_t spawn_id, uint32_t spell_id, + virtual EQApplicationPacket* InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, uint32_t spell_id, const char* spell_name_override = "") const = 0; + // Everything else is specializations of logic needed to build strings that differ between patches virtual EQApplicationPacket* Fizzle(Mob* m, uint32_t type, uint32_t message, uint32_t spell_id) const = 0; - -protected: - virtual uint32_t ResolveID(uint32_t id) const = 0; - virtual void SendSimple(Client* c, uint32_t color, uint32_t string_id, uint32_t distance) const = 0; - virtual void SendFormatted(Client* c, uint32_t color, uint32_t string_id, uint32_t distance, - const char* a1 = nullptr, const char* a2 = nullptr, const char* a3 = nullptr, - const char* a4 = nullptr, const char* a5 = nullptr, const char* a6 = nullptr, - const char* a7 = nullptr, const char* a8 = nullptr, const char* a9 = nullptr) const = 0; }; } // namespace Zone::Message diff --git a/zone/patch/components/message/titanium.cpp b/zone/patch/components/message/titanium.cpp index 3a71b7513..34b01b5b2 100644 --- a/zone/patch/components/message/titanium.cpp +++ b/zone/patch/components/message/titanium.cpp @@ -24,23 +24,52 @@ #include "common/serialize_buffer.h" namespace ZoneClient::Message { -void Titanium::Simple(Client* c, uint32_t color, uint32_t id, uint32_t distance) const { +EQApplicationPacket* Titanium::Simple(uint32_t color, uint32_t id) const { uint32_t string_id = ResolveID(id); - if (string_id > 0) - SendSimple(c, color, string_id, distance); + if (string_id > 0) { + auto outapp = new EQApplicationPacket(OP_SimpleMessage, sizeof(SimpleMessage_Struct)); + auto* sms = reinterpret_cast(outapp->pBuffer); + sms->string_id = string_id; + sms->color = color; + sms->unknown8 = 0; + + return outapp; + } + + return nullptr; } -void Titanium::Formatted(Client* c, uint32_t color, uint32_t id, - const char* a1, const char* a2, const char* a3, - const char* a4, const char* a5, const char* a6, - const char* a7, const char* a8, const char* a9, - uint32_t distance) const { +EQApplicationPacket* Titanium::Formatted(uint32_t color, uint32_t id, + const char* a1, const char* a2, const char* a3, + const char* a4, const char* a5, const char* a6, + const char* a7, const char* a8, const char* a9) const { uint32_t string_id = ResolveID(id); - if (string_id > 0) - SendFormatted(c, color, string_id, distance, a1, a2, a3, a4, a5, a6, a7, a8, a9); + if (string_id > 0) { + if (!a1) + return Simple(color, id); + + const char* args[] = {a1, a2, a3, a4, a5, a6, a7, a8, a9}; + + SerializeBuffer buf(20); + buf.WriteInt32(0); + buf.WriteInt32(string_id); + buf.WriteInt32(color); + + for (const auto* arg : args) { + if (!arg) + break; + buf.WriteString(arg); + } + + buf.WriteInt8(0); + + return new EQApplicationPacket(OP_FormattedMessage, std::move(buf)); + } + + return nullptr; } -EQApplicationPacket* Titanium::InterruptSpell(Client* c, uint32_t message, uint32_t spawn_id, uint32_t spell_id, +EQApplicationPacket* Titanium::InterruptSpell(uint32_t message, uint32_t spawn_id, uint32_t spell_id, const char* spell_name_override) const { auto outapp = new EQApplicationPacket(OP_InterruptCast, sizeof(InterruptCast_Struct)); auto ic = reinterpret_cast(outapp->pBuffer); @@ -51,9 +80,9 @@ EQApplicationPacket* Titanium::InterruptSpell(Client* c, uint32_t message, uint3 return outapp; } -EQApplicationPacket* Titanium::InterruptSpellOther(Mob* m, uint32_t message, uint32_t spawn_id, uint32_t spell_id, +EQApplicationPacket* Titanium::InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, uint32_t spell_id, const char* spell_name_override) const { - auto name = m->GetCleanName(); + auto name = sender->GetCleanName(); auto outapp = new EQApplicationPacket(OP_InterruptCast, sizeof(InterruptCast_Struct) + strlen(name) + 1); auto ic = reinterpret_cast(outapp->pBuffer); ic->messageid = ResolveID(message); @@ -73,51 +102,4 @@ uint32_t Titanium::ResolveID(uint32_t id) const { return id; } -// Could override these in patches if the format of the packets differ, but they are all compatible -void Titanium::SendSimple(Client* c, uint32_t color, uint32_t string_id, uint32_t distance) const { - auto outapp = new EQApplicationPacket(OP_SimpleMessage, sizeof(SimpleMessage_Struct)); - auto* sms = reinterpret_cast(outapp->pBuffer); - sms->string_id = string_id; - sms->color = color; - sms->unknown8 = 0; - - if (distance > 0) - entity_list.QueueCloseClients(c, outapp, false, distance); - else - c->QueuePacket(outapp); - - safe_delete(outapp); -} - -void Titanium::SendFormatted( - Client* c, uint32_t color, uint32_t string_id, uint32_t distance, - const char* a1, const char* a2, const char* a3, - const char* a4, const char* a5, const char* a6, - const char* a7, const char* a8, const char* a9) const { - if (!a1) { - SendSimple(c, color, string_id, distance); - } else { - const char* args[] = {a1, a2, a3, a4, a5, a6, a7, a8, a9}; - - SerializeBuffer buf(20); - buf.WriteInt32(0); - buf.WriteInt32(string_id); - buf.WriteInt32(color); - - for (const auto* arg : args) { - if (!arg) - break; - buf.WriteString(arg); - } - - buf.WriteInt8(0); - - auto outapp = std::make_unique(OP_FormattedMessage, std::move(buf)); - - if (distance > 0) - entity_list.QueueCloseClients(c, outapp.get(), false, distance); - else - c->QueuePacket(outapp.get()); - } -} } // namespace ZoneClient::Message diff --git a/zone/patch/components/message/titanium.h b/zone/patch/components/message/titanium.h index 9f55af171..0f9ef46d9 100644 --- a/zone/patch/components/message/titanium.h +++ b/zone/patch/components/message/titanium.h @@ -26,28 +26,22 @@ public: constexpr Titanium() {} constexpr ~Titanium() override {} - void Simple(Client* c, uint32_t color, uint32_t id, uint32_t distance = 0) const override; + EQApplicationPacket* Simple(uint32_t color, uint32_t id) const override; - void Formatted(Client* c, uint32_t color, uint32_t id, - const char* a1 = nullptr, const char* a2 = nullptr, const char* a3 = nullptr, - const char* a4 = nullptr, const char* a5 = nullptr, const char* a6 = nullptr, - const char* a7 = nullptr, const char* a8 = nullptr, const char* a9 = nullptr, - uint32_t distance = 0) const override; + EQApplicationPacket* Formatted(uint32_t color, uint32_t id, + const char* a1 = nullptr, const char* a2 = nullptr, const char* a3 = nullptr, + const char* a4 = nullptr, const char* a5 = nullptr, const char* a6 = nullptr, + const char* a7 = nullptr, const char* a8 = nullptr, const char* a9 = nullptr) const override; - EQApplicationPacket* InterruptSpell(Client* c, uint32_t message, uint32_t spawn_id, uint32_t spell_id, + EQApplicationPacket* InterruptSpell(uint32_t message, uint32_t spawn_id, uint32_t spell_id, const char* spell_name_override = "") const override; - EQApplicationPacket* InterruptSpellOther(Mob* m, uint32_t message, uint32_t spawn_id, uint32_t spell_id, + EQApplicationPacket* InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, uint32_t spell_id, const char* spell_name_override = "") const override; EQApplicationPacket* Fizzle(Mob* m, uint32_t type, uint32_t message, uint32_t spell_id) const override; protected: - uint32_t ResolveID(uint32_t id) const override; - void SendSimple(Client* c, uint32_t color, uint32_t string_id, uint32_t distance) const override; - void SendFormatted(Client* c, uint32_t color, uint32_t string_id, uint32_t distance, - const char* a1 = nullptr, const char* a2 = nullptr, const char* a3 = nullptr, - const char* a4 = nullptr, const char* a5 = nullptr, const char* a6 = nullptr, - const char* a7 = nullptr, const char* a8 = nullptr, const char* a9 = nullptr) const override; + virtual uint32_t ResolveID(uint32_t id) const; }; } // namespace Zone::Message diff --git a/zone/patch/components/message/tob.cpp b/zone/patch/components/message/tob.cpp index 4ba73c824..84c62f54a 100644 --- a/zone/patch/components/message/tob.cpp +++ b/zone/patch/components/message/tob.cpp @@ -72,7 +72,7 @@ uint32_t TOB::ResolveID(uint32_t id) const { } } -EQApplicationPacket* TOB::InterruptSpell(Client* c, uint32_t message, uint32_t spawn_id, uint32_t spell_id, const char* spell_name_override) const { +EQApplicationPacket* TOB::InterruptSpell(uint32_t message, uint32_t spawn_id, uint32_t spell_id, const char* spell_name_override) const { std::string spell_name = spell_name_override == nullptr || *spell_name_override == '\0' ? GetSpellName(spell_id) : spell_name_override; @@ -89,7 +89,7 @@ EQApplicationPacket* TOB::InterruptSpell(Client* c, uint32_t message, uint32_t s return outapp; } -EQApplicationPacket* TOB::InterruptSpellOther(Mob* m, uint32_t message, uint32_t spawn_id, uint32_t spell_id, +EQApplicationPacket* TOB::InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, uint32_t spell_id, const char* spell_name_override) const { std::string spell_name = spell_name_override == nullptr || *spell_name_override == '\0' ? GetSpellName(spell_id) @@ -97,7 +97,7 @@ EQApplicationPacket* TOB::InterruptSpellOther(Mob* m, uint32_t message, uint32_t std::string spell_link = Links::FormatSpellLink(spell_id, spell_name); - auto name = m->GetCleanName(); + auto name = sender->GetCleanName(); auto outapp = new EQApplicationPacket(OP_InterruptCast, sizeof(InterruptCast_Struct) + strlen(name) + spell_link.size() + 2); auto ic = reinterpret_cast(outapp->pBuffer); ic->messageid = ResolveID(message); diff --git a/zone/patch/components/message/tob.h b/zone/patch/components/message/tob.h index e7d1d8b4e..a0d9d3ec3 100644 --- a/zone/patch/components/message/tob.h +++ b/zone/patch/components/message/tob.h @@ -25,9 +25,9 @@ public: constexpr TOB() {} constexpr ~TOB() override {} - EQApplicationPacket* InterruptSpell(Client* c, uint32_t message, uint32_t spawn_id, uint32_t spell_id, + EQApplicationPacket* InterruptSpell(uint32_t message, uint32_t spawn_id, uint32_t spell_id, const char* spell_name_override) const override; - EQApplicationPacket* InterruptSpellOther(Mob* m, uint32_t message, uint32_t spawn_id, uint32_t spell_id, + EQApplicationPacket* InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, uint32_t spell_id, const char* spell_name_override) const override; protected: diff --git a/zone/spells.cpp b/zone/spells.cpp index d6fcb425c..f2e1df516 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -1348,7 +1348,7 @@ void Mob::InterruptSpell(uint16 message, uint16 color, uint16 spellid) ZoneClient::ClientPatch::QueueCloseClients( this, true, RuleI(Range, SongMessages), nullptr, true, IsClient() ? FilterPCSpells : FilterNPCSpells)( - &ZoneClient::Message::IMessage::InterruptSpellOther, message_other, GetID(), spellid, ""); + &ZoneClient::Message::IMessage::InterruptSpellOther, this, message_other, GetID(), spellid, ""); } // this is like interrupt, just it doesn't spam interrupt packets to everyone