mirror of
https://github.com/songoda/UltimateTimber.git
synced 2024-11-29 05:16:29 +01:00
Version 0.0.7
- Fixed tree parser's odd behaviors - Tree parser is now mostly non-static - Cleaned up code - Added more comments
This commit is contained in:
parent
54ab6c9690
commit
2773986039
2
pom.xml
2
pom.xml
@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>ultimatetimber</groupId>
|
||||
<artifactId>UltimateTimber</artifactId>
|
||||
<version>0.0.5</version>
|
||||
<version>0.0.7</version>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.songoda.ultimatetimber.treefall;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -8,11 +7,14 @@ import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.Damageable;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
public class AxeDurability {
|
||||
|
||||
/*
|
||||
This class handles all durability damage dealt to the axe used to chop down the tree, only takes into account
|
||||
wood blocks chopped down
|
||||
*/
|
||||
public static void adjustAxeDamage(LinkedHashSet<Block> blocks, Player player) {
|
||||
|
||||
if (!(player.getInventory().getItemInMainHand().getType().equals(Material.DIAMOND_AXE) ||
|
||||
|
@ -14,6 +14,13 @@ import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class CustomLoot {
|
||||
|
||||
/*
|
||||
This is a very simple config parser for items
|
||||
Each item is a new line in a list
|
||||
Each line includes the keywords "Material:" and "Chance:" seperated by a ","
|
||||
The chance is a percentage
|
||||
It throws specific errors on startup when an invalid configuration is detected
|
||||
*/
|
||||
private static HashMap<ItemStack, Double> itemMap = new HashMap<>();
|
||||
|
||||
public static void doCustomItemDrop(Location location) {
|
||||
|
@ -2,6 +2,7 @@ package com.songoda.ultimatetimber.treefall;
|
||||
|
||||
import com.songoda.ultimatetimber.UltimateTimber;
|
||||
import com.songoda.ultimatetimber.configurations.DefaultConfig;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
@ -15,7 +16,7 @@ public class EventFilter {
|
||||
*/
|
||||
public static boolean eventIsValid(BlockBreakEvent event) {
|
||||
UltimateTimber plugin = UltimateTimber.getInstance();
|
||||
|
||||
|
||||
/*
|
||||
General catchers
|
||||
*/
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.songoda.ultimatetimber.treefall;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
@ -46,142 +47,165 @@ public class TreeChecker {
|
||||
Material.RED_MUSHROOM_BLOCK
|
||||
));
|
||||
|
||||
public static LinkedHashSet<Block> parseTree(Block block, boolean isSourceBlock) {
|
||||
/*
|
||||
A list of materials found in a forest, allows the plugin to work in dense woods
|
||||
*/
|
||||
private static List<Material> forestMaterials = new ArrayList<>(Arrays.asList(
|
||||
Material.AIR,
|
||||
Material.CAVE_AIR,
|
||||
Material.VOID_AIR,
|
||||
Material.VINE,
|
||||
Material.ROSE_BUSH,
|
||||
Material.ORANGE_TULIP,
|
||||
Material.PINK_TULIP,
|
||||
Material.RED_TULIP,
|
||||
Material.POPPY,
|
||||
Material.WHITE_TULIP,
|
||||
Material.OXEYE_DAISY,
|
||||
Material.AZURE_BLUET,
|
||||
Material.BLUE_ORCHID,
|
||||
Material.ALLIUM,
|
||||
Material.DANDELION,
|
||||
Material.DANDELION_YELLOW,
|
||||
Material.LILAC,
|
||||
Material.PEONY,
|
||||
Material.TALL_GRASS,
|
||||
Material.FERN,
|
||||
Material.LARGE_FERN,
|
||||
Material.DEAD_BUSH,
|
||||
Material.BROWN_MUSHROOM,
|
||||
Material.RED_MUSHROOM,
|
||||
Material.GRASS,
|
||||
Material.SPRUCE_SAPLING,
|
||||
Material.OAK_SAPLING,
|
||||
Material.JUNGLE_SAPLING,
|
||||
Material.ACACIA_SAPLING,
|
||||
Material.BIRCH_SAPLING,
|
||||
Material.DARK_OAK_SAPLING,
|
||||
Material.DIRT,
|
||||
Material.COARSE_DIRT,
|
||||
Material.GRASS_BLOCK
|
||||
));
|
||||
|
||||
public LinkedHashSet<Block> validTreeHandler(Block block, boolean isSourceBlock) {
|
||||
|
||||
LinkedHashSet<Block> blocks = parseTree(block, isSourceBlock);
|
||||
|
||||
if (blocks == null)
|
||||
return null;
|
||||
|
||||
boolean containsLeaves = false;
|
||||
|
||||
for (Block localBlock : blocks)
|
||||
if (TreeChecker.validTreeMaterials.contains(localBlock.getType())) {
|
||||
containsLeaves = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!containsLeaves)
|
||||
return null;
|
||||
|
||||
return blocks;
|
||||
|
||||
}
|
||||
|
||||
public LinkedHashSet<Block> parseTree(Block block, boolean isSourceBlock) {
|
||||
|
||||
/*
|
||||
Check if material is valid
|
||||
Check if material is parsed by this plugin
|
||||
*/
|
||||
if (!validMaterials.contains(block.getType())) return null;
|
||||
|
||||
/*
|
||||
Check if block is surrounded by air (bottom blocks are)
|
||||
Every third block expand one block laterally until the main block line reaches air or the max height is reached
|
||||
offset determines the search radius aroudn the main trunk
|
||||
maxheight sets the maximum height the plugin will crawl through to find a tree
|
||||
*/
|
||||
int offset = 1;
|
||||
int offset = 0;
|
||||
int maxHeight = 31;
|
||||
|
||||
/*
|
||||
This is used to crawl the location up the tree
|
||||
centralBlockLocation is used to keep track of the main trunk
|
||||
originalMaterial keeps track of what log type the plugin is looking for
|
||||
*/
|
||||
Location blockLocation = block.getLocation().clone();
|
||||
Location centralBlockLocation = block.getLocation().clone();
|
||||
Material originalMaterial = block.getType();
|
||||
|
||||
for (int i = 0; i < maxHeight; i++) {
|
||||
|
||||
if ((i + 1) % 2 == 0 && offset < 6)
|
||||
/*
|
||||
Offset increases as it goes up the tree in order to cover the area a tree would take
|
||||
*/
|
||||
if (offset < 6)
|
||||
offset++;
|
||||
|
||||
/*
|
||||
This expands the inverted search pyramid vertically
|
||||
The search works in a reverse conical shape
|
||||
*/
|
||||
int xOffset = -offset;
|
||||
for (int j = xOffset; j < offset + 1; j++) {
|
||||
for (int x = -offset; x < offset + 1; x++) {
|
||||
|
||||
int zOffset = -offset;
|
||||
for (int z = -offset; z < offset + 1; z++) {
|
||||
|
||||
for (int k = zOffset; k < offset + 1; k++) {
|
||||
Block thisBlock = centralBlockLocation.clone().add(new Vector(x, 0, z)).getBlock();
|
||||
|
||||
Block thisBlock = blockLocation.clone().add(new Vector(xOffset, 0, zOffset)).getBlock();
|
||||
|
||||
if (allBlocks.contains(thisBlock)) continue;
|
||||
if (allBlocks.contains(thisBlock))
|
||||
continue;
|
||||
|
||||
/*
|
||||
This exclusion list should include everything you may find near trees as to not invalidate trees
|
||||
in natural forests and such
|
||||
Construction blocks aren't included because that would bust buildings.
|
||||
This adds a bit of tolerance for trees that exist on dirt ledges
|
||||
*/
|
||||
|
||||
if ((thisBlock.getType().equals(Material.DIRT) ||
|
||||
thisBlock.getType().equals(Material.COARSE_DIRT) ||
|
||||
thisBlock.getType().equals(Material.GRASS_BLOCK)) &&
|
||||
(i > 1) && isSourceBlock) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
Exclude anything that isn't a part of a tree or a forest to avoid destroying houses
|
||||
*/
|
||||
if (!thisBlock.getType().equals(originalMaterial) &&
|
||||
!validTreeMaterials.contains(thisBlock.getType()) &&
|
||||
!thisBlock.getType().equals(Material.AIR) &&
|
||||
!thisBlock.getType().equals(Material.VINE) &&
|
||||
!thisBlock.getType().equals(Material.ROSE_BUSH) &&
|
||||
!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.OXEYE_DAISY) &&
|
||||
!thisBlock.getType().equals(Material.AZURE_BLUET) &&
|
||||
!thisBlock.getType().equals(Material.BLUE_ORCHID) &&
|
||||
!thisBlock.getType().equals(Material.ALLIUM) &&
|
||||
!thisBlock.getType().equals(Material.DANDELION) &&
|
||||
!thisBlock.getType().equals(Material.DANDELION_YELLOW) &&
|
||||
!thisBlock.getType().equals(Material.LILAC) &&
|
||||
!thisBlock.getType().equals(Material.PEONY) &&
|
||||
!thisBlock.getType().equals(Material.TALL_GRASS) &&
|
||||
!thisBlock.getType().equals(Material.FERN) &&
|
||||
!thisBlock.getType().equals(Material.LARGE_FERN) &&
|
||||
!thisBlock.getType().equals(Material.DEAD_BUSH) &&
|
||||
!thisBlock.getType().equals(Material.BROWN_MUSHROOM) &&
|
||||
!thisBlock.getType().equals(Material.RED_MUSHROOM) &&
|
||||
!thisBlock.getType().equals(Material.GRASS) &&
|
||||
!thisBlock.getType().equals(Material.SPRUCE_SAPLING) &&
|
||||
!thisBlock.getType().equals(Material.OAK_SAPLING) &&
|
||||
!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.VOID_AIR) &&
|
||||
!thisBlock.getType().equals(Material.CAVE_AIR) &&
|
||||
!thisBlock.getType().equals(Material.DIRT) &&
|
||||
!thisBlock.getType().equals(Material.COARSE_DIRT) &&
|
||||
!thisBlock.getType().equals(Material.GRASS_BLOCK)) {
|
||||
|
||||
!forestMaterials.contains(thisBlock.getType()))
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!thisBlock.getType().equals(Material.AIR) &&
|
||||
!thisBlock.getType().equals(Material.CAVE_AIR) &&
|
||||
!thisBlock.getType().equals(Material.VOID_AIR) &&
|
||||
!thisBlock.getType().equals(Material.DIRT) &&
|
||||
!thisBlock.getType().equals(Material.COARSE_DIRT) &&
|
||||
!thisBlock.getType().equals(Material.GRASS_BLOCK)) {
|
||||
|
||||
/*
|
||||
This adds blocks to later be felled
|
||||
*/
|
||||
if (validMaterials.contains(thisBlock.getType()) || validTreeMaterials.contains(thisBlock.getType())) {
|
||||
allBlocks.add(thisBlock);
|
||||
}
|
||||
|
||||
zOffset++;
|
||||
|
||||
}
|
||||
|
||||
xOffset++;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Increment the height of the block location
|
||||
Continue crawling up the main trunk
|
||||
*/
|
||||
blockLocation.add(new Vector(0, 1, 0));
|
||||
centralBlockLocation.add(new Vector(0, 1, 0));
|
||||
|
||||
/*
|
||||
Detect if it's the end of the tree
|
||||
If a block above it continues the same material type as the original block, continue with that block as the
|
||||
new source block
|
||||
If it doesn't break the loop and return the blocks list
|
||||
If it doesn't and it's air or a leaf, scan for adjacent blocks to see if the tree continues in another
|
||||
direction. This is necessary for acacias and some of the wider tree variants.
|
||||
*/
|
||||
if (blockLocation.getBlock().getType().equals(Material.AIR) || validTreeMaterials.contains(blockLocation.getBlock().getType())) {
|
||||
if (centralBlockLocation.getBlock().getType().equals(Material.AIR) || validTreeMaterials.contains(centralBlockLocation.getBlock().getType())) {
|
||||
|
||||
if (isSourceBlock && blockLocation.clone().subtract(block.getLocation().clone()).getY() < 2)
|
||||
if (isSourceBlock && centralBlockLocation.clone().subtract(block.getLocation().clone()).getY() < 2)
|
||||
return null;
|
||||
|
||||
ArrayList<Block> newBlocks = scanNearbyBranching(originalMaterial, blockLocation);
|
||||
ArrayList<Block> newBlocks = scanNearbyBranching(originalMaterial, centralBlockLocation);
|
||||
if (newBlocks != null)
|
||||
for (Block newBlock : newBlocks) {
|
||||
LinkedHashSet<Block> newBlockList = parseTree(newBlock, false);
|
||||
if (newBlockList == null) {
|
||||
if (newBlockList == null)
|
||||
return null;
|
||||
} else {
|
||||
else
|
||||
allBlocks.addAll(newBlocks);
|
||||
}
|
||||
}
|
||||
else if (blockLocation.getBlock().getType().equals(Material.AIR))
|
||||
else if (centralBlockLocation.getBlock().getType().equals(Material.AIR))
|
||||
break;
|
||||
|
||||
}
|
||||
@ -192,12 +216,15 @@ public class TreeChecker {
|
||||
|
||||
}
|
||||
|
||||
private static LinkedHashSet<Block> allBlocks = new LinkedHashSet<>();
|
||||
/*
|
||||
This stores all the blocks returned later on
|
||||
*/
|
||||
private LinkedHashSet<Block> allBlocks = new LinkedHashSet<>();
|
||||
|
||||
/*
|
||||
Some trees veer to a side as they reach the top, this scans for blocks adjacent to the air block above the trunk
|
||||
This method scans for branching atop the tree when the crawled upon block of the tree trunk is either air or a leaf block
|
||||
*/
|
||||
private static ArrayList<Block> scanNearbyBranching(Material originalMaterial, Location location) {
|
||||
private ArrayList<Block> scanNearbyBranching(Material originalMaterial, Location location) {
|
||||
|
||||
ArrayList<Block> newBlocks = new ArrayList<>();
|
||||
|
||||
|
@ -2,6 +2,7 @@ package com.songoda.ultimatetimber.treefall;
|
||||
|
||||
import com.songoda.ultimatetimber.UltimateTimber;
|
||||
import com.songoda.ultimatetimber.configurations.DefaultConfig;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
@ -22,28 +23,20 @@ public class TreeFallEvent implements Listener {
|
||||
public void onTreeBreak(BlockBreakEvent event) {
|
||||
|
||||
if (!EventFilter.eventIsValid(event)) return;
|
||||
LinkedHashSet<Block> blocks = TreeChecker.parseTree(event.getBlock(), true);
|
||||
TreeChecker treeChecker = new TreeChecker();
|
||||
LinkedHashSet<Block> blocks = treeChecker.validTreeHandler(event.getBlock(), true);
|
||||
|
||||
/*
|
||||
Check if the list of blocks carried over from the tree parser contains everything you'd expect from a tree
|
||||
Previous list will be null if no valid tree is found
|
||||
*/
|
||||
if (blocks == null)
|
||||
return;
|
||||
|
||||
boolean containsLeaves = false;
|
||||
|
||||
for (Block block : blocks)
|
||||
if (TreeChecker.validTreeMaterials.contains(block.getType())) {
|
||||
containsLeaves = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!containsLeaves)
|
||||
return;
|
||||
|
||||
/*
|
||||
Everything beyond this point assumes that the tree was valid
|
||||
*/
|
||||
FileConfiguration fileConfiguration = UltimateTimber.getInstance().getConfig();
|
||||
|
||||
|
||||
if (fileConfiguration.getBoolean(DefaultConfig.ACCURATE_AXE_DURABILITY))
|
||||
AxeDurability.adjustAxeDamage(blocks, event.getPlayer());
|
||||
if (fileConfiguration.getBoolean(DefaultConfig.CUSTOM_AUDIO))
|
||||
|
@ -7,7 +7,7 @@ public class LeafToSaplingConverter {
|
||||
/*
|
||||
Defaults to returning the same material type that is fed into it
|
||||
*/
|
||||
public static Material convertLeaves(Material material){
|
||||
public static Material convertLeaves(Material material) {
|
||||
|
||||
switch (material) {
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
name: UltimateTimber
|
||||
version: 0.0.5
|
||||
version: 0.0.7
|
||||
author: Songoda
|
||||
main: com.songoda.ultimatetimber.UltimateTimber
|
||||
api-version: 1.13
|
||||
|
@ -1,5 +1,5 @@
|
||||
name: UltimateTimber
|
||||
version: 0.0.5
|
||||
version: 0.0.6
|
||||
author: Songoda
|
||||
main: com.songoda.ultimatetimber.UltimateTimber
|
||||
api-version: 1.13
|
||||
|
Loading…
Reference in New Issue
Block a user