55
66import java .lang .reflect .Constructor ;
77import java .lang .reflect .Field ;
8- import java .lang .reflect .InvocationTargetException ;
98import java .lang .reflect .Method ;
9+ import java .lang .reflect .Proxy ;
1010import java .util .Arrays ;
11+ import java .util .logging .Level ;
1112
1213public class BukkitPluginMessageSender extends AbstractBukkitPluginMessageSender {
1314
@@ -21,10 +22,14 @@ public class BukkitPluginMessageSender extends AbstractBukkitPluginMessageSender
2122
2223 private Constructor <?> packetPlayOutCustomPayloadConstructor ;
2324 private Constructor <?> packetPlayOutMinecraftKeyConstructor ;
25+ private Class <?> minecraftKeyClass ;
26+ private Class <?> customPacketPayloadClass ;
2427 private boolean useMinecraftKey ;
28+ private boolean usePacketPayload ;
2529
2630 // Bukkit 1.8+ support
2731 private Class <?> packetDataSerializerClass ;
32+ private Method packetDataSerializerWriteBytesMethod ;
2833 private Constructor <?> packetDataSerializerConstructor ;
2934
3035 private Method wrappedBufferMethod ;
@@ -67,7 +72,11 @@ public BukkitPluginMessageSender(AbstractBukkitBadlionPlugin apiBukkit) {
6772
6873 Class <?> packetPlayOutCustomPayloadClass = this .getClass ("net.minecraft.network.protocol.game.PacketPlayOutCustomPayload" );
6974 if (packetPlayOutCustomPayloadClass == null ) {
70- throw new RuntimeException ("Failed to find PacketPlayOutCustomPayload class" );
75+ packetPlayOutCustomPayloadClass = this .getClass ("net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket" );
76+
77+ if (packetPlayOutCustomPayloadClass == null ) {
78+ throw new RuntimeException ("Failed to find PacketPlayOutCustomPayload class" );
79+ }
7180 }
7281
7382 this .packetPlayOutCustomPayloadConstructor = this .getConstructor (packetPlayOutCustomPayloadClass , String .class , byte [].class );
@@ -102,16 +111,27 @@ public BukkitPluginMessageSender(AbstractBukkitBadlionPlugin apiBukkit) {
102111 // If we made it this far in theory we are on at least 1.8
103112 this .packetPlayOutCustomPayloadConstructor = this .getConstructor (packetPlayOutCustomPayloadClass , String .class , this .packetDataSerializerClass );
104113 if (this .packetPlayOutCustomPayloadConstructor == null ) {
105- Class <?> minecraftKeyClass = this .getClass ("net.minecraft.resources.MinecraftKey" );
114+ this . minecraftKeyClass = this .getClass ("net.minecraft.resources.MinecraftKey" );
106115
107116 // Fix for Paper in newer versions
108- this .packetPlayOutCustomPayloadConstructor = this .getConstructor (packetPlayOutCustomPayloadClass , minecraftKeyClass , this .packetDataSerializerClass );
117+ this .packetPlayOutCustomPayloadConstructor = this .getConstructor (packetPlayOutCustomPayloadClass , this . minecraftKeyClass , this .packetDataSerializerClass );
109118
110119 if (this .packetPlayOutCustomPayloadConstructor == null ) {
111- throw new RuntimeException ("Failed to find PacketPlayOutCustomPayload constructor 2x" );
120+ this .customPacketPayloadClass = this .getClass ("net.minecraft.network.protocol.common.custom.CustomPacketPayload" );
121+
122+ if (this .customPacketPayloadClass != null ) {
123+ this .packetPlayOutCustomPayloadConstructor = this .getConstructor (packetPlayOutCustomPayloadClass , this .customPacketPayloadClass );
124+ this .packetDataSerializerWriteBytesMethod = this .getMethod (this .packetDataSerializerClass , "c" , byte [].class );
125+ this .packetPlayOutMinecraftKeyConstructor = this .getConstructor (this .minecraftKeyClass , String .class );
126+ this .usePacketPayload = true ;
127+ }
128+
129+ if (this .packetPlayOutCustomPayloadConstructor == null ) {
130+ throw new RuntimeException ("Failed to find PacketPlayOutCustomPayload constructor 2x" );
131+ }
112132 } else {
113133 this .useMinecraftKey = true ;
114- this .packetPlayOutMinecraftKeyConstructor = this .getConstructor (minecraftKeyClass , String .class );
134+ this .packetPlayOutMinecraftKeyConstructor = this .getConstructor (this . minecraftKeyClass , String .class );
115135 }
116136 }
117137 }
@@ -134,9 +154,18 @@ public BukkitPluginMessageSender(AbstractBukkitBadlionPlugin apiBukkit) {
134154 if (!this .versionSuffix .contains ("v1_17" )) {
135155 final Class <?> packet1_18Class = this .getClass ("net.minecraft.network.protocol.Packet" );
136156
137- this .sendPacketMethod = this .getMethod (playerConnectionClass , "a" , packet1_18Class );
138- if (this .sendPacketMethod == null ) {
139- throw new RuntimeException ("Failed to find PlayerConnection.a(Packet)" );
157+ if (this .usePacketPayload ) {
158+ this .sendPacketMethod = this .getMethod (playerConnectionClass .getSuperclass (), "b" , packet1_18Class );
159+
160+ if (this .sendPacketMethod == null ) {
161+ throw new RuntimeException ("Failed to find PlayerConnection.b(Packet)" );
162+ }
163+ } else {
164+ this .sendPacketMethod = this .getMethod (playerConnectionClass , "a" , packet1_18Class );
165+
166+ if (this .sendPacketMethod == null ) {
167+ throw new RuntimeException ("Failed to find PlayerConnection.a(Packet)" );
168+ }
140169 }
141170
142171 } else {
@@ -151,16 +180,32 @@ public BukkitPluginMessageSender(AbstractBukkitBadlionPlugin apiBukkit) {
151180 public void sendPluginMessagePacket (Player player , String channel , Object data ) {
152181 try {
153182 Object packet ;
183+
154184 // Newer MC version, setup ByteBuf object
155185 if (this .packetDataSerializerClass != null ) {
156- Object byteBuf = this .wrappedBufferMethod .invoke (null , data );
157- Object packetDataSerializer = this .packetDataSerializerConstructor .newInstance (byteBuf );
158-
159- if (this .useMinecraftKey ) {
160- Object key = this .packetPlayOutMinecraftKeyConstructor .newInstance (channel );
161- packet = this .packetPlayOutCustomPayloadConstructor .newInstance (key , packetDataSerializer );
186+ if (this .usePacketPayload ) {
187+ Object payload = Proxy .newProxyInstance (this .getClass ().getClassLoader (), new Class []{this .customPacketPayloadClass }, (proxy , method , args ) -> {
188+ if (method .getReturnType ().equals (BukkitPluginMessageSender .this .minecraftKeyClass )) {
189+ return this .packetPlayOutMinecraftKeyConstructor .newInstance (channel );
190+ } else if (args .length == 1 && this .packetDataSerializerClass .isAssignableFrom (args [0 ].getClass ())) {
191+ this .packetDataSerializerWriteBytesMethod .invoke (args [0 ], data );
192+ return null ;
193+ }
194+
195+ return null ;
196+ });
197+
198+ packet = this .packetPlayOutCustomPayloadConstructor .newInstance (payload );
162199 } else {
163- packet = this .packetPlayOutCustomPayloadConstructor .newInstance (channel , packetDataSerializer );
200+ Object byteBuf = this .wrappedBufferMethod .invoke (null , data );
201+ Object packetDataSerializer = this .packetDataSerializerConstructor .newInstance (byteBuf );
202+
203+ if (this .useMinecraftKey ) {
204+ Object key = this .packetPlayOutMinecraftKeyConstructor .newInstance (channel );
205+ packet = this .packetPlayOutCustomPayloadConstructor .newInstance (key , packetDataSerializer );
206+ } else {
207+ packet = this .packetPlayOutCustomPayloadConstructor .newInstance (channel , packetDataSerializer );
208+ }
164209 }
165210 } else {
166211 // Work our magic to make the packet
@@ -172,9 +217,8 @@ public void sendPluginMessagePacket(Player player, String channel, Object data)
172217 Object playerConnection = this .playerConnectionField .get (nmsPlayer );
173218 this .sendPacketMethod .invoke (playerConnection , packet );
174219
175- } catch (IllegalAccessException | InvocationTargetException | InstantiationException e ) {
176- this .apiBukkit .getLogger ().severe ("Failed to send BLC mod packet" );
177- e .printStackTrace ();
220+ } catch (Throwable throwable ) {
221+ this .apiBukkit .getLogger ().log (Level .SEVERE , "Failed to send BLC mod packet" , throwable );
178222 }
179223 }
180224
0 commit comments