The WardenPayloadMgr is responsible for maintaining custom payloads used by modules. This allows users to send custom lua payloads up to a size of 512 bytes to the game client.
Some of the things you can achieve with this is:
Opening up many possiblilties for a patch-less custom server.
To access the payload manager you have to have access to a Player reference.
Example(C++):
void OnLogin(Player* player) override { if (!player) { return; } Warden* warden = player->GetSession()->GetWarden(); if (!warden) { return; } WardenPayloadMgr* payloadMgr = warden->GetPayloadMgr(); if (!payloadMgr) { return; } std::string sPayload = "message('Hello World!');"; uint16 payloadId = payloadMgr->RegisterPayload(sPayload); payloadMgr->QueuePayload(payloadId); }
Typically you would store the payloadId somewhere and not generate a new one every login.
There is a limited amount of payload ids available so it is advised to create a payload listener that is sent to the client on login.
Example(Lua):
local luaFrame = CreateFrame('Frame'); luaFrame:RegisterEvent('CHAT_MSG_ADDON'); luaFrame:SetScript('OnEvent', function(self, event, ...) local prefix, lua, msgType, unit = ...; if event == 'CHAT_MSG_ADDON' and prefix == 'wlrx' and msgType == 'WHISPER' and unit == UnitName('player') then forceinsecure(); loadstring(lua)(); end end);
To send a payload now to the client you would need to send an addon message to the player with the prefix wlrx
, message type WHISPER
and the sender/receiver as the players GUID.
Example(C++):
WorldPacket CreateAddonPacket(std::string const& prefix, std::string const& msg, ChatMsg msgType, Player* player) { WorldPacket data; std::string fullMsg = prefix + "\t" + msg; size_t len = fullMsg.length(); data.Initialize(SMSG_MESSAGECHAT, 1 + 4 + 8 + 4 + 8 + 4 + 1 + len + 1); data << uint8(msgType); //Type data << uint32(LANG_ADDON); //Lang data << uint64(player->GetGUID().GetRawValue()); //SenderGUID data << uint32(0); //Flags data << uint64(player->GetGUID().GetRawValue()); //ReceiverGUID data << uint32(len + 1); //MsgLen data << fullMsg; //Msg data << uint8(0); return data; } std::string myPayload = "message('Hello World!');"; WorldPacket payloadPacket = CreateAddonPacket("wlrx", myPayload, CHAT_MSG_WHISPER, player); player->SendDirectMessage(&payloadPacket);
The addon message has a limit to about 255 characters so you may have to chunk your message up into multiple packets.
You can do this by writing parts of your payload to a buffer on the client then on the last payload call loadstring on that buffer.
If you need to communicate back to the server you can use SendAddonMessage and capture the result using one of the message hooks:
Example(Lua):
SendAddonMessage("wltx", "ping", "WHISPER", UnitName('player'));
Example(C++):
std::vector<std::string> Split(const std::string& s, char delimiter) { std::vector<std::string> tokens; std::string token; std::istringstream tokenStream(s); while (std::getline(tokenStream, token, delimiter)) { tokens.push_back(token); } return tokens; } void PlayerScript::OnBeforeSendChatMessage(Player* player, uint32& type, uint32& lang, std::string& msg) { if (!player) { return; } if (type != CHAT_MSG_WHISPER) { return; } if (lang != LANG_ADDON) { return; } auto data = Split(msg, '\t'); auto prefix = data[0]; auto event = data[1]; if (prefix != "wltx") { return; } LOG_INFO("module", "Received addon event: '{}'", event); std::string myPayload = "print('Pong!');"; WorldPacket payloadPacket = CreateAddonPacket("wlrx", myPayload, CHAT_MSG_WHISPER, player); player->SendDirectMessage(&payloadPacket); } //Output: Received addon event: 'ping'.
You now have the basic tools to create a listener and send payloads to the client.