Player move optimization.

This commit is contained in:
Kneesnap 2019-09-22 12:09:48 -07:00
parent d9ca07b195
commit 0ecc238e6a
4 changed files with 56 additions and 34 deletions

View File

@ -6,6 +6,7 @@ package net.jitse.npclib.api;
import net.jitse.npclib.api.skin.Skin;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
public interface NPC {
@ -35,6 +36,13 @@ public interface NPC {
*/
Location getLocation();
/**
* Get the world the NPC is located in.
*
* @return The world the NPC is located in.
*/
World getWorld();
/**
* Create all necessary packets for the NPC so it can be shown to players.
*

View File

@ -13,6 +13,7 @@ import net.jitse.npclib.api.events.NPCShowEvent;
import net.jitse.npclib.api.skin.Skin;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
@ -104,6 +105,11 @@ public abstract class SimpleNPC implements NPC, PacketHandler {
return location;
}
@Override
public World getWorld() {
return location != null ? location.getWorld() : null;
}
public int getEntityId() {
return entityId;
}

View File

@ -15,7 +15,10 @@ import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import java.util.*;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
/**
* @author Jitse Boonstra
@ -47,42 +50,40 @@ public class PacketListener {
}
private boolean handleInteractPacket(Player player, Object packet) {
if (packetPlayInUseEntityClazz.isInstance(packet)) {
SimpleNPC npc = null;
int packetEntityId = (int) entityIdField.get(packet);
if (!packetPlayInUseEntityClazz.isInstance(packet))
return true; // We aren't handling the packet.
SimpleNPC npc = null;
int packetEntityId = (int) entityIdField.get(packet);
// 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.
// 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;
}
for (SimpleNPC testNPC : NPCManager.getAllNPCs()) {
if (testNPC.isShown(player) && testNPC.getEntityId() == packetEntityId) {
npc = testNPC;
break;
}
}
if (npc == null) {
// Default player, not doing magic with the packet.
return true;
}
if (npc == null) {
// Default player, not doing magic with the packet.
return true;
}
if (delay.contains(player.getUniqueId())) { // There is an active delay.
return false;
}
NPCInteractEvent.ClickType clickType = actionField.get(packet).toString().equals("ATTACK")
? NPCInteractEvent.ClickType.LEFT_CLICK : NPCInteractEvent.ClickType.RIGHT_CLICK;
delay.add(player.getUniqueId());
Bukkit.getScheduler().runTask(plugin, new TaskCallNpcInteractEvent(new NPCInteractEvent(player, clickType, npc), this));
if (delay.contains(player.getUniqueId())) { // There is an active delay.
return false;
}
return true;
NPCInteractEvent.ClickType clickType = actionField.get(packet).toString().equals("ATTACK")
? NPCInteractEvent.ClickType.LEFT_CLICK : NPCInteractEvent.ClickType.RIGHT_CLICK;
delay.add(player.getUniqueId());
Bukkit.getScheduler().runTask(plugin, new TaskCallNpcInteractEvent(new NPCInteractEvent(player, clickType, npc), this));
return false;
}
// This would be a non-static lambda, and its usage matters, so we'll make it a full class.
@ -102,7 +103,7 @@ public class PacketListener {
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()))
if (!Objects.equals(playerLocation.getWorld(), eventToCall.getNPC().getWorld()))
return; // If the NPC and player are not in the same world, abort!
double distance = player.getLocation(playerLocation).distanceSquared(eventToCall.getNPC().getLocation());

View File

@ -8,6 +8,7 @@ import net.jitse.npclib.NPCLib;
import net.jitse.npclib.internal.NPCManager;
import net.jitse.npclib.internal.SimpleNPC;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -46,7 +47,7 @@ public class PlayerListener implements Listener {
// The PlayerTeleportEvent is call, and will handle visibility in the new world.
for (SimpleNPC npc : NPCManager.getAllNPCs()) {
if (npc.getLocation().getWorld().equals(from)) {
if (npc.getWorld().equals(from)) {
if (!npc.getAutoHidden().contains(player.getUniqueId())) {
npc.getAutoHidden().add(player.getUniqueId());
npc.hide(player, true, false);
@ -57,7 +58,12 @@ public class PlayerListener implements Listener {
@EventHandler
public void onPlayerMove(PlayerMoveEvent event) {
handleMove(event.getPlayer());
Location from = event.getFrom();
Location to = event.getTo();
if (to == null || (from.getBlockX() != to.getBlockX()
|| from.getBlockY() != to.getBlockY()
|| from.getBlockZ() != to.getBlockZ()))
handleMove(event.getPlayer()); // Verify the player changed which block they are on. Since PlayerMoveEvent is one of the most called events, this is worth it.
}
@EventHandler
@ -72,7 +78,7 @@ public class PlayerListener implements Listener {
continue; // NPC was never supposed to be shown to the player.
}
if (!npc.getLocation().getWorld().equals(world)) {
if (!npc.getWorld().equals(world)) {
continue; // NPC is not in the same world.
}
@ -80,8 +86,9 @@ public class PlayerListener implements Listener {
// This will cause issues otherwise (e.g. custom skin disappearing).
double hideDistance = instance.getAutoHideDistance();
double distanceSquared = player.getLocation().distanceSquared(npc.getLocation());
boolean inRange = distanceSquared <= (Math.pow(hideDistance, 2))
&& distanceSquared <= (Math.pow(Bukkit.getViewDistance() << 4, 2));
int tempRange = Bukkit.getViewDistance() << 4;
boolean inRange = distanceSquared <= (hideDistance * hideDistance) && distanceSquared <= (tempRange * tempRange); // Avoids Math.pow due to how intensive it is. Could make a static utility function for it.
if (npc.getAutoHidden().contains(player.getUniqueId())) {
// Check if the player and NPC are within the range to sendShowPackets it again.
if (inRange) {