From b8ba24a60b4318e3bb2a21458325e0f33d37678b Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Wed, 24 Feb 2021 11:33:49 -0800 Subject: [PATCH] Fix packets list in 21w08a --- burger/toppings/packetinstructions.py | 8 ++++++++ burger/util.py | 28 ++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/burger/toppings/packetinstructions.py b/burger/toppings/packetinstructions.py index 2018a200..f3fedd76 100644 --- a/burger/toppings/packetinstructions.py +++ b/burger/toppings/packetinstructions.py @@ -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) diff --git a/burger/util.py b/burger/util.py index 7cc84f16..8920a2de 100644 --- a/burger/util.py +++ b/burger/util.py @@ -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. + 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 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] @@ -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 == "" - # 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 == "" + # 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): """