Sylian
TrustedTrusted
LEVEL 28
56 XP
So, after taking a break from WoW Emulation, I got the itch to return to WoW Emulation. I quit because I could not figure out how to send a WorldPacket.
Last night, I spent a few hours trying to understand how the specific WorldPacket "SMSG_MESSAGECHAT" worked. I figured it out, so now I want to share it with all of you, since I don't see anyone else talking about it.
Most people would ask why we want to learn about this specific WorldPacket.
We want to learn how to utilize this WorldPacket because we can communicate Server <-> Client. This way, we send a chat message from the server to the client, which might not sound important at all, but by doing this, we can send data from the server to the client.
We made a module for our server that increases a random attribute for each kill the player gets. We also created an add-on to show the increases and maybe the number of kills the player has done.
Now, we are stuck because we need to somehow transfer the data from the module to the player add-on, and this is where the WorldPacket comes into play!
Now that we have built an example, we can start breaking down the packet to understand it and rebuild it in our module.
Let's first see how the WorldPacket looks when the client receives it from the server.

This looks scary, but it's much easier to understand when you break it down, so let's do that!
Here is the packet breakdown and what each byte(s) means. Remember to build the packet correctly; your client won't accept it if not.
01 = The channel the message should be sent to, "01" is the /say channel.
07 00 00 00 = The language the message was sent as, "07" is LANG_COMMON.
02 00 00 00 00 00 00 00 = The characters GUID that we want our message to be sent to, in this case, my characters GUID is "02"
00 00 00 00 = These empty bytes are what is called a "Null Terminator," these are important because, as I said before, we NEED to build the packet correctly
02 00 00 00 00 00 00 00 = The characters GUID again, I honestly don't understand why it wants the GUID again.
08 00 00 00 = The message length + 1.
45 6D 75 64 65 76 73 00 = The message we want to send; these bytes mean just "Emudevs," but depending on the message you send, they will be a longer or smaller array of bytes.
00 = This is a single byte we again NEED to add to the end of the packet.
Now that we understand how the packet sent works, we can recreate it inside our module using C++. So, let's go ahead and recreate it.
We want to recreate and send the packet in our module, but we must ensure it is sent to the correct player.
So, for our example, we want to override the function called when the player kills another creature, so let's do that first.
After all this has been setup, we will go ahead and build/compile our module again and start the server.
If everything is correct, our player would say, "StatIncrease:[CharacterName]" after each kill.
As you can see, it works perfectly!

I hope this guide/tutorial helped some of you work with world packets!
Credits:
@Jens -> Explained some of the details behind World Packets!
Last night, I spent a few hours trying to understand how the specific WorldPacket "SMSG_MESSAGECHAT" worked. I figured it out, so now I want to share it with all of you, since I don't see anyone else talking about it.
Most people would ask why we want to learn about this specific WorldPacket.
We want to learn how to utilize this WorldPacket because we can communicate Server <-> Client. This way, we send a chat message from the server to the client, which might not sound important at all, but by doing this, we can send data from the server to the client.
Example
We made a module for our server that increases a random attribute for each kill the player gets. We also created an add-on to show the increases and maybe the number of kills the player has done.
Now, we are stuck because we need to somehow transfer the data from the module to the player add-on, and this is where the WorldPacket comes into play!
Breaking Down The Packet
Now that we have built an example, we can start breaking down the packet to understand it and rebuild it in our module.
Let's first see how the WorldPacket looks when the client receives it from the server.

This looks scary, but it's much easier to understand when you break it down, so let's do that!
Here is the packet breakdown and what each byte(s) means. Remember to build the packet correctly; your client won't accept it if not.
01 = The channel the message should be sent to, "01" is the /say channel.
07 00 00 00 = The language the message was sent as, "07" is LANG_COMMON.
02 00 00 00 00 00 00 00 = The characters GUID that we want our message to be sent to, in this case, my characters GUID is "02"
00 00 00 00 = These empty bytes are what is called a "Null Terminator," these are important because, as I said before, we NEED to build the packet correctly
02 00 00 00 00 00 00 00 = The characters GUID again, I honestly don't understand why it wants the GUID again.
08 00 00 00 = The message length + 1.
45 6D 75 64 65 76 73 00 = The message we want to send; these bytes mean just "Emudevs," but depending on the message you send, they will be a longer or smaller array of bytes.
00 = This is a single byte we again NEED to add to the end of the packet.
Now that we understand how the packet sent works, we can recreate it inside our module using C++. So, let's go ahead and recreate it.
Recreating Our Packet In C++
We want to recreate and send the packet in our module, but we must ensure it is sent to the correct player.
So, for our example, we want to override the function called when the player kills another creature, so let's do that first.
C++:
void OnCreatureKill(Player* p, Creature* c) override
{
if (!p)
return;
// Stores the players GUID for the packet.
uint64 guid = p->GetGUID().GetRawValue();
// Prefix for our addon.
std::string addonPrefix = "StatIncreaser:";
// Data we want to send with it, for this tutorial I will just make it send the characters name with it.
std::string addonData = p->GetName();
// The world packet we want to send, so that is SMSG_MESSAGECHAT.
WorldPacket data(SMSG_MESSAGECHAT, 200);
// ---->>> PLEASE NOTE: You DO NOT send accounts or sensitive data using CHAT_MSG_SAY! You would do CHAT_MSG_WHISPER instead of the CHAT_MSG_SAY!!
// The first byte of the packet was the chat channel to which we wanted to send the message, CHAT_MSG_SAY.
data << (uint8)CHAT_MSG_SAY;
// ---->>>> PLEASE NOTE: You normally send data using the LANG_ADDON, but since this is a showcase, I will send it via the LANG_COMMON to show it works!!
// We want to understand the message coming into the player so that we will send the packet as LANG_COMMON.
data << (uint32)LANG_COMMON;
// Now we add the GUID of our character to the packet.
data << guid;
// Null terminator
data << '\0';
// Adding the GUID for a second time.
data << guid;
// Now, we add the addonPrefix and addonData length together and + 1; this is the message size.
uint32 messageSize = addonPrefix.length() + addonData.length() + 1;
// Add the messageSize to the packet.
data << messageSize;
// Adds the addonPrefix and addonData text to the packet.
data << addonPrefix + addonData;
// Now that we are at the end of the packet, we add the last "00" to close the packet correctly.
data << (byte)0;
// Last thing we do is send the world packet to the player who got a kill.
p->SendDirectMessage(&data);
LOG_ERROR("sql.sql", "Sending addon message -> " + addonPrefix + addonData);
}
After all this has been setup, we will go ahead and build/compile our module again and start the server.
If everything is correct, our player would say, "StatIncrease:[CharacterName]" after each kill.
As you can see, it works perfectly!

I hope this guide/tutorial helped some of you work with world packets!
Credits:
@Jens -> Explained some of the details behind World Packets!
Last edited: