Optimize important code, add distance interaction check.
This commit is contained in:
@@ -11,12 +11,11 @@ import net.jitse.npclib.api.events.NPCInteractEvent;
|
|||||||
import net.jitse.npclib.internal.NPCManager;
|
import net.jitse.npclib.internal.NPCManager;
|
||||||
import net.jitse.npclib.internal.SimpleNPC;
|
import net.jitse.npclib.internal.SimpleNPC;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Jitse Boonstra
|
* @author Jitse Boonstra
|
||||||
@@ -49,31 +48,66 @@ public class PacketListener {
|
|||||||
|
|
||||||
private boolean handleInteractPacket(Player player, Object packet) {
|
private boolean handleInteractPacket(Player player, Object packet) {
|
||||||
if (packetPlayInUseEntityClazz.isInstance(packet)) {
|
if (packetPlayInUseEntityClazz.isInstance(packet)) {
|
||||||
SimpleNPC npc = NPCManager.getAllNPCs().stream().filter(
|
SimpleNPC npc = null;
|
||||||
check -> check.isShown(player) && check.getEntityId() == (int) entityIdField.get(packet))
|
int packetEntityId = (int) entityIdField.get(packet);
|
||||||
.findFirst().orElse(null);
|
|
||||||
|
|
||||||
|
// Not using streams here is an intentional choice.
|
||||||
|
// Packet listeners is one of the few places where it is important to write optimized code.
|
||||||
|
// Lambdas (And the stream api) create a massive amount of objects, especially if it isn't a static lambda.
|
||||||
|
// So, we're avoiding them here.
|
||||||
|
// ~ Kneesnap, 9 / 20 / 2019.
|
||||||
|
|
||||||
|
for (SimpleNPC testNPC : NPCManager.getAllNPCs()) {
|
||||||
|
if (testNPC.isShown(player) && testNPC.getEntityId() == packetEntityId) {
|
||||||
|
npc = testNPC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (npc == null) {
|
if (npc == null) {
|
||||||
// Default player, not doing magic with the packet.
|
// Default player, not doing magic with the packet.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delay.contains(player.getUniqueId())) {
|
if (delay.contains(player.getUniqueId())) { // There is an active delay.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NPCInteractEvent.ClickType clickType = actionField.get(packet).toString().equals("ATTACK")
|
NPCInteractEvent.ClickType clickType = actionField.get(packet).toString().equals("ATTACK")
|
||||||
? NPCInteractEvent.ClickType.LEFT_CLICK : NPCInteractEvent.ClickType.RIGHT_CLICK;
|
? NPCInteractEvent.ClickType.LEFT_CLICK : NPCInteractEvent.ClickType.RIGHT_CLICK;
|
||||||
|
|
||||||
Bukkit.getScheduler().runTask(plugin, () ->
|
delay.add(player.getUniqueId());
|
||||||
Bukkit.getPluginManager().callEvent(new NPCInteractEvent(player, clickType, npc)));
|
Bukkit.getScheduler().runTask(plugin, new TaskCallNpcInteractEvent(new NPCInteractEvent(player, clickType, npc), this));
|
||||||
|
|
||||||
UUID uuid = player.getUniqueId();
|
|
||||||
delay.add(uuid);
|
|
||||||
Bukkit.getScheduler().runTask(plugin, () -> delay.remove(uuid));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This would be a non-static lambda, and its usage matters, so we'll make it a full class.
|
||||||
|
private static final class TaskCallNpcInteractEvent implements Runnable {
|
||||||
|
private NPCInteractEvent eventToCall;
|
||||||
|
private PacketListener listener;
|
||||||
|
|
||||||
|
private static Location playerLocation = new Location(null, 0, 0, 0);
|
||||||
|
|
||||||
|
TaskCallNpcInteractEvent(NPCInteractEvent eventToCall, PacketListener listener) {
|
||||||
|
this.eventToCall = eventToCall;
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Player player = eventToCall.getWhoClicked();
|
||||||
|
this.listener.delay.remove(player.getUniqueId()); // Remove the NPC from the interact cooldown.
|
||||||
|
|
||||||
|
if (!Objects.equals(playerLocation.getWorld(), eventToCall.getNPC().getLocation().getWorld()))
|
||||||
|
return; // If the NPC and player are not in the same world, abort!
|
||||||
|
|
||||||
|
double distance = player.getLocation(playerLocation).distanceSquared(eventToCall.getNPC().getLocation());
|
||||||
|
if (distance <= 64) // Only handle the interaction if the player is within interaction range. This way, hacked clients can't interact with NPCs that they shouldn't be able to interact with.
|
||||||
|
Bukkit.getPluginManager().callEvent(this.eventToCall);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user