mirror of
https://github.com/songoda/UltimateTimber.git
synced 2024-11-29 05:16:29 +01:00
Version 0.0.4
- Fixed issues related to loot - Added poppy to valid forest setting - Redid the animation class for more reliable fallen block detection
This commit is contained in:
parent
920b437e6d
commit
a235d3d803
2
pom.xml
2
pom.xml
@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>ultimatetimber</groupId>
|
||||
<artifactId>UltimateTimber</artifactId>
|
||||
<version>0.0.3</version>
|
||||
<version>0.0.4</version>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
@ -2,6 +2,7 @@ package com.songoda.ultimatetimber;
|
||||
|
||||
import com.songoda.ultimatetimber.commands.CommandHandler;
|
||||
import com.songoda.ultimatetimber.configurations.DefaultConfig;
|
||||
import com.songoda.ultimatetimber.treefall.TreeFallAnimation;
|
||||
import com.songoda.ultimatetimber.treefall.TreeFallEvent;
|
||||
import com.songoda.ultimatetimber.utils.Methods;
|
||||
import org.bukkit.Bukkit;
|
||||
@ -38,6 +39,11 @@ public class UltimateTimber extends JavaPlugin {
|
||||
*/
|
||||
Bukkit.getServer().getPluginManager().registerEvents(new TreeFallEvent(), this);
|
||||
|
||||
/*
|
||||
Prevent falling blocks from forming new blocks on the floor
|
||||
*/
|
||||
Bukkit.getServer().getPluginManager().registerEvents(new TreeFallAnimation(), this);
|
||||
|
||||
/*
|
||||
Initialize and cache config
|
||||
*/
|
||||
|
@ -88,6 +88,7 @@ public class TreeChecker {
|
||||
!thisBlock.getType().equals(Material.ORANGE_TULIP) &&
|
||||
!thisBlock.getType().equals(Material.PINK_TULIP) &&
|
||||
!thisBlock.getType().equals(Material.RED_TULIP) &&
|
||||
!thisBlock.getType().equals(Material.POPPY) &&
|
||||
!thisBlock.getType().equals(Material.WHITE_TULIP) &&
|
||||
!thisBlock.getType().equals(Material.TALL_GRASS) &&
|
||||
!thisBlock.getType().equals(Material.FERN) &&
|
||||
@ -101,7 +102,9 @@ public class TreeChecker {
|
||||
!thisBlock.getType().equals(Material.JUNGLE_SAPLING) &&
|
||||
!thisBlock.getType().equals(Material.ACACIA_SAPLING) &&
|
||||
!thisBlock.getType().equals(Material.BIRCH_SAPLING) &&
|
||||
!thisBlock.getType().equals(Material.DARK_OAK_SAPLING))
|
||||
!thisBlock.getType().equals(Material.DARK_OAK_SAPLING) &&
|
||||
!thisBlock.getType().equals(Material.VOID_AIR) &&
|
||||
!thisBlock.getType().equals(Material.CAVE_AIR))
|
||||
return null;
|
||||
|
||||
if (validSurroundingMaterials.contains(thisBlock.getType()))
|
||||
|
@ -2,37 +2,143 @@ package com.songoda.ultimatetimber.treefall;
|
||||
|
||||
import com.songoda.ultimatetimber.UltimateTimber;
|
||||
import com.songoda.ultimatetimber.configurations.DefaultConfig;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.FallingBlock;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityChangeBlockEvent;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class TreeFallAnimation {
|
||||
public class TreeFallAnimation implements Listener {
|
||||
|
||||
/*
|
||||
This field gets updated based on player permissions, doubles loot from trees
|
||||
*/
|
||||
private boolean hasBonusLoot;
|
||||
|
||||
public boolean hasBonusLoot() {
|
||||
return this.hasBonusLoot;
|
||||
}
|
||||
|
||||
private void setHasBonusLoot(boolean bool) {
|
||||
this.hasBonusLoot = bool;
|
||||
}
|
||||
|
||||
/*
|
||||
If a player's tool has the silk touch enchantment, it changes the loot table
|
||||
*/
|
||||
private boolean hasSilkTouch;
|
||||
|
||||
public boolean hasSilkTouch() {
|
||||
return this.hasSilkTouch;
|
||||
}
|
||||
|
||||
private void setHasSilkTouch(boolean bool) {
|
||||
this.hasSilkTouch = bool;
|
||||
}
|
||||
|
||||
/*
|
||||
This field stores every falling block in this instance of the animation
|
||||
This list is also used to identify if a falling block is a part of an animation
|
||||
*/
|
||||
private ArrayList<FallingBlock> fallingBlocks = new ArrayList<>();
|
||||
|
||||
public boolean isFallingTreeBlock(FallingBlock fallingBlock) {
|
||||
return this.fallingBlocks.contains(fallingBlock);
|
||||
}
|
||||
|
||||
private void registerFallingBlock(FallingBlock fallingBlock) {
|
||||
this.fallingBlocks.add(fallingBlock);
|
||||
}
|
||||
|
||||
private void unregisterFallingBlock(FallingBlock fallingBlock) {
|
||||
this.fallingBlocks.remove(fallingBlock);
|
||||
}
|
||||
|
||||
private ArrayList<FallingBlock> getAllFallingBlocks() {
|
||||
return this.fallingBlocks;
|
||||
}
|
||||
|
||||
/*
|
||||
Register all instances of falling trees.
|
||||
*/
|
||||
public static ArrayList<TreeFallAnimation> treeFallAnimationInstances = new ArrayList<>();
|
||||
|
||||
public boolean isInTreeFallInstance(FallingBlock fallingBlock) {
|
||||
for (TreeFallAnimation treeFallAnimation : treeFallAnimationInstances)
|
||||
if (treeFallAnimation.isFallingTreeBlock(fallingBlock))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public TreeFallAnimation getTreeFallAnimation(FallingBlock fallingBlock) {
|
||||
for (TreeFallAnimation treeFallAnimation : treeFallAnimationInstances)
|
||||
if (treeFallAnimation.isFallingTreeBlock(fallingBlock))
|
||||
return treeFallAnimation;
|
||||
return null;
|
||||
}
|
||||
|
||||
private void registerTreeFallInstance() {
|
||||
treeFallAnimationInstances.add(this);
|
||||
}
|
||||
|
||||
private void unregisterTreeFallAnimation() {
|
||||
if (this.fallingBlocks.isEmpty())
|
||||
treeFallAnimationInstances.remove(this);
|
||||
}
|
||||
|
||||
/*
|
||||
This animation has multiple phases.
|
||||
Initially, the tree will start slowly toppling over.
|
||||
After a short while, it goes over the tipping point and the fall accelerates.
|
||||
*/
|
||||
public static void startAnimation(Block originalBlock, ArrayList<Block> blocks, Player player) {
|
||||
|
||||
public void startAnimation(Block originalBlock, ArrayList<Block> blocks, Player player) {
|
||||
/*
|
||||
This vector makes sure that the entire tree falls in the same direction from the same reference point
|
||||
*/
|
||||
Vector velocityVector = originalBlock.getLocation().clone().subtract(player.getLocation().clone()).toVector().normalize().setY(0);
|
||||
|
||||
registerTreeFallInstance();
|
||||
setHasBonusLoot(player.hasPermission("ultimatetimber.bonusloot"));
|
||||
|
||||
/*
|
||||
Register private properties
|
||||
*/
|
||||
if (player.getInventory().getItemInMainHand().getType().equals(Material.DIAMOND_AXE) ||
|
||||
player.getInventory().getItemInMainHand().getType().equals(Material.GOLDEN_AXE) ||
|
||||
player.getInventory().getItemInMainHand().getType().equals(Material.IRON_AXE) ||
|
||||
player.getInventory().getItemInMainHand().getType().equals(Material.STONE_AXE) ||
|
||||
player.getInventory().getItemInMainHand().getType().equals(Material.WOODEN_AXE))
|
||||
if (player.getInventory().getItemInMainHand().getEnchantments().containsKey(Enchantment.SILK_TOUCH))
|
||||
{
|
||||
setHasSilkTouch(true);
|
||||
Bukkit.getLogger().warning("test");
|
||||
}
|
||||
else
|
||||
setHasSilkTouch(false);
|
||||
else
|
||||
setHasSilkTouch(false);
|
||||
|
||||
for (Block block : blocks) {
|
||||
|
||||
if (block.getType().equals(Material.AIR)) continue;
|
||||
|
||||
FallingBlock fallingBlock = block.getWorld().spawnFallingBlock(block.getLocation(), block.getBlockData());
|
||||
fallingBlock.setDropItem(false);
|
||||
|
||||
registerFallingBlock(fallingBlock);
|
||||
|
||||
/*
|
||||
Dropping air causes some issues
|
||||
*/
|
||||
if (block.getType().equals(Material.AIR)) continue;
|
||||
|
||||
/*
|
||||
Remove original block
|
||||
@ -45,7 +151,7 @@ public class TreeFallAnimation {
|
||||
*/
|
||||
double multiplier = (block.getLocation().getY() - player.getLocation().getY()) * 0.1;
|
||||
|
||||
startPhaseOneAnimation(fallingBlock, velocityVector, multiplier, player);
|
||||
startPhaseOneAnimation(fallingBlock, velocityVector, multiplier);
|
||||
|
||||
}
|
||||
|
||||
@ -54,13 +160,12 @@ public class TreeFallAnimation {
|
||||
/*
|
||||
Phase one of the animation, the tree starts slowly tipping over
|
||||
*/
|
||||
private static void startPhaseOneAnimation(FallingBlock fallingBlock, Vector velocityVector, double multiplier, Player player) {
|
||||
private void startPhaseOneAnimation(FallingBlock fallingBlock, Vector velocityVector, double multiplier) {
|
||||
|
||||
/*
|
||||
Vertical offset so top of the tree sways faster than the base
|
||||
*/
|
||||
fallingBlock.setVelocity(velocityVector.clone().multiply(multiplier));
|
||||
fallingBlock.setDropItem(true);
|
||||
/*
|
||||
No gravity helps with the initial surrounding block detection (somehow) and with the initial trunk rigidity aspect
|
||||
required for the effect to look convincing
|
||||
@ -69,7 +174,7 @@ public class TreeFallAnimation {
|
||||
|
||||
fallingBlock.setVelocity(fallingBlock.getVelocity().multiply(0.2));
|
||||
|
||||
new BukkitRunnable() {
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
@ -78,7 +183,7 @@ public class TreeFallAnimation {
|
||||
/*
|
||||
Phase 2 has to be launched from here as to not override effects
|
||||
*/
|
||||
runPhaseTwoAnimation(fallingBlock, player);
|
||||
runPhaseTwoAnimation(fallingBlock);
|
||||
|
||||
}
|
||||
}.runTaskLater(UltimateTimber.getInstance(), 20);
|
||||
@ -89,30 +194,29 @@ public class TreeFallAnimation {
|
||||
Phase two of the animation, the tree picks up speed until it is on the ground
|
||||
For safety's sake, it disintegrates after a 4 seconds
|
||||
*/
|
||||
private static void runPhaseTwoAnimation(FallingBlock fallingBlock, Player player) {
|
||||
private void runPhaseTwoAnimation(FallingBlock fallingBlock) {
|
||||
UltimateTimber plugin = UltimateTimber.getInstance();
|
||||
new BukkitRunnable() {
|
||||
int counter = 0;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
if (!fallingBlock.isValid()){
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Safeguard to prevent errors that come from glitchy Minecraft behavior
|
||||
*/
|
||||
if (counter > 20 * 3 ) {
|
||||
runFallingBlockImpact(fallingBlock);
|
||||
cancel();
|
||||
}
|
||||
|
||||
if (counter < 10)
|
||||
fallingBlock.setVelocity(fallingBlock.getVelocity().multiply(1.3));
|
||||
if (counter > 20 * 3 || hasNearbySolidBlock(fallingBlock)) {
|
||||
cancel();
|
||||
TreeLoot.convertFallingBlock(fallingBlock, player);
|
||||
fallingBlock.remove();
|
||||
fallingBlock.getLocation().getWorld().spawnParticle(Particle.SMOKE_LARGE, fallingBlock.getLocation(), 3, 0.2, 0.2, 0.2, 0.05);
|
||||
|
||||
FileConfiguration fileConfiguration = plugin.getConfig();
|
||||
|
||||
if (UltimateTimber.getInstance().getConfig().getBoolean(DefaultConfig.REPLANT_FROM_LEAVES))
|
||||
TreeReplant.leafFallReplant(fallingBlock);
|
||||
if (fileConfiguration.getBoolean(DefaultConfig.DAMAGE_PLAYERS))
|
||||
TreeEntityDamage.runDamage(fallingBlock);
|
||||
if (fileConfiguration.getBoolean(DefaultConfig.CUSTOM_AUDIO))
|
||||
TreeSounds.fallNoise(fallingBlock, counter);
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
}.runTaskTimer(plugin, 0, 1);
|
||||
@ -120,22 +224,49 @@ public class TreeFallAnimation {
|
||||
}
|
||||
|
||||
/*
|
||||
Since the block accelerates as it falls, increase the search radius the longer it has been falling for
|
||||
Catch tree blocks falling down
|
||||
*/
|
||||
private static boolean hasNearbySolidBlock(FallingBlock fallingBlock) {
|
||||
@EventHandler
|
||||
public void blockDrop(EntityChangeBlockEvent event) {
|
||||
|
||||
if (!fallingBlock.getLocation().clone().subtract(new Vector(0, 1, 0)).getBlock().getType().equals(Material.AIR))
|
||||
return true;
|
||||
if (!(event.getEntity() instanceof FallingBlock)) return;
|
||||
if (!isInTreeFallInstance((FallingBlock) event.getEntity())) return;
|
||||
|
||||
event.setCancelled(true);
|
||||
|
||||
FallingBlock fallingBlock = (FallingBlock) event.getEntity();
|
||||
|
||||
runFallingBlockImpact(fallingBlock);
|
||||
|
||||
}
|
||||
|
||||
private void runFallingBlockImpact(FallingBlock fallingBlock){
|
||||
|
||||
TreeFallAnimation treeFallAnimation = getTreeFallAnimation(fallingBlock);
|
||||
treeFallAnimation.unregisterFallingBlock(fallingBlock);
|
||||
if (treeFallAnimation.getAllFallingBlocks().isEmpty())
|
||||
unregisterTreeFallAnimation();
|
||||
|
||||
UltimateTimber plugin = UltimateTimber.getInstance();
|
||||
FileConfiguration fileConfiguration = plugin.getConfig();
|
||||
|
||||
/*
|
||||
Lower comparative intensity by predicting the blocks through which the falling block will pass by by checking
|
||||
its velocity
|
||||
Run block fall aftermath
|
||||
*/
|
||||
Location predictedLocation = fallingBlock.getLocation().clone().add(fallingBlock.getVelocity().multiply(2));
|
||||
TreeLoot.convertFallingBlock(fallingBlock, treeFallAnimation.hasBonusLoot(), treeFallAnimation.hasSilkTouch());
|
||||
if (UltimateTimber.getInstance().getConfig().getBoolean(DefaultConfig.REPLANT_FROM_LEAVES))
|
||||
TreeReplant.leafFallReplant(fallingBlock);
|
||||
if (fileConfiguration.getBoolean(DefaultConfig.DAMAGE_PLAYERS))
|
||||
TreeEntityDamage.runDamage(fallingBlock);
|
||||
if (fileConfiguration.getBoolean(DefaultConfig.CUSTOM_AUDIO))
|
||||
TreeSounds.fallNoise(fallingBlock);
|
||||
|
||||
if (predictedLocation.getY() < 1) return true;
|
||||
fallingBlock.getLocation().getWorld().spawnParticle(Particle.SMOKE_LARGE, fallingBlock.getLocation(), 3, 0.2, 0.2, 0.2, 0.05);
|
||||
|
||||
return !predictedLocation.getBlock().getType().equals(Material.AIR);
|
||||
/*
|
||||
Make sure the falling block gets culled
|
||||
*/
|
||||
fallingBlock.remove();
|
||||
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,8 @@ public class TreeFallEvent implements Listener {
|
||||
AxeDurability.adjustAxeDamage(blocks, event.getPlayer());
|
||||
if (fileConfiguration.getBoolean(DefaultConfig.CUSTOM_AUDIO))
|
||||
TreeSounds.tipOverNoise(event.getBlock().getLocation());
|
||||
TreeFallAnimation.startAnimation(event.getBlock(), blocks, event.getPlayer());
|
||||
TreeFallAnimation treeFallAnimation = new TreeFallAnimation();
|
||||
treeFallAnimation.startAnimation(event.getBlock(), blocks, event.getPlayer());
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,14 @@
|
||||
package com.songoda.ultimatetimber.treefall;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.FallingBlock;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class TreeLoot {
|
||||
|
||||
public static void convertFallingBlock(FallingBlock fallingBlock, Player player) {
|
||||
public static void convertFallingBlock(FallingBlock fallingBlock, boolean hasBonusLoot, boolean hasSilkTouch) {
|
||||
|
||||
Material material;
|
||||
|
||||
@ -42,28 +40,29 @@ public class TreeLoot {
|
||||
if (material.equals(Material.VINE))
|
||||
return;
|
||||
|
||||
if (player.getInventory().getItemInMainHand().getType().equals(Material.DIAMOND_AXE) ||
|
||||
player.getInventory().getItemInMainHand().getType().equals(Material.GOLDEN_AXE) ||
|
||||
player.getInventory().getItemInMainHand().getType().equals(Material.IRON_AXE) ||
|
||||
player.getInventory().getItemInMainHand().getType().equals(Material.STONE_AXE) ||
|
||||
player.getInventory().getItemInMainHand().getType().equals(Material.WOODEN_AXE))
|
||||
if (player.getInventory().getItemInMainHand().getEnchantments().containsKey(Enchantment.SILK_TOUCH))
|
||||
fallingBlock.getWorld().dropItem(fallingBlock.getLocation(), new ItemStack(fallingBlock.getBlockData().getMaterial(), 1));
|
||||
if (hasSilkTouch) {
|
||||
if (hasBonusLoot)
|
||||
fallingBlock.getWorld().dropItem(fallingBlock.getLocation(), new ItemStack(material, 1));
|
||||
fallingBlock.getWorld().dropItem(fallingBlock.getLocation(), new ItemStack(fallingBlock.getBlockData().getMaterial(), 1));
|
||||
return;
|
||||
}
|
||||
|
||||
if (material.equals(Material.ACACIA_SAPLING) ||
|
||||
material.equals(Material.BIRCH_SAPLING) ||
|
||||
material.equals(Material.DARK_OAK_SAPLING) ||
|
||||
material.equals(Material.JUNGLE_SAPLING) ||
|
||||
material.equals(Material.OAK_SAPLING) ||
|
||||
material.equals(Material.SPRUCE_SAPLING))
|
||||
material.equals(Material.SPRUCE_SAPLING)) {
|
||||
if (ThreadLocalRandom.current().nextDouble() < 0.05) {
|
||||
if (player.hasPermission("ultimatetimber.bonusloot"))
|
||||
if (hasBonusLoot)
|
||||
fallingBlock.getWorld().dropItem(fallingBlock.getLocation(), new ItemStack(material, 1));
|
||||
fallingBlock.getWorld().dropItem(fallingBlock.getLocation(), new ItemStack(material, 1));
|
||||
return;
|
||||
}
|
||||
} else return;
|
||||
}
|
||||
|
||||
if (player.hasPermission("ultimatetimber.bonusloot"))
|
||||
|
||||
if (hasBonusLoot)
|
||||
fallingBlock.getWorld().dropItem(fallingBlock.getLocation(), new ItemStack(material, 1));
|
||||
fallingBlock.getWorld().dropItem(fallingBlock.getLocation(), new ItemStack(material, 1));
|
||||
|
||||
|
@ -12,8 +12,8 @@ public class TreeSounds {
|
||||
|
||||
}
|
||||
|
||||
public static void fallNoise(FallingBlock fallingBlock, int counter) {
|
||||
if (counter < 20)
|
||||
public static void fallNoise(FallingBlock fallingBlock) {
|
||||
if (fallingBlock.getTicksLived() < 20)
|
||||
fallingBlock.getWorld().playSound(fallingBlock.getLocation(), Sound.BLOCK_ANVIL_FALL, 3F, 0.1F);
|
||||
else
|
||||
fallingBlock.getWorld().playSound(fallingBlock.getLocation(), Sound.BLOCK_WOOD_FALL, 3F, 0.1F);
|
||||
|
@ -1,5 +1,5 @@
|
||||
name: UltimateTimber
|
||||
version: 0.0.3
|
||||
version: 0.0.4
|
||||
author: Songoda
|
||||
main: com.songoda.ultimatetimber.UltimateTimber
|
||||
api-version: 1.13
|
||||
@ -14,6 +14,7 @@ permissions:
|
||||
children:
|
||||
ultimatetimber.chop: true
|
||||
ultimatetimber.bonusloot: true
|
||||
ultimatetimber.reload: true
|
||||
ultimatetimber.chop:
|
||||
description: Allows players to trigger the trees toppling down effect
|
||||
default: op
|
||||
|
Loading…
Reference in New Issue
Block a user