Skip to content

Commit

Permalink
Fix packets list in 21w08a
Browse files Browse the repository at this point in the history
  • Loading branch information
Pokechu22 committed Feb 17, 2022
1 parent 15fbe0c commit b8ba24a
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 5 deletions.
8 changes: 8 additions & 0 deletions burger/toppings/packetinstructions.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,15 @@ def operations(classloader, classname, classes, verbose, args=None,
methods = list(cf.methods.find(returns="V", args="L" + classes["packet.packetbuffer"] + ";"))

if len(methods) == 2:
# Assume the second method is the one that writes
method = methods[1]
elif len(methods) == 1:
# 21w08a+: A constructor or static method now handles reading.
# The constructor still returns void, so the above case is still
# usually hit, but the static method returns the packet. When
# the static method exists, there only is one matching method,
# so just assume that that method handles writing.
method = methods[0]
else:
if cf.super_.name.value != "java/lang/Object":
return _PIT.operations(classloader, cf.super_.name.value + ".class", classes, verbose)
Expand Down
28 changes: 23 additions & 5 deletions burger/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@ def class_from_invokedynamic(ins, cf):
"""
Gets the class type for an invokedynamic instruction that
calls a constructor.
This function is used for the packet list. Prior to 21w08a, packets
had a no-arg constructor, and were registered as a Supplier<Packet>.
In 21w08a, the packet fields were made final, and the no-arg constructor
was replaced with a constructor taking the PacketBuffer and registered as
a Function<PacketBuffer, Packet> instead. However, some packets (such as
the movement-related ones) have a class hierarchy and don't use the
constructor approach, and instead have a static method taking the
PacketBuffer and creating the packet instead. Thus, for invokedynamic uses
that construct an object (REF_newInvokeSpecial), this function returns the
type of object that is constructed, while invokedynamic uses that invoke a
static method (REF_invokeStatic) have this function return the invoked
function's return type.
"""
const = ins.operands[0]
bootstrap = cf.bootstrap_methods[const.method_attr_index]
Expand All @@ -21,11 +34,16 @@ def class_from_invokedynamic(ins, cf):
# Now check the arguments. Note that LambdaMetafactory has some
# arguments automatically filled in.
methodhandle = cf.constants.get(bootstrap.bootstrap_args[1])
assert methodhandle.reference_kind == 8 # REF_newInvokeSpecial
assert methodhandle.reference.name_and_type.name == "<init>"
# OK, now that we've done all those checks, just get the type
# from the constructor.
return methodhandle.reference.class_.name.value
assert methodhandle.reference_kind in (6, 8)
if methodhandle.reference_kind == 8: # REF_newInvokeSpecial
assert methodhandle.reference.name_and_type.name == "<init>"
# OK, now that we've done all those checks, just get the type
# from the constructor.
return methodhandle.reference.class_.name.value
elif methodhandle.reference_kind == 6: # REF_invokeStatic
desc = method_descriptor(methodhandle.reference.name_and_type.descriptor.value)
assert desc.returns.name != "void"
return desc.returns.name

def stringify_invokedynamic(obj, ins, cf):
"""
Expand Down

0 comments on commit b8ba24a

Please sign in to comment.