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:
MagmaGuy 2018-11-03 20:49:10 +00:00
commit 61cc2b4337
6 changed files with 388 additions and 0 deletions

70
pom.xml Normal file
View 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>

View 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;
}
}

View 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() {
}
}

View 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);
}
}

View File

View 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]