From 6e8db9f0b7af24f729042d7d62b479d69fb0cc0a Mon Sep 17 00:00:00 2001 From: LoneDev6 Date: Mon, 21 Dec 2020 12:28:53 +0100 Subject: [PATCH] Optimizations - removed useless "presents" hashset - added another presents scheduling to avoid loading chunks to spawn presents - added presentsCounter to the tree serializer to avoid losing presents scheduling on restarts - location util to calculate chunk keys - new hashmap to find tree by chunk faster --- pom.xml | 6 ++ src/main/java/ru/meloncode/xmas/Events.java | 16 ++++ .../java/ru/meloncode/xmas/MagicTree.java | 74 +++++++++++++------ .../ru/meloncode/xmas/TreeSerializer.java | 9 ++- src/main/java/ru/meloncode/xmas/XMas.java | 11 +++ .../meloncode/xmas/utils/LocationUtils.java | 24 ++++++ 6 files changed, 117 insertions(+), 23 deletions(-) create mode 100644 src/main/java/ru/meloncode/xmas/utils/LocationUtils.java diff --git a/pom.xml b/pom.xml index 5a49d06..b894d55 100644 --- a/pom.xml +++ b/pom.xml @@ -81,6 +81,12 @@ commons-lang3 3.0 + + org.jetbrains + annotations + 17.0.0 + compile + \ No newline at end of file diff --git a/src/main/java/ru/meloncode/xmas/Events.java b/src/main/java/ru/meloncode/xmas/Events.java index b295654..5ce427c 100644 --- a/src/main/java/ru/meloncode/xmas/Events.java +++ b/src/main/java/ru/meloncode/xmas/Events.java @@ -13,13 +13,16 @@ import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.ItemSpawnEvent; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.StructureGrowEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.SkullMeta; +import org.jetbrains.annotations.Nullable; import ru.meloncode.xmas.utils.TextUtils; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -293,4 +296,17 @@ private void disableFireworkDamage(EntityDamageByEntityEvent e) } } } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) + private void chunkLoad(ChunkLoadEvent e) + { + Collection trees = XMas.getAllTreesInChunk(e.getChunk()); + if(trees == null) + return; + for(MagicTree tree : trees) + { + if(tree.hasScheduledPresents()) + tree.spawnScheduledPresents(); + } + } } diff --git a/src/main/java/ru/meloncode/xmas/MagicTree.java b/src/main/java/ru/meloncode/xmas/MagicTree.java index 80884a0..da86ce7 100644 --- a/src/main/java/ru/meloncode/xmas/MagicTree.java +++ b/src/main/java/ru/meloncode/xmas/MagicTree.java @@ -21,11 +21,11 @@ public class MagicTree { private final UUID owner; private final Location location; private final UUID treeuid; - private final Set presents = new HashSet<>(); TreeLevel level; private Map levelupRequirements; private Set blocks; - private long presentCounter = 0; + private long presentCounter; + private int scheduledPresents; public MagicTree(UUID owner, TreeLevel level, Location location) { this.treeuid = UUID.randomUUID(); @@ -35,16 +35,22 @@ public MagicTree(UUID owner, TreeLevel level, Location location) { this.levelupRequirements = new HashMap<>(level.getLevelupRequirements()); if (Main.inProgress) build(); + presentCounter = 0; + scheduledPresents = 0; } - public MagicTree(UUID owner, UUID uid, TreeLevel level, Location location, Map levelupRequirements) { + public MagicTree(UUID owner, UUID uid, TreeLevel level, Location location, Map levelupRequirements, + long presentCounter, int scheduledPresents) { this.owner = owner; this.treeuid = uid; this.level = level; this.location = location; this.levelupRequirements = new HashMap<>(levelupRequirements); + this.presentCounter = 0; + this.presentCounter = presentCounter; if (Main.inProgress) build(); + this.scheduledPresents = scheduledPresents; } public static MagicTree getTreeByBlock(Block block) { @@ -186,29 +192,35 @@ public void build() { @SuppressWarnings("deprecation") public void spawnPresent() { + if(!location.getWorld().isChunkLoaded((int)location.getX() / 16, (int)location.getZ() / 16)) + { + if(scheduledPresents + 1 <= 8) + scheduledPresents++; + return; + } + Location presentLoc = location.clone().add(-1 + Main.RANDOM.nextInt(3), 0, -1 + Main.RANDOM.nextInt(3)); Block pBlock = presentLoc.getBlock(); - if (presents.size() <= 3) { - if (!pBlock.getType().isSolid() && pBlock.getType() != Material.SPRUCE_SAPLING) { - pBlock.setType(Material.PLAYER_HEAD); - BlockState state = pBlock.getState(); - if (state instanceof Skull) { - Skull skull = (Skull) state; - BlockFace face; - do { - face = BlockFace.values()[Main.RANDOM.nextInt(BlockFace.values().length)]; - } - while (face == BlockFace.DOWN || face == BlockFace.UP || face == BlockFace.SELF); - //skull.setRotation(face); - Rotatable skullRotatable = (Rotatable) skull.getBlockData(); - skullRotatable.setRotation(face); - //skull.setSkullType(SkullType.PLAYER); - skull.setType(Material.PLAYER_HEAD); - //skull.setOwner(); - skull.setOwningPlayer(Bukkit.getOfflinePlayer(Main.getHeads().get(Main.RANDOM.nextInt(Main.getHeads().size())))); - skull.update(true); + if (!pBlock.getType().isSolid() && pBlock.getType() != Material.SPRUCE_SAPLING) + { + pBlock.setType(Material.PLAYER_HEAD); + BlockState state = pBlock.getState(); + if (state instanceof Skull) { + Skull skull = (Skull) state; + BlockFace face; + do { + face = BlockFace.values()[Main.RANDOM.nextInt(BlockFace.values().length)]; } + while (face == BlockFace.DOWN || face == BlockFace.UP || face == BlockFace.SELF); + //skull.setRotation(face); + Rotatable skullRotatable = (Rotatable) skull.getBlockData(); + skullRotatable.setRotation(face); + //skull.setSkullType(SkullType.PLAYER); + skull.setType(Material.PLAYER_HEAD); + //skull.setOwner(); + skull.setOwningPlayer(Bukkit.getOfflinePlayer(Main.getHeads().get(Main.RANDOM.nextInt(Main.getHeads().size())))); + skull.update(true); } } } @@ -279,4 +291,22 @@ public void end() { } XMas.removeTree(this); } + + public long getPresentCounter() { + return presentCounter; + } + + public int getScheduledPresents() { + return scheduledPresents; + } + + public boolean hasScheduledPresents() { + return scheduledPresents > 0; + } + + public void spawnScheduledPresents() { + for(int i = scheduledPresents; i > 0; i--) + spawnPresent(); + scheduledPresents = 0; + } } diff --git a/src/main/java/ru/meloncode/xmas/TreeSerializer.java b/src/main/java/ru/meloncode/xmas/TreeSerializer.java index 79bf0d6..b4108d9 100644 --- a/src/main/java/ru/meloncode/xmas/TreeSerializer.java +++ b/src/main/java/ru/meloncode/xmas/TreeSerializer.java @@ -26,6 +26,8 @@ public static void loadTrees(JavaPlugin plugin, World world) { TreeLevel level; int x, y, z; Location loc; + long presentCounter; + int scheduledPresents; if (trees.getConfigurationSection("trees") != null && trees.getConfigurationSection("trees").getKeys(false).size() > 0) { for (String cKey : trees.getConfigurationSection("trees").getKeys(false)) { @@ -44,7 +46,10 @@ public static void loadTrees(JavaPlugin plugin, World world) { } else { requirements = new HashMap<>(); } - XMas.addMagicTree(new MagicTree(owner, treeUID, level, loc, requirements)); + presentCounter = trees.getLong("trees." + cKey + ".present_counter", 0); + scheduledPresents = trees.getInt("trees." + cKey + ".scheduled_presents", 0); + + XMas.addMagicTree(new MagicTree(owner, treeUID, level, loc, requirements, presentCounter, scheduledPresents)); } catch (Exception e) { plugin.getLogger().severe(String.format("Error while loading tree `%s`", cKey)); e.printStackTrace(); @@ -76,6 +81,8 @@ public static void saveTree(MagicTree tree) { } catch (IOException e) { e.printStackTrace(); } + trees.set("trees." + cKey + ".present_counter", tree.getPresentCounter()); + trees.set("trees." + cKey + ".scheduled_presents", tree.getScheduledPresents()); } public static void removeTree(MagicTree tree) { diff --git a/src/main/java/ru/meloncode/xmas/XMas.java b/src/main/java/ru/meloncode/xmas/XMas.java index e0c24a2..7335851 100644 --- a/src/main/java/ru/meloncode/xmas/XMas.java +++ b/src/main/java/ru/meloncode/xmas/XMas.java @@ -1,5 +1,6 @@ package ru.meloncode.xmas; +import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; @@ -7,6 +8,8 @@ import org.bukkit.block.Skull; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; +import ru.meloncode.xmas.utils.LocationUtils; import ru.meloncode.xmas.utils.TextUtils; import java.util.ArrayList; @@ -20,11 +23,13 @@ class XMas { private static final ConcurrentHashMap trees = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap> trees_byChunk = new ConcurrentHashMap<>(); public static ItemStack XMAS_CRYSTAL; public static void createMagicTree(Player player, Location loc) { MagicTree tree = new MagicTree(player.getUniqueId(), TreeLevel.SAPLING, loc); trees.put(tree.getTreeUID(), tree); + trees_byChunk.computeIfAbsent(LocationUtils.getChunkKey(tree.getLocation()), aLong -> new ArrayList<>()).add(tree); tree.save(); } @@ -37,10 +42,16 @@ public static Collection getAllTrees() { return trees.values(); } + @Nullable + public static Collection getAllTreesInChunk(Chunk chunk) { + return trees_byChunk.get(LocationUtils.getChunkKey(chunk)); + } + public static void removeTree(MagicTree tree) { tree.unbuild(); TreeSerializer.removeTree(tree); trees.remove(tree.getTreeUID()); + trees_byChunk.remove(LocationUtils.getChunkKey(tree.getLocation())); } public static void processPresent(Block block, Player player) { diff --git a/src/main/java/ru/meloncode/xmas/utils/LocationUtils.java b/src/main/java/ru/meloncode/xmas/utils/LocationUtils.java new file mode 100644 index 0000000..f6b8283 --- /dev/null +++ b/src/main/java/ru/meloncode/xmas/utils/LocationUtils.java @@ -0,0 +1,24 @@ +package ru.meloncode.xmas.utils; + +import org.bukkit.Chunk; +import org.bukkit.Location; + +public class LocationUtils { + public static long getChunkKey(Chunk chunk) { + return getChunkKey(chunk.getX(), chunk.getZ()); + } + public static long getChunkKey(Location location) { + return getChunkKey(location.getBlockX(), location.getBlockZ()); + } + + public static long getChunkKey(int x, int z) { + x = floor(x) >> 4; + z = floor(z) >> 4; + return (((long) x) << 32) | (z & 0xFFFFFFFFL); + } + + public static int floor(double num) { + int floor = (int) num; + return floor == num ? floor : floor - (int) (Double.doubleToRawLongBits(num) >>> 63); + } +}