12
12
import com .comphenix .protocol .utility .MinecraftReflection ;
13
13
import com .comphenix .protocol .utility .StreamSerializer ;
14
14
import io .netty .buffer .ByteBuf ;
15
+ import io .netty .buffer .Unpooled ;
16
+
15
17
import java .lang .reflect .Constructor ;
16
18
import java .lang .reflect .Method ;
17
19
import java .lang .reflect .Modifier ;
18
20
import java .util .Objects ;
21
+
19
22
import net .bytebuddy .ByteBuddy ;
20
23
import net .bytebuddy .dynamic .loading .ClassLoadingStrategy ;
21
24
import net .bytebuddy .implementation .FieldAccessor ;
@@ -40,26 +43,32 @@ public final class CustomPacketPayloadWrapper {
40
43
private static final Class <?> MINECRAFT_KEY_CLASS ;
41
44
private static final Class <?> CUSTOM_PACKET_PAYLOAD_CLASS ;
42
45
43
- private static final MethodAccessor WRITE_BYTES_METHOD ;
44
46
private static final ConstructorAccessor PAYLOAD_WRAPPER_CONSTRUCTOR ;
45
47
48
+ private static final MethodAccessor GET_ID_PAYLOAD_METHOD ;
49
+ private static final MethodAccessor SERIALIZE_PAYLOAD_METHOD ;
50
+
46
51
private static final EquivalentConverter <CustomPacketPayloadWrapper > CONVERTER ;
47
52
48
53
static {
49
54
try {
50
- // using this method is a small hack to prevent fuzzy from finding the renamed "getBytes(byte[])" method
51
- // the method we're extracting here is: writeBytes(byte[] data, int arrayStartInclusive, int arrayEndExclusive)
52
- Class <?> packetDataSerializer = MinecraftReflection . getPacketDataSerializerClass ();
53
- Method writeBytes = FuzzyReflection .fromClass (packetDataSerializer , false ).getMethod (FuzzyMethodContract .newBuilder ()
55
+ MINECRAFT_KEY_CLASS = MinecraftReflection . getMinecraftKeyClass ();
56
+ CUSTOM_PACKET_PAYLOAD_CLASS = MinecraftReflection . getMinecraftClass ( "network.protocol.common.custom.CustomPacketPayload" );
57
+
58
+ Method getPayloadId = FuzzyReflection .fromClass (CUSTOM_PACKET_PAYLOAD_CLASS ).getMethod (FuzzyMethodContract .newBuilder ()
54
59
.banModifier (Modifier .STATIC )
55
- .requireModifier (Modifier .PUBLIC )
56
- .parameterExactArray (byte [].class , int .class , int .class )
57
- .returnTypeExact (packetDataSerializer )
60
+ .returnTypeExact (MINECRAFT_KEY_CLASS )
61
+ .parameterCount (0 )
58
62
.build ());
59
- WRITE_BYTES_METHOD = Accessors .getMethodAccessor (writeBytes );
63
+ GET_ID_PAYLOAD_METHOD = Accessors .getMethodAccessor (getPayloadId );
60
64
61
- MINECRAFT_KEY_CLASS = MinecraftReflection .getMinecraftKeyClass ();
62
- CUSTOM_PACKET_PAYLOAD_CLASS = MinecraftReflection .getMinecraftClass ("network.protocol.common.custom.CustomPacketPayload" );
65
+ Method serializePayloadData = FuzzyReflection .fromClass (CUSTOM_PACKET_PAYLOAD_CLASS ).getMethod (FuzzyMethodContract .newBuilder ()
66
+ .banModifier (Modifier .STATIC )
67
+ .returnTypeVoid ()
68
+ .parameterCount (1 )
69
+ .parameterDerivedOf (ByteBuf .class , 0 )
70
+ .build ());
71
+ SERIALIZE_PAYLOAD_METHOD = Accessors .getMethodAccessor (serializePayloadData );
63
72
64
73
Constructor <?> payloadWrapperConstructor = makePayloadWrapper ();
65
74
PAYLOAD_WRAPPER_CONSTRUCTOR = Accessors .getConstructorAccessor (payloadWrapperConstructor );
@@ -153,23 +162,36 @@ public static EquivalentConverter<CustomPacketPayloadWrapper> getConverter() {
153
162
}
154
163
155
164
/**
156
- * Constructs this wrapper from an incoming ServerboundCustomPayloadPacket.UnknownPayload. All other types of
157
- * payloads are not supported and will result in an exception.
165
+ * Constructs this wrapper from any CustomPayload type.
158
166
* <p>
159
- * Note: the buffer of the given UnknownPayload will <strong>NOT</strong> be released by this operation. Make sure
167
+ * Note: the buffer of the given payload (if any) will <strong>NOT</strong> be released by this operation. Make sure
160
168
* to release the buffer manually if you discard the packet to prevent memory leaks.
161
169
*
162
- * @param unknownPayload the instance of the unknown payload to convert to this wrapper.
163
- * @return a wrapper holding the minecraft key and payload of the given UnknownPayload instance.
170
+ * @param payload the instance of the custom payload to convert to this wrapper.
171
+ * @return a wrapper holding the minecraft key and payload of the given custom payload instance.
164
172
*/
165
- public static CustomPacketPayloadWrapper fromUnknownPayload (Object unknownPayload ) {
166
- StructureModifier <Object > modifier = new StructureModifier <>(unknownPayload .getClass ()).withTarget (unknownPayload );
167
- Object messageId = modifier .withType (MINECRAFT_KEY_CLASS ).read (0 );
168
- ByteBuf messagePayload = (ByteBuf ) modifier .withType (ByteBuf .class ).read (0 );
169
-
173
+ public static CustomPacketPayloadWrapper fromUnknownPayload (Object payload ) {
174
+ Object messageId = GET_ID_PAYLOAD_METHOD .invoke (payload );
170
175
MinecraftKey id = MinecraftKey .getConverter ().getSpecific (messageId );
171
- byte [] payload = StreamSerializer .getDefault ().getBytesAndRelease (messagePayload .retain ());
172
- return new CustomPacketPayloadWrapper (payload , id );
176
+
177
+ // we read and retain the underlying buffer in case the class uses a buffer to store the data
178
+ // this way, when passing the packet to further handling, the buffer is not released and can be re-used
179
+ StructureModifier <Object > modifier = new StructureModifier <>(payload .getClass ()).withTarget (payload );
180
+ byte [] messagePayload = modifier .withType (ByteBuf .class ).optionRead (0 )
181
+ .map (buffer -> {
182
+ ByteBuf buf = (ByteBuf ) buffer ;
183
+ byte [] data = StreamSerializer .getDefault ().getBytesAndRelease (buf .markReaderIndex ().retain ());
184
+ buf .resetReaderIndex ();
185
+ return data ;
186
+ })
187
+ .orElseGet (() -> {
188
+ ByteBuf buffer = Unpooled .buffer ();
189
+ Object serializer = MinecraftReflection .getPacketDataSerializer (buffer );
190
+ SERIALIZE_PAYLOAD_METHOD .invoke (payload , serializer );
191
+ return StreamSerializer .getDefault ().getBytesAndRelease (buffer );
192
+ });
193
+
194
+ return new CustomPacketPayloadWrapper (messagePayload , id );
173
195
}
174
196
175
197
/**
@@ -217,7 +239,7 @@ public Object newHandle() {
217
239
@ SuppressWarnings ("unused" )
218
240
static final class CustomPacketPayloadInterceptionHandler {
219
241
public static void intercept (@ FieldValue ("payload" ) byte [] payload , @ Argument (0 ) Object packetBuffer ) {
220
- WRITE_BYTES_METHOD . invoke ( packetBuffer , payload , 0 , payload . length );
242
+ (( ByteBuf ) packetBuffer ). writeBytes ( payload );
221
243
}
222
244
}
223
245
}
0 commit comments