LabyMod /
labymod-server-api
| 1 | package net.labymod.serverapi.bukkit.utils; |
||
| 2 | |||
| 3 | import io.netty.buffer.ByteBuf; |
||
| 4 | import io.netty.buffer.Unpooled; |
||
| 5 | import lombok.Getter; |
||
| 6 | import net.labymod.serverapi.bukkit.LabyModPlugin; |
||
| 7 | import org.bukkit.Bukkit; |
||
| 8 | import org.bukkit.entity.Player; |
||
| 9 | |||
| 10 | import java.lang.reflect.Constructor; |
||
| 11 | import java.lang.reflect.Field; |
||
| 12 | import java.lang.reflect.InvocationTargetException; |
||
| 13 | import java.lang.reflect.Method; |
||
| 14 | |||
| 15 | /** |
||
| 16 | * Class created by qlow | Jan |
||
| 17 | */ |
||
| 18 | public class PacketUtils { |
||
| 19 | |||
| 20 | private String version; |
||
| 21 | |||
| 22 | private Class<?> packetClass; |
||
| 23 | |||
| 24 | private Class<?> packetPlayOutCustomPayloadClass; |
||
| 25 | private Constructor<?> customPayloadConstructor; |
||
| 26 | private boolean customPayloadHasBytes; |
||
| 27 | |||
| 28 | private Class<?> packetDataSerializerClass; |
||
| 29 | private Constructor<?> packetDataSerializerConstructor; |
||
| 30 | |||
| 31 | private Method getHandleMethod; |
||
| 32 | private Field playerConnectionField; |
||
| 33 | @Getter |
||
| 34 | private Field networkManagerField; |
||
| 35 | |||
| 36 | public PacketUtils() { |
||
| 37 | this.version = Bukkit.getServer().getClass().getPackage().getName().replace( ".", "," ).split( "," )[3]; |
||
| 38 | |||
| 39 | try { |
||
| 40 | this.packetClass = getNmsClass( "Packet" ); |
||
| 41 | this.packetPlayOutCustomPayloadClass = getNmsClass( "PacketPlayOutCustomPayload" ); |
||
| 42 | this.networkManagerField = getNmsClass( "PlayerConnection" ).getDeclaredField( "networkManager" ); |
||
| 43 | } catch ( ClassNotFoundException | NoSuchFieldException e ) { |
||
| 44 | e.printStackTrace(); |
||
|
0 ignored issues
–
show
Best Practice
introduced
by
Loading history...
|
|||
| 45 | } |
||
| 46 | |||
| 47 | if ( this.packetPlayOutCustomPayloadClass != null ) { |
||
| 48 | for ( Constructor<?> constructors : packetPlayOutCustomPayloadClass.getDeclaredConstructors() ) { |
||
| 49 | if ( constructors.getParameterTypes().length == 2 && constructors.getParameterTypes()[1] == byte[].class ) { |
||
| 50 | customPayloadHasBytes = true; |
||
| 51 | customPayloadConstructor = constructors; |
||
| 52 | } else if ( constructors.getParameterTypes().length == 2 && constructors.getParameterTypes()[1].getSimpleName().equals( "PacketDataSerializer" ) ) { |
||
|
0 ignored issues
–
show
Comparing classes by name is not safe, since class names must only be unique within a package. Consider using the
instanceOf() operator instead.
Loading history...
|
|||
| 53 | customPayloadConstructor = constructors; |
||
| 54 | } |
||
| 55 | } |
||
| 56 | |||
| 57 | if ( !customPayloadHasBytes ) { |
||
| 58 | try { |
||
| 59 | packetDataSerializerClass = getNmsClass( "PacketDataSerializer" ); |
||
| 60 | packetDataSerializerConstructor = packetDataSerializerClass.getDeclaredConstructor( ByteBuf.class ); |
||
| 61 | } catch ( Exception ex ) { |
||
| 62 | ex.printStackTrace(); |
||
|
0 ignored issues
–
show
|
|||
| 63 | LabyModPlugin.getInstance().getLogger().severe( "Couldn't find a valid constructor for PacketPlayOutCustomPayload. Disabling the plugin." ); |
||
| 64 | Bukkit.getPluginManager().disablePlugin( LabyModPlugin.getInstance() ); |
||
| 65 | } |
||
| 66 | } |
||
| 67 | } |
||
| 68 | } |
||
| 69 | |||
| 70 | /** |
||
| 71 | * Gets the player's nms-handle |
||
| 72 | * |
||
| 73 | * @param player the bukkit-player |
||
| 74 | * @return the nms-handle |
||
| 75 | */ |
||
| 76 | public Object getPlayerHandle( Player player ) { |
||
| 77 | try { |
||
| 78 | if ( getHandleMethod == null ) |
||
| 79 | getHandleMethod = player.getClass().getMethod( "getHandle" ); |
||
| 80 | |||
| 81 | // Getting the player's nms-handle |
||
| 82 | return getHandleMethod.invoke( player ); |
||
| 83 | } catch ( Exception ex ) { |
||
| 84 | ex.printStackTrace(); |
||
|
0 ignored issues
–
show
|
|||
| 85 | } |
||
| 86 | |||
| 87 | return null; |
||
| 88 | } |
||
| 89 | |||
| 90 | /** |
||
| 91 | * Gets the player's connection |
||
| 92 | * |
||
| 93 | * @param nmsPlayer the player's nms-handle |
||
| 94 | * @return the player-connection |
||
| 95 | */ |
||
| 96 | public Object getPlayerConnection( Object nmsPlayer ) { |
||
| 97 | try { |
||
| 98 | if ( playerConnectionField == null ) |
||
| 99 | playerConnectionField = nmsPlayer.getClass().getField( "playerConnection" ); |
||
| 100 | |||
| 101 | // Getting the player's connection |
||
| 102 | return playerConnectionField.get( nmsPlayer ); |
||
| 103 | } catch ( IllegalAccessException | NoSuchFieldException e ) { |
||
| 104 | e.printStackTrace(); |
||
|
0 ignored issues
–
show
|
|||
| 105 | } |
||
| 106 | |||
| 107 | return null; |
||
| 108 | } |
||
| 109 | |||
| 110 | /** |
||
| 111 | * Sends a packet to the given player |
||
| 112 | * |
||
| 113 | * @param player the player the packet should be sent to |
||
| 114 | * @param packet the packet that should be sent to the player |
||
| 115 | */ |
||
| 116 | public void sendPacket( Player player, Object packet ) { |
||
| 117 | try { |
||
| 118 | // Getting the player's nms-handle |
||
| 119 | Object nmsPlayer = getPlayerHandle( player ); |
||
| 120 | |||
| 121 | // Getting the player's connection |
||
| 122 | Object playerConnection = getPlayerConnection( nmsPlayer ); |
||
| 123 | |||
| 124 | // Sending the packet |
||
| 125 | playerConnection.getClass().getMethod( "sendPacket", packetClass ).invoke( playerConnection, packet ); |
||
| 126 | } catch ( Exception ex ) { |
||
| 127 | ex.printStackTrace(); |
||
|
0 ignored issues
–
show
|
|||
| 128 | } |
||
| 129 | } |
||
| 130 | |||
| 131 | /** |
||
| 132 | * Gets a constructed plugin message packet |
||
| 133 | * |
||
| 134 | * @param channel the channel-name |
||
| 135 | * @param bytes the bytes that should be sent with the packet |
||
| 136 | * @return a plugin-message packet |
||
| 137 | */ |
||
| 138 | public Object getPluginMessagePacket( String channel, byte[] bytes ) { |
||
| 139 | try { |
||
| 140 | return customPayloadConstructor.newInstance( channel, customPayloadHasBytes ? bytes : packetDataSerializerConstructor.newInstance( Unpooled.wrappedBuffer( bytes ) ) ); |
||
| 141 | } catch ( NullPointerException | InstantiationException | IllegalAccessException | InvocationTargetException e ) { |
||
| 142 | LabyModPlugin.getInstance().getLogger().severe( "Couldn't construct a custom-payload packet (Channel: " + channel + "):" ); |
||
| 143 | e.printStackTrace(); |
||
|
0 ignored issues
–
show
|
|||
| 144 | } |
||
| 145 | |||
| 146 | return null; |
||
| 147 | } |
||
| 148 | |||
| 149 | /** |
||
| 150 | * Gets a nms-class |
||
| 151 | * |
||
| 152 | * @param nmsClassName the nms-class name |
||
| 153 | * @return the multi-version compatible name of the class including the package |
||
| 154 | * @throws ClassNotFoundException if the class wasn't found |
||
| 155 | */ |
||
| 156 | public Class<?> getNmsClass( String nmsClassName ) throws ClassNotFoundException { |
||
| 157 | return Class.forName( "net.minecraft.server." + version + "." + nmsClassName ); |
||
| 158 | } |
||
| 159 | } |
||
| 160 |