Cleaned up some code (#10).
This commit is contained in:
@@ -20,11 +20,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a very tiny alternative to ProtocolLib.
|
* Minimized version of TinyProtocol by Kristian suited for NPCLib.
|
||||||
* <p>
|
|
||||||
* It now supports intercepting packets during login and status ping (such as OUT_SERVER_PING)!
|
|
||||||
*
|
|
||||||
* @author Kristian
|
|
||||||
*/
|
*/
|
||||||
public abstract class LegacyTinyProtocol {
|
public abstract class LegacyTinyProtocol {
|
||||||
private static final AtomicInteger ID = new AtomicInteger(0);
|
private static final AtomicInteger ID = new AtomicInteger(0);
|
||||||
@@ -56,7 +52,7 @@ public abstract class LegacyTinyProtocol {
|
|||||||
private Listener listener;
|
private Listener listener;
|
||||||
|
|
||||||
// Channels that have already been removed
|
// 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
|
// List of network markers
|
||||||
private List<Object> networkManagers;
|
private List<Object> networkManagers;
|
||||||
@@ -70,39 +66,32 @@ public abstract class LegacyTinyProtocol {
|
|||||||
// Current handler name
|
// Current handler name
|
||||||
private String handlerName;
|
private String handlerName;
|
||||||
|
|
||||||
protected volatile boolean closed;
|
private volatile boolean closed;
|
||||||
protected Plugin plugin;
|
protected Plugin plugin;
|
||||||
|
|
||||||
/**
|
protected LegacyTinyProtocol(final 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) {
|
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
|
||||||
// Compute handler name
|
// Compute handler name
|
||||||
this.handlerName = getHandlerName();
|
this.handlerName = "tiny-" + plugin.getName() + "-" + ID.incrementAndGet();
|
||||||
|
|
||||||
// Prepare existing players
|
// Prepare existing players
|
||||||
registerBukkitEvents();
|
registerBukkitEvents();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
System.out.println("Attempting to inject into netty");
|
System.out.println("[NPCLib] Attempting to inject into netty.");
|
||||||
registerChannelHandler();
|
registerChannelHandler();
|
||||||
registerPlayers(plugin);
|
registerPlayers(plugin);
|
||||||
} catch (IllegalArgumentException ex) {
|
} catch (IllegalArgumentException ex) {
|
||||||
// Damn you, late bind
|
// Damn you, late bind
|
||||||
plugin.getLogger().info("Attempting to delay injection.");
|
plugin.getLogger().info("[NPCLib] Attempting to delay injection.");
|
||||||
|
|
||||||
new BukkitRunnable() {
|
new BukkitRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
registerChannelHandler();
|
registerChannelHandler();
|
||||||
registerPlayers(plugin);
|
registerPlayers(plugin);
|
||||||
plugin.getLogger().info("Injection complete.");
|
plugin.getLogger().info("[NPCLib] Injection complete.");
|
||||||
}
|
}
|
||||||
}.runTask(plugin);
|
}.runTask(plugin);
|
||||||
}
|
}
|
||||||
@@ -112,6 +101,7 @@ public abstract class LegacyTinyProtocol {
|
|||||||
// Handle connected channels
|
// Handle connected channels
|
||||||
endInitProtocol = new ChannelInitializer<Channel>() {
|
endInitProtocol = new ChannelInitializer<Channel>() {
|
||||||
|
|
||||||
|
@SuppressWarnings("all")
|
||||||
@Override
|
@Override
|
||||||
protected void initChannel(Channel channel) throws Exception {
|
protected void initChannel(Channel channel) throws Exception {
|
||||||
try {
|
try {
|
||||||
@@ -123,7 +113,7 @@ public abstract class LegacyTinyProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} 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
|
// This is executed before Minecraft's channel handler
|
||||||
beginInitProtocol = new ChannelInitializer<Channel>() {
|
beginInitProtocol = new ChannelInitializer<Channel>() {
|
||||||
|
|
||||||
|
@SuppressWarnings("all")
|
||||||
@Override
|
@Override
|
||||||
protected void initChannel(Channel channel) throws Exception {
|
protected void initChannel(Channel channel) throws Exception {
|
||||||
channel.pipeline().addLast(endInitProtocol);
|
channel.pipeline().addLast(endInitProtocol);
|
||||||
@@ -141,6 +132,7 @@ public abstract class LegacyTinyProtocol {
|
|||||||
|
|
||||||
serverChannelHandler = new ChannelInboundHandlerAdapter() {
|
serverChannelHandler = new ChannelInboundHandlerAdapter() {
|
||||||
|
|
||||||
|
@SuppressWarnings("all")
|
||||||
@Override
|
@Override
|
||||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||||
Channel channel = (Channel) msg;
|
Channel channel = (Channel) msg;
|
||||||
@@ -152,12 +144,10 @@ public abstract class LegacyTinyProtocol {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Register bukkit events.
|
|
||||||
*/
|
|
||||||
private void registerBukkitEvents() {
|
private void registerBukkitEvents() {
|
||||||
listener = new Listener() {
|
listener = new Listener() {
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
public final void onPlayerLogin(PlayerJoinEvent e) {
|
public final void onPlayerLogin(PlayerJoinEvent e) {
|
||||||
if (closed)
|
if (closed)
|
||||||
@@ -171,6 +161,7 @@ public abstract class LegacyTinyProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public final void onPluginDisable(PluginDisableEvent e) {
|
public final void onPluginDisable(PluginDisableEvent e) {
|
||||||
if (e.getPlugin().equals(plugin)) {
|
if (e.getPlugin().equals(plugin)) {
|
||||||
@@ -205,9 +196,9 @@ public abstract class LegacyTinyProtocol {
|
|||||||
Channel serverChannel = ((ChannelFuture) item).channel();
|
Channel serverChannel = ((ChannelFuture) item).channel();
|
||||||
|
|
||||||
serverChannels.add(serverChannel);
|
serverChannels.add(serverChannel);
|
||||||
;
|
|
||||||
serverChannel.pipeline().addFirst(serverChannelHandler);
|
serverChannel.pipeline().addFirst(serverChannelHandler);
|
||||||
System.out.println("Server channel handler injected (" + serverChannel + ")");
|
System.out.println("[NPCLib] Server channel handler injected (" + serverChannel + ")");
|
||||||
looking = false;
|
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) {
|
public Object onPacketInAsync(Player sender, Object packet) {
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void injectPlayer(Player player) {
|
||||||
* 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) {
|
|
||||||
injectChannelInternal(getChannel(player)).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) {
|
private PacketInterceptor injectChannelInternal(Channel channel) {
|
||||||
try {
|
try {
|
||||||
PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName);
|
PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName);
|
||||||
@@ -367,13 +254,7 @@ public abstract class LegacyTinyProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private Channel getChannel(Player player) {
|
||||||
* Retrieve the Netty channel associated with a player. This is cached.
|
|
||||||
*
|
|
||||||
* @param player - the player.
|
|
||||||
* @return The Netty channel.
|
|
||||||
*/
|
|
||||||
public Channel getChannel(Player player) {
|
|
||||||
Channel channel = channelLookup.get(player.getName());
|
Channel channel = channelLookup.get(player.getName());
|
||||||
|
|
||||||
// Lookup channel again
|
// Lookup channel again
|
||||||
@@ -387,37 +268,7 @@ public abstract class LegacyTinyProtocol {
|
|||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getProtocolVersion(Player player) {
|
private void uninjectChannel(final Channel channel) {
|
||||||
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) {
|
|
||||||
// No need to guard against this if we're closing
|
// No need to guard against this if we're closing
|
||||||
if (!closed) {
|
if (!closed) {
|
||||||
uninjectedChannels.add(channel);
|
uninjectedChannels.add(channel);
|
||||||
@@ -427,36 +278,13 @@ public abstract class LegacyTinyProtocol {
|
|||||||
channel.eventLoop().execute(() -> channel.pipeline().remove(handlerName));
|
channel.eventLoop().execute(() -> channel.pipeline().remove(handlerName));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void close() {
|
||||||
* 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() {
|
|
||||||
if (!closed) {
|
if (!closed) {
|
||||||
closed = true;
|
closed = true;
|
||||||
|
|
||||||
// Remove our handlers
|
// Remove our handlers
|
||||||
for (Player player : plugin.getServer().getOnlinePlayers()) {
|
for (Player player : plugin.getServer().getOnlinePlayers()) {
|
||||||
uninjectPlayer(player);
|
uninjectChannel(getChannel(player));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up Bukkit
|
// 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 {
|
private final class PacketInterceptor extends ChannelDuplexHandler {
|
||||||
// Updated by the login event
|
// Updated by the login event
|
||||||
public volatile Player player;
|
public volatile Player player;
|
||||||
@@ -491,25 +314,12 @@ public abstract class LegacyTinyProtocol {
|
|||||||
try {
|
try {
|
||||||
msg = onPacketInAsync(player, msg);
|
msg = onPacketInAsync(player, msg);
|
||||||
} catch (Exception e) {
|
} 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) {
|
if (msg != null) {
|
||||||
super.channelRead(ctx, msg);
|
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;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a very tiny alternative to ProtocolLib.
|
* Minimized version of TinyProtocol by Kristian suited for NPCLib.
|
||||||
* <p>
|
|
||||||
* It now supports intercepting packets during login and status ping (such as OUT_SERVER_PING)!
|
|
||||||
*
|
|
||||||
* @author Kristian
|
|
||||||
*/
|
*/
|
||||||
public abstract class TinyProtocol {
|
public abstract class TinyProtocol {
|
||||||
private static final AtomicInteger ID = new AtomicInteger(0);
|
private static final AtomicInteger ID = new AtomicInteger(0);
|
||||||
@@ -53,7 +49,7 @@ public abstract class TinyProtocol {
|
|||||||
private Listener listener;
|
private Listener listener;
|
||||||
|
|
||||||
// Channels that have already been removed
|
// 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
|
// List of network markers
|
||||||
private List<Object> networkManagers;
|
private List<Object> networkManagers;
|
||||||
@@ -67,38 +63,32 @@ public abstract class TinyProtocol {
|
|||||||
// Current handler name
|
// Current handler name
|
||||||
private String handlerName;
|
private String handlerName;
|
||||||
|
|
||||||
protected volatile boolean closed;
|
private volatile boolean closed;
|
||||||
protected Plugin plugin;
|
protected Plugin plugin;
|
||||||
|
|
||||||
/**
|
protected TinyProtocol(final 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) {
|
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
|
||||||
// Compute handler name
|
// Compute handler name
|
||||||
this.handlerName = getHandlerName();
|
this.handlerName = "tiny-" + plugin.getName() + "-" + ID.incrementAndGet();
|
||||||
|
|
||||||
// Prepare existing players
|
// Prepare existing players
|
||||||
registerBukkitEvents();
|
registerBukkitEvents();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
System.out.println("[NPCLib] Attempting to inject into netty.");
|
||||||
registerChannelHandler();
|
registerChannelHandler();
|
||||||
registerPlayers(plugin);
|
registerPlayers(plugin);
|
||||||
} catch (IllegalArgumentException ex) {
|
} catch (IllegalArgumentException ex) {
|
||||||
// Damn you, late bind
|
// 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() {
|
new BukkitRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
registerChannelHandler();
|
registerChannelHandler();
|
||||||
registerPlayers(plugin);
|
registerPlayers(plugin);
|
||||||
plugin.getLogger().info("[TinyProtocol] Late bind injection successful.");
|
plugin.getLogger().info("[NPCLib] Injection complete.");
|
||||||
}
|
}
|
||||||
}.runTask(plugin);
|
}.runTask(plugin);
|
||||||
}
|
}
|
||||||
@@ -108,6 +98,7 @@ public abstract class TinyProtocol {
|
|||||||
// Handle connected channels
|
// Handle connected channels
|
||||||
endInitProtocol = new ChannelInitializer<Channel>() {
|
endInitProtocol = new ChannelInitializer<Channel>() {
|
||||||
|
|
||||||
|
@SuppressWarnings("all")
|
||||||
@Override
|
@Override
|
||||||
protected void initChannel(Channel channel) throws Exception {
|
protected void initChannel(Channel channel) throws Exception {
|
||||||
try {
|
try {
|
||||||
@@ -119,7 +110,7 @@ public abstract class TinyProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} 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
|
// This is executed before Minecraft's channel handler
|
||||||
beginInitProtocol = new ChannelInitializer<Channel>() {
|
beginInitProtocol = new ChannelInitializer<Channel>() {
|
||||||
|
|
||||||
|
@SuppressWarnings("all")
|
||||||
@Override
|
@Override
|
||||||
protected void initChannel(Channel channel) throws Exception {
|
protected void initChannel(Channel channel) throws Exception {
|
||||||
channel.pipeline().addLast(endInitProtocol);
|
channel.pipeline().addLast(endInitProtocol);
|
||||||
@@ -137,6 +129,7 @@ public abstract class TinyProtocol {
|
|||||||
|
|
||||||
serverChannelHandler = new ChannelInboundHandlerAdapter() {
|
serverChannelHandler = new ChannelInboundHandlerAdapter() {
|
||||||
|
|
||||||
|
@SuppressWarnings("all")
|
||||||
@Override
|
@Override
|
||||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||||
Channel channel = (Channel) msg;
|
Channel channel = (Channel) msg;
|
||||||
@@ -149,12 +142,10 @@ public abstract class TinyProtocol {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Register bukkit events.
|
|
||||||
*/
|
|
||||||
private void registerBukkitEvents() {
|
private void registerBukkitEvents() {
|
||||||
listener = new Listener() {
|
listener = new Listener() {
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
public final void onPlayerLogin(PlayerLoginEvent e) {
|
public final void onPlayerLogin(PlayerLoginEvent e) {
|
||||||
if (closed)
|
if (closed)
|
||||||
@@ -168,6 +159,7 @@ public abstract class TinyProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public final void onPluginDisable(PluginDisableEvent e) {
|
public final void onPluginDisable(PluginDisableEvent e) {
|
||||||
if (e.getPlugin().equals(plugin)) {
|
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);
|
List<Object> list = Reflection.getField(serverConnection.getClass(), List.class, i).get(serverConnection);
|
||||||
|
|
||||||
for (Object item : list) {
|
for (Object item : list) {
|
||||||
if (!ChannelFuture.class.isInstance(item))
|
if (!(item instanceof ChannelFuture))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Channel future that contains the server connection
|
// Channel future that contains the server connection
|
||||||
@@ -216,17 +208,12 @@ public abstract class TinyProtocol {
|
|||||||
final ChannelPipeline pipeline = serverChannel.pipeline();
|
final ChannelPipeline pipeline = serverChannel.pipeline();
|
||||||
|
|
||||||
// Remove channel handler
|
// Remove channel handler
|
||||||
serverChannel.eventLoop().execute(new Runnable() {
|
serverChannel.eventLoop().execute(() -> {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
try {
|
||||||
pipeline.remove(serverChannelHandler);
|
pipeline.remove(serverChannelHandler);
|
||||||
} catch (NoSuchElementException e) {
|
} catch (NoSuchElementException e) {
|
||||||
// That's fine
|
// That's fine
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -237,120 +224,14 @@ public abstract class TinyProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public Object onPacketInAsync(Player sender, Object packet) {
|
||||||
* 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) {
|
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void injectPlayer(Player player) {
|
||||||
* 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) {
|
|
||||||
injectChannelInternal(getChannel(player)).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) {
|
private PacketInterceptor injectChannelInternal(Channel channel) {
|
||||||
try {
|
try {
|
||||||
PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName);
|
PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName);
|
||||||
@@ -369,13 +250,7 @@ public abstract class TinyProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private Channel getChannel(Player player) {
|
||||||
* Retrieve the Netty channel associated with a player. This is cached.
|
|
||||||
*
|
|
||||||
* @param player - the player.
|
|
||||||
* @return The Netty channel.
|
|
||||||
*/
|
|
||||||
public Channel getChannel(Player player) {
|
|
||||||
Channel channel = channelLookup.get(player.getName());
|
Channel channel = channelLookup.get(player.getName());
|
||||||
|
|
||||||
// Lookup channel again
|
// Lookup channel again
|
||||||
@@ -389,69 +264,20 @@ public abstract class TinyProtocol {
|
|||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void close() {
|
||||||
* 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() {
|
|
||||||
if (!closed) {
|
if (!closed) {
|
||||||
closed = true;
|
closed = true;
|
||||||
|
|
||||||
// Remove our handlers
|
// Remove our handlers
|
||||||
for (Player player : plugin.getServer().getOnlinePlayers()) {
|
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
|
// 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 {
|
private final class PacketInterceptor extends ChannelDuplexHandler {
|
||||||
// Updated by the login event
|
// Updated by the login event
|
||||||
public volatile Player player;
|
public volatile Player player;
|
||||||
@@ -476,9 +297,9 @@ public abstract class TinyProtocol {
|
|||||||
handleLoginStart(channel, msg);
|
handleLoginStart(channel, msg);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
msg = onPacketInAsync(player, channel, msg);
|
msg = onPacketInAsync(player, msg);
|
||||||
} catch (Exception e) {
|
} 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) {
|
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) {
|
private void handleLoginStart(Channel channel, Object packet) {
|
||||||
if (PACKET_LOGIN_IN_START.isInstance(packet)) {
|
if (PACKET_LOGIN_IN_START.isInstance(packet)) {
|
||||||
Object profile = getGameProfile.get(packet);
|
Object profile = getGameProfile.get(packet);
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ package net.jitse.npclib;
|
|||||||
|
|
||||||
import net.jitse.npclib.api.NPC;
|
import net.jitse.npclib.api.NPC;
|
||||||
import net.jitse.npclib.listeners.ChunkListener;
|
import net.jitse.npclib.listeners.ChunkListener;
|
||||||
import net.jitse.npclib.listeners.LegacyPacketListener;
|
|
||||||
import net.jitse.npclib.listeners.PacketListener;
|
import net.jitse.npclib.listeners.PacketListener;
|
||||||
import net.jitse.npclib.listeners.PlayerListener;
|
import net.jitse.npclib.listeners.PlayerListener;
|
||||||
import net.jitse.npclib.skin.Skin;
|
import net.jitse.npclib.skin.Skin;
|
||||||
@@ -67,11 +66,7 @@ public class NPCLib {
|
|||||||
pluginManager.registerEvents(new ChunkListener(), plugin);
|
pluginManager.registerEvents(new ChunkListener(), plugin);
|
||||||
|
|
||||||
// Boot the according packet listener.
|
// Boot the according packet listener.
|
||||||
if (Bukkit.getBukkitVersion().contains("1.7")) {
|
new PacketListener().start(plugin, Bukkit.getBukkitVersion().contains("1.7"));
|
||||||
new LegacyPacketListener().start(plugin);
|
|
||||||
} else {
|
|
||||||
new PacketListener().start(plugin);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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;
|
package net.jitse.npclib.listeners;
|
||||||
|
|
||||||
|
import com.comphenix.tinyprotocol.LegacyTinyProtocol;
|
||||||
import com.comphenix.tinyprotocol.Reflection;
|
import com.comphenix.tinyprotocol.Reflection;
|
||||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||||
import io.netty.channel.Channel;
|
|
||||||
import net.jitse.npclib.NPCManager;
|
import net.jitse.npclib.NPCManager;
|
||||||
import net.jitse.npclib.api.NPC;
|
import net.jitse.npclib.api.NPC;
|
||||||
import net.jitse.npclib.events.NPCInteractEvent;
|
import net.jitse.npclib.events.NPCInteractEvent;
|
||||||
@@ -34,11 +34,13 @@ public class PacketListener {
|
|||||||
// Prevent players from clicking at very high speeds.
|
// Prevent players from clicking at very high speeds.
|
||||||
private final Set<UUID> delay = new HashSet<>();
|
private final Set<UUID> delay = new HashSet<>();
|
||||||
|
|
||||||
public void start(JavaPlugin plugin) {
|
public void start(JavaPlugin plugin, boolean is1_7) {
|
||||||
new TinyProtocol(plugin) {
|
if (is1_7) {
|
||||||
|
// 1.7 R4 packet interaction.
|
||||||
|
new LegacyTinyProtocol(plugin) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object onPacketInAsync(Player player, Channel channel, Object packet) {
|
public Object onPacketInAsync(Player player, Object packet) {
|
||||||
|
|
||||||
if (packetPlayInUseEntityClazz.isInstance(packet)) {
|
if (packetPlayInUseEntityClazz.isInstance(packet)) {
|
||||||
NPC npc = NPCManager.getAllNPCs().stream().filter(
|
NPC npc = NPCManager.getAllNPCs().stream().filter(
|
||||||
@@ -47,7 +49,7 @@ public class PacketListener {
|
|||||||
|
|
||||||
if (npc == null) {
|
if (npc == null) {
|
||||||
// Default player, not doing magic with the packet.
|
// Default player, not doing magic with the packet.
|
||||||
return super.onPacketInAsync(player, channel, packet);
|
return super.onPacketInAsync(player, packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delay.contains(player.getUniqueId())) {
|
if (delay.contains(player.getUniqueId())) {
|
||||||
@@ -65,8 +67,44 @@ public class PacketListener {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.onPacketInAsync(player, channel, packet);
|
return super.onPacketInAsync(player, packet);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// 1.8 (and above) packet interaction.
|
||||||
|
new TinyProtocol(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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user