WardenPayloadMgr 负责维护模块使用的自定义负载(payload)。 这允许用户向游戏客户端发送最大 512 字节的自定义 lua 负载。
你可以用它实现的一些事情有:
为无补丁(patch-less)的自定义服务器开启了许多可能性。
要访问负载管理器,你必须能够获得一个 Player 引用。
示例(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);
}
通常你会将 payloadId 存储在某处,而不是每次登录都生成一个新的。
可用的负载 ID 数量有限,因此建议创建一个负载监听器,在登录时发送给客户端。
示例(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);
现在要向客户端发送负载,你需要向玩家发送一条前缀为 wlrx、消息类型为 WHISPER、发送者/接收者为玩家 GUID 的插件消息。
示例(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);
插件消息大约有 255 个字符的限制,所以你可能需要将消息分块成多个数据包。
你可以通过在客户端将负载的一部分写入缓冲区,然后在最后一个负载调用时对该缓冲区执行 loadstring 来实现这一点。
如果你需要与服务器通信,可以使用 SendAddonMessage,并使用其中一个消息钩子捕获结果:
示例(Lua):
SendAddonMessage("wltx", "ping", "WHISPER", UnitName('player'));
示例(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'.
你现在已经拥有了创建监听器并向客户端发送负载的基本工具。