The packets library will be a little easier to understand if you clear up a few other details about the packet events.
The game client and server communicate at discrete intervals. Since the flow of information isn't continuous, they
each cram as much information as possible into each communication. What they actually send back and forth are giant
strings of binary data (packets), which they then break up into the smaller "chunks" of information (hp updates,
information about mobs, etc.). Confusingly, everyone has taken to calling the chunks (hence 'incoming chunk'/
'outgoing chunk') packets, but the important bit is that packets (or more properly, chunks) are just strings.
When you call windower.register_event, you pass it a string and a function. The string tells Luacore during which event to
call the function. When the event occurs, Luacore calls the function and passes it the arguments listed on the dev wiki
and, depending on the event, might use any return value to alter what occurs in the game-client process after the event.
More specific to your code:
windower.register_event('outgoing chunk',function(id,data, modified, injected, blocked)
You've told Luacore to call an anonymous function when the client attempts to add a chunk to the next not-yet-fully-
formed outgoing packet. You've defined five parameters in the function, and Luacore will pass the following
arguments to each:
id -- Luacore will pass a number to this parameter which identifies the type of information in the chunk.
Luacore pulls this out of the first four bytes of data in the chunk (I think? I don't really remember),
and someone has gone to great lengths to detail what type of information the number corresponds to in
the fields.lua file.
data -- Luacore will pass the chunk to this parameter. Some people label this parameter 'original' to distinguish
it from the next parameter.
modified -- The incoming/outgoing chunk events both use return values from your functions to modify the string that
will eventually be tacked onto the forming packet. It's important to remember that your anonymous function
probably isn't the only function that Luacore is calling when the event occurs: other addons might ask
Luacore to handle the event as well. Luacore calls the functions in the order that it receives them, so if
another addon with an incoming/outgoing event was loaded first, that addon's function will run first and
may modify the chunk. Luacore will pass that modified version of the chunk to this parameter. If no other
addons have modified the chunk, this version will be the same as the argument sent to the previous parameter.
injected -- Luacore will pass a boolean to this parameter which indicates if the chunk was created and injected by an
addon rather than by the client.
blocked -- Luacore will pass a boolean to this parameter which indicates if another addon has requested that the chunk
not be added to the packet. Your addon can request this by registering a function which returns the boolean
value true. If the chunk is not added to the packet, the server will not receive any of the information
contained in the chunk.
What's important to keep in mind here is that the function you pass to windower.register_event is just a function.
It operates like any other function you'd write, and the only thing you really have to be sure to do is to declare a parameter
for each argument you expect Luacore to pass for the event.
if id == 0x05b then
You've identified which type of chunk should be analyzed. Primo!
local p = packets.parse('outgoing', data)
You've called the packets library function 'parse' and passed the direction of the chunk and the original, unmodified chunk.
The parse function takes the chunk-a string
, which is not very human-readable, and uses the bit and pack libraries along with the
description of the chunk in fields.lua to form a table
with keys and values that are readable representations of the data
contained in the chunk.
if p["Option Index"] == 0 and p["_unknown1"] == 16384 then
p["Option Index"] = 2
p["_unknown1"] = 38
p["Automated Message"] = true
modified = p._raw
You've changed the values of a few keys in the table created by the parse function. That's fine, and if you want to modify the chunk,
that's the first step. (Side note: if you know what the _unknown1 field's data is, you should update fields.lua with a description and
a name that indicates its use, and submit a pull request on Github.) Next, you've done something strange: you've set modified, a parameter
of your function which Luacore passed the modified version of the chunk to, equal to p._raw, which is a copy of the original chunk passed
to the parse function. There's nothing syntactically incorrect about reassigning the value of a parameter, but parameters are essentially
local variables; Luacore can't see them, or anything else that happens inside of the function. It just throws some arguments at a function
you defined and hopes for the best.
In order to communicate back to Luacore via the outgoing chunk event, you need to return a value from the function. Earlier, I said that
returning true would tell Luacore not to add the chunk to the packet. Returning a string instead will tell Luacore that you want it to
add that string to the packet instead of the original chunk.
There remains one hurdle: you don't have a string to return. The parse function left you with a table. It contains all of the information
needed to form the string, but it's not concatenated and it's not in the correct order. Luckily the build function in the packets library
handles recreating the string, so you're closer than you think.
That should do it.
Things you might consider:
You're modifying the original chunk, rather than the modified version. If an addon had previously modified the chunk, you've scrapped
its changes. That's probably not a problem in this case, but in general it could cause a problem.
The packets library is generally "safer" in that it's easier to use. It's also more readable! It's nice for anyone who's reading over your
addon, because they don't have to pull out their copy of fields.lua and lookup the packing strings just to figure out what you're doing.
The only downside is that it does parse the entire chunk by default, which might seem wasteful if you're only after one value. Generally,
that's no big deal (computers are fast) and you can tell it not to parse values by passing a table to packets.parse as well. The only time
you shouldn't use it is when you want to analyze the action packet, which is big and weird. You can use the actions library for that.