Avoid unintentionally loading loads of chunks with Location#getChunk

This commit is contained in:
Kneesnap 2019-09-22 12:23:09 -07:00
parent 3b62c85e7e
commit dfa1d14f0e
1 changed files with 44 additions and 32 deletions

View File

@ -9,12 +9,14 @@ import net.jitse.npclib.internal.NPCManager;
import net.jitse.npclib.internal.SimpleNPC;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.ChunkUnloadEvent;
import java.util.Objects;
import java.util.UUID;
/**
@ -33,20 +35,18 @@ public class ChunkListener implements Listener {
Chunk chunk = event.getChunk();
for (SimpleNPC npc : NPCManager.getAllNPCs()) {
Chunk npcChunk = npc.getLocation().getChunk();
if (!isSameChunk(npc.getLocation(), chunk))
continue; // We aren't unloading the chunk with the NPC in it.
if (chunk.equals(npcChunk)) {
// Unloaded chunk with NPC in it. Hiding it from all players currently shown to.
for (UUID uuid : npc.getShown()) {
// Safety check so it doesn't send packets if the NPC has already
// been automatically despawned by the system.
if (npc.getAutoHidden().contains(uuid)) {
continue;
}
npc.hide(Bukkit.getPlayer(uuid), true, true);
// We found an NPC in the chunk being unloaded. Time to hide this NPC from all players.
for (UUID uuid : npc.getShown()) {
// Safety check so it doesn't send packets if the NPC has already
// been automatically despawned by the system.
if (npc.getAutoHidden().contains(uuid)) {
continue;
}
npc.hide(Bukkit.getPlayer(uuid), true, true);
}
}
}
@ -56,33 +56,45 @@ public class ChunkListener implements Listener {
Chunk chunk = event.getChunk();
for (SimpleNPC npc : NPCManager.getAllNPCs()) {
Chunk npcChunk = npc.getLocation().getChunk();
if (!isSameChunk(npc.getLocation(), chunk))
continue; // The NPC is not in the loaded chunk.
if (chunk.equals(npcChunk)) {
// Loaded chunk with NPC in it. Showing it to the players again.
// The chunk being loaded has this NPC in it. Showing it to all the players again.
for (UUID uuid : npc.getShown()) {
// Make sure not to respawn a not-hidden NPC.
if (!npc.getAutoHidden().contains(uuid)) {
continue;
}
for (UUID uuid : npc.getShown()) {
// Make sure not to respawn a not-hidden NPC.
if (!npc.getAutoHidden().contains(uuid)) {
continue;
}
Player player = Bukkit.getPlayer(uuid);
if (player == null)
continue; // Couldn't find the player, so skip.
Player player = Bukkit.getPlayer(uuid);
if (!Objects.equals(npc.getWorld(), player.getWorld())) {
continue; // Player and NPC are not in the same world.
}
if (!npcChunk.getWorld().equals(player.getWorld())) {
continue; // Player and NPC are not in the same world.
}
double hideDistance = instance.getAutoHideDistance();
double distanceSquared = player.getLocation().distanceSquared(npc.getLocation());
boolean inRange = distanceSquared <= (hideDistance * hideDistance) || distanceSquared <= (Bukkit.getViewDistance() << 4);
double hideDistance = instance.getAutoHideDistance();
double distanceSquared = player.getLocation().distanceSquared(npc.getLocation());
boolean inRange = distanceSquared <= (hideDistance * hideDistance) || distanceSquared <= (Bukkit.getViewDistance() << 4);
// Show the NPC (if in range).
if (inRange) {
npc.show(player, true);
}
// Show the NPC (if in range).
if (inRange) {
npc.show(player, true);
}
}
}
}
private static int getChunkCoordinate(int coordinate) {
return coordinate >> 4;
}
// Using Location#getChunk will load the chunk, which is a pretty hefty task, so we'll want to avoid it.
// Using Location#getChunk would effectively mean we'd load every chunk an NPC is located in when any chunk is unloaded.
private static boolean isSameChunk(Location loc, Chunk chunk) {
return getChunkCoordinate(loc.getBlockX()) == chunk.getX()
&& getChunkCoordinate(loc.getBlockZ()) == chunk.getZ();
}
}