diff --git a/src/main/java/world/bentobox/twerk/Settings.java b/src/main/java/world/bentobox/twerk/Settings.java index 19a3b8e..03569c0 100644 --- a/src/main/java/world/bentobox/twerk/Settings.java +++ b/src/main/java/world/bentobox/twerk/Settings.java @@ -20,7 +20,15 @@ public class Settings implements ConfigObject { @ConfigComment("If the player has not twerked enough, then the tree will not grow faster.") @ConfigEntry(path = "minimum-twerks") private int minimumTwerks = 4; + + @ConfigComment("Hold to twerk. Accessibility feature. Instead of hitting the crouch button continuously, hold it down.") + @ConfigEntry(path = "hold-for-twerk") + private boolean holdForTwerk = false; + @ConfigComment("Use sprinting to grow trees instead of twerking.") + @ConfigEntry(path = "sprint-to-grow") + private boolean sprintToGrow = false; + @ConfigComment("Range to look for saplings when twerking. A range of 5 will look +/- 5 blocks in all directions around the player") @ConfigComment("Making this too big will lag your server.") @ConfigEntry(path = "range") @@ -196,4 +204,32 @@ public int getRange() { public void setRange(int range) { this.range = range; } + + /** + * @return the holdForTwerk + */ + public boolean isHoldForTwerk() { + return holdForTwerk; + } + + /** + * @param holdForTwerk the holdForTwerk to set + */ + public void setHoldForTwerk(boolean holdForTwerk) { + this.holdForTwerk = holdForTwerk; + } + + /** + * @return the sprintToGrow + */ + public boolean isSprintToGrow() { + return sprintToGrow; + } + + /** + * @param sprintToGrow the sprintToGrow to set + */ + public void setSprintToGrow(boolean sprintToGrow) { + this.sprintToGrow = sprintToGrow; + } } diff --git a/src/main/java/world/bentobox/twerk/listeners/TreeGrowListener.java b/src/main/java/world/bentobox/twerk/listeners/TreeGrowListener.java index d363b1c..037325b 100644 --- a/src/main/java/world/bentobox/twerk/listeners/TreeGrowListener.java +++ b/src/main/java/world/bentobox/twerk/listeners/TreeGrowListener.java @@ -27,6 +27,7 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.player.PlayerToggleSneakEvent; +import org.bukkit.event.player.PlayerToggleSprintEvent; import org.bukkit.event.world.StructureGrowEvent; import org.eclipse.jdt.annotation.NonNull; @@ -80,6 +81,8 @@ public class TreeGrowListener implements Listener { private Map twerkCount; private Set isTwerking; private Map plantedTrees; + private Set twerkers = new HashSet<>(); + private Set sprinters = new HashSet<>(); public TreeGrowListener(@NonNull TwerkingForTrees addon) { this.addon = addon; @@ -98,7 +101,7 @@ protected void runChecker() { plantedTrees.values().removeIf(i -> !isTwerking.contains(i)); } , 0L, 40L); - // Every 20 seconds + // Every 10 seconds Bukkit.getScheduler().runTaskTimer(addon.getPlugin(), () -> plantedTrees .entrySet() @@ -107,6 +110,14 @@ protected void runChecker() { .map(Map.Entry::getKey) .forEach(b -> Util.getChunkAtAsync(b).thenRun(() -> growTree(b.getBlock()))) , 10L, 400L); + // Simulate twerking + if (addon.getSettings().isHoldForTwerk()) { + Bukkit.getScheduler().runTaskTimer(addon.getPlugin(), () -> twerkers.forEach(this::twerk), 0L, 5L); + } + // Sprinting + if (addon.getSettings().isSprintToGrow()) { + Bukkit.getScheduler().runTaskTimer(addon.getPlugin(), () -> sprinters.forEach(this::twerk), 0L, 5L); + } } protected void growTree(Block b) { @@ -117,7 +128,8 @@ protected void growTree(Block b) { // Try to grow big tree if possible if (SAPLING_TO_BIG_TREE_TYPE.containsKey(t) && bigTreeSaplings(b)) { return; - } else if (SAPLING_TO_TREE_TYPE.containsKey(t)) { + } + if (SAPLING_TO_TREE_TYPE.containsKey(t)) { TreeType type = SAPLING_TO_TREE_TYPE.getOrDefault(b.getType(), TreeType.TREE); b.setType(Material.AIR); @@ -174,30 +186,52 @@ protected void showSparkles(Block b) { protected boolean bigTreeSaplings(Block b) { Material treeType = b.getType(); TreeType type = SAPLING_TO_BIG_TREE_TYPE.get(treeType); - for (List q : QUADS) { - if (q.stream().map(b::getRelative).allMatch(c -> c.getType().equals(treeType))) { - // All the same sapling type found in this quad - q.stream().map(b::getRelative).forEach(c -> c.setType(Material.AIR)); - // Get the tree planting location - Location l = b.getRelative(q.get(0)).getLocation(); - if (b.getWorld().generateTree(l, type, new BlockChangeHandler(addon, b.getWorld()))) { - if (addon.getSettings().isEffectsEnabled()) { - showSparkles(b); - } - if (addon.getSettings().isSoundsEnabled()) { - b.getWorld().playSound(b.getLocation(), addon.getSettings().getSoundsGrowingBigTreeSound(), - (float)addon.getSettings().getSoundsGrowingBigTreeVolume(), (float)addon.getSettings().getSoundsGrowingBigTreePitch()); - } + + for (List quad : QUADS) { + if (isQuadOfSameType(b, quad, treeType)) { + clearSaplings(b, quad); + Location treeLocation = b.getRelative(quad.get(0)).getLocation(); + + if (generateBigTree(b, treeLocation, type)) { + playBigTreeEffectsAndSounds(b); return true; } else { - // Generation failed, reset saplings - q.stream().map(b::getRelative).forEach(c -> c.setType(treeType)); + resetSaplings(b, quad, treeType); } } } return false; } + private boolean isQuadOfSameType(Block b, List quad, Material treeType) { + return quad.stream().map(b::getRelative).allMatch(c -> c.getType().equals(treeType)); + } + + private void clearSaplings(Block b, List quad) { + quad.stream().map(b::getRelative).forEach(c -> c.setType(Material.AIR)); + } + + private boolean generateBigTree(Block b, Location location, TreeType type) { + return b.getWorld().generateTree(location, RAND, type, + bs -> Flags.TREES_GROWING_OUTSIDE_RANGE.isSetForWorld(bs.getWorld()) + || addon.getIslands().getProtectedIslandAt(bs.getLocation()).isPresent()); + } + + private void playBigTreeEffectsAndSounds(Block b) { + if (addon.getSettings().isEffectsEnabled()) { + showSparkles(b); + } + if (addon.getSettings().isSoundsEnabled()) { + b.getWorld().playSound(b.getLocation(), addon.getSettings().getSoundsGrowingBigTreeSound(), + (float) addon.getSettings().getSoundsGrowingBigTreeVolume(), + (float) addon.getSettings().getSoundsGrowingBigTreePitch()); + } + } + + private void resetSaplings(Block b, List quad, Material treeType) { + quad.stream().map(b::getRelative).forEach(c -> c.setType(treeType)); + } + protected void showSparkles(Block b) { AROUND.stream().map(b::getRelative).map(Block::getLocation).forEach(x -> x.getWorld().playEffect(x, addon.getSettings().getEffectsTwerk(), 0)); } @@ -214,18 +248,48 @@ public void onTreeGrow(StructureGrowEvent e) { @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onTwerk(PlayerToggleSneakEvent e) { - if (!e.getPlayer().getWorld().getEnvironment().equals(Environment.NORMAL) - || !addon.getPlugin().getIWM().inWorld(Util.getWorld(e.getPlayer().getWorld())) - || e.getPlayer().isFlying() - || !e.getPlayer().hasPermission(addon.getPlugin().getIWM().getPermissionPrefix(e.getPlayer().getWorld()) + "twerkingfortrees")) { + if (check(e.getPlayer())) { + return; + } + if (addon.getSettings().isHoldForTwerk()) { + Player player = e.getPlayer(); + if (!twerkers.add(player)) { + twerkers.remove(player); + } + return; + } + twerk(e.getPlayer()); + } + + private boolean check(Player player) { + return !player.getWorld().getEnvironment().equals(Environment.NORMAL) + || !addon.getPlugin().getIWM().inWorld(Util.getWorld(player.getWorld())) || player.isFlying() + || !player.hasPermission( + addon.getPlugin().getIWM().getPermissionPrefix(player.getWorld()) + "twerkingfortrees"); + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onSprint(PlayerToggleSprintEvent e) { + if (check(e.getPlayer())) { return; } + if (addon.getSettings().isSprintToGrow()) { + Player player = e.getPlayer(); + if (!sprinters.add(player)) { + sprinters.remove(player); + } + return; + } + twerk(e.getPlayer()); + } + + private void twerk(Player player) { // Get the island - addon.getIslands().getIslandAt(e.getPlayer().getLocation()).ifPresent(i -> { + addon.getIslands().getIslandAt(player.getLocation()).ifPresent(i -> { // Check if there are any planted saplings around player if (!twerkCount.containsKey(i) || twerkCount.get(i) == 0) { // New twerking effort - getNearbySaplings(e.getPlayer(), i); + getNearbySaplings(player, i); } if (!plantedTrees.values().contains(i)) { // None, so return @@ -235,15 +299,17 @@ public void onTwerk(PlayerToggleSneakEvent e) { twerkCount.putIfAbsent(i, 0); int count = twerkCount.get(i) + 1; twerkCount.put(i, count); - if (count == addon.getSettings().getMinimumTwerks()) { - e.getPlayer().playSound(e.getPlayer().getLocation(), addon.getSettings().getSoundsTwerkSound(), + if (count >= addon.getSettings().getMinimumTwerks()) { + player.playSound(player.getLocation(), addon.getSettings().getSoundsTwerkSound(), (float)addon.getSettings().getSoundsTwerkVolume(), (float)addon.getSettings().getSoundsTwerkPitch()); - e.getPlayer().spawnParticle(Particle.SPELL, e.getPlayer().getLocation(), 20, 3D, 0D, 3D); + player.spawnParticle(Particle.SPELL, player.getLocation(), 20, 3D, 0D, 3D); } }); + } private void getNearbySaplings(Player player, Island i) { + plantedTrees.values().removeIf(i::equals); int range = addon.getSettings().getRange(); for (int x = player.getLocation().getBlockX() - range ; x <= player.getLocation().getBlockX() + range; x++) { for (int y = player.getLocation().getBlockY() - range ; y <= player.getLocation().getBlockY() + range; y++) { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index ed85884..78ebee4 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,8 +1,12 @@ -# TwerkingForTrees configuration file. -# +# TwerkingForTrees configuration file. {$version} +# # How many times the player must twerk before the tree start growing faster. # If the player has not twerked enough, then the tree will not grow faster. minimum-twerks: 4 +# Hold to twerk. Accessibility feature. Instead of hitting the crouch button continuously, hold it down. +hold-for-twerk: false +# Use sprinting to grow trees instead of twerking. +sprint-to-grow: false # Range to look for saplings when twerking. A range of 5 will look +/- 5 blocks in all directions around the player # Making this too big will lag your server. range: 5