summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/documentation-index.md1
-rw-r--r--docs/how-to-use-warden-payload-mgr.md150
2 files changed, 151 insertions, 0 deletions
diff --git a/docs/documentation-index.md b/docs/documentation-index.md
index 4d2055e..d23e998 100644
--- a/docs/documentation-index.md
+++ b/docs/documentation-index.md
@@ -33,6 +33,7 @@ redirect_from: /documentation_index
* [Doxygen Documentation](https://www.azerothcore.org/pages/doxygen/index.html)
* [Exit Codes](exitcodes.md)
* [How to Debug and Restart](how-to-restart-and-debug.md)
+* [How to Use Warden Payload Manager](how-to-use-warden-payload-mgr.md)
* [IP2LOCATION](ip2location.md)
* [Logging Configuration](logging-configuration.md)
* [Monitoring AzerothCore with Grafana](monitoring-azerothcore-with-grafana.md)
diff --git a/docs/how-to-use-warden-payload-mgr.md b/docs/how-to-use-warden-payload-mgr.md
new file mode 100644
index 0000000..99470ac
--- /dev/null
+++ b/docs/how-to-use-warden-payload-mgr.md
@@ -0,0 +1,150 @@
+# How to use the Warden Payload Manager
+
+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:
+- Interaction with the client interface (add custom frames)
+- Access to client CVars
+- Access to protected lua functions.
+
+Opening up many possiblilties for a patch-less custom server.
+
+## Accessing the Payload Manager
+
+To access the payload manager you have to have access to a Player reference.
+
+**Example(C++):**
+```cpp
+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.
+
+## Writing a Payload Addon Listener
+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):**
+```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++):**
+```cpp
+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](https://wowwiki-archive.fandom.com/wiki/API_SendAddonMessage) and capture the result using one of the message hooks:
+
+**Example(Lua):**
+```lua
+SendAddonMessage("wltx", "ping", "WHISPER", UnitName('player'));
+```
+
+**Example(C++):**
+```cpp
+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. \ No newline at end of file