mirror of
https://github.com/songoda/UltimateTimber.git
synced 2024-11-29 05:16:29 +01:00
Version 0.0.1
- Initial commit of the TreeAssist recode - Added the animation - Added solid block detection - Added prototype drop mechanic - Added the config file (not fully hooked up to the filters yet)
This commit is contained in:
commit
61cc2b4337
70
pom.xml
Normal file
70
pom.xml
Normal file
@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>epictimber</groupId>
|
||||
<artifactId>EpicTimber</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<defaultGoal>clean resources:resources package</defaultGoal>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.6.2</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.3</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<!--Spigot API-->
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.13-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!--Bukkit API-->
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
<version>1.13-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
40
src/main/java/com/songoda/epictimber/DefaultConfig.java
Normal file
40
src/main/java/com/songoda/epictimber/DefaultConfig.java
Normal file
@ -0,0 +1,40 @@
|
||||
package com.songoda.epictimber;
|
||||
|
||||
import org.bukkit.configuration.Configuration;
|
||||
|
||||
public class DefaultConfig {
|
||||
|
||||
/*
|
||||
This value is just cached so it can easily and safely be accessed during runtime
|
||||
*/
|
||||
public static Configuration configuration;
|
||||
|
||||
/*
|
||||
Storing these values in final strings makes it so you can change the keys or refactor their names later on without
|
||||
ever having to alter any code directly.
|
||||
Also they are easier to refer to using an IDE.
|
||||
*/
|
||||
public static final String AXES_ONLY = "Only topple down trees cut down using axes";
|
||||
public static final String ACCURATE_AXE_DURABILITY = "Lower durability proportionately to the amount of blocks toppled down";
|
||||
public static final String CREATIVE_DISALLOWED = "Players in creative mode can't topple down trees";
|
||||
public static final String PERMISSIONS_ONLY = "Only allow players with the permission node to topple down trees";
|
||||
|
||||
|
||||
public static void initialize() {
|
||||
|
||||
Configuration newConfiguration = EpicTimber.plugin.getConfig();
|
||||
|
||||
newConfiguration.addDefault(AXES_ONLY, true);
|
||||
newConfiguration.addDefault(ACCURATE_AXE_DURABILITY, true);
|
||||
newConfiguration.addDefault(CREATIVE_DISALLOWED, true);
|
||||
newConfiguration.addDefault(PERMISSIONS_ONLY, true);
|
||||
|
||||
newConfiguration.options().copyDefaults(true);
|
||||
|
||||
EpicTimber.plugin.saveDefaultConfig();
|
||||
|
||||
configuration = newConfiguration;
|
||||
|
||||
}
|
||||
|
||||
}
|
38
src/main/java/com/songoda/epictimber/EpicTimber.java
Normal file
38
src/main/java/com/songoda/epictimber/EpicTimber.java
Normal file
@ -0,0 +1,38 @@
|
||||
package com.songoda.epictimber;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
/*
|
||||
Note: In this plugin, I have called the act of a tree falling over with pseudo-physics "toppling over". This is reflected
|
||||
in the documentation, config files and variable names.
|
||||
PS: MagmaGuy was here
|
||||
*/
|
||||
|
||||
public class EpicTimber extends JavaPlugin {
|
||||
|
||||
public static Plugin plugin;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
|
||||
plugin = this;
|
||||
/*
|
||||
Register the main event that handles toppling down trees
|
||||
*/
|
||||
Bukkit.getServer().getPluginManager().registerEvents(new TreeFallHandler(), this);
|
||||
|
||||
/*
|
||||
Initialize and cache config
|
||||
*/
|
||||
DefaultConfig.initialize();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
|
||||
}
|
||||
|
||||
}
|
230
src/main/java/com/songoda/epictimber/TreeFallHandler.java
Normal file
230
src/main/java/com/songoda/epictimber/TreeFallHandler.java
Normal file
@ -0,0 +1,230 @@
|
||||
package com.songoda.epictimber;
|
||||
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.FallingBlock;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class TreeFallHandler implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onTreeBreak(BlockBreakEvent event) {
|
||||
|
||||
if (event.isCancelled()) return;
|
||||
parseTree(event.getBlock(), event.getPlayer());
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Incorporate all checks that would disqualify this event from happening
|
||||
*/
|
||||
private static boolean eventIsValid(BlockBreakEvent event) {
|
||||
/*
|
||||
General catchers
|
||||
*/
|
||||
if (event.isCancelled()) return false;
|
||||
if (!validMaterials.contains(event.getBlock().getType())) return false;
|
||||
/*
|
||||
Config-based catchers
|
||||
*/
|
||||
if (DefaultConfig.configuration.getBoolean(DefaultConfig.CREATIVE_DISALLOWED) &&
|
||||
event.getPlayer().getGameMode().equals(GameMode.CREATIVE))
|
||||
return false;
|
||||
return !DefaultConfig.configuration.getBoolean(DefaultConfig.AXES_ONLY) ||
|
||||
(event.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.DIAMOND_AXE) ||
|
||||
event.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.GOLDEN_AXE) ||
|
||||
event.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.IRON_AXE) ||
|
||||
event.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.STONE_AXE) ||
|
||||
event.getPlayer().getInventory().getItemInMainHand().getType().equals(Material.WOODEN_AXE));
|
||||
}
|
||||
|
||||
/*
|
||||
Used to check if a tree is a tree
|
||||
*/
|
||||
private static List<Material> validMaterials = new ArrayList<>(Arrays.asList(
|
||||
Material.ACACIA_LOG,
|
||||
Material.BIRCH_LOG,
|
||||
Material.DARK_OAK_LOG,
|
||||
Material.JUNGLE_LOG,
|
||||
Material.OAK_LOG,
|
||||
Material.SPRUCE_LOG
|
||||
));
|
||||
|
||||
/*
|
||||
Used to limit the blocks that constitute a tree
|
||||
*/
|
||||
private static List<Material> validSurroundingMaterials = new ArrayList<>(Arrays.asList(
|
||||
Material.ACACIA_LEAVES,
|
||||
Material.BIRCH_LEAVES,
|
||||
Material.DARK_OAK_LEAVES,
|
||||
Material.JUNGLE_LEAVES,
|
||||
Material.OAK_LEAVES,
|
||||
Material.SPRUCE_LEAVES,
|
||||
Material.COCOA_BEANS
|
||||
));
|
||||
|
||||
private static void parseTree(Block block, Player player) {
|
||||
/*
|
||||
Check if material is valid
|
||||
*/
|
||||
if (!validMaterials.contains(block.getType())) return;
|
||||
|
||||
ArrayList<Block> blocks = new ArrayList<>();
|
||||
|
||||
boolean containsSecondaryBlock = false;
|
||||
|
||||
/*
|
||||
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
|
||||
*/
|
||||
int offset = 1;
|
||||
int maxHeight = 31; //make configurable
|
||||
|
||||
for (int i = 0; i < maxHeight; i++) {
|
||||
|
||||
if ((i + 1) % 3 == 0)
|
||||
offset++;
|
||||
|
||||
/*
|
||||
This expands the inverted search pyramid vertically
|
||||
*/
|
||||
int xOffset = -offset;
|
||||
for (int j = xOffset - 1; j < offset; j++) {
|
||||
|
||||
int zOffset = -offset;
|
||||
|
||||
for (int k = zOffset - 1; k < offset; k++) {
|
||||
|
||||
Block thisBlock = block.getLocation().clone().add(new Vector(xOffset, i, zOffset)).getBlock();
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
if (!thisBlock.getType().equals(block.getType()) &&
|
||||
!validSurroundingMaterials.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.WHITE_TULIP) &&
|
||||
!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))
|
||||
return;
|
||||
|
||||
if (validSurroundingMaterials.contains(thisBlock.getType()))
|
||||
containsSecondaryBlock = true;
|
||||
|
||||
if (!thisBlock.getType().equals(Material.AIR))
|
||||
blocks.add(thisBlock);
|
||||
|
||||
zOffset++;
|
||||
|
||||
}
|
||||
|
||||
xOffset++;
|
||||
|
||||
}
|
||||
|
||||
if (block.getLocation().clone().add(new Vector(0, i, 0)).getBlock().getType().equals(Material.AIR))
|
||||
if (i > 1)
|
||||
break;
|
||||
else
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
If there are no leaves, don't see it as a tree
|
||||
*/
|
||||
if (!containsSecondaryBlock) return;
|
||||
|
||||
toppleAnimation(block, blocks, player);
|
||||
|
||||
}
|
||||
|
||||
private static void toppleAnimation(Block originalBlock, ArrayList<Block> blocks, Player player) {
|
||||
|
||||
Vector velocityVector = originalBlock.getLocation().clone().subtract(player.getLocation().clone()).toVector().normalize().setY(0);
|
||||
|
||||
for (Block block : blocks) {
|
||||
|
||||
if (block.getType().equals(Material.AIR)) continue;
|
||||
|
||||
FallingBlock fallingBlock = block.getWorld().spawnFallingBlock(block.getLocation(), block.getBlockData());
|
||||
|
||||
/*
|
||||
Set tipping over effect
|
||||
The horizontal velocity going away from the player increases as the Y moves away from the player
|
||||
*/
|
||||
block.setType(Material.AIR);
|
||||
double multiplier = (block.getLocation().getY() - player.getLocation().getY()) * 0.1;
|
||||
fallingBlock.setVelocity(velocityVector.clone().multiply(multiplier));
|
||||
fallingBlock.setDropItem(true);
|
||||
fallingBlock.setGravity(false);
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fallingBlock.setGravity(true);
|
||||
}
|
||||
}.runTaskLater(EpicTimber.plugin, 5);
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fallingBlock.setVelocity(fallingBlock.getVelocity().subtract(new Vector(0, 0.05, 0)));
|
||||
if (hasNearbySolidBlock(fallingBlock)) {
|
||||
cancel();
|
||||
fallingBlock.getWorld().dropItem(fallingBlock.getLocation(), new ItemStack(fallingBlock.getBlockData().getMaterial(), 1));
|
||||
fallingBlock.remove();
|
||||
fallingBlock.getLocation().getWorld().spawnParticle(Particle.SMOKE_LARGE, fallingBlock.getLocation(), 3, 0.2, 0.2, 0.2, 0.05);
|
||||
}
|
||||
}
|
||||
}.runTaskTimer(EpicTimber.plugin, 0, 1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Since the block accelerates as it falls, increase the search radius the longer it has been falling for
|
||||
*/
|
||||
private static boolean hasNearbySolidBlock(FallingBlock fallingBlock) {
|
||||
|
||||
if (!fallingBlock.getLocation().subtract(new Vector(0, 1, 0)).getBlock().getType().equals(Material.AIR))
|
||||
return true;
|
||||
|
||||
/*
|
||||
Lower comparative intensity by predicting the blocks through which the falling block will pass by by checking
|
||||
its velocity
|
||||
*/
|
||||
Location predictedLocation = fallingBlock.getLocation().clone().add(fallingBlock.getVelocity());
|
||||
|
||||
return !predictedLocation.getBlock().getType().equals(Material.AIR);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
0
src/main/resources/config.yml
Normal file
0
src/main/resources/config.yml
Normal file
10
src/main/resources/plugin.yml
Normal file
10
src/main/resources/plugin.yml
Normal file
@ -0,0 +1,10 @@
|
||||
name: EpicTimber
|
||||
version: 0.0.1
|
||||
author: Songoda
|
||||
main: com.songoda.epictimber.EpicTimber
|
||||
api-version: 1.13
|
||||
commands:
|
||||
epictimber:
|
||||
description: Does something, probably
|
||||
usage: /epictimber
|
||||
aliases: [ep]
|
Loading…
Reference in New Issue
Block a user