From 2f7265592104032f7a1b25105ffe282df895679f Mon Sep 17 00:00:00 2001 From: jameslfc19 Date: Fri, 24 Jul 2020 22:41:09 +0100 Subject: [PATCH] Fixed Chunk Loading Issues Lots of processes were causing chunks to stay loaded. Including the removal of entities in onEnable() Everything is done on a per chunk basis now. --- .../minecraft/chests/ChestsPlusPlus.java | 5 +- .../interfaces/VirtualCraftingHolder.java | 1 + .../chests/listeners/HopperListener.java | 12 +- .../chests/listeners/InventoryListener.java | 14 +-- .../chests/listeners/WorldListener.java | 8 ++ .../minecraft/chests/misc/Utils.java | 105 ++++++++++-------- .../runnables/VirtualChestToHopper.java | 5 +- .../storage/abstracts/AbstractStorage.java | 5 +- 8 files changed, 82 insertions(+), 73 deletions(-) diff --git a/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/ChestsPlusPlus.java b/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/ChestsPlusPlus.java index cd7da46..863e7c3 100644 --- a/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/ChestsPlusPlus.java +++ b/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/ChestsPlusPlus.java @@ -86,9 +86,6 @@ public class ChestsPlusPlus extends JavaPlugin { API.register(this); ApiSpecific.init(); - //Remove entities that could have been left behind from bad save files/crashes etc. - Utils.fixEntities(); - //Register commands new ChestLinkCommand().register(this); new AutoCraftCommand().register(this); @@ -150,6 +147,8 @@ public class ChestsPlusPlus extends JavaPlugin { public void onDisable() { super.onDisable(); Config.save(); + //Remove entities that could have been left behind from bad save files/crashes etc. + Utils.fixEntities(); } } diff --git a/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/interfaces/VirtualCraftingHolder.java b/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/interfaces/VirtualCraftingHolder.java index 0d4faef..adba61d 100644 --- a/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/interfaces/VirtualCraftingHolder.java +++ b/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/interfaces/VirtualCraftingHolder.java @@ -210,6 +210,7 @@ public class VirtualCraftingHolder implements InventoryHolder { */ public void craftItem(){ for(LocationInfo location : storage.getLocations()){ + if(Utils.isLocationChunkLoaded(location.getLocation())) continue; Block block = location.getLocation().getBlock(); Block blockBelow = block.getRelative(BlockFace.DOWN); Block blockAbove = block.getRelative(BlockFace.UP); diff --git a/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/listeners/HopperListener.java b/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/listeners/HopperListener.java index 2c3b9f0..898c4c6 100644 --- a/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/listeners/HopperListener.java +++ b/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/listeners/HopperListener.java @@ -55,12 +55,14 @@ public class HopperListener implements Listener { new BukkitRunnable() { @Override public void run() { - int hopperAmount = SpigotConfig.getWorldSettings(location.getWorld().getName()).getHopperAmount(); - if(Utils.moveToOtherInventory(event.getSource(), hopperAmount, storage.getInventory())){ - storage.updateDisplayItem(); + if(location != null) { + int hopperAmount = SpigotConfig.getWorldSettings(location.getWorld()).getHopperAmount(); + if (Utils.moveToOtherInventory(event.getSource(), hopperAmount, storage.getInventory())) { + storage.updateDisplayItem(); + } + if (event.getDestination().getHolder() != null) event.getDestination().getHolder().getInventory().clear(); + if (storage.getInventory().getViewers().size() > 0) storage.sort(); } - event.getDestination().getHolder().getInventory().clear(); - if(storage.getInventory().getViewers().size() > 0) storage.sort(); } }.runTaskLater(ChestsPlusPlus.PLUGIN, 1); } diff --git a/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/listeners/InventoryListener.java b/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/listeners/InventoryListener.java index e333f3f..f7d76a2 100644 --- a/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/listeners/InventoryListener.java +++ b/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/listeners/InventoryListener.java @@ -74,13 +74,7 @@ public class InventoryListener implements Listener { Utils.closeInventorySound((Player) event.getPlayer(), event.getInventory()); } event.getViewers().remove(event.getPlayer()); - vHolder.getStorage().getLocations().forEach(locationInfo -> { - Block block = locationInfo.getLocation().getBlock(); - if(block.getState() instanceof Container){ - Container chest = (Container) block.getState(); - Bukkit.getScheduler().scheduleSyncDelayedTask(ChestsPlusPlus.PLUGIN, () -> ApiSpecific.getChestOpener().setLidOpen(event.getInventory(),chest,false),1); - } - }); + Utils.closeStorageInventory(vHolder.getStorage()); vHolder.getStorage().onItemDisplayUpdate(InventorySorter.getMostCommonItem(event.getInventory())); } if(holder instanceof VirtualCraftingHolder){ @@ -114,12 +108,10 @@ public class InventoryListener implements Listener { Inventory inventory = event.getInventory(); if(inventory.getHolder() instanceof VirtualCraftingHolder){ Player p = (Player) event.getWhoClicked(); -// Bukkit.broadcastMessage(event.getRawSlots().toString()); for(int slot : event.getRawSlots()) { if(slot >= p.getOpenInventory().getTopInventory().getSize()) continue; -// Bukkit.broadcastMessage("Drag! "+slot+" cursor: "+event.getOldCursor()); setCraftingItem(event.getInventory(),slot,event.getOldCursor()); event.setCancelled(true); } @@ -131,19 +123,15 @@ public class InventoryListener implements Listener { Player player = (Player) event.getWhoClicked(); if(event.getView().getTopInventory().getHolder() instanceof VirtualCraftingHolder){ -// Bukkit.broadcastMessage("Click: "+event.getAction()); - if(event.getAction() == InventoryAction.COLLECT_TO_CURSOR || event.getAction() == InventoryAction.MOVE_TO_OTHER_INVENTORY || event.getAction() == InventoryAction.NOTHING) { -// Bukkit.broadcastMessage("Cancelled!"); event.setCancelled(true); player.updateInventory(); return; } if(event.getClickedInventory() == player.getOpenInventory().getTopInventory()){ -// Bukkit.broadcastMessage("Clicked: "+event.getSlot()); if(event.getSlot() == 0) event.setCancelled(true); if(event.getSlot() >= 1 && event.getSlot() <= 9){ setCraftingItem(event.getInventory(),event.getSlot(),event.getCursor()); diff --git a/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/listeners/WorldListener.java b/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/listeners/WorldListener.java index 64a3962..3408f7a 100644 --- a/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/listeners/WorldListener.java +++ b/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/listeners/WorldListener.java @@ -5,6 +5,7 @@ import com.jamesdpeters.minecraft.chests.misc.Utils; import com.jamesdpeters.minecraft.chests.serialize.Config; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.event.world.WorldSaveEvent; import org.bukkit.scheduler.BukkitRunnable; @@ -31,4 +32,11 @@ public class WorldListener implements Listener { public void onWorldLoad(WorldLoadEvent event){ Utils.removeEntities(event.getWorld()); } + + @EventHandler + public void onChunkLoad(ChunkLoadEvent event){ + if(!event.isNewChunk()){ + Utils.fixEntities(event.getChunk()); + } + } } diff --git a/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/misc/Utils.java b/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/misc/Utils.java index d2a91f5..e5ba139 100644 --- a/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/misc/Utils.java +++ b/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/misc/Utils.java @@ -8,16 +8,14 @@ import com.jamesdpeters.minecraft.chests.interfaces.VirtualInventoryHolder; import com.jamesdpeters.minecraft.chests.storage.chestlink.ChestLinkStorage; import org.bukkit.*; import org.bukkit.block.*; +import org.bukkit.entity.Entity; import org.bukkit.entity.ItemFrame; import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.persistence.PersistentDataType; -import org.bukkit.plugin.RegisteredListener; import org.bukkit.util.Vector; import java.io.BufferedReader; @@ -30,6 +28,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; public class Utils { @@ -39,22 +38,17 @@ public class Utils { storage.getLocations().forEach(locationInfo -> { Location location = locationInfo.getLocation(); if (location != null) { - int chunkX = locationInfo.getLocation().getBlockX() >> 4; - int chunkZ = locationInfo.getLocation().getBlockZ() >> 4; - World world = location.getWorld(); - if (world != null && world.isChunkLoaded(chunkX, chunkZ)) { - chestOpenAnimation(storage.getInventory(), locationInfo.getLocation()); - } + containerOpenAnimation(storage.getInventory(), locationInfo.getLocation()); } }); } else { - chestOpenAnimation(storage.getInventory(), openedChestLocation); + containerOpenAnimation(storage.getInventory(), openedChestLocation); } player.openInventory(storage.getInventory()); } - private static void chestOpenAnimation(Inventory inventory, Location location){ - if (location != null) { + private static void containerOpenAnimation(Inventory inventory, Location location){ + if (location != null && Utils.isLocationChunkLoaded(location)) { Block block = location.getBlock(); if (block.getState() instanceof Container) { Container chest = (Container) block.getState(); @@ -63,6 +57,25 @@ public class Utils { } } + public static void closeStorageInventory(ChestLinkStorage storage){ + storage.getLocations().forEach(locationInfo -> { + Location location = locationInfo.getLocation(); + if (location != null) { + containerCloseAnimation(storage.getInventory(), locationInfo.getLocation()); + } + }); + } + + private static void containerCloseAnimation(Inventory inventory, Location location){ + if (location != null && Utils.isLocationChunkLoaded(location)) { + Block block = location.getBlock(); + if (block.getState() instanceof Container) { + Container chest = (Container) block.getState(); + Bukkit.getScheduler().scheduleSyncDelayedTask(ChestsPlusPlus.PLUGIN,() -> ApiSpecific.getChestOpener().setLidOpen(inventory, chest, false),1); + } + } + } + public static void openChestInventory(Player player, Inventory inventory){ VirtualInventoryHolder holder = (VirtualInventoryHolder) inventory.getHolder(); if (holder != null) holder.onPlayerRemoteOpened(player.getUniqueId()); @@ -196,15 +209,36 @@ public class Utils { }); } + public static void fixEntities(Chunk chunk){ + removeEntities(chunk); + setItemFrames(chunk); + } + public static void removeEntities(World world){ - world.getEntities().forEach(entity -> { - Integer val = entity.getPersistentDataContainer().get(Values.PluginKey, PersistentDataType.INTEGER); - if(val != null && val == 1) entity.remove(); - }); + world.getEntities().forEach(Utils::removeEntity); + } + + public static void removeEntities(Chunk chunk){ + for (Entity entity : chunk.getEntities()) { + removeEntity(entity); + } + } + + private static void removeEntity(Entity entity){ + Integer val = entity.getPersistentDataContainer().get(Values.PluginKey, PersistentDataType.INTEGER); + if(val != null && val == 1) entity.remove(); } public static void setItemFrames(World world){ - world.getEntities().stream().filter(entity -> + setItemFrames(world.getEntities().stream()); + } + + public static void setItemFrames(Chunk chunk){ + setItemFrames(Arrays.stream(chunk.getEntities())); + } + + private static void setItemFrames(Stream entityStream){ + entityStream.filter(entity -> (entity instanceof ItemFrame && entity.getLocation().getBlock().getRelative(((ItemFrame) entity).getAttachedFace()).getState() instanceof Hopper)) .forEach(entity -> ApiSpecific.getNmsProvider().setItemFrameVisible((ItemFrame) entity, !Settings.isFilterItemFrameInvisible())); @@ -218,39 +252,14 @@ public class Utils { if(value != null) list.add(value); } - public static void saveLoadedChunksToCSV(){ - PrintWriter outputFile = getOutputFile("LoadedChunks@"+System.currentTimeMillis()+".csv"); // this sends the output to file1 - - // Write the file as a comma seperated file (.csv) so it can be read it into EXCEL - outputFile.println("Chunk X, Chunk Z, World"); - - // now make a loop to write the contents of each step to disk, one number at a time - Bukkit.getWorlds().forEach(world -> { - for (Chunk loadedChunk : world.getLoadedChunks()) { - outputFile.println(loadedChunk.getX()+", "+loadedChunk.getZ()+", "+world.getName()); - } - }); - outputFile.close(); // close the output file - System.out.println("Saved CSV Data"); - } - - private static PrintWriter getOutputFile(String filenamePath){ - try { - Path path = Paths.get("outputs/"+filenamePath); - Files.createDirectories(path.getParent()); - FileWriter file = new FileWriter(String.valueOf(path)); // this creates the file with the given name - return new PrintWriter(file); // this sends the output to file - } catch (IOException e) { - System.err.println("File couldn't be accessed it may be being used by another process!"); - System.err.println("Close the file and press Enter to try again!"); - BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); - try { reader.readLine(); } catch (IOException ex) { ex.printStackTrace(); } - return getOutputFile(filenamePath); - } - } - public static boolean isAir(Block block){ return (block.getType() == Material.AIR) || (block.getType() == Material.CAVE_AIR); } + public static boolean isLocationChunkLoaded(Location location){ + int chunkX = location.getBlockX() >> 4; + int chunkZ = location.getBlockZ() >> 4; + return location.getWorld() != null && location.getWorld().isChunkLoaded(chunkX, chunkZ); + } + } diff --git a/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/runnables/VirtualChestToHopper.java b/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/runnables/VirtualChestToHopper.java index b5efd6f..215b3d9 100644 --- a/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/runnables/VirtualChestToHopper.java +++ b/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/runnables/VirtualChestToHopper.java @@ -7,6 +7,7 @@ import com.jamesdpeters.minecraft.chests.misc.Utils; import com.jamesdpeters.minecraft.chests.serialize.LocationInfo; import com.jamesdpeters.minecraft.chests.serialize.SpigotConfig; import com.jamesdpeters.minecraft.chests.storage.chestlink.ChestLinkStorage; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.block.Hopper; import org.bukkit.scheduler.BukkitRunnable; @@ -34,14 +35,14 @@ public class VirtualChestToHopper extends BukkitRunnable { for(LocationInfo location : storage.getLocations()) { if(location != null) { if (location.getLocation() != null) { - if(!location.getLocation().getChunk().isLoaded() && !Settings.isRunHoppersInUnloadedChunks()) continue; + if(!Settings.isRunHoppersInUnloadedChunks() && !Utils.isLocationChunkLoaded(location.getLocation())) continue; Location below = location.getLocation().clone().subtract(0, 1, 0); if (below.getBlock().getState() instanceof Hopper) { Hopper hopper = (Hopper) below.getBlock().getState(); if (below.getBlock().isBlockIndirectlyPowered() || below.getBlock().isBlockPowered()) { continue; } - int hopperAmount = SpigotConfig.getWorldSettings(location.getLocation().getWorld().getName()).getHopperAmount(); + int hopperAmount = SpigotConfig.getWorldSettings(location.getLocation().getWorld()).getHopperAmount(); if(Utils.moveToOtherInventory(storage.getInventory(), hopperAmount, hopper.getInventory(), HopperFilter.getHopperFilters(below.getBlock()))){ storage.updateDisplayItem(); } diff --git a/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/storage/abstracts/AbstractStorage.java b/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/storage/abstracts/AbstractStorage.java index 8fbaeb9..63a8092 100644 --- a/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/storage/abstracts/AbstractStorage.java +++ b/ChestsPlusPlus_Main/src/main/java/com/jamesdpeters/minecraft/chests/storage/abstracts/AbstractStorage.java @@ -3,6 +3,7 @@ package com.jamesdpeters.minecraft.chests.storage.abstracts; import com.jamesdpeters.minecraft.chests.ChestsPlusPlus; import com.jamesdpeters.minecraft.chests.api.ApiSpecific; import com.jamesdpeters.minecraft.chests.misc.Permissions; +import com.jamesdpeters.minecraft.chests.misc.Utils; import com.jamesdpeters.minecraft.chests.misc.Values; import com.jamesdpeters.minecraft.chests.serialize.LocationInfo; import org.bukkit.Bukkit; @@ -140,7 +141,7 @@ public abstract class AbstractStorage implements ConfigurationSerializable { private void updateSign(){ Bukkit.getOnlinePlayers().forEach(player -> { for (LocationInfo locationInfo : locationInfoList) { - if (locationInfo.getSignLocation() != null) { + if (locationInfo.getSignLocation() != null && Utils.isLocationChunkLoaded(locationInfo.getSignLocation())) { if (displayItem != null) player.sendBlockChange(locationInfo.getSignLocation(), air); else locationInfo.getSignLocation().getBlock().getState().update(); } @@ -412,7 +413,7 @@ public abstract class AbstractStorage implements ConfigurationSerializable { private BlockData air = Material.AIR.createBlockData(); private void updateClient(LocationInfo location){ - if(location.getLocation() == null) return; + if(location.getLocation() == null || !Utils.isLocationChunkLoaded(location.getLocation())) return; World world = location.getLocation().getWorld(); if(world != null) {