Cleaned up some code (#10).
This commit is contained in:
parent
7101542328
commit
06cec6c0bf
|
@ -20,11 +20,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* Represents a very tiny alternative to ProtocolLib.
|
||||
* <p>
|
||||
* It now supports intercepting packets during login and status ping (such as OUT_SERVER_PING)!
|
||||
*
|
||||
* @author Kristian
|
||||
* Minimized version of TinyProtocol by Kristian suited for NPCLib.
|
||||
*/
|
||||
public abstract class LegacyTinyProtocol {
|
||||
private static final AtomicInteger ID = new AtomicInteger(0);
|
||||
|
@ -56,7 +52,7 @@ public abstract class LegacyTinyProtocol {
|
|||
private Listener listener;
|
||||
|
||||
// Channels that have already been removed
|
||||
private Set<Channel> uninjectedChannels = Collections.newSetFromMap(new MapMaker().weakKeys().<Channel, Boolean>makeMap());
|
||||
private Set<Channel> uninjectedChannels = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap());
|
||||
|
||||
// List of network markers
|
||||
private List<Object> networkManagers;
|
||||
|
@ -70,39 +66,32 @@ public abstract class LegacyTinyProtocol {
|
|||
// Current handler name
|
||||
private String handlerName;
|
||||
|
||||
protected volatile boolean closed;
|
||||
private volatile boolean closed;
|
||||
protected Plugin plugin;
|
||||
|
||||
/**
|
||||
* Construct a new instance of TinyProtocol, and start intercepting packets for all connected clients and future clients.
|
||||
* <p>
|
||||
* You can construct multiple instances per plugin.
|
||||
*
|
||||
* @param plugin - the plugin.
|
||||
*/
|
||||
public LegacyTinyProtocol(final Plugin plugin) {
|
||||
protected LegacyTinyProtocol(final Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
|
||||
// Compute handler name
|
||||
this.handlerName = getHandlerName();
|
||||
this.handlerName = "tiny-" + plugin.getName() + "-" + ID.incrementAndGet();
|
||||
|
||||
// Prepare existing players
|
||||
registerBukkitEvents();
|
||||
|
||||
try {
|
||||
System.out.println("Attempting to inject into netty");
|
||||
System.out.println("[NPCLib] Attempting to inject into netty.");
|
||||
registerChannelHandler();
|
||||
registerPlayers(plugin);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Damn you, late bind
|
||||
plugin.getLogger().info("Attempting to delay injection.");
|
||||
plugin.getLogger().info("[NPCLib] Attempting to delay injection.");
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
registerChannelHandler();
|
||||
registerPlayers(plugin);
|
||||
plugin.getLogger().info("Injection complete.");
|
||||
plugin.getLogger().info("[NPCLib] Injection complete.");
|
||||
}
|
||||
}.runTask(plugin);
|
||||
}
|
||||
|
@ -112,6 +101,7 @@ public abstract class LegacyTinyProtocol {
|
|||
// Handle connected channels
|
||||
endInitProtocol = new ChannelInitializer<Channel>() {
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@Override
|
||||
protected void initChannel(Channel channel) throws Exception {
|
||||
try {
|
||||
|
@ -123,7 +113,7 @@ public abstract class LegacyTinyProtocol {
|
|||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Cannot inject incomming channel " + channel, e);
|
||||
plugin.getLogger().log(Level.SEVERE, "[NPCLib] Cannot inject incomming channel " + channel, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,6 +122,7 @@ public abstract class LegacyTinyProtocol {
|
|||
// This is executed before Minecraft's channel handler
|
||||
beginInitProtocol = new ChannelInitializer<Channel>() {
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@Override
|
||||
protected void initChannel(Channel channel) throws Exception {
|
||||
channel.pipeline().addLast(endInitProtocol);
|
||||
|
@ -141,6 +132,7 @@ public abstract class LegacyTinyProtocol {
|
|||
|
||||
serverChannelHandler = new ChannelInboundHandlerAdapter() {
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
Channel channel = (Channel) msg;
|
||||
|
@ -152,12 +144,10 @@ public abstract class LegacyTinyProtocol {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Register bukkit events.
|
||||
*/
|
||||
private void registerBukkitEvents() {
|
||||
listener = new Listener() {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public final void onPlayerLogin(PlayerJoinEvent e) {
|
||||
if (closed)
|
||||
|
@ -171,6 +161,7 @@ public abstract class LegacyTinyProtocol {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@EventHandler
|
||||
public final void onPluginDisable(PluginDisableEvent e) {
|
||||
if (e.getPlugin().equals(plugin)) {
|
||||
|
@ -205,9 +196,9 @@ public abstract class LegacyTinyProtocol {
|
|||
Channel serverChannel = ((ChannelFuture) item).channel();
|
||||
|
||||
serverChannels.add(serverChannel);
|
||||
;
|
||||
|
||||
serverChannel.pipeline().addFirst(serverChannelHandler);
|
||||
System.out.println("Server channel handler injected (" + serverChannel + ")");
|
||||
System.out.println("[NPCLib] Server channel handler injected (" + serverChannel + ")");
|
||||
looking = false;
|
||||
}
|
||||
}
|
||||
|
@ -237,118 +228,14 @@ public abstract class LegacyTinyProtocol {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when the server is starting to send a packet to a player.
|
||||
* <p>
|
||||
* Note that this is not executed on the main thread.
|
||||
*
|
||||
* @param receiver - the receiving player, NULL for early login/status packets.
|
||||
* @param packet - the packet being sent.
|
||||
* @return The packet to send instead, or NULL to cancel the transmission.
|
||||
*/
|
||||
public Object onPacketOutAsync(Player receiver, Object packet) {
|
||||
return packet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when the server has received a packet from a given player.
|
||||
* <p>
|
||||
* Use {@link Channel#remoteAddress()} to get the remote address of the client.
|
||||
*
|
||||
* @param sender - the player that sent the packet, NULL for early login/status packets.
|
||||
* @param packet - the packet being received.
|
||||
* @return The packet to recieve instead, or NULL to cancel.
|
||||
*/
|
||||
public Object onPacketInAsync(Player sender, Object packet) {
|
||||
return packet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a packet to a particular player.
|
||||
* <p>
|
||||
* Note that {@link #onPacketOutAsync(Player, Object)} will be invoked with this packet.
|
||||
*
|
||||
* @param player - the destination player.
|
||||
* @param packet - the packet to send.
|
||||
*/
|
||||
public void sendPacket(Player player, Object packet) {
|
||||
sendPacket(getChannel(player), packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a packet to a particular client.
|
||||
* <p>
|
||||
* Note that {@link #onPacketOutAsync(Player, Object)} will be invoked with this packet.
|
||||
*
|
||||
* @param channel - client identified by a channel.
|
||||
* @param packet - the packet to send.
|
||||
*/
|
||||
public void sendPacket(Channel channel, Object packet) {
|
||||
channel.pipeline().writeAndFlush(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretend that a given packet has been received from a player.
|
||||
* <p>
|
||||
* Note that {@link #onPacketInAsync(Player, Object)} will be invoked with this packet.
|
||||
*
|
||||
* @param player - the player that sent the packet.
|
||||
* @param packet - the packet that will be received by the server.
|
||||
*/
|
||||
public void receivePacket(Player player, Object packet) {
|
||||
receivePacket(getChannel(player), packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretend that a given packet has been received from a given client.
|
||||
* <p>
|
||||
* Note that {@link #onPacketInAsync(Player, Object)} will be invoked with this packet.
|
||||
*
|
||||
* @param channel - client identified by a channel.
|
||||
* @param packet - the packet that will be received by the server.
|
||||
*/
|
||||
public void receivePacket(Channel channel, Object packet) {
|
||||
channel.pipeline().context("encoder").fireChannelRead(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the name of the channel injector, default implementation is "tiny-" + plugin name + "-" + a unique ID.
|
||||
* <p>
|
||||
* Note that this method will only be invoked once. It is no longer necessary to override this to support multiple instances.
|
||||
*
|
||||
* @return A unique channel handler name.
|
||||
*/
|
||||
protected String getHandlerName() {
|
||||
return "tiny-" + plugin.getName() + "-" + ID.incrementAndGet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom channel handler to the given player's channel pipeline, allowing us to intercept sent and received packets.
|
||||
* <p>
|
||||
* This will automatically be called when a player has logged in.
|
||||
*
|
||||
* @param player - the player to inject.
|
||||
*/
|
||||
public void injectPlayer(Player player) {
|
||||
private void injectPlayer(Player player) {
|
||||
injectChannelInternal(getChannel(player)).player = player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom channel handler to the given channel.
|
||||
*
|
||||
* @param channel - the channel to inject.
|
||||
* @return The intercepted channel, or NULL if it has already been injected.
|
||||
*/
|
||||
public void injectChannel(Channel channel) {
|
||||
injectChannelInternal(channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom channel handler to the given channel.
|
||||
*
|
||||
* @param channel - the channel to inject.
|
||||
* @return The packet interceptor.
|
||||
*/
|
||||
private PacketInterceptor injectChannelInternal(Channel channel) {
|
||||
try {
|
||||
PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName);
|
||||
|
@ -367,13 +254,7 @@ public abstract class LegacyTinyProtocol {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Netty channel associated with a player. This is cached.
|
||||
*
|
||||
* @param player - the player.
|
||||
* @return The Netty channel.
|
||||
*/
|
||||
public Channel getChannel(Player player) {
|
||||
private Channel getChannel(Player player) {
|
||||
Channel channel = channelLookup.get(player.getName());
|
||||
|
||||
// Lookup channel again
|
||||
|
@ -387,37 +268,7 @@ public abstract class LegacyTinyProtocol {
|
|||
return channel;
|
||||
}
|
||||
|
||||
public int getProtocolVersion(Player player) {
|
||||
Channel channel = channelLookup.get(player.getName());
|
||||
|
||||
// Lookup channel again
|
||||
if (channel == null) {
|
||||
Object connection = getConnection.get(getPlayerHandle.invoke(player));
|
||||
Object manager = getManager.get(connection);
|
||||
|
||||
channelLookup.put(player.getName(), channel = getChannel.get(manager));
|
||||
}
|
||||
|
||||
return protocolLookup.get(channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninject a specific player.
|
||||
*
|
||||
* @param player - the injected player.
|
||||
*/
|
||||
public void uninjectPlayer(Player player) {
|
||||
uninjectChannel(getChannel(player));
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninject a specific channel.
|
||||
* <p>
|
||||
* This will also disable the automatic channel injection that occurs when a player has properly logged in.
|
||||
*
|
||||
* @param channel - the injected channel.
|
||||
*/
|
||||
public void uninjectChannel(final Channel channel) {
|
||||
private void uninjectChannel(final Channel channel) {
|
||||
// No need to guard against this if we're closing
|
||||
if (!closed) {
|
||||
uninjectedChannels.add(channel);
|
||||
|
@ -427,36 +278,13 @@ public abstract class LegacyTinyProtocol {
|
|||
channel.eventLoop().execute(() -> channel.pipeline().remove(handlerName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given player has been injected by TinyProtocol.
|
||||
*
|
||||
* @param player - the player.
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public boolean hasInjected(Player player) {
|
||||
return hasInjected(getChannel(player));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given channel has been injected by TinyProtocol.
|
||||
*
|
||||
* @param channel - the channel.
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public boolean hasInjected(Channel channel) {
|
||||
return channel.pipeline().get(handlerName) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cease listening for packets. This is called automatically when your plugin is disabled.
|
||||
*/
|
||||
public final void close() {
|
||||
private void close() {
|
||||
if (!closed) {
|
||||
closed = true;
|
||||
|
||||
// Remove our handlers
|
||||
for (Player player : plugin.getServer().getOnlinePlayers()) {
|
||||
uninjectPlayer(player);
|
||||
uninjectChannel(getChannel(player));
|
||||
}
|
||||
|
||||
// Clean up Bukkit
|
||||
|
@ -465,11 +293,6 @@ public abstract class LegacyTinyProtocol {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel handler that is inserted into the player's channel pipeline, allowing us to intercept sent and received packets.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
private final class PacketInterceptor extends ChannelDuplexHandler {
|
||||
// Updated by the login event
|
||||
public volatile Player player;
|
||||
|
@ -491,25 +314,12 @@ public abstract class LegacyTinyProtocol {
|
|||
try {
|
||||
msg = onPacketInAsync(player, msg);
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Error in onPacketInAsync().", e);
|
||||
plugin.getLogger().log(Level.SEVERE, "[NPCLib] Error in onPacketInAsync().", e);
|
||||
}
|
||||
|
||||
if (msg != null) {
|
||||
super.channelRead(ctx, msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||
try {
|
||||
msg = onPacketOutAsync(player, msg);
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Error in onPacketOutAsync().", e);
|
||||
}
|
||||
|
||||
if (msg != null) {
|
||||
super.write(ctx, msg, promise);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,11 +21,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* Represents a very tiny alternative to ProtocolLib.
|
||||
* <p>
|
||||
* It now supports intercepting packets during login and status ping (such as OUT_SERVER_PING)!
|
||||
*
|
||||
* @author Kristian
|
||||
* Minimized version of TinyProtocol by Kristian suited for NPCLib.
|
||||
*/
|
||||
public abstract class TinyProtocol {
|
||||
private static final AtomicInteger ID = new AtomicInteger(0);
|
||||
|
@ -53,7 +49,7 @@ public abstract class TinyProtocol {
|
|||
private Listener listener;
|
||||
|
||||
// Channels that have already been removed
|
||||
private Set<Channel> uninjectedChannels = Collections.newSetFromMap(new MapMaker().weakKeys().<Channel, Boolean>makeMap());
|
||||
private Set<Channel> uninjectedChannels = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap());
|
||||
|
||||
// List of network markers
|
||||
private List<Object> networkManagers;
|
||||
|
@ -67,38 +63,32 @@ public abstract class TinyProtocol {
|
|||
// Current handler name
|
||||
private String handlerName;
|
||||
|
||||
protected volatile boolean closed;
|
||||
private volatile boolean closed;
|
||||
protected Plugin plugin;
|
||||
|
||||
/**
|
||||
* Construct a new instance of TinyProtocol, and start intercepting packets for all connected clients and future clients.
|
||||
* <p>
|
||||
* You can construct multiple instances per plugin.
|
||||
*
|
||||
* @param plugin - the plugin.
|
||||
*/
|
||||
public TinyProtocol(final Plugin plugin) {
|
||||
protected TinyProtocol(final Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
|
||||
// Compute handler name
|
||||
this.handlerName = getHandlerName();
|
||||
this.handlerName = "tiny-" + plugin.getName() + "-" + ID.incrementAndGet();
|
||||
|
||||
// Prepare existing players
|
||||
registerBukkitEvents();
|
||||
|
||||
try {
|
||||
System.out.println("[NPCLib] Attempting to inject into netty.");
|
||||
registerChannelHandler();
|
||||
registerPlayers(plugin);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Damn you, late bind
|
||||
plugin.getLogger().info("[TinyProtocol] Delaying server channel injection due to late bind.");
|
||||
plugin.getLogger().info("[NPCLib] Attempting to delay injection.");
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
registerChannelHandler();
|
||||
registerPlayers(plugin);
|
||||
plugin.getLogger().info("[TinyProtocol] Late bind injection successful.");
|
||||
plugin.getLogger().info("[NPCLib] Injection complete.");
|
||||
}
|
||||
}.runTask(plugin);
|
||||
}
|
||||
|
@ -108,6 +98,7 @@ public abstract class TinyProtocol {
|
|||
// Handle connected channels
|
||||
endInitProtocol = new ChannelInitializer<Channel>() {
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@Override
|
||||
protected void initChannel(Channel channel) throws Exception {
|
||||
try {
|
||||
|
@ -119,7 +110,7 @@ public abstract class TinyProtocol {
|
|||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Cannot inject incomming channel " + channel, e);
|
||||
plugin.getLogger().log(Level.SEVERE, "[NPCLib] Cannot inject incomming channel " + channel, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,6 +119,7 @@ public abstract class TinyProtocol {
|
|||
// This is executed before Minecraft's channel handler
|
||||
beginInitProtocol = new ChannelInitializer<Channel>() {
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@Override
|
||||
protected void initChannel(Channel channel) throws Exception {
|
||||
channel.pipeline().addLast(endInitProtocol);
|
||||
|
@ -137,6 +129,7 @@ public abstract class TinyProtocol {
|
|||
|
||||
serverChannelHandler = new ChannelInboundHandlerAdapter() {
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
Channel channel = (Channel) msg;
|
||||
|
@ -149,12 +142,10 @@ public abstract class TinyProtocol {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Register bukkit events.
|
||||
*/
|
||||
private void registerBukkitEvents() {
|
||||
listener = new Listener() {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public final void onPlayerLogin(PlayerLoginEvent e) {
|
||||
if (closed)
|
||||
|
@ -168,6 +159,7 @@ public abstract class TinyProtocol {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@EventHandler
|
||||
public final void onPluginDisable(PluginDisableEvent e) {
|
||||
if (e.getPlugin().equals(plugin)) {
|
||||
|
@ -195,7 +187,7 @@ public abstract class TinyProtocol {
|
|||
List<Object> list = Reflection.getField(serverConnection.getClass(), List.class, i).get(serverConnection);
|
||||
|
||||
for (Object item : list) {
|
||||
if (!ChannelFuture.class.isInstance(item))
|
||||
if (!(item instanceof ChannelFuture))
|
||||
break;
|
||||
|
||||
// Channel future that contains the server connection
|
||||
|
@ -216,17 +208,12 @@ public abstract class TinyProtocol {
|
|||
final ChannelPipeline pipeline = serverChannel.pipeline();
|
||||
|
||||
// Remove channel handler
|
||||
serverChannel.eventLoop().execute(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
pipeline.remove(serverChannelHandler);
|
||||
} catch (NoSuchElementException e) {
|
||||
// That's fine
|
||||
}
|
||||
serverChannel.eventLoop().execute(() -> {
|
||||
try {
|
||||
pipeline.remove(serverChannelHandler);
|
||||
} catch (NoSuchElementException e) {
|
||||
// That's fine
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -237,120 +224,14 @@ public abstract class TinyProtocol {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when the server is starting to send a packet to a player.
|
||||
* <p>
|
||||
* Note that this is not executed on the main thread.
|
||||
*
|
||||
* @param receiver - the receiving player, NULL for early login/status packets.
|
||||
* @param channel - the channel that received the packet. Never NULL.
|
||||
* @param packet - the packet being sent.
|
||||
* @return The packet to send instead, or NULL to cancel the transmission.
|
||||
*/
|
||||
public Object onPacketOutAsync(Player receiver, Channel channel, Object packet) {
|
||||
public Object onPacketInAsync(Player sender, Object packet) {
|
||||
return packet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when the server has received a packet from a given player.
|
||||
* <p>
|
||||
* Use {@link Channel#remoteAddress()} to get the remote address of the client.
|
||||
*
|
||||
* @param sender - the player that sent the packet, NULL for early login/status packets.
|
||||
* @param channel - channel that received the packet. Never NULL.
|
||||
* @param packet - the packet being received.
|
||||
* @return The packet to recieve instead, or NULL to cancel.
|
||||
*/
|
||||
public Object onPacketInAsync(Player sender, Channel channel, Object packet) {
|
||||
return packet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a packet to a particular player.
|
||||
* <p>
|
||||
* Note that {@link #onPacketOutAsync(Player, Channel, Object)} will be invoked with this packet.
|
||||
*
|
||||
* @param player - the destination player.
|
||||
* @param packet - the packet to send.
|
||||
*/
|
||||
public void sendPacket(Player player, Object packet) {
|
||||
sendPacket(getChannel(player), packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a packet to a particular client.
|
||||
* <p>
|
||||
* Note that {@link #onPacketOutAsync(Player, Channel, Object)} will be invoked with this packet.
|
||||
*
|
||||
* @param channel - client identified by a channel.
|
||||
* @param packet - the packet to send.
|
||||
*/
|
||||
public void sendPacket(Channel channel, Object packet) {
|
||||
channel.pipeline().writeAndFlush(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretend that a given packet has been received from a player.
|
||||
* <p>
|
||||
* Note that {@link #onPacketInAsync(Player, Channel, Object)} will be invoked with this packet.
|
||||
*
|
||||
* @param player - the player that sent the packet.
|
||||
* @param packet - the packet that will be received by the server.
|
||||
*/
|
||||
public void receivePacket(Player player, Object packet) {
|
||||
receivePacket(getChannel(player), packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretend that a given packet has been received from a given client.
|
||||
* <p>
|
||||
* Note that {@link #onPacketInAsync(Player, Channel, Object)} will be invoked with this packet.
|
||||
*
|
||||
* @param channel - client identified by a channel.
|
||||
* @param packet - the packet that will be received by the server.
|
||||
*/
|
||||
public void receivePacket(Channel channel, Object packet) {
|
||||
channel.pipeline().context("encoder").fireChannelRead(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the name of the channel injector, default implementation is "tiny-" + plugin name + "-" + a unique ID.
|
||||
* <p>
|
||||
* Note that this method will only be invoked once. It is no longer necessary to override this to support multiple instances.
|
||||
*
|
||||
* @return A unique channel handler name.
|
||||
*/
|
||||
protected String getHandlerName() {
|
||||
return "tiny-" + plugin.getName() + "-" + ID.incrementAndGet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom channel handler to the given player's channel pipeline, allowing us to intercept sent and received packets.
|
||||
* <p>
|
||||
* This will automatically be called when a player has logged in.
|
||||
*
|
||||
* @param player - the player to inject.
|
||||
*/
|
||||
public void injectPlayer(Player player) {
|
||||
private void injectPlayer(Player player) {
|
||||
injectChannelInternal(getChannel(player)).player = player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom channel handler to the given channel.
|
||||
*
|
||||
* @param channel - the channel to inject.
|
||||
* @return The intercepted channel, or NULL if it has already been injected.
|
||||
*/
|
||||
public void injectChannel(Channel channel) {
|
||||
injectChannelInternal(channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom channel handler to the given channel.
|
||||
*
|
||||
* @param channel - the channel to inject.
|
||||
* @return The packet interceptor.
|
||||
*/
|
||||
private PacketInterceptor injectChannelInternal(Channel channel) {
|
||||
try {
|
||||
PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName);
|
||||
|
@ -369,13 +250,7 @@ public abstract class TinyProtocol {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Netty channel associated with a player. This is cached.
|
||||
*
|
||||
* @param player - the player.
|
||||
* @return The Netty channel.
|
||||
*/
|
||||
public Channel getChannel(Player player) {
|
||||
private Channel getChannel(Player player) {
|
||||
Channel channel = channelLookup.get(player.getName());
|
||||
|
||||
// Lookup channel again
|
||||
|
@ -389,69 +264,20 @@ public abstract class TinyProtocol {
|
|||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninject a specific player.
|
||||
*
|
||||
* @param player - the injected player.
|
||||
*/
|
||||
public void uninjectPlayer(Player player) {
|
||||
uninjectChannel(getChannel(player));
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninject a specific channel.
|
||||
* <p>
|
||||
* This will also disable the automatic channel injection that occurs when a player has properly logged in.
|
||||
*
|
||||
* @param channel - the injected channel.
|
||||
*/
|
||||
public void uninjectChannel(final Channel channel) {
|
||||
// No need to guard against this if we're closing
|
||||
if (!closed) {
|
||||
uninjectedChannels.add(channel);
|
||||
}
|
||||
|
||||
// See ChannelInjector in ProtocolLib, line 590
|
||||
channel.eventLoop().execute(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
channel.pipeline().remove(handlerName);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given player has been injected by TinyProtocol.
|
||||
*
|
||||
* @param player - the player.
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public boolean hasInjected(Player player) {
|
||||
return hasInjected(getChannel(player));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given channel has been injected by TinyProtocol.
|
||||
*
|
||||
* @param channel - the channel.
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public boolean hasInjected(Channel channel) {
|
||||
return channel.pipeline().get(handlerName) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cease listening for packets. This is called automatically when your plugin is disabled.
|
||||
*/
|
||||
public final void close() {
|
||||
private void close() {
|
||||
if (!closed) {
|
||||
closed = true;
|
||||
|
||||
// Remove our handlers
|
||||
for (Player player : plugin.getServer().getOnlinePlayers()) {
|
||||
uninjectPlayer(player);
|
||||
// No need to guard against this if we're closing
|
||||
Channel channel = getChannel(player);
|
||||
if (!closed) {
|
||||
uninjectedChannels.add(channel);
|
||||
}
|
||||
|
||||
// See ChannelInjector in ProtocolLib, line 590
|
||||
channel.eventLoop().execute(() -> channel.pipeline().remove(handlerName));
|
||||
}
|
||||
|
||||
// Clean up Bukkit
|
||||
|
@ -460,11 +286,6 @@ public abstract class TinyProtocol {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel handler that is inserted into the player's channel pipeline, allowing us to intercept sent and received packets.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
private final class PacketInterceptor extends ChannelDuplexHandler {
|
||||
// Updated by the login event
|
||||
public volatile Player player;
|
||||
|
@ -476,9 +297,9 @@ public abstract class TinyProtocol {
|
|||
handleLoginStart(channel, msg);
|
||||
|
||||
try {
|
||||
msg = onPacketInAsync(player, channel, msg);
|
||||
msg = onPacketInAsync(player, msg);
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Error in onPacketInAsync().", e);
|
||||
plugin.getLogger().log(Level.SEVERE, "[NPCLib] Error in onPacketInAsync().", e);
|
||||
}
|
||||
|
||||
if (msg != null) {
|
||||
|
@ -486,19 +307,6 @@ public abstract class TinyProtocol {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||
try {
|
||||
msg = onPacketOutAsync(player, ctx.channel(), msg);
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Error in onPacketOutAsync().", e);
|
||||
}
|
||||
|
||||
if (msg != null) {
|
||||
super.write(ctx, msg, promise);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleLoginStart(Channel channel, Object packet) {
|
||||
if (PACKET_LOGIN_IN_START.isInstance(packet)) {
|
||||
Object profile = getGameProfile.get(packet);
|
||||
|
|
|
@ -6,7 +6,6 @@ package net.jitse.npclib;
|
|||
|
||||
import net.jitse.npclib.api.NPC;
|
||||
import net.jitse.npclib.listeners.ChunkListener;
|
||||
import net.jitse.npclib.listeners.LegacyPacketListener;
|
||||
import net.jitse.npclib.listeners.PacketListener;
|
||||
import net.jitse.npclib.listeners.PlayerListener;
|
||||
import net.jitse.npclib.skin.Skin;
|
||||
|
@ -67,11 +66,7 @@ public class NPCLib {
|
|||
pluginManager.registerEvents(new ChunkListener(), plugin);
|
||||
|
||||
// Boot the according packet listener.
|
||||
if (Bukkit.getBukkitVersion().contains("1.7")) {
|
||||
new LegacyPacketListener().start(plugin);
|
||||
} else {
|
||||
new PacketListener().start(plugin);
|
||||
}
|
||||
new PacketListener().start(plugin, Bukkit.getBukkitVersion().contains("1.7"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Jitse Boonstra
|
||||
*/
|
||||
|
||||
package net.jitse.npclib.listeners;
|
||||
|
||||
import com.comphenix.tinyprotocol.LegacyTinyProtocol;
|
||||
import com.comphenix.tinyprotocol.Reflection;
|
||||
import net.jitse.npclib.NPCManager;
|
||||
import net.jitse.npclib.api.NPC;
|
||||
import net.jitse.npclib.events.NPCInteractEvent;
|
||||
import net.jitse.npclib.events.click.ClickType;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Jitse Boonstra
|
||||
*/
|
||||
public class LegacyPacketListener {
|
||||
|
||||
// Classes:
|
||||
private final Class<?> packetPlayInUseEntityClazz = Reflection.getMinecraftClass("PacketPlayInUseEntity");
|
||||
|
||||
// Fields:
|
||||
private final Reflection.FieldAccessor entityIdField = Reflection.getField(packetPlayInUseEntityClazz, "a", int.class);
|
||||
private final Reflection.FieldAccessor actionField = Reflection.getField(packetPlayInUseEntityClazz, "action", Object.class);
|
||||
|
||||
// Prevent players from clicking at very high speeds.
|
||||
private final Set<UUID> delay = new HashSet<>();
|
||||
|
||||
public void start(JavaPlugin plugin) {
|
||||
new LegacyTinyProtocol(plugin) {
|
||||
|
||||
@Override
|
||||
public Object onPacketInAsync(Player player, Object packet) {
|
||||
|
||||
if (packetPlayInUseEntityClazz.isInstance(packet)) {
|
||||
NPC npc = NPCManager.getAllNPCs().stream().filter(
|
||||
check -> check.isActuallyShown(player) && check.getEntityId() == (int) entityIdField.get(packet))
|
||||
.findFirst().orElse(null);
|
||||
|
||||
if (npc == null) {
|
||||
// Default player, not doing magic with the packet.
|
||||
return super.onPacketInAsync(player, packet);
|
||||
}
|
||||
|
||||
if (delay.contains(player.getUniqueId())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ClickType clickType = actionField.get(packet).toString()
|
||||
.equals("ATTACK") ? ClickType.LEFT_CLICK : ClickType.RIGHT_CLICK;
|
||||
|
||||
Bukkit.getPluginManager().callEvent(new NPCInteractEvent(player, clickType, npc));
|
||||
|
||||
UUID uuid = player.getUniqueId();
|
||||
delay.add(uuid);
|
||||
Bukkit.getScheduler().runTask(plugin, () -> delay.remove(uuid));
|
||||
return null;
|
||||
}
|
||||
|
||||
return super.onPacketInAsync(player, packet);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
package net.jitse.npclib.listeners;
|
||||
|
||||
import com.comphenix.tinyprotocol.LegacyTinyProtocol;
|
||||
import com.comphenix.tinyprotocol.Reflection;
|
||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||
import io.netty.channel.Channel;
|
||||
import net.jitse.npclib.NPCManager;
|
||||
import net.jitse.npclib.api.NPC;
|
||||
import net.jitse.npclib.events.NPCInteractEvent;
|
||||
|
@ -34,39 +34,77 @@ public class PacketListener {
|
|||
// Prevent players from clicking at very high speeds.
|
||||
private final Set<UUID> delay = new HashSet<>();
|
||||
|
||||
public void start(JavaPlugin plugin) {
|
||||
new TinyProtocol(plugin) {
|
||||
public void start(JavaPlugin plugin, boolean is1_7) {
|
||||
if (is1_7) {
|
||||
// 1.7 R4 packet interaction.
|
||||
new LegacyTinyProtocol(plugin) {
|
||||
|
||||
@Override
|
||||
public Object onPacketInAsync(Player player, Channel channel, Object packet) {
|
||||
@Override
|
||||
public Object onPacketInAsync(Player player, Object packet) {
|
||||
|
||||
if (packetPlayInUseEntityClazz.isInstance(packet)) {
|
||||
NPC npc = NPCManager.getAllNPCs().stream().filter(
|
||||
check -> check.isActuallyShown(player) && check.getEntityId() == (int) entityIdField.get(packet))
|
||||
.findFirst().orElse(null);
|
||||
if (packetPlayInUseEntityClazz.isInstance(packet)) {
|
||||
NPC npc = NPCManager.getAllNPCs().stream().filter(
|
||||
check -> check.isActuallyShown(player) && check.getEntityId() == (int) entityIdField.get(packet))
|
||||
.findFirst().orElse(null);
|
||||
|
||||
if (npc == null) {
|
||||
// Default player, not doing magic with the packet.
|
||||
return super.onPacketInAsync(player, channel, packet);
|
||||
}
|
||||
if (npc == null) {
|
||||
// Default player, not doing magic with the packet.
|
||||
return super.onPacketInAsync(player, packet);
|
||||
}
|
||||
|
||||
if (delay.contains(player.getUniqueId())) {
|
||||
if (delay.contains(player.getUniqueId())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ClickType clickType = actionField.get(packet).toString()
|
||||
.equals("ATTACK") ? ClickType.LEFT_CLICK : ClickType.RIGHT_CLICK;
|
||||
|
||||
Bukkit.getPluginManager().callEvent(new NPCInteractEvent(player, clickType, npc));
|
||||
|
||||
UUID uuid = player.getUniqueId();
|
||||
delay.add(uuid);
|
||||
Bukkit.getScheduler().runTask(plugin, () -> delay.remove(uuid));
|
||||
return null;
|
||||
}
|
||||
|
||||
ClickType clickType = actionField.get(packet).toString()
|
||||
.equals("ATTACK") ? ClickType.LEFT_CLICK : ClickType.RIGHT_CLICK;
|
||||
|
||||
Bukkit.getPluginManager().callEvent(new NPCInteractEvent(player, clickType, npc));
|
||||
|
||||
UUID uuid = player.getUniqueId();
|
||||
delay.add(uuid);
|
||||
Bukkit.getScheduler().runTask(plugin, () -> delay.remove(uuid));
|
||||
return null;
|
||||
return super.onPacketInAsync(player, packet);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
// 1.8 (and above) packet interaction.
|
||||
new TinyProtocol(plugin) {
|
||||
|
||||
return super.onPacketInAsync(player, channel, packet);
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public Object onPacketInAsync(Player player, Object packet) {
|
||||
|
||||
if (packetPlayInUseEntityClazz.isInstance(packet)) {
|
||||
NPC npc = NPCManager.getAllNPCs().stream().filter(
|
||||
check -> check.isActuallyShown(player) && check.getEntityId() == (int) entityIdField.get(packet))
|
||||
.findFirst().orElse(null);
|
||||
|
||||
if (npc == null) {
|
||||
// Default player, not doing magic with the packet.
|
||||
return super.onPacketInAsync(player, packet);
|
||||
}
|
||||
|
||||
if (delay.contains(player.getUniqueId())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ClickType clickType = actionField.get(packet).toString()
|
||||
.equals("ATTACK") ? ClickType.LEFT_CLICK : ClickType.RIGHT_CLICK;
|
||||
|
||||
Bukkit.getPluginManager().callEvent(new NPCInteractEvent(player, clickType, npc));
|
||||
|
||||
UUID uuid = player.getUniqueId();
|
||||
delay.add(uuid);
|
||||
Bukkit.getScheduler().runTask(plugin, () -> delay.remove(uuid));
|
||||
return null;
|
||||
}
|
||||
|
||||
return super.onPacketInAsync(player, packet);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue