11package net .badlion .bukkitapi ;
22
3- import org .bukkit .Bukkit ;
43import org .bukkit .entity .Player ;
54
65import java .lang .reflect .Constructor ;
@@ -19,13 +18,16 @@ public class BukkitPluginMessageSender extends AbstractBukkitPluginMessageSender
1918 private final Method sendPacketMethod ;
2019
2120 private String versionSuffix ;
21+ private String versionName ;
2222
2323 private Constructor <?> packetPlayOutCustomPayloadConstructor ;
2424 private Constructor <?> packetPlayOutMinecraftKeyConstructor ;
25+ private Constructor <?> discardedPayloadConstructor ;
2526 private Class <?> minecraftKeyClass ;
2627 private Class <?> customPacketPayloadClass ;
2728 private boolean useMinecraftKey ;
2829 private boolean usePacketPayload ;
30+ private boolean useDiscardedPayload ;
2931
3032 // Bukkit 1.8+ support
3133 private Class <?> packetDataSerializerClass ;
@@ -39,23 +41,29 @@ public BukkitPluginMessageSender(AbstractBukkitBadlionPlugin apiBukkit) {
3941 this .apiBukkit = apiBukkit ;
4042
4143 // Get the v1_X_Y from the end of the package name, e.g. v_1_7_R4 or v_1_12_R1
42- String packageName = Bukkit .getServer ().getClass ().getPackage ().getName ();
44+ String packageName = this . apiBukkit .getServer ().getClass ().getPackage ().getName ();
4345 String [] parts = packageName .split ("\\ ." );
4446
4547 if (parts .length > 0 ) {
4648 String suffix = parts [parts .length - 1 ];
4749 if (!suffix .startsWith ("v" )) {
48- throw new RuntimeException ("Failed to find version for running Minecraft server, got suffix " + suffix );
50+ // 1.20.5+ support
51+ if ("craftbukkit" .equals (suffix )) {
52+ suffix = "" ;
53+ } else {
54+ throw new RuntimeException ("Failed to find version for running Minecraft server, got suffix " + suffix );
55+ }
4956 }
5057
5158 this .versionSuffix = suffix ;
59+ this .versionName = this .apiBukkit .getServer ().getVersion ();
5260
53- this .apiBukkit .getLogger ().info ("Found version " + this .versionSuffix );
61+ this .apiBukkit .getLogger ().info ("Found version " + this .versionSuffix + " (" + this . versionName + ")" );
5462 }
5563
5664 // We need to use reflection because Bukkit by default handles plugin messages in a really silly way
5765 // Reflection stuff
58- Class <?> craftPlayerClass = this .getClass ("org.bukkit.craftbukkit." + this .versionSuffix + ".entity.CraftPlayer" );
66+ Class <?> craftPlayerClass = this .getClass (this . versionSuffix == null || this . versionSuffix . isEmpty () ? "org.bukkit.craftbukkit.entity.CraftPlayer" : "org.bukkit.craftbukkit." + this .versionSuffix + ".entity.CraftPlayer" );
5967 if (craftPlayerClass == null ) {
6068 throw new RuntimeException ("Failed to find CraftPlayer class" );
6169 }
@@ -124,6 +132,16 @@ public BukkitPluginMessageSender(AbstractBukkitBadlionPlugin apiBukkit) {
124132 this .packetDataSerializerWriteBytesMethod = this .getMethod (this .packetDataSerializerClass , "c" , byte [].class );
125133 this .packetPlayOutMinecraftKeyConstructor = this .getConstructor (this .minecraftKeyClass , String .class );
126134 this .usePacketPayload = true ;
135+
136+ Class <?> discardedPayloadClass = this .getClass ("net.minecraft.network.protocol.common.custom.DiscardedPayload" );
137+
138+ if (discardedPayloadClass != null ) {
139+ this .discardedPayloadConstructor = this .getConstructor (discardedPayloadClass , this .minecraftKeyClass , byteBufClass );
140+
141+ if (this .discardedPayloadConstructor != null ) {
142+ this .useDiscardedPayload = true ;
143+ }
144+ }
127145 }
128146
129147 if (this .packetPlayOutCustomPayloadConstructor == null ) {
@@ -141,35 +159,47 @@ public BukkitPluginMessageSender(AbstractBukkitBadlionPlugin apiBukkit) {
141159 throw new RuntimeException ("Failed to find CraftPlayer.getHandle()" );
142160 }
143161
162+ Field playerConnectionField ;
163+
144164 if (this .versionSuffix .contains ("v1_17" ) || this .versionSuffix .contains ("v1_18" ) || this .versionSuffix .contains ("v1_19" )) {
145- this . playerConnectionField = this .getField (nmsPlayerClass , "b" );
165+ playerConnectionField = this .getField (nmsPlayerClass , "b" );
146166 } else {
147- this .playerConnectionField = this .getField (nmsPlayerClass , "c" );
167+ playerConnectionField = this .getField (nmsPlayerClass , "c" );
168+ }
169+
170+ if (playerConnectionField == null ) {
171+ playerConnectionField = this .getField (nmsPlayerClass , "connection" );
148172 }
149173
150- if (this .playerConnectionField == null ) {
174+ if (playerConnectionField != null ) {
175+ this .playerConnectionField = playerConnectionField ;
176+ } else {
151177 throw new RuntimeException ("Failed to find EntityPlayer.playerConnection" );
152178 }
153179
154180 if (!this .versionSuffix .contains ("v1_17" )) {
155181 final Class <?> packet1_18Class = this .getClass ("net.minecraft.network.protocol.Packet" );
182+ Method sendPacketMethod ;
156183
157184 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- }
185+ sendPacketMethod = this .getMethod (playerConnectionClass .getSuperclass (), "b" , packet1_18Class );
163186 } else {
164- this .sendPacketMethod = this .getMethod (playerConnectionClass , "a" , packet1_18Class );
187+ sendPacketMethod = this .getMethod (playerConnectionClass , "a" , packet1_18Class );
188+ }
165189
166- if (this .sendPacketMethod == null ) {
167- throw new RuntimeException ("Failed to find PlayerConnection.a(Packet)" );
168- }
190+ if (sendPacketMethod == null ) {
191+ sendPacketMethod = this .getMethod (playerConnectionClass .getSuperclass (), "send" , packet1_18Class );
192+ }
193+
194+ if (sendPacketMethod != null ) {
195+ this .sendPacketMethod = sendPacketMethod ;
196+ } else {
197+ throw new RuntimeException ("Failed to find PlayerConnection.send(Packet)" );
169198 }
170199
171200 } else {
172201 this .sendPacketMethod = this .getMethod (playerConnectionClass , "sendPacket" );
202+
173203 if (this .sendPacketMethod == null ) {
174204 throw new RuntimeException ("Failed to find PlayerConnection.sendPacket()" );
175205 }
@@ -184,17 +214,28 @@ public void sendPluginMessagePacket(Player player, String channel, Object data)
184214 // Newer MC version, setup ByteBuf object
185215 if (this .packetDataSerializerClass != null ) {
186216 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- }
217+ Object payload ;
218+
219+ if (this .useDiscardedPayload ) {
220+ // 1.20.5+
221+ payload = this .discardedPayloadConstructor .newInstance (
222+ this .packetPlayOutMinecraftKeyConstructor .newInstance (channel ),
223+ this .wrappedBufferMethod .invoke (null , data )
224+ );
225+ } else {
226+ // 1.20.2 - 1.20.4
227+ payload = Proxy .newProxyInstance (this .getClass ().getClassLoader (), new Class []{this .customPacketPayloadClass }, (proxy , method , args ) -> {
228+ if (method .getReturnType ().equals (BukkitPluginMessageSender .this .minecraftKeyClass )) {
229+ return this .packetPlayOutMinecraftKeyConstructor .newInstance (channel );
230+ } else if (args .length == 1 && this .packetDataSerializerClass .isAssignableFrom (args [0 ].getClass ())) {
231+ this .packetDataSerializerWriteBytesMethod .invoke (args [0 ], data );
232+ return null ;
233+ }
194234
195- return null ;
196- });
235+ return null ;
236+ });
197237
238+ }
198239 packet = this .packetPlayOutCustomPayloadConstructor .newInstance (payload );
199240 } else {
200241 Object byteBuf = this .wrappedBufferMethod .invoke (null , data );
0 commit comments