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:
MagmaGuy 2018-11-06 20:18:16 +00:00
parent 920b437e6d
commit a235d3d803
8 changed files with 197 additions and 56 deletions

View File

@ -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>

View File

@ -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
*/

View File

@ -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()))

View File

@ -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();
}

View File

@ -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());
}

View File

@ -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));

View File

@ -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);

View File

@ -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