Moved formatted message into the new tob patch and cleaned up a bit

This commit is contained in:
dannuic
2026-04-22 16:11:01 -06:00
parent 46dce8499f
commit 79be47430c
18 changed files with 256 additions and 150 deletions
+11 -11
View File
@@ -1,18 +1,18 @@
set(message_component_sources
titanium.cpp
rof2.cpp
tob.cpp
titanium.cpp
rof2.cpp
tob.cpp
)
set(message_component_headers
IMessage.h
titanium.h
sof.h
sod.h
uf.h
rof.h
rof2.h
tob.h
IMessage.h
titanium.h
sof.h
sod.h
uf.h
rof.h
rof2.h
tob.h
)
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" PREFIX "Source Files" FILES ${message_component_sources})
+10 -10
View File
@@ -26,8 +26,8 @@ class Mob;
class EQApplicationPacket;
namespace ZoneClient::Message {
class IMessage {
class IMessage
{
public:
constexpr IMessage() {}
constexpr virtual ~IMessage() {}
@@ -35,19 +35,19 @@ public:
// 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;
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(uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override = "") const = 0;
virtual EQApplicationPacket* InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override = "") const = 0;
const char* spell_name_override = "") const = 0;
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(uint32_t type, uint32_t message, uint32_t spell_id) const = 0;
virtual EQApplicationPacket* FizzleOther(uint32_t type, uint32_t message, uint32_t spell_id, const char* caster) const = 0;
virtual EQApplicationPacket* FizzleOther(uint32_t type, uint32_t message, uint32_t spell_id,
const char* caster) const = 0;
};
} // namespace Zone::Message
+2 -3
View File
@@ -20,11 +20,10 @@
#include "zone/patch/components/message/uf.h"
namespace ZoneClient::Message {
class RoF : public UF {
class RoF : public UF
{
public:
constexpr RoF() {}
constexpr ~RoF() override {}
};
} // namespace Zone::Message
+2 -3
View File
@@ -20,11 +20,10 @@
#include "zone/patch/components/message/rof.h"
namespace ZoneClient::Message {
class RoF2 : public RoF {
class RoF2 : public RoF
{
public:
constexpr RoF2() {}
constexpr ~RoF2() override {}
};
} // namespace Zone::Message
+2 -3
View File
@@ -20,11 +20,10 @@
#include "zone/patch/components/message/sof.h"
namespace ZoneClient::Message {
class SoD : public SoF {
class SoD : public SoF
{
public:
constexpr SoD() {}
constexpr ~SoD() override {}
};
} // namespace Zone::Message
+2 -3
View File
@@ -20,11 +20,10 @@
#include "zone/patch/components/message/titanium.h"
namespace ZoneClient::Message {
class SoF : public Titanium {
class SoF : public Titanium
{
public:
constexpr SoF() {}
constexpr ~SoF() override {}
};
} // namespace Zone::Message
+25 -19
View File
@@ -24,7 +24,8 @@
#include "common/serialize_buffer.h"
namespace ZoneClient::Message {
EQApplicationPacket* Titanium::Simple(uint32_t color, uint32_t id) const {
EQApplicationPacket* Titanium::Simple(uint32_t color, uint32_t id) const
{
uint32_t string_id = ResolveID(id);
if (string_id > 0) {
auto outapp = new EQApplicationPacket(OP_SimpleMessage, sizeof(SimpleMessage_Struct));
@@ -39,26 +40,25 @@ EQApplicationPacket* Titanium::Simple(uint32_t color, uint32_t id) const {
return nullptr;
}
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 {
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) {
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);
for (const auto* a : {a1, a2, a3, a4, a5, a6, a7, a8, a9}) {
if (a != nullptr)
buf.WriteString(a);
}
buf.WriteInt8(0);
@@ -69,8 +69,10 @@ EQApplicationPacket* Titanium::Formatted(uint32_t color, uint32_t id,
return nullptr;
}
EQApplicationPacket* Titanium::InterruptSpell(uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override) const {
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<InterruptCast_Struct*>(outapp->pBuffer);
ic->messageid = ResolveID(message);
@@ -80,8 +82,10 @@ EQApplicationPacket* Titanium::InterruptSpell(uint32_t message, uint32_t spawn_i
return outapp;
}
EQApplicationPacket* Titanium::InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override) const {
EQApplicationPacket* Titanium::InterruptSpellOther(
Mob* sender, uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override) const
{
auto name = sender->GetCleanName();
auto outapp = new EQApplicationPacket(OP_InterruptCast, sizeof(InterruptCast_Struct) + strlen(name) + 1);
auto ic = reinterpret_cast<InterruptCast_Struct*>(outapp->pBuffer);
@@ -91,19 +95,21 @@ EQApplicationPacket* Titanium::InterruptSpellOther(Mob* sender, uint32_t message
return outapp;
}
EQApplicationPacket* Titanium::Fizzle(uint32_t type, uint32_t message, uint32_t spell_id) const {
EQApplicationPacket* Titanium::Fizzle(uint32_t type, uint32_t message, uint32_t spell_id) const
{
return Simple(type, message);
}
EQApplicationPacket* Titanium::FizzleOther(uint32_t type, uint32_t message, uint32_t spell_id, const char* caster) const {
EQApplicationPacket* Titanium::FizzleOther(uint32_t type, uint32_t message, uint32_t spell_id, const char* caster) const
{
return Formatted(type, message, caster);
}
// A value of 0 means that the string isn't mapped in this client, valid string ids start at 1
uint32_t Titanium::ResolveID(uint32_t id) const {
uint32_t Titanium::ResolveID(uint32_t id) const
{
// passthrough — string IDs are defined at the base client level;
// override in patches where IDs need remapping
return id;
}
} // namespace ZoneClient::Message
+9 -9
View File
@@ -20,8 +20,8 @@
#include "zone/patch/components/message/IMessage.h"
namespace ZoneClient::Message {
class Titanium : public IMessage {
class Titanium : public IMessage
{
public:
constexpr Titanium() {}
constexpr ~Titanium() override {}
@@ -29,20 +29,20 @@ public:
EQApplicationPacket* Simple(uint32_t color, uint32_t id) 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;
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(uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override = "") const override;
const char* spell_name_override = "") const override;
EQApplicationPacket* InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override = "") const override;
const char* spell_name_override = "") const override;
EQApplicationPacket* Fizzle(uint32_t type, uint32_t message, uint32_t spell_id) const override;
EQApplicationPacket* FizzleOther(uint32_t type, uint32_t message, uint32_t spell_id, const char* caster) const override;
EQApplicationPacket* FizzleOther(uint32_t type, uint32_t message,
uint32_t spell_id, const char* caster) const override;
protected:
virtual uint32_t ResolveID(uint32_t id) const;
};
} // namespace Zone::Message
+141 -12
View File
@@ -20,12 +20,13 @@
#include "common/links.h"
namespace ZoneClient::Message {
struct TOBStringIDs {
struct TOBStringIDs
{
static constexpr uint32_t DisarmedTrap = 1458; // You successfully disarmed the trap
};
uint32_t TOB::ResolveID(uint32_t id) const {
uint32_t TOB::ResolveID(uint32_t id) const
{
switch (id) {
case YOU_FLURRY:
case BOW_DOUBLE_DAMAGE:
@@ -72,10 +73,134 @@ uint32_t TOB::ResolveID(uint32_t id) const {
}
}
EQApplicationPacket* TOB::InterruptSpell(uint32_t message, uint32_t spawn_id, uint32_t spell_id, const char* spell_name_override) const {
// TOB is the first patch to fully support links in the client. This helper function is therefore internal to TOB
// because any future patches would default to the TOB message strings
static void ServerToTOBConvertLinks(std::string& message_out, const std::string& message_in)
{
if (message_in.find('\x12') == std::string::npos) {
message_out = message_in;
return;
}
auto segments = Strings::Split(message_in, '\x12');
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
if (segment_iter & 1) {
auto etag = std::stoi(segments[segment_iter].substr(0, 1));
switch (etag) {
case 0: {
size_t index = 1;
auto item_id = segments[segment_iter].substr(index, 5);
index += 5;
auto aug1 = segments[segment_iter].substr(index, 5);
index += 5;
auto aug2 = segments[segment_iter].substr(index, 5);
index += 5;
auto aug3 = segments[segment_iter].substr(index, 5);
index += 5;
auto aug4 = segments[segment_iter].substr(index, 5);
index += 5;
auto aug5 = segments[segment_iter].substr(index, 5);
index += 5;
auto aug6 = segments[segment_iter].substr(index, 5);
index += 5;
auto is_evolving = segments[segment_iter].substr(index, 1);
index += 1;
auto evolutionGroup = segments[segment_iter].substr(index, 4);
index += 4;
auto evolutionLevel = segments[segment_iter].substr(index, 2);
index += 2;
auto ornamentationIconID = segments[segment_iter].substr(index, 5);
index += 5;
auto itemHash = segments[segment_iter].substr(index, 8);
index += 8;
auto text = segments[segment_iter].substr(index);
message_out.push_back('\x12');
message_out.push_back('0'); //etag item
message_out.append(item_id);
message_out.append(aug1);
message_out.append("00000");
message_out.append(aug2);
message_out.append("00000");
message_out.append(aug3);
message_out.append("00000");
message_out.append(aug4);
message_out.append("00000");
message_out.append(aug5);
message_out.append("00000");
message_out.append(aug6);
message_out.append("00000");
message_out.append(is_evolving);
message_out.append(evolutionGroup);
message_out.append(evolutionLevel);
message_out.append(ornamentationIconID);
message_out.append("00000");
message_out.append(itemHash);
message_out.append(text);
message_out.push_back('\x12');
break;
}
default:
//unsupported etag right now; just pass it as is
message_out.push_back('\x12');
message_out.append(segments[segment_iter]);
message_out.push_back('\x12');
break;
}
} else {
message_out.append(segments[segment_iter]);
}
}
}
EQApplicationPacket* TOB::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) {
SerializeBuffer buffer(49);
// 49 is the minimum size needed for this packet since each arg writes at least 4 bytes
buffer.WriteUInt32(0);
// This is a string written like the message arrays, but it seems to be discarded by the client
buffer.WriteUInt8(0); // 0 is a zone packet, 1 is a world packet -- these are always sent from zone from here
buffer.WriteUInt32(string_id);
buffer.WriteUInt32(color);
for (auto a : {a1, a2, a3, a4, a5, a6, a7, a8, a9}) {
if (a != nullptr) {
std::string new_message;
ServerToTOBConvertLinks(new_message, a);
buffer.WriteLengthString(new_message);
} else
buffer.WriteUInt32(0);
}
return new EQApplicationPacket(OP_FormattedMessage, std::move(buffer));
}
return nullptr;
}
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;
? GetSpellName(spell_id)
: spell_name_override;
std::string spell_link = Links::FormatSpellLink(spell_id, spell_name);
@@ -90,15 +215,17 @@ EQApplicationPacket* TOB::InterruptSpell(uint32_t message, uint32_t spawn_id, ui
}
EQApplicationPacket* TOB::InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override) const {
const char* spell_name_override) const
{
std::string spell_name = spell_name_override == nullptr || *spell_name_override == '\0'
? GetSpellName(spell_id)
: spell_name_override;
? GetSpellName(spell_id)
: spell_name_override;
std::string spell_link = Links::FormatSpellLink(spell_id, spell_name);
auto name = sender->GetCleanName();
auto outapp = new EQApplicationPacket(OP_InterruptCast, sizeof(InterruptCast_Struct) + strlen(name) + spell_link.size() + 2);
auto outapp = new EQApplicationPacket(OP_InterruptCast,
sizeof(InterruptCast_Struct) + strlen(name) + spell_link.size() + 2);
auto ic = reinterpret_cast<InterruptCast_Struct*>(outapp->pBuffer);
ic->messageid = ResolveID(message);
ic->spawnid = spawn_id;
@@ -107,14 +234,16 @@ EQApplicationPacket* TOB::InterruptSpellOther(Mob* sender, uint32_t message, uin
return outapp;
}
EQApplicationPacket* TOB::Fizzle(uint32_t type, uint32_t message, uint32_t spell_id) const {
EQApplicationPacket* TOB::Fizzle(uint32_t type, uint32_t message, uint32_t spell_id) const
{
std::string spell_name(GetSpellName(spell_id));
std::string spell_link = Links::FormatSpellLink(spell_id, spell_name);
return Formatted(type, message, spell_link.c_str());
}
EQApplicationPacket* TOB::FizzleOther(uint32_t type, uint32_t message, uint32_t spell_id, const char* caster) const {
EQApplicationPacket* TOB::FizzleOther(uint32_t type, uint32_t message, uint32_t spell_id, const char* caster) const
{
std::string spell_name(GetSpellName(spell_id));
std::string spell_link = Links::FormatSpellLink(spell_id, spell_name);
+11 -5
View File
@@ -20,21 +20,27 @@
#include "zone/patch/components/message/rof2.h"
namespace ZoneClient::Message {
class TOB : public RoF2 {
class TOB : public RoF2
{
public:
constexpr TOB() {}
constexpr ~TOB() 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(uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override) const override;
const char* spell_name_override) const override;
EQApplicationPacket* InterruptSpellOther(Mob* sender, uint32_t message, uint32_t spawn_id, uint32_t spell_id,
const char* spell_name_override) const override;
const char* spell_name_override) const override;
EQApplicationPacket* Fizzle(uint32_t type, uint32_t message, uint32_t spell_id) const override;
EQApplicationPacket* FizzleOther(uint32_t type, uint32_t message, uint32_t spell_id, const char* caster) const override;
EQApplicationPacket*
FizzleOther(uint32_t type, uint32_t message, uint32_t spell_id, const char* caster) const override;
protected:
uint32_t ResolveID(uint32_t id) const override;
};
} // namespace Zone::Message
+2 -3
View File
@@ -20,11 +20,10 @@
#include "patch/components/message/sod.h"
namespace ZoneClient::Message {
class UF : public SoD {
class UF : public SoD
{
public:
constexpr UF() {}
constexpr ~UF() override {}
};
} // namespace Zone::Message