Updated to standalone Core

This commit is contained in:
Fernando Pettinelli 2023-06-26 09:08:39 -04:00
parent e04a4af615
commit 21cbc470f6
50 changed files with 1113 additions and 1810 deletions

View File

@ -1,29 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.songoda</groupId>
<artifactId>UltimateTimber</artifactId>
<version>2.3.7</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>Core</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.18-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.songoda</groupId>
<artifactId>SongodaCore</artifactId>
<version>2.6.19</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,123 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.songoda</groupId>
<artifactId>UltimateTimber</artifactId>
<version>2.3.7</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>Plugin</artifactId>
<packaging>jar</packaging>
<build>
<finalName>${project.parent.artifactId}-${project.parent.version}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<showDeprecation>false</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>com.google.code.maven-replacer-plugin</groupId>
<artifactId>replacer</artifactId>
<version>1.5.3</version>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>replace</goal>
</goals>
</execution>
</executions>
<configuration>
<file>${project.build.directory}/classes/plugin.yml</file>
<replacements>
<replacement>
<token>maven-version-number</token>
<value>${project.version}</value>
</replacement>
</replacements>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<id>shaded</id>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedArtifactAttached>false</shadedArtifactAttached>
<createDependencyReducedPom>false</createDependencyReducedPom>
<minimizeJar>true</minimizeJar>
<artifactSet>
<includes>
<include>com.songoda:SongodaCore</include>
<include>com.songoda:Core</include>
</includes>
</artifactSet>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
<filter>
<artifact>com.songoda:Lootables</artifact>
<excludes>
<exclude>com/songoda/core/**</exclude>
</excludes>
</filter>
</filters>
<relocations>
<relocation>
<pattern>com.songoda.core</pattern>
<shadedPattern>${project.groupId}.ultimatetimber.core</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.18-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>Core</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,27 +0,0 @@
# General Messages
general:
nametag:
prefix: '&8[&6UltimateTimber&8] '
nopermission: '&cYou don''t have permission for that!'
# Command Messages
command:
reload:
description: 'Reloads the config.'
reloaded: '&7Configuration and locale files have been reloaded.'
toggle:
description: 'Toggles your chopping mode'
enabled: '&7Chopping Mode: &aEnabled'
disabled: '&7Chopping Mode: &cDisabled'
give:
not-a-player: '&cNot a player.'
given: '&fGiven to player &a%player%'
no-axe: '&cAxe could not be loaded.'
# Event Messages
event:
'on':
cooldown: '&eYou are on cooldown and cannot topple trees right now.'

View File

@ -1,31 +0,0 @@
name: UltimateTimber
version: maven-version-number
authors: [Songoda]
main: com.songoda.ultimatetimber.UltimateTimber
api-version: 1.13
softdepend: [mcMMO, Jobs, CoreProtect]
commands:
ut:
description: Reloads the configuration file
usage: /ultimatetimber reload
aliases: [ultimatetimber]
permissions:
ultimatetimber.*:
description: Inherits all plugin permissions
children:
ultimatetimber.chop: true
ultimatetimber.bonusloot: true
ultimatetimber.reload: true
ultimatetimber.bypasscooldown: true
ultimatetimber.chop:
description: Allows players to trigger the trees toppling down effect
default: op
ultimatetimber.bonusloot:
description: Doubles the loot obtained from trees
default: op
ultimatetimber.reload:
description: Reloads the configuration file
default: op
ultimatetimber.bypasscooldown:
description: Allows a player to bypass the tree topple cooldown
default: op

View File

@ -1,200 +0,0 @@
package com.songoda.ultimatetimber;
import com.songoda.core.SongodaCore;
import com.songoda.core.SongodaPlugin;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.configuration.Config;
import com.songoda.core.hooks.LogManager;
import com.songoda.ultimatetimber.commands.CommandGiveAxe;
import com.songoda.ultimatetimber.commands.CommandReload;
import com.songoda.ultimatetimber.commands.CommandToggle;
import com.songoda.ultimatetimber.manager.ChoppingManager;
import com.songoda.ultimatetimber.manager.ConfigurationManager;
import com.songoda.ultimatetimber.manager.Manager;
import com.songoda.ultimatetimber.manager.PlacedBlockManager;
import com.songoda.ultimatetimber.manager.SaplingManager;
import com.songoda.ultimatetimber.manager.TreeAnimationManager;
import com.songoda.ultimatetimber.manager.TreeDefinitionManager;
import com.songoda.ultimatetimber.manager.TreeDetectionManager;
import com.songoda.ultimatetimber.manager.TreeFallManager;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class UltimateTimber extends SongodaPlugin {
private static UltimateTimber INSTANCE;
private Set<Manager> managers;
private ChoppingManager choppingManager;
private ConfigurationManager configurationManager;
private com.songoda.core.commands.CommandManager commandManager;
private PlacedBlockManager placedBlockManager;
private SaplingManager saplingManager;
private TreeAnimationManager treeAnimationManager;
private TreeDefinitionManager treeDefinitionManager;
private TreeDetectionManager treeDetectionManager;
private TreeFallManager treeFallManager;
public static UltimateTimber getInstance() {
return INSTANCE;
}
@Override
public void onPluginLoad() {
INSTANCE = this;
}
@Override
public void onPluginEnable() {
// Run Songoda Updater
SongodaCore.registerPlugin(this, 18, CompatibleMaterial.IRON_AXE);
// Load hooks
LogManager.load();
// Setup plugin commands
this.commandManager = new com.songoda.core.commands.CommandManager(this);
this.commandManager.addMainCommand("ut")
.addSubCommands(
new CommandReload(this),
new CommandToggle(this),
new CommandGiveAxe(this)
);
// Register managers
this.managers = new HashSet<>();
this.choppingManager = this.registerManager(ChoppingManager.class);
this.configurationManager = new ConfigurationManager(this);
this.placedBlockManager = this.registerManager(PlacedBlockManager.class);
this.saplingManager = this.registerManager(SaplingManager.class);
this.treeAnimationManager = this.registerManager(TreeAnimationManager.class);
this.treeDefinitionManager = this.registerManager(TreeDefinitionManager.class);
this.treeDetectionManager = this.registerManager(TreeDetectionManager.class);
this.treeFallManager = this.registerManager(TreeFallManager.class);
this.reloadConfig();
}
@Override
public void onPluginDisable() {
this.disable();
}
@Override
public void onDataLoad() {
}
@Override
public void onConfigReload() {
this.configurationManager.reload();
this.managers.forEach(Manager::reload);
this.setLocale(getConfig().getString("locale"), true);
}
@Override
public List<Config> getExtraConfig() {
return null;
}
/**
* Disables most of the plugin
*/
public void disable() {
this.configurationManager.disable();
this.managers.forEach(Manager::disable);
}
/**
* Registers a manager
*
* @param managerClass The class of the manager to create a new instance of
* @param <T> extends Manager
* @return A new instance of the given manager class
*/
private <T extends Manager> T registerManager(Class<T> managerClass) {
try {
T newManager = managerClass.getConstructor(UltimateTimber.class).newInstance(this);
this.managers.add(newManager);
return newManager;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
/**
* Gets the chopping manager
*
* @return The ChoppingManager instance
*/
public ChoppingManager getChoppingManager() {
return this.choppingManager;
}
/**
* Gets the configuration manager
*
* @return The ConfigurationManager instance
*/
public ConfigurationManager getConfigurationManager() {
return this.configurationManager;
}
/**
* Gets the placed block manager
*
* @return The PlacedBlockManager instance
*/
public PlacedBlockManager getPlacedBlockManager() {
return this.placedBlockManager;
}
/**
* Gets the sapling manager
*
* @return The SaplingManager instance
*/
public SaplingManager getSaplingManager() {
return this.saplingManager;
}
/**
* Gets the tree animation manager
*
* @return The TreeAnimationManager instance
*/
public TreeAnimationManager getTreeAnimationManager() {
return this.treeAnimationManager;
}
/**
* Gets the tree definition manager
*
* @return The TreeDefinitionManager instance
*/
public TreeDefinitionManager getTreeDefinitionManager() {
return this.treeDefinitionManager;
}
/**
* Gets the tree detection manager
*
* @return The TreeDetectionManager instance
*/
public TreeDetectionManager getTreeDetectionManager() {
return this.treeDetectionManager;
}
/**
* Gets the tree fall manager
*
* @return The TreeFallManager instance
*/
public TreeFallManager getTreeFallManager() {
return this.treeFallManager;
}
}

View File

@ -1,80 +0,0 @@
package com.songoda.ultimatetimber.commands;
import com.songoda.core.commands.AbstractCommand;
import com.songoda.core.utils.PlayerUtils;
import com.songoda.ultimatetimber.UltimateTimber;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.List;
public class CommandGiveAxe extends AbstractCommand {
private final UltimateTimber plugin;
public CommandGiveAxe(UltimateTimber plugin) {
super(CommandType.CONSOLE_OK, true, "give");
this.plugin = plugin;
}
@Override
protected ReturnType runCommand(CommandSender sender, String... args) {
if (args.length < 1)
return ReturnType.SYNTAX_ERROR;
Player player = Bukkit.getPlayer(args[0]);
if (player == null) {
if (args[0].trim().equalsIgnoreCase("me")) {
if (!(sender instanceof Player))
return ReturnType.NEEDS_PLAYER;
player = (Player) sender;
} else {
plugin.getLocale().getMessageOrDefault("command.give.not-a-player", "&cNot a player.")
.sendPrefixedMessage(sender);
return ReturnType.FAILURE;
}
}
ItemStack axe = plugin.getTreeDefinitionManager().getRequiredAxe();
if (axe == null) {
plugin.getLocale().getMessageOrDefault("command.give.no-axe", "&cThe axe could not be loaded.")
.sendPrefixedMessage(sender);
return ReturnType.FAILURE;
}
player.getInventory().addItem(axe);
plugin.getLocale().getMessageOrDefault("command.give.given", "&fAxe given to &a%player%")
.processPlaceholder("player", player.getName())
.sendPrefixedMessage(sender);
return ReturnType.SUCCESS;
}
@Override
protected List<String> onTab(CommandSender commandSender, String... args) {
List<String> suggestions = null;
if (args.length == 1) {
suggestions = PlayerUtils.getVisiblePlayerNames(commandSender, args[0]);
suggestions.add("me");
}
return suggestions;
}
@Override
public String getPermissionNode() {
return "ultimatetimber.give";
}
@Override
public String getSyntax() {
return "give <player/me>";
}
@Override
public String getDescription() {
return "Give a required axe.";
}
}

View File

@ -1,45 +0,0 @@
package com.songoda.ultimatetimber.commands;
import com.songoda.core.commands.AbstractCommand;
import com.songoda.ultimatetimber.UltimateTimber;
import org.bukkit.command.CommandSender;
import java.util.List;
public class CommandReload extends AbstractCommand {
private final UltimateTimber plugin;
public CommandReload(UltimateTimber plugin) {
super(CommandType.CONSOLE_OK, "reload");
this.plugin = plugin;
}
@Override
protected ReturnType runCommand(CommandSender sender, String... args) {
plugin.reloadConfig();
plugin.getLocale().getMessage("command.reload.reloaded").sendPrefixedMessage(sender);
return ReturnType.SUCCESS;
}
@Override
protected List<String> onTab(CommandSender sender, String... args) {
return null;
}
@Override
public String getPermissionNode() {
return "ultimatetimber.reload";
}
@Override
public String getSyntax() {
return "reload";
}
@Override
public String getDescription() {
return plugin.getLocale().getMessage("command.reload.description").getMessage();
}
}

View File

@ -1,49 +0,0 @@
package com.songoda.ultimatetimber.commands;
import com.songoda.core.commands.AbstractCommand;
import com.songoda.ultimatetimber.UltimateTimber;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.List;
public class CommandToggle extends AbstractCommand {
private final UltimateTimber plugin;
public CommandToggle(UltimateTimber plugin) {
super(CommandType.CONSOLE_OK, "toggle");
this.plugin = plugin;
}
@Override
protected ReturnType runCommand(CommandSender sender, String... args) {
if (UltimateTimber.getInstance().getChoppingManager().togglePlayer((Player) sender)) {
plugin.getLocale().getMessage("command.toggle.enabled").sendPrefixedMessage(sender);
} else {
plugin.getLocale().getMessage("command.toggle.disabled").sendPrefixedMessage(sender);
}
return ReturnType.SUCCESS;
}
@Override
protected List<String> onTab(CommandSender sender, String... args) {
return null;
}
@Override
public String getPermissionNode() {
return "ultimatetimber.toggle";
}
@Override
public String getSyntax() {
return "toggle";
}
@Override
public String getDescription() {
return plugin.getLocale().getMessage("command.toggle.description").getMessage();
}
}

View File

@ -1,40 +0,0 @@
package com.songoda.ultimatetimber.events;
import com.songoda.ultimatetimber.tree.DetectedTree;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
/**
* Called when a tree will fall
*/
public class TreeFallEvent extends TreeEvent implements Cancellable {
private boolean cancelled = false;
public TreeFallEvent(Player player, DetectedTree detectedTree) {
super(player, detectedTree);
}
private static final HandlerList handlers = new HandlerList();
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public boolean isCancelled() {
return this.cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
}

View File

@ -1,94 +0,0 @@
package com.songoda.ultimatetimber.manager;
import com.songoda.ultimatetimber.UltimateTimber;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
public class ChoppingManager extends Manager {
private final Set<UUID> disabledPlayers;
private final Map<UUID, Boolean> cooldownedPlayers;
private boolean useCooldown;
private int cooldownAmount;
public ChoppingManager(UltimateTimber ultimateTimber) {
super(ultimateTimber);
this.disabledPlayers = new HashSet<>();
this.cooldownedPlayers = new HashMap<>();
}
@Override
public void reload() {
this.useCooldown = ConfigurationManager.Setting.PLAYER_TREE_TOPPLE_COOLDOWN.getBoolean();
this.cooldownAmount = ConfigurationManager.Setting.PLAYER_TREE_TOPPLE_COOLDOWN_LENGTH.getInt();
}
@Override
public void disable() {
this.disabledPlayers.clear();
this.cooldownedPlayers.clear();
}
/**
* Toggles a player's chopping status
*
* @param player The player to toggle
* @return True if the player has chopping enabled, or false if they have it disabled
*/
public boolean togglePlayer(Player player) {
if (this.disabledPlayers.contains(player.getUniqueId())) {
this.disabledPlayers.remove(player.getUniqueId());
return true;
} else {
this.disabledPlayers.add(player.getUniqueId());
return false;
}
}
/**
* Checks if a player has chopping enabled
*
* @param player The player to check
* @return True if the player has chopping enabled, or false if they have it disabled
*/
public boolean isChopping(Player player) {
return !this.disabledPlayers.contains(player.getUniqueId());
}
/**
* Sets a player into cooldown
*
* @param player The player to cooldown
*/
public void cooldownPlayer(Player player) {
if (!this.useCooldown || player.hasPermission("ultimatetimber.bypasscooldown"))
return;
this.cooldownedPlayers.put(player.getUniqueId(), false);
Bukkit.getScheduler().scheduleSyncDelayedTask(UltimateTimber.getInstance(), () ->
this.cooldownedPlayers.remove(player.getUniqueId()), this.cooldownAmount * 20L);
}
/**
* Checks if a player is in cooldown
*
* @param player The player to check
* @return True if the player can topple trees, otherwise false
*/
public boolean isInCooldown(Player player) {
boolean cooldowned = this.useCooldown && this.cooldownedPlayers.containsKey(player.getUniqueId());
if (cooldowned && !this.cooldownedPlayers.get(player.getUniqueId())) {
this.plugin.getLocale().getMessage("event.on.cooldown").sendPrefixedMessage(player);
this.cooldownedPlayers.replace(player.getUniqueId(), true);
}
return cooldowned;
}
}

View File

@ -1,210 +0,0 @@
package com.songoda.ultimatetimber.manager;
import com.songoda.ultimatetimber.UltimateTimber;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.util.List;
public class ConfigurationManager extends Manager {
public enum Setting {
SERVER_TYPE(SettingType.STRING),
LOCALE(SettingType.STRING),
DISABLED_WORLDS(SettingType.STRING_LIST),
MAX_LOGS_PER_CHOP(SettingType.INT),
DESTROY_LEAVES(SettingType.BOOLEAN),
LEAVES_REQUIRED_FOR_TREE(SettingType.INT),
REALISTIC_TOOL_DAMAGE(SettingType.BOOLEAN),
PROTECT_TOOL(SettingType.BOOLEAN),
APPLY_SILK_TOUCH(SettingType.BOOLEAN),
APPLY_SILK_TOUCH_TOOL_DAMAGE(SettingType.BOOLEAN),
ALWAYS_REPLANT_SAPLING(SettingType.BOOLEAN),
BREAK_ENTIRE_TREE_BASE(SettingType.BOOLEAN),
DESTROY_INITIATED_BLOCK(SettingType.BOOLEAN),
ONLY_DETECT_LOGS_UPWARDS(SettingType.BOOLEAN),
ONLY_TOPPLE_WHILE(SettingType.STRING),
ALLOW_CREATIVE_MODE(SettingType.BOOLEAN),
REQUIRE_CHOP_PERMISSION(SettingType.BOOLEAN),
PLAYER_TREE_TOPPLE_COOLDOWN(SettingType.BOOLEAN),
PLAYER_TREE_TOPPLE_COOLDOWN_LENGTH(SettingType.INT),
IGNORE_REQUIRED_TOOLS(SettingType.BOOLEAN),
REPLANT_SAPLINGS(SettingType.BOOLEAN),
REPLANT_SAPLINGS_COOLDOWN(SettingType.INT),
FALLING_BLOCKS_REPLANT_SAPLINGS(SettingType.BOOLEAN),
FALLING_BLOCKS_REPLANT_SAPLINGS_CHANCE(SettingType.DOUBLE),
FALLING_BLOCKS_DEAL_DAMAGE(SettingType.BOOLEAN),
FALLING_BLOCK_DAMAGE(SettingType.INT),
ADD_ITEMS_TO_INVENTORY(SettingType.BOOLEAN),
USE_CUSTOM_SOUNDS(SettingType.BOOLEAN),
USE_CUSTOM_PARTICLES(SettingType.BOOLEAN),
BONUS_LOOT_MULTIPLIER(SettingType.DOUBLE),
IGNORE_PLACED_BLOCKS(SettingType.BOOLEAN),
IGNORE_PLACED_BLOCKS_MEMORY_SIZE(SettingType.INT),
HOOKS_APPLY_EXPERIENCE(SettingType.BOOLEAN),
HOOKS_APPLY_EXTRA_DROPS(SettingType.BOOLEAN),
HOOKS_REQUIRE_ABILITY_ACTIVE(SettingType.BOOLEAN),
TREE_ANIMATION_TYPE(SettingType.STRING),
SCATTER_TREE_BLOCKS_ON_GROUND(SettingType.BOOLEAN),
FRAGILE_BLOCKS(SettingType.STRING_LIST);
private SettingType settingType;
private Object value = null;
Setting(SettingType settingType) {
this.settingType = settingType;
}
/**
* Gets the setting as a boolean
*
* @return The setting as a boolean
*/
public boolean getBoolean() {
this.loadValue();
return (boolean) this.value;
}
/**
* Gets the setting as an int
*
* @return The setting as an int
*/
public int getInt() {
this.loadValue();
return (int) this.value;
}
/**
* Gets the setting as a double
*
* @return The setting a double
*/
public double getDouble() {
this.loadValue();
return (double) this.value;
}
/**
* Gets the setting as a String
*
* @return The setting a String
*/
public String getString() {
this.loadValue();
return (String) this.value;
}
/**
* Gets the setting as a string list
*
* @return The setting as a string list
*/
@SuppressWarnings("unchecked")
public List<String> getStringList() {
this.loadValue();
return (List<String>) this.value;
}
/**
* Resets the cached value
*/
public void reset() {
this.value = null;
}
/**
* Loads the value from the config and caches it if it isn't set yet
*/
private void loadValue() {
if (this.value != null)
return;
FileConfiguration config = UltimateTimber.getInstance().getConfigurationManager().getConfig();
switch (this.settingType) {
case BOOLEAN:
this.value = config.getBoolean(this.getNameAsKey());
break;
case INT:
this.value = config.getInt(this.getNameAsKey());
break;
case DOUBLE:
this.value = config.getDouble(this.getNameAsKey());
break;
case STRING:
this.value = config.getString(this.getNameAsKey());
break;
case STRING_LIST:
this.value = config.getStringList(this.getNameAsKey());
break;
}
}
/**
* Gets the name of this Setting as a FileConfiguration-compatible key
*
* @return The key for a FileConfiguration
*/
private String getNameAsKey() {
return this.name().replace("_", "-").toLowerCase();
}
}
private enum SettingType {
BOOLEAN,
INT,
DOUBLE,
STRING,
STRING_LIST
}
private YamlConfiguration configuration;
public ConfigurationManager(UltimateTimber ultimateTimber) {
super(ultimateTimber);
}
@Override
public void reload() {
this.plugin.getCoreConfig().load();
File configFile = new File(this.plugin.getDataFolder() + "/config.yml");
// If an old config still exists, rename it so it doesn't interfere
if (configFile.exists() && this.plugin.getConfig().get("server-type") == null) {
File renameConfigTo = new File(this.plugin.getDataFolder() + "/config-old.yml");
configFile.renameTo(renameConfigTo);
configFile = new File(this.plugin.getDataFolder() + "/config.yml");
}
// Create the new config if it doesn't exist
if (!configFile.exists()) {
String newConfigName = "config.yml";
File newConfigFile = new File(this.plugin.getDataFolder() + "/" + newConfigName);
this.plugin.saveResource(newConfigName, false);
newConfigFile.renameTo(configFile);
}
this.configuration = YamlConfiguration.loadConfiguration(configFile);
for (Setting setting : Setting.values())
setting.reset();
}
@Override
public void disable() {
for (Setting setting : Setting.values())
setting.reset();
}
/**
* Gets the config.yml as a YamlConfiguration
*
* @return The YamlConfiguration of the config.yml
*/
public YamlConfiguration getConfig() {
return this.configuration;
}
}

View File

@ -1,23 +0,0 @@
package com.songoda.ultimatetimber.manager;
import com.songoda.ultimatetimber.UltimateTimber;
public abstract class Manager {
protected UltimateTimber plugin;
Manager(UltimateTimber plugin) {
this.plugin = plugin;
}
/**
* Reloads the Manager's settings
*/
public abstract void reload();
/**
* Cleans up the Manager's resources
*/
public abstract void disable();
}

193
pom.xml
View File

@ -1,34 +1,80 @@
<project xmlns="http://maven.apache.org/POM/4.0.0">
<?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>com.songoda</groupId>
<groupId>com.craftaro</groupId>
<artifactId>UltimateTimber</artifactId>
<version>2.3.7</version>
<packaging>pom</packaging>
<version>3.0.0</version>
<!-- Run 'mvn versions:set -DgenerateBackupPoms=false -DnewVersion=X.Y.Z' to update version recursively -->
<name>UltimateTimber</name>
<modules>
<module>UltimateTimber/Core</module>
<module>UltimateTimber/Plugin</module>
</modules>
<properties>
<java.version>11</java.version>
<java.release>11</java.release>
<repositories>
<repository>
<id>public</id>
<url>https://repo.songoda.com/repository/public/</url>
</repository>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<release>${java.release}</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>${project.name}-${project.version}</finalName>
<createDependencyReducedPom>false</createDependencyReducedPom>
<minimizeJar>true</minimizeJar>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/**</exclude>
<exclude>LICENSE</exclude>
<exclude>LICENSE.**</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<pluginRepositories>
<pluginRepository>
@ -37,79 +83,38 @@
</pluginRepository>
</pluginRepositories>
<repositories>
<repository>
<id>spigotmc-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<build>
<defaultGoal>clean install</defaultGoal>
<sourceDirectory>src</sourceDirectory>
<testSourceDirectory>test</testSourceDirectory>
<repository>
<id>songoda-public</id>
<url>https://repo.songoda.com/repository/public/</url>
</repository>
</repositories>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.19.3-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<scope>provided</scope>
</dependency>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
<inherited>false</inherited>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
<configuration>
<outputDirectory>jars</outputDirectory>
<stripVersion>true</stripVersion>
<artifactItems>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>McMMO</artifactId>
<version>${project.version}</version>
</artifactItem>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>Plugin</artifactId>
<version>${project.version}</version>
</artifactItem>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>Core</artifactId>
<version>${project.version}</version>
</artifactItem>
</artifactItems>
</configuration>
<inherited>false</inherited>
</plugin>
</plugins>
<resources>
<resource>
<directory>resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<dependency>
<groupId>com.craftaro</groupId>
<artifactId>craftarocore-core</artifactId>
<version>3.0.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,105 @@
package com.craftaro.ultimatetimber;
import com.craftaro.core.CraftaroPlugin;
import com.craftaro.core.configuration.Config;
import com.craftaro.core.locale.LocaleManager;
import com.craftaro.ultimatetimber.managers.*;
import com.craftaro.ultimatetimber.commands.UltimateTimberCommands;
import com.craftaro.ultimatetimber.database.migrations._1_CreateTables;
import com.craftaro.ultimatetimber.listeners.ConnectionListeners;
import com.craftaro.ultimatetimber.players.PlayerManager;
import org.bukkit.Bukkit;
import java.io.File;
import java.util.Arrays;
public class UltimateTimber extends CraftaroPlugin {
private static UltimateTimber INSTANCE;
public static UltimateTimber getInstance() {
return INSTANCE;
}
private Config mainConfig;
private LocaleManager localeManager;
private PlayerManager playerManager;
private PlacedBlockManager placedBlockManager;
private TreeDefinitionManager treeDefinitionManager;
private SaplingManager saplingManager;
private TreeAnimationManager treeAnimationManager;
private TreeDetectionManager treeDetectionManager;
private TreeFallManager treeFallManager;
@Override
public void onPluginEnable() {
INSTANCE = this;
initDatabase(Arrays.asList(new _1_CreateTables()));
this.mainConfig = createUpdatingConfig(new File(getDataFolder(), "config.yml"));
this.localeManager = new LocaleManager(this);
this.playerManager = new PlayerManager(this);
this.placedBlockManager = new PlacedBlockManager(this);
this.treeDefinitionManager = new TreeDefinitionManager(this);
this.saplingManager = new SaplingManager(this);
this.treeAnimationManager = new TreeAnimationManager(this);
this.treeDetectionManager = new TreeDetectionManager(this);
this.treeFallManager = new TreeFallManager(this);
Bukkit.getPluginManager().registerEvents(new ConnectionListeners(this), this);
getCommandManager().register(new UltimateTimberCommands(this));
}
public void reloadPlugin() {
this.mainConfig = createUpdatingConfig(new File(getDataFolder(), "config.yml"));
this.localeManager = new LocaleManager(this);
this.treeDetectionManager = new TreeDetectionManager(this);
}
@Override
public void onPluginDisable() {
playerManager.saveAllPlayers();
}
@Override
protected int getPluginId() {
return 0;
}
@Override
protected String getPluginIcon() {
return "OAK_SAPLING";
}
public Config getMainConfig() {
return mainConfig;
}
public LocaleManager getLocaleManager() {
return localeManager;
}
public PlayerManager getPlayerManager() {
return playerManager;
}
public PlacedBlockManager getPlacedBlockManager() {
return placedBlockManager;
}
public TreeDefinitionManager getTreeDefinitionManager() {
return treeDefinitionManager;
}
public SaplingManager getSaplingManager() {
return saplingManager;
}
public TreeAnimationManager getTreeAnimationManager() {
return treeAnimationManager;
}
public TreeDetectionManager getTreeDetectionManager() {
return treeDetectionManager;
}
}

View File

@ -1,15 +1,10 @@
package com.songoda.ultimatetimber.animation;
package com.craftaro.ultimatetimber.animation;
import com.songoda.core.compatibility.CompatibleHand;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.ultimatetimber.UltimateTimber;
import com.songoda.ultimatetimber.tree.DetectedTree;
import com.songoda.ultimatetimber.tree.FallingTreeBlock;
import com.songoda.ultimatetimber.tree.ITreeBlock;
import com.songoda.ultimatetimber.tree.TreeBlock;
import com.songoda.ultimatetimber.tree.TreeBlockSet;
import com.songoda.ultimatetimber.utils.BlockUtils;
import org.bukkit.Bukkit;
import com.craftaro.ultimatetimber.UltimateTimber;
import com.craftaro.ultimatetimber.tree.*;
import com.craftaro.ultimatetimber.utils.BlockUtils;
import com.craftaro.core.compatibility.CompatibleHand;
import com.craftaro.core.third_party.com.cryptomorin.xseries.XMaterial;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
@ -26,7 +21,7 @@ public abstract class TreeAnimation {
protected final boolean hasSilkTouch;
protected TreeBlockSet<FallingBlock> fallingTreeBlocks;
TreeAnimation(TreeAnimationType treeAnimationType, DetectedTree detectedTree, Player player) {
protected TreeAnimation(TreeAnimationType treeAnimationType, DetectedTree detectedTree, Player player) {
this.treeAnimationType = treeAnimationType;
this.detectedTree = detectedTree;
this.player = player;
@ -99,9 +94,9 @@ public abstract class TreeAnimation {
protected FallingTreeBlock convertToFallingBlock(TreeBlock treeBlock) {
Location location = treeBlock.getLocation().clone().add(0.5, 0, 0.5);
Block block = treeBlock.getBlock();
CompatibleMaterial material = CompatibleMaterial.getMaterial(block);
XMaterial material = XMaterial.matchXMaterial(block.getType());
if (material.isAir()) {
if (material == XMaterial.AIR) {
this.replaceBlock(treeBlock);
return null;
}
@ -138,4 +133,4 @@ public abstract class TreeAnimation {
}
}
}
}

View File

@ -1,4 +1,4 @@
package com.songoda.ultimatetimber.animation;
package com.craftaro.ultimatetimber.animation;
/**
* The types of tree animations that are available
@ -21,4 +21,4 @@ public enum TreeAnimationType {
return value;
return TreeAnimationType.FANCY;
}
}
}

View File

@ -1,18 +1,13 @@
package com.songoda.ultimatetimber.animation;
package com.craftaro.ultimatetimber.animation.impl;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.ultimatetimber.UltimateTimber;
import com.songoda.ultimatetimber.manager.ConfigurationManager;
import com.songoda.ultimatetimber.tree.DetectedTree;
import com.songoda.ultimatetimber.tree.FallingTreeBlock;
import com.songoda.ultimatetimber.tree.ITreeBlock;
import com.songoda.ultimatetimber.tree.TreeBlock;
import com.songoda.ultimatetimber.tree.TreeBlockSet;
import com.songoda.ultimatetimber.tree.TreeBlockType;
import com.songoda.ultimatetimber.tree.TreeDefinition;
import com.songoda.ultimatetimber.utils.BlockUtils;
import com.songoda.ultimatetimber.utils.ParticleUtils;
import com.songoda.ultimatetimber.utils.SoundUtils;
import com.craftaro.ultimatetimber.UltimateTimber;
import com.craftaro.ultimatetimber.animation.TreeAnimation;
import com.craftaro.ultimatetimber.animation.TreeAnimationType;
import com.craftaro.ultimatetimber.tree.*;
import com.craftaro.ultimatetimber.utils.BlockUtils;
import com.craftaro.ultimatetimber.utils.ParticleUtils;
import com.craftaro.ultimatetimber.utils.SoundUtils;
import com.craftaro.core.third_party.com.cryptomorin.xseries.XMaterial;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
@ -31,10 +26,10 @@ public class TreeAnimationCrumble extends TreeAnimation {
@Override
public void playAnimation(Runnable whenFinished) {
UltimateTimber ultimateTimber = UltimateTimber.getInstance();
UltimateTimber plugin = UltimateTimber.getInstance();
boolean useCustomSound = ConfigurationManager.Setting.USE_CUSTOM_SOUNDS.getBoolean();
boolean useCustomParticles = ConfigurationManager.Setting.USE_CUSTOM_PARTICLES.getBoolean();
boolean useCustomSound = plugin.getMainConfig().getBoolean("Settings.Use Custom Sounds");
boolean useCustomParticles = plugin.getMainConfig().getBoolean("Settings.Use Custom Particles");
// Order blocks by y-axis, lowest first, but shuffled randomly
int currentY = -1;
@ -65,10 +60,10 @@ public class TreeAnimationCrumble extends TreeAnimation {
for (int i = 0; i < 3 && !partition.isEmpty(); i++) {
ITreeBlock<Block> treeBlock = partition.remove(0);
if (treeBlock.getTreeBlockType().equals(TreeBlockType.LOG)) {
if (td.getLogMaterial().stream().noneMatch(x -> x.equals(CompatibleMaterial.getMaterial(treeBlock.getBlock()))))
if (td.getLogMaterial().stream().noneMatch(x -> x.equals(XMaterial.matchXMaterial(treeBlock.getBlock().getType()))))
continue;
} else if (treeBlock.getTreeBlockType().equals(TreeBlockType.LEAF)) {
if (td.getLeafMaterial().stream().noneMatch(x -> x.equals(CompatibleMaterial.getMaterial(treeBlock.getBlock()))))
if (td.getLeafMaterial().stream().noneMatch(x -> x.equals(XMaterial.matchXMaterial(treeBlock.getBlock().getType()))))
continue;
}
@ -99,7 +94,6 @@ public class TreeAnimationCrumble extends TreeAnimation {
this.cancel();
}
}
}.runTaskTimer(ultimateTimber, 0, 1);
}.runTaskTimer(plugin, 0, 1);
}
}

View File

@ -1,16 +1,13 @@
package com.songoda.ultimatetimber.animation;
package com.craftaro.ultimatetimber.animation.impl;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.ultimatetimber.UltimateTimber;
import com.songoda.ultimatetimber.manager.ConfigurationManager;
import com.songoda.ultimatetimber.manager.TreeDefinitionManager;
import com.songoda.ultimatetimber.tree.DetectedTree;
import com.songoda.ultimatetimber.tree.ITreeBlock;
import com.songoda.ultimatetimber.tree.TreeBlock;
import com.songoda.ultimatetimber.tree.TreeBlockType;
import com.songoda.ultimatetimber.tree.TreeDefinition;
import com.songoda.ultimatetimber.utils.ParticleUtils;
import com.songoda.ultimatetimber.utils.SoundUtils;
import com.craftaro.ultimatetimber.UltimateTimber;
import com.craftaro.ultimatetimber.animation.TreeAnimation;
import com.craftaro.ultimatetimber.tree.*;
import com.craftaro.ultimatetimber.utils.ParticleUtils;
import com.craftaro.ultimatetimber.utils.SoundUtils;
import com.craftaro.core.third_party.com.cryptomorin.xseries.XMaterial;
import com.craftaro.ultimatetimber.animation.TreeAnimationType;
import com.craftaro.ultimatetimber.managers.TreeDefinitionManager;
import org.bukkit.block.Block;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Player;
@ -30,11 +27,12 @@ public class TreeAnimationDisintegrate extends TreeAnimation {
@Override
public void playAnimation(Runnable whenFinished) {
UltimateTimber ultimateTimber = UltimateTimber.getInstance();
TreeDefinitionManager treeDefinitionManager = ultimateTimber.getTreeDefinitionManager();
UltimateTimber plugin = UltimateTimber.getInstance();
TreeDefinitionManager treeDefinitionManager = plugin.getTreeDefinitionManager();
boolean useCustomSound = plugin.getMainConfig().getBoolean("Settings.Use Custom Sounds");
boolean useCustomParticles = plugin.getMainConfig().getBoolean("Settings.Use Custom Particles");
boolean useCustomSound = ConfigurationManager.Setting.USE_CUSTOM_SOUNDS.getBoolean();
boolean useCustomParticles = ConfigurationManager.Setting.USE_CUSTOM_PARTICLES.getBoolean();
List<ITreeBlock<Block>> orderedLogBlocks = new ArrayList<>(this.detectedTree.getDetectedTreeBlocks().getLogBlocks());
orderedLogBlocks.sort(Comparator.comparingInt(x -> x.getLocation().getBlockY()));
@ -76,10 +74,10 @@ public class TreeAnimationDisintegrate extends TreeAnimation {
for (ITreeBlock<Block> treeBlock : toDestroy) {
if (treeBlock.getTreeBlockType().equals(TreeBlockType.LOG)) {
if (td.getLogMaterial().stream().noneMatch(x -> x.equals(CompatibleMaterial.getMaterial(treeBlock.getBlock()))))
if (td.getLogMaterial().stream().noneMatch(x -> x.equals(XMaterial.matchXMaterial(treeBlock.getBlock().getType()))))
continue;
} else if (treeBlock.getTreeBlockType().equals(TreeBlockType.LEAF)) {
if (td.getLeafMaterial().stream().noneMatch(x -> x.equals(CompatibleMaterial.getMaterial(treeBlock.getBlock()))))
if (td.getLeafMaterial().stream().noneMatch(x -> x.equals(XMaterial.matchXMaterial(treeBlock.getBlock().getType()))))
continue;
}
@ -93,7 +91,7 @@ public class TreeAnimationDisintegrate extends TreeAnimation {
whenFinished.run();
}
}
}.runTaskTimer(ultimateTimber, 0, 1);
}.runTaskTimer(plugin, 0, 1);
}
}
}

View File

@ -1,16 +1,13 @@
package com.songoda.ultimatetimber.animation;
package com.craftaro.ultimatetimber.animation.impl;
import com.songoda.ultimatetimber.UltimateTimber;
import com.songoda.ultimatetimber.manager.ConfigurationManager;
import com.songoda.ultimatetimber.manager.TreeAnimationManager;
import com.songoda.ultimatetimber.tree.DetectedTree;
import com.songoda.ultimatetimber.tree.FallingTreeBlock;
import com.songoda.ultimatetimber.tree.ITreeBlock;
import com.songoda.ultimatetimber.tree.TreeBlock;
import com.songoda.ultimatetimber.tree.TreeBlockSet;
import com.songoda.ultimatetimber.utils.BlockUtils;
import com.songoda.ultimatetimber.utils.ParticleUtils;
import com.songoda.ultimatetimber.utils.SoundUtils;
import com.craftaro.ultimatetimber.UltimateTimber;
import com.craftaro.ultimatetimber.animation.TreeAnimation;
import com.craftaro.ultimatetimber.managers.TreeAnimationManager;
import com.craftaro.ultimatetimber.tree.*;
import com.craftaro.ultimatetimber.utils.BlockUtils;
import com.craftaro.ultimatetimber.utils.ParticleUtils;
import com.craftaro.ultimatetimber.utils.SoundUtils;
import com.craftaro.ultimatetimber.animation.TreeAnimationType;
import org.bukkit.block.Block;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Player;
@ -25,10 +22,10 @@ public class TreeAnimationFancy extends TreeAnimation {
@Override
public void playAnimation(Runnable whenFinished) {
UltimateTimber ultimateTimber = UltimateTimber.getInstance();
UltimateTimber plugin = UltimateTimber.getInstance();
boolean useCustomSound = ConfigurationManager.Setting.USE_CUSTOM_SOUNDS.getBoolean();
boolean useCustomParticles = ConfigurationManager.Setting.USE_CUSTOM_PARTICLES.getBoolean();
boolean useCustomSound = plugin.getMainConfig().getBoolean("Settings.Use Custom Sounds");
boolean useCustomParticles = plugin.getMainConfig().getBoolean("Settings.Use Custom Particles");
ITreeBlock<Block> initialTreeBlock = this.detectedTree.getDetectedTreeBlocks().getInitialLogBlock();
FallingTreeBlock initialFallingBlock = this.convertToFallingBlock((TreeBlock)this.detectedTree.getDetectedTreeBlocks().getInitialLogBlock());
@ -48,7 +45,7 @@ public class TreeAnimationFancy extends TreeAnimation {
this.fallingTreeBlocks.add(fallingTreeBlock);
if (useCustomParticles)
ParticleUtils.playFallingParticles(treeBlock);
ParticleUtils.playFallingParticles(treeBlock);
double multiplier = (treeBlock.getLocation().getY() - this.player.getLocation().getY()) * 0.05;
fallingBlock.setVelocity(velocityVector.clone().multiply(multiplier));
@ -82,14 +79,14 @@ public class TreeAnimationFancy extends TreeAnimation {
this.timer++;
if (this.timer > 4 * 20) {
TreeAnimationManager treeAnimationManager = ultimateTimber.getTreeAnimationManager();
TreeAnimationManager treeAnimationManager = plugin.getTreeAnimationManager();
for (ITreeBlock<FallingBlock> fallingTreeBlock : TreeAnimationFancy.this.fallingTreeBlocks.getAllTreeBlocks())
treeAnimationManager.runFallingBlockImpact(TreeAnimationFancy.this, fallingTreeBlock);
whenFinished.run();
this.cancel();
}
}
}.runTaskTimer(ultimateTimber, 20L, 1L);
}.runTaskTimer(plugin, 20L, 1L);
}
}
}

View File

@ -1,13 +1,14 @@
package com.songoda.ultimatetimber.animation;
package com.craftaro.ultimatetimber.animation.impl;
import com.songoda.ultimatetimber.UltimateTimber;
import com.songoda.ultimatetimber.manager.ConfigurationManager;
import com.songoda.ultimatetimber.manager.TreeDefinitionManager;
import com.songoda.ultimatetimber.tree.DetectedTree;
import com.songoda.ultimatetimber.tree.ITreeBlock;
import com.songoda.ultimatetimber.tree.TreeBlock;
import com.songoda.ultimatetimber.utils.ParticleUtils;
import com.songoda.ultimatetimber.utils.SoundUtils;
import com.craftaro.ultimatetimber.UltimateTimber;
import com.craftaro.ultimatetimber.animation.TreeAnimation;
import com.craftaro.ultimatetimber.tree.DetectedTree;
import com.craftaro.ultimatetimber.tree.ITreeBlock;
import com.craftaro.ultimatetimber.tree.TreeBlock;
import com.craftaro.ultimatetimber.utils.ParticleUtils;
import com.craftaro.ultimatetimber.utils.SoundUtils;
import com.craftaro.ultimatetimber.animation.TreeAnimationType;
import com.craftaro.ultimatetimber.managers.TreeDefinitionManager;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
@ -19,12 +20,13 @@ public class TreeAnimationNone extends TreeAnimation {
@Override
public void playAnimation(Runnable whenFinished) {
UltimateTimber plugin = UltimateTimber.getInstance();
TreeDefinitionManager treeDefinitionManager = UltimateTimber.getInstance().getTreeDefinitionManager();
if (ConfigurationManager.Setting.USE_CUSTOM_SOUNDS.getBoolean())
if (plugin.getMainConfig().getBoolean("Settings.Use Custom Sounds"))
SoundUtils.playFallingSound(this.detectedTree.getDetectedTreeBlocks().getInitialLogBlock());
if (ConfigurationManager.Setting.USE_CUSTOM_PARTICLES.getBoolean())
if (plugin.getMainConfig().getBoolean("Settings.Use Custom Particles"))
for (ITreeBlock<Block> treeBlock : this.detectedTree.getDetectedTreeBlocks().getAllTreeBlocks())
ParticleUtils.playFallingParticles(treeBlock);
@ -36,4 +38,4 @@ public class TreeAnimationNone extends TreeAnimation {
whenFinished.run();
}
}
}

View File

@ -0,0 +1,58 @@
package com.craftaro.ultimatetimber.commands;
import com.craftaro.ultimatetimber.UltimateTimber;
import com.craftaro.core.third_party.revxrsal.commands.annotation.Command;
import com.craftaro.core.third_party.revxrsal.commands.annotation.DefaultFor;
import com.craftaro.core.third_party.revxrsal.commands.annotation.Named;
import com.craftaro.core.third_party.revxrsal.commands.annotation.Subcommand;
import com.craftaro.core.third_party.revxrsal.commands.bukkit.annotation.CommandPermission;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@Command({"ut", "ultimatetimber"})
public class UltimateTimberCommands {
private final UltimateTimber plugin;
public UltimateTimberCommands(UltimateTimber plugin) {
this.plugin = plugin;
}
@DefaultFor({"ut", "ultimatetimber"})
public void onHelp(CommandSender sender) {
plugin.getLocaleManager().getMessageList("command.help").sendMessage(sender);
}
@Subcommand("giveaxe")
@CommandPermission("ultimatetimber.give")
public void onGiveAxe(CommandSender sender, @Named("player") Player player) {
ItemStack axe = plugin.getTreeDefinitionManager().getRequiredAxe();
if (axe == null) {
plugin.getLocaleManager().getMessage("command.give.no-axe").sendMessage(sender);
return;
}
player.getInventory().addItem(axe);
plugin.getLocaleManager().getMessage("command.give.given")
.replace("%player%", player.getName())
.sendMessage(sender);
}
@Subcommand("toggle")
@CommandPermission("ultimatetimber.toggle")
public void onToggle(Player player) {
if (plugin.getPlayerManager().togglePlayer(player)) {
plugin.getLocaleManager().getMessage("command.toggle.enabled").sendMessage(player);
} else {
plugin.getLocaleManager().getMessage("command.toggle.disabled").sendMessage(player);
}
}
@Subcommand("reload")
@CommandPermission("ultimatetimber.reload")
public void onReload(CommandSender sender) {
plugin.reloadPlugin();
plugin.getLocaleManager().getMessage("command.reload.success").sendMessage(sender);
}
}

View File

@ -0,0 +1,25 @@
package com.craftaro.ultimatetimber.database.migrations;
import com.craftaro.core.database.DataMigration;
import com.craftaro.core.database.DatabaseConnector;
import com.craftaro.core.third_party.org.jooq.impl.SQLDataType;
/**
* Creates the database tables
*/
public class _1_CreateTables extends DataMigration {
public _1_CreateTables() {
super(1);
}
@Override
public void migrate(DatabaseConnector connector, String tablePrefix) {
connector.connectDSL(context -> context.createTableIfNotExists(tablePrefix + "players")
.column("uuid", SQLDataType.VARCHAR(36))
.column("chopping_enabled", SQLDataType.BOOLEAN)
.column("last_chopping_use", SQLDataType.BIGINT)
.primaryKey("uuid")
.execute());
}
}

View File

@ -1,6 +1,6 @@
package com.songoda.ultimatetimber.events;
package com.craftaro.ultimatetimber.events;
import com.songoda.ultimatetimber.tree.DetectedTree;
import com.craftaro.ultimatetimber.tree.DetectedTree;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerEvent;
@ -9,7 +9,7 @@ import org.bukkit.event.player.PlayerEvent;
*/
public abstract class TreeEvent extends PlayerEvent {
protected final DetectedTree detectedTree;
protected final DetectedTree detectedTree;
public TreeEvent(Player player, DetectedTree detectedTree) {
super(player);
@ -18,11 +18,11 @@ public abstract class TreeEvent extends PlayerEvent {
/**
* Get the tree blocks
*
*
* @return The blocks that are part of the tree
*/
public DetectedTree getDetectedTree() {
return this.detectedTree;
}
}
}

View File

@ -1,20 +1,20 @@
package com.songoda.ultimatetimber.events;
package com.craftaro.ultimatetimber.events;
import com.songoda.ultimatetimber.tree.DetectedTree;
import com.craftaro.ultimatetimber.tree.DetectedTree;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
/**
* Called when a tree fell
*/
public class TreeFellEvent extends TreeEvent {
public class TreePostFallEvent extends TreeEvent {
public TreeFellEvent(Player player, DetectedTree detectedTree) {
public TreePostFallEvent(Player player, DetectedTree detectedTree) {
super(player, detectedTree);
}
private static final HandlerList handlers = new HandlerList();
@Override
public HandlerList getHandlers() {
return handlers;
@ -23,5 +23,5 @@ public class TreeFellEvent extends TreeEvent {
public static HandlerList getHandlerList() {
return handlers;
}
}
}

View File

@ -0,0 +1,40 @@
package com.craftaro.ultimatetimber.events;
import com.craftaro.ultimatetimber.tree.DetectedTree;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
/**
* Called when a tree will fall
*/
public class TreePreFallEvent extends TreeEvent implements Cancellable {
private boolean cancelled = false;
public TreePreFallEvent(Player player, DetectedTree detectedTree) {
super(player, detectedTree);
}
private static final HandlerList handlers = new HandlerList();
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public boolean isCancelled() {
return this.cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
}

View File

@ -0,0 +1,25 @@
package com.craftaro.ultimatetimber.listeners;
import com.craftaro.ultimatetimber.UltimateTimber;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
public class ConnectionListeners implements Listener {
private final UltimateTimber plugin;
public ConnectionListeners(UltimateTimber plugin) {
this.plugin = plugin;
}
@EventHandler
public void onJoin(PlayerJoinEvent event) {
plugin.getPlayerManager().loadPlayer(event.getPlayer());
}
@EventHandler
public void onQuit(PlayerQuitEvent event) {
plugin.getPlayerManager().savePlayer(event.getPlayer());
}
}

View File

@ -1,9 +1,8 @@
package com.songoda.ultimatetimber.manager;
package com.craftaro.ultimatetimber.managers;
import com.songoda.ultimatetimber.UltimateTimber;
import com.songoda.ultimatetimber.events.TreeFellEvent;
import com.songoda.ultimatetimber.tree.ITreeBlock;
import org.bukkit.Bukkit;
import com.craftaro.ultimatetimber.UltimateTimber;
import com.craftaro.ultimatetimber.events.TreePostFallEvent;
import com.craftaro.ultimatetimber.tree.ITreeBlock;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
@ -16,45 +15,27 @@ import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.LeavesDecayEvent;
import org.bukkit.event.world.StructureGrowEvent;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.*;
public class PlacedBlockManager extends Manager implements Listener {
public class PlacedBlockManager implements Listener {
private Set<Location> placedBlocks;
private boolean ignorePlacedBlocks;
private int maxPlacedBlockMemorySize;
public PlacedBlockManager(UltimateTimber ultimateTimber) {
super(ultimateTimber);
Bukkit.getPluginManager().registerEvents(this, ultimateTimber);
}
@Override
public void reload() {
this.ignorePlacedBlocks = ConfigurationManager.Setting.IGNORE_PLACED_BLOCKS.getBoolean();
this.maxPlacedBlockMemorySize = ConfigurationManager.Setting.IGNORE_PLACED_BLOCKS_MEMORY_SIZE.getInt();
// Ensures the oldest entry is removed if it exceeds the limit
private final UltimateTimber plugin;
private final Set<Location> placedBlocks;
public PlacedBlockManager(UltimateTimber plugin) {
this.plugin = plugin;
this.placedBlocks = Collections.newSetFromMap(new LinkedHashMap<Location, Boolean>() {
@Override
protected boolean removeEldestEntry(Map.Entry<Location, Boolean> eldest) {
return this.size() > PlacedBlockManager.this.maxPlacedBlockMemorySize;
return this.size() > plugin.getMainConfig().getInt("Settings.Ignore Placed Blocks Memory Size");
}
});
}
@Override
public void disable() {
this.placedBlocks.clear();
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockPlaced(BlockPlaceEvent event) {
if (!this.ignorePlacedBlocks)
if (isDisabled()) {
return;
}
// Ignore stripping logs
if (event.getBlockPlaced().getType().name().contains("STRIPPED") && !event.getBlockReplacedState().getType().equals(Material.AIR))
@ -65,36 +46,41 @@ public class PlacedBlockManager extends Manager implements Listener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockBreak(BlockBreakEvent event) {
if (!this.ignorePlacedBlocks)
if (isDisabled()) {
return;
}
this.internalProtect(event.getBlock(), false);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onLeafDecay(LeavesDecayEvent event) {
if (!this.ignorePlacedBlocks)
if (isDisabled()) {
return;
}
this.internalProtect(event.getBlock(), false);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onStructureGrow(StructureGrowEvent event) {
if (!this.ignorePlacedBlocks)
if (isDisabled())
return;
for (BlockState blockState : event.getBlocks())
for (BlockState blockState : event.getBlocks()) {
this.internalProtect(blockState.getBlock(), false);
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onTreeFell(TreeFellEvent event) {
if (!this.ignorePlacedBlocks)
public void onTreeFell(TreePostFallEvent event) {
if (isDisabled()) {
return;
}
for (ITreeBlock<Block> treeBlock : event.getDetectedTree().getDetectedTreeBlocks().getAllTreeBlocks())
for (ITreeBlock<Block> treeBlock : event.getDetectedTree().getDetectedTreeBlocks().getAllTreeBlocks()) {
this.internalProtect(treeBlock.getBlock(), false);
}
}
/**
@ -121,4 +107,7 @@ public class PlacedBlockManager extends Manager implements Listener {
return this.placedBlocks.contains(block.getLocation());
}
public boolean isDisabled() {
return plugin.getMainConfig().getInt("Settings.Ignore Placed Blocks Memory Size") <= 0;
}
}

View File

@ -1,10 +1,10 @@
package com.songoda.ultimatetimber.manager;
package com.craftaro.ultimatetimber.managers;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.ultimatetimber.UltimateTimber;
import com.songoda.ultimatetimber.tree.ITreeBlock;
import com.songoda.ultimatetimber.tree.TreeBlockType;
import com.songoda.ultimatetimber.tree.TreeDefinition;
import com.craftaro.ultimatetimber.UltimateTimber;
import com.craftaro.ultimatetimber.tree.ITreeBlock;
import com.craftaro.ultimatetimber.tree.TreeBlockType;
import com.craftaro.ultimatetimber.tree.TreeDefinition;
import com.craftaro.core.third_party.com.cryptomorin.xseries.XMaterial;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
@ -12,28 +12,15 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
public class SaplingManager extends Manager {
private Random random;
private Set<Location> protectedSaplings;
public SaplingManager(UltimateTimber ultimateTimber) {
super(ultimateTimber);
this.random = new Random();
this.protectedSaplings = new HashSet<>();
}
@Override
public void reload() {
}
@Override
public void disable() {
public class SaplingManager {
private final UltimateTimber plugin;
private final Set<Location> protectedSaplings = new HashSet<>();
public SaplingManager(UltimateTimber plugin) {
this.plugin = plugin;
}
/**
@ -44,14 +31,16 @@ public class SaplingManager extends Manager {
* @param treeBlock The ITreeBlock to replant for
*/
public void replantSapling(TreeDefinition treeDefinition, ITreeBlock treeBlock) {
if (!ConfigurationManager.Setting.REPLANT_SAPLINGS.getBoolean())
if (!plugin.getMainConfig().getBoolean("Settings.Replant Saplings")) {
return;
}
Block block = treeBlock.getLocation().getBlock();
if (!block.getType().equals(Material.AIR) || treeBlock.getTreeBlockType().equals(TreeBlockType.LEAF))
if (!block.getType().equals(Material.AIR) || treeBlock.getTreeBlockType().equals(TreeBlockType.LEAF)) {
return;
}
Bukkit.getScheduler().scheduleSyncDelayedTask(this.plugin, () -> this.internalReplant(treeDefinition, treeBlock), 1L);
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> internalReplant(treeDefinition, treeBlock), 1L);
}
/**
@ -62,12 +51,14 @@ public class SaplingManager extends Manager {
* @param treeBlock The ITreeBlock to replant for
*/
public void replantSaplingWithChance(TreeDefinition treeDefinition, ITreeBlock treeBlock) {
if (!ConfigurationManager.Setting.FALLING_BLOCKS_REPLANT_SAPLINGS.getBoolean() || !treeBlock.getLocation().getBlock().getType().equals(Material.AIR))
if (!plugin.getMainConfig().getBoolean("Settings.Falling Blocks Replant Saplings") || !treeBlock.getLocation().getBlock().getType().equals(Material.AIR)) {
return;
}
double chance = ConfigurationManager.Setting.FALLING_BLOCKS_REPLANT_SAPLINGS_CHANCE.getDouble();
if (this.random.nextDouble() > chance / 100)
double chance = plugin.getMainConfig().getDouble("Settings.Falling Blocks Replant Saplings Chance");
if (ThreadLocalRandom.current().nextDouble() > chance / 100) {
return;
}
Bukkit.getScheduler().scheduleSyncDelayedTask(this.plugin, () -> this.internalReplant(treeDefinition, treeBlock), 1L);
}
@ -84,8 +75,8 @@ public class SaplingManager extends Manager {
Block block = treeBlock.getLocation().getBlock();
Block blockBelow = block.getRelative(BlockFace.DOWN);
boolean isValidSoil = false;
for (CompatibleMaterial soilMaterial : treeDefinitionManager.getPlantableSoilMaterial(treeDefinition)) {
if (soilMaterial.equals(CompatibleMaterial.getMaterial(blockBelow))) {
for (XMaterial soilMaterial : treeDefinitionManager.getPlantableSoilMaterial(treeDefinition)) {
if (soilMaterial.equals(XMaterial.matchXMaterial(blockBelow.getType()))) {
isValidSoil = true;
break;
}
@ -94,10 +85,10 @@ public class SaplingManager extends Manager {
if (!isValidSoil)
return;
CompatibleMaterial material = treeDefinition.getSaplingMaterial();
material.applyToBlock(block);
XMaterial material = treeDefinition.getSaplingMaterial();
block.setType(material.parseMaterial());
int cooldown = ConfigurationManager.Setting.REPLANT_SAPLINGS_COOLDOWN.getInt();
int cooldown = plugin.getMainConfig().getInt("Settings.Replant Saplings Cooldown");
if (cooldown != 0) {
this.protectedSaplings.add(block.getLocation());
Bukkit.getScheduler().scheduleSyncDelayedTask(this.plugin, () -> this.protectedSaplings.remove(block.getLocation()), cooldown * 20L);
@ -113,5 +104,4 @@ public class SaplingManager extends Manager {
public boolean isSaplingProtected(Block block) {
return this.protectedSaplings.contains(block.getLocation());
}
}

View File

@ -1,19 +1,19 @@
package com.songoda.ultimatetimber.manager;
package com.craftaro.ultimatetimber.managers;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.ultimatetimber.UltimateTimber;
import com.songoda.ultimatetimber.animation.TreeAnimation;
import com.songoda.ultimatetimber.animation.TreeAnimationCrumble;
import com.songoda.ultimatetimber.animation.TreeAnimationDisintegrate;
import com.songoda.ultimatetimber.animation.TreeAnimationFancy;
import com.songoda.ultimatetimber.animation.TreeAnimationNone;
import com.songoda.ultimatetimber.animation.TreeAnimationType;
import com.songoda.ultimatetimber.tree.DetectedTree;
import com.songoda.ultimatetimber.tree.ITreeBlock;
import com.songoda.ultimatetimber.tree.TreeDefinition;
import com.songoda.ultimatetimber.utils.ParticleUtils;
import com.songoda.ultimatetimber.utils.SoundUtils;
import com.craftaro.ultimatetimber.UltimateTimber;
import com.craftaro.ultimatetimber.tree.DetectedTree;
import com.craftaro.ultimatetimber.tree.ITreeBlock;
import com.craftaro.ultimatetimber.tree.TreeDefinition;
import com.craftaro.ultimatetimber.utils.ParticleUtils;
import com.craftaro.ultimatetimber.utils.SoundUtils;
import com.craftaro.core.compatibility.ServerVersion;
import com.craftaro.core.third_party.com.cryptomorin.xseries.XMaterial;
import com.craftaro.ultimatetimber.animation.TreeAnimation;
import com.craftaro.ultimatetimber.animation.TreeAnimationType;
import com.craftaro.ultimatetimber.animation.impl.TreeAnimationCrumble;
import com.craftaro.ultimatetimber.animation.impl.TreeAnimationDisintegrate;
import com.craftaro.ultimatetimber.animation.impl.TreeAnimationFancy;
import com.craftaro.ultimatetimber.animation.impl.TreeAnimationNone;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
@ -29,28 +29,18 @@ import org.bukkit.event.entity.EntityChangeBlockEvent;
import java.util.HashSet;
import java.util.Set;
public class TreeAnimationManager extends Manager implements Listener, Runnable {
public class TreeAnimationManager implements Listener, Runnable {
private final UltimateTimber plugin;
private final Set<TreeAnimation> activeAnimations;
private final int taskId;
public TreeAnimationManager(UltimateTimber ultimateTimber) {
super(ultimateTimber);
public TreeAnimationManager(UltimateTimber plugin) {
this.plugin = plugin;
this.activeAnimations = new HashSet<>();
this.taskId = -1;
Bukkit.getPluginManager().registerEvents(this, ultimateTimber);
Bukkit.getScheduler().runTaskTimer(this.plugin, this, 0, 1L);
}
@Override
public void reload() {
this.activeAnimations.clear();
}
@Override
public void disable() {
this.activeAnimations.clear();
Bukkit.getScheduler().cancelTask(this.taskId);
Bukkit.getPluginManager().registerEvents(this, plugin);
Bukkit.getScheduler().runTaskTimer(plugin, this, 0, 1L);
}
@Override
@ -79,7 +69,7 @@ public class TreeAnimationManager extends Manager implements Listener, Runnable
* @param player The Player who toppled the tree
*/
public void runAnimation(DetectedTree detectedTree, Player player) {
switch (TreeAnimationType.fromString(ConfigurationManager.Setting.TREE_ANIMATION_TYPE.getString())) {
switch (TreeAnimationType.fromString(plugin.getMainConfig().getString("Settings.Tree Animation Type"))) {
case FANCY:
this.registerTreeAnimation(new TreeAnimationFancy(detectedTree, player));
break;
@ -150,8 +140,8 @@ public class TreeAnimationManager extends Manager implements Listener, Runnable
*/
public void runFallingBlockImpact(TreeAnimation treeAnimation, ITreeBlock<FallingBlock> treeBlock) {
TreeDefinitionManager treeDefinitionManager = this.plugin.getTreeDefinitionManager();
boolean useCustomSound = ConfigurationManager.Setting.USE_CUSTOM_SOUNDS.getBoolean();
boolean useCustomParticles = ConfigurationManager.Setting.USE_CUSTOM_PARTICLES.getBoolean();
boolean useCustomSound = plugin.getMainConfig().getBoolean("Settings.Use Custom Sounds");
boolean useCustomParticles = plugin.getMainConfig().getBoolean("Settings.Use Custom Particles");
TreeDefinition treeDefinition = treeAnimation.getDetectedTree().getTreeDefinition();
if (useCustomParticles)
@ -160,8 +150,8 @@ public class TreeAnimationManager extends Manager implements Listener, Runnable
SoundUtils.playLandingSound(treeBlock);
Block block = treeBlock.getLocation().subtract(0, 1, 0).getBlock();
if (ConfigurationManager.Setting.FRAGILE_BLOCKS.getStringList().contains(block.getType().toString())) {
block.getWorld().dropItemNaturally(block.getLocation(), CompatibleMaterial.getMaterial(block).getItem());
if (plugin.getMainConfig().getStringList("Settings.Fragile Blocks").contains(block.getType().toString())) {
block.getWorld().dropItemNaturally(block.getLocation(), XMaterial.matchXMaterial(block.getType()).parseItem());
block.breakNaturally();
}
@ -179,15 +169,15 @@ public class TreeAnimationManager extends Manager implements Listener, Runnable
if (!this.isBlockInAnimation(fallingBlock))
return;
if (ConfigurationManager.Setting.FALLING_BLOCKS_DEAL_DAMAGE.getBoolean()) {
int damage = ConfigurationManager.Setting.FALLING_BLOCK_DAMAGE.getInt();
if (plugin.getMainConfig().getBoolean("Settings.Falling Blocks Deal Damage")) {
int damage = plugin.getMainConfig().getInt("Settings.Falling Block Damage");
for (Entity entity : fallingBlock.getNearbyEntities(0.5, 0.5, 0.5)) {
if (!(entity instanceof LivingEntity)) continue;
((LivingEntity) entity).damage(damage, fallingBlock);
}
}
if (ConfigurationManager.Setting.SCATTER_TREE_BLOCKS_ON_GROUND.getBoolean()) {
if (plugin.getMainConfig().getBoolean("Settings.Scatter Tree Blocks On Ground")) {
TreeAnimation treeAnimation = this.getAnimationForBlock(fallingBlock);
if (treeAnimation != null) {
treeAnimation.removeFallingBlock(fallingBlock);
@ -197,4 +187,4 @@ public class TreeAnimationManager extends Manager implements Listener, Runnable
event.setCancelled(true);
}
}
}

View File

@ -1,182 +1,164 @@
package com.songoda.ultimatetimber.manager;
package com.craftaro.ultimatetimber.managers;
import com.craftaro.core.compatibility.ServerVersion;
import com.craftaro.core.configuration.Config;
import com.craftaro.core.third_party.com.cryptomorin.xseries.XMaterial;
import com.craftaro.core.third_party.de.tr7zw.nbtapi.NBTItem;
import com.craftaro.core.third_party.dev.triumphteam.gui.builder.item.ItemBuilder;
import com.craftaro.core.third_party.net.kyori.adventure.text.Component;
import com.craftaro.core.third_party.net.kyori.adventure.text.minimessage.MiniMessage;
import com.craftaro.ultimatetimber.UltimateTimber;
import com.craftaro.ultimatetimber.tree.ITreeBlock;
import com.craftaro.ultimatetimber.tree.TreeBlockType;
import com.craftaro.ultimatetimber.tree.TreeDefinition;
import com.craftaro.ultimatetimber.tree.TreeLoot;
import com.craftaro.ultimatetimber.utils.BlockUtils;
import com.google.common.base.Strings;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.core.hooks.McMMOHook;
import com.songoda.core.third_party.de.tr7zw.nbtapi.NBTItem;
import com.songoda.core.utils.TextUtils;
import com.songoda.ultimatetimber.UltimateTimber;
import com.songoda.ultimatetimber.tree.ITreeBlock;
import com.songoda.ultimatetimber.tree.TreeBlockType;
import com.songoda.ultimatetimber.tree.TreeDefinition;
import com.songoda.ultimatetimber.tree.TreeLoot;
import com.songoda.ultimatetimber.utils.BlockUtils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.simpleyaml.configuration.ConfigurationSection;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.io.File;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
public class TreeDefinitionManager extends Manager {
public class TreeDefinitionManager {
private final Random random;
private final Set<TreeDefinition> treeDefinitions;
private final Set<CompatibleMaterial> globalPlantableSoil;
private final Set<TreeLoot> globalLogLoot, globalLeafLoot, globalEntireTreeLoot;
private final Set<ItemStack> globalRequiredTools;
private final UltimateTimber plugin;
private final Set<TreeDefinition> treeDefinitions = new HashSet<>();
private final Set<XMaterial> globalPlantableSoil = new HashSet<>();
private final Set<TreeLoot> globalLogLoot = new HashSet<>(),
globalLeafLoot = new HashSet<>(),
globalEntireTreeLoot = new HashSet<>();
private final Set<ItemStack> globalRequiredTools = new HashSet<>();
private boolean globalAxeRequired;
private ItemStack requiredAxe;
private String requiredAxeKey;
public TreeDefinitionManager(UltimateTimber ultimateTimber) {
super(ultimateTimber);
this.random = new Random();
this.treeDefinitions = new HashSet<>();
this.globalPlantableSoil = new HashSet<>();
this.globalLogLoot = new HashSet<>();
this.globalLeafLoot = new HashSet<>();
this.globalEntireTreeLoot = new HashSet<>();
this.globalRequiredTools = new HashSet<>();
}
@Override
public void reload() {
this.treeDefinitions.clear();
this.globalPlantableSoil.clear();
this.globalLogLoot.clear();
this.globalLeafLoot.clear();
this.globalEntireTreeLoot.clear();
this.globalRequiredTools.clear();
ConfigurationManager configurationManager = this.plugin.getConfigurationManager();
YamlConfiguration config = configurationManager.getConfig();
public TreeDefinitionManager(UltimateTimber plugin) {
this.plugin = plugin;
Config config = plugin.createUpdatingConfig(new File(plugin.getDataFolder(), "trees.yml"));
// Load tree settings
ConfigurationSection treeSection = config.getConfigurationSection("trees");
top:
for (String key : treeSection.getKeys(false)) {
ConfigurationSection tree = treeSection.getConfigurationSection(key);
Set<CompatibleMaterial> logMaterials = new HashSet<>();
Set<CompatibleMaterial> leafMaterials = new HashSet<>();
CompatibleMaterial saplingMaterial;
Set<CompatibleMaterial> plantableSoilMaterial = new HashSet<>();
double maxLogDistanceFromTrunk;
int maxLeafDistanceFromLog;
boolean detectLeavesDiagonally;
boolean dropOriginalLog;
boolean dropOriginalLeaf;
Set<TreeLoot> logLoot = new HashSet<>();
Set<TreeLoot> leafLoot = new HashSet<>();
Set<TreeLoot> entireTreeLoot = new HashSet<>();
Set<ItemStack> requiredTools = new HashSet<>();
boolean requiredAxe;
Set<XMaterial> logMaterials = new HashSet<>();
for (String materialString : tree.getStringList("logs")) {
CompatibleMaterial material = CompatibleMaterial.getMaterial(materialString);
if (material == null || material.getMaterial() == null) continue top;
logMaterials.add(material);
XMaterial.matchXMaterial(materialString).ifPresent(logMaterials::add);
}
Set<XMaterial> leafMaterials = new HashSet<>();
for (String materialString : tree.getStringList("leaves")) {
CompatibleMaterial material = CompatibleMaterial.getMaterial(materialString);
if (material == null || material.getMaterial() == null) continue top;
leafMaterials.add(material);
XMaterial.matchXMaterial(materialString).ifPresent(leafMaterials::add);
}
saplingMaterial = CompatibleMaterial.getMaterial(tree.getString("sapling"));
XMaterial saplingMaterial;
Optional<XMaterial> optionalSapling = XMaterial.matchXMaterial(tree.getString("sapling"));
if (!optionalSapling.isPresent()) {
plugin.getLogger().warning("Configuration for tree " + key + " has encountered an error: Invalid sapling material.");
continue;
}
saplingMaterial = optionalSapling.get();
Set<XMaterial> plantableSoilMaterial = new HashSet<>();
for (String materialString : tree.getStringList("plantable-soil")) {
CompatibleMaterial material = CompatibleMaterial.getMaterial(materialString);
if (material == null || material.getMaterial() == null) continue top;
plantableSoilMaterial.add(material);
XMaterial.matchXMaterial(materialString).ifPresent(leafMaterials::add);
}
maxLogDistanceFromTrunk = tree.getDouble("max-log-distance-from-trunk");
maxLeafDistanceFromLog = tree.getInt("max-leaf-distance-from-log");
detectLeavesDiagonally = tree.getBoolean("search-for-leaves-diagonally");
dropOriginalLog = tree.getBoolean("drop-original-log");
dropOriginalLeaf = tree.getBoolean("drop-original-leaf");
double maxLogDistanceFromTrunk = tree.getDouble("max-log-distance-from-trunk");
int maxLeafDistanceFromLog = tree.getInt("max-leaf-distance-from-log");
boolean detectLeavesDiagonally = tree.getBoolean("search-for-leaves-diagonally");
boolean dropOriginalLog = tree.getBoolean("drop-original-log");
boolean dropOriginalLeaf = tree.getBoolean("drop-original-leaf");
Set<TreeLoot> logLoot = new HashSet<>();
ConfigurationSection logLootSection = tree.getConfigurationSection("log-loot");
if (logLootSection != null)
for (String lootKey : logLootSection.getKeys(false))
if (logLootSection != null) {
for (String lootKey : logLootSection.getKeys(false)) {
logLoot.add(this.getTreeLootEntry(TreeBlockType.LOG, logLootSection.getConfigurationSection(lootKey)));
ConfigurationSection leafLootSection = tree.getConfigurationSection("leaf-loot");
if (leafLootSection != null)
for (String lootKey : leafLootSection.getKeys(false))
leafLoot.add(this.getTreeLootEntry(TreeBlockType.LEAF, leafLootSection.getConfigurationSection(lootKey)));
ConfigurationSection entireTreeLootSection = tree.getConfigurationSection("entire-tree-loot");
if (entireTreeLootSection != null)
for (String lootKey : entireTreeLootSection.getKeys(false))
entireTreeLoot.add(this.getTreeLootEntry(TreeBlockType.LEAF, entireTreeLootSection.getConfigurationSection(lootKey)));
for (String itemStackString : tree.getStringList("required-tools")) {
CompatibleMaterial material = CompatibleMaterial.getMaterial(itemStackString);
if (material == null) continue top;
requiredTools.add(material.getItem());
}
}
requiredAxe = tree.getBoolean("required-axe", false);
Set<TreeLoot> leafLoot = new HashSet<>();
ConfigurationSection leafLootSection = tree.getConfigurationSection("leaf-loot");
if (leafLootSection != null) {
for (String lootKey : leafLootSection.getKeys(false)) {
leafLoot.add(this.getTreeLootEntry(TreeBlockType.LEAF, leafLootSection.getConfigurationSection(lootKey)));
}
}
Set<TreeLoot> entireTreeLoot = new HashSet<>();
ConfigurationSection entireTreeLootSection = tree.getConfigurationSection("entire-tree-loot");
if (entireTreeLootSection != null) {
for (String lootKey : entireTreeLootSection.getKeys(false)) {
entireTreeLoot.add(this.getTreeLootEntry(TreeBlockType.LEAF, entireTreeLootSection.getConfigurationSection(lootKey)));
}
}
Set<ItemStack> requiredTools = new HashSet<>();
for (String itemStackString : tree.getStringList("required-tools")) {
XMaterial.matchXMaterial(itemStackString).ifPresent(material -> requiredTools.add(material.parseItem()));
}
boolean requiredAxe = tree.getBoolean("required-axe", false);
this.treeDefinitions.add(new TreeDefinition(key, logMaterials, leafMaterials, saplingMaterial, plantableSoilMaterial, maxLogDistanceFromTrunk,
maxLeafDistanceFromLog, detectLeavesDiagonally, dropOriginalLog, dropOriginalLeaf, logLoot, leafLoot, entireTreeLoot, requiredTools, requiredAxe));
}
// Load global plantable soil
for (String material : config.getStringList("global-plantable-soil"))
this.globalPlantableSoil.add(CompatibleMaterial.getMaterial(material));
for (String material : config.getStringList("global-plantable-soil")) {
XMaterial.matchXMaterial(material).ifPresent(globalPlantableSoil::add);
}
// Load global log drops
ConfigurationSection logSection = config.getConfigurationSection("global-log-loot");
if (logSection != null)
for (String lootKey : logSection.getKeys(false))
if (logSection != null) {
for (String lootKey : logSection.getKeys(false)) {
this.globalLogLoot.add(this.getTreeLootEntry(TreeBlockType.LOG, logSection.getConfigurationSection(lootKey)));
}
}
// Load global leaf drops
ConfigurationSection leafSection = config.getConfigurationSection("global-leaf-loot");
if (leafSection != null)
for (String lootKey : leafSection.getKeys(false))
if (leafSection != null) {
for (String lootKey : leafSection.getKeys(false)) {
this.globalLeafLoot.add(this.getTreeLootEntry(TreeBlockType.LEAF, leafSection.getConfigurationSection(lootKey)));
}
}
// Load global entire tree drops
ConfigurationSection entireTreeSection = config.getConfigurationSection("global-entire-tree-loot");
if (entireTreeSection != null)
for (String lootKey : entireTreeSection.getKeys(false))
if (entireTreeSection != null) {
for (String lootKey : entireTreeSection.getKeys(false)) {
this.globalEntireTreeLoot.add(this.getTreeLootEntry(TreeBlockType.LOG, entireTreeSection.getConfigurationSection(lootKey)));
}
}
// Load global tools
for (String itemStackString : config.getStringList("global-required-tools")) {
ItemStack tool = CompatibleMaterial.getMaterial(itemStackString).getItem();
if (tool == null) continue;
this.globalRequiredTools.add(tool);
XMaterial.matchXMaterial(itemStackString).ifPresent(material -> globalRequiredTools.add(material.parseItem()));
}
this.globalAxeRequired = config.getBoolean("global-required-axe", false);
// Load required axe
if (config.contains("required-axe"))
if (config.contains("required-axe")) {
loadAxe(config);
}
}
private void loadAxe(YamlConfiguration config) {
private void loadAxe(Config config) {
// Reset the axe loaded, but load the NBT anyway in case someone wanted to use another plugin to give it.
this.requiredAxeKey = config.getString("required-axe.nbt");
this.requiredAxe = null;
@ -188,24 +170,23 @@ public class TreeDefinitionManager extends Manager {
return;
}
CompatibleMaterial material = CompatibleMaterial.getMaterial(typeString);
if (material == null) {
Optional<XMaterial> material = XMaterial.matchXMaterial(typeString);
if (!material.isPresent()) {
plugin.getLogger().warning("Material " + typeString + " is invalid.");
return;
}
ItemStack item = material.getItem();
ItemStack item = material.get().parseItem();
// Add display name and lore
String displayName = TextUtils.formatText(config.getString("required-axe.name"));
List<String> lore = config.getStringList("required-axe.lore").stream()
.map(TextUtils::formatText)
Component displayName = MiniMessage.miniMessage().deserialize(config.getString("required-axe.name"));
List<Component> lore = config.getStringList("required-axe.lore").stream()
.map(text -> MiniMessage.miniMessage().deserialize(text))
.collect(Collectors.toList());
ItemMeta meta = item.getItemMeta();
meta.setDisplayName(displayName);
meta.setLore(lore);
ItemBuilder itemBuilder = ItemBuilder.from(item)
.name(displayName)
.lore(lore);
// Enchants
for (String enchantString : config.getStringList("required-axe.enchants")) {
@ -229,10 +210,10 @@ public class TreeDefinitionManager extends Manager {
continue;
}
meta.addEnchant(enchantment, level, true);
itemBuilder = itemBuilder.enchant(enchantment, level, true);
}
item.setItemMeta(meta);
item = itemBuilder.build();
// Apply NBT
NBTItem nbtItem = new NBTItem(item);
@ -258,11 +239,6 @@ public class TreeDefinitionManager extends Manager {
return globalAxeRequired;
}
@Override
public void disable() {
this.treeDefinitions.clear();
}
/**
* Gets a Set of possible TreeDefinitions that match the given Block
*
@ -288,8 +264,8 @@ public class TreeDefinitionManager extends Manager {
switch (treeBlockType) {
case LOG:
for (TreeDefinition treeDefinition : possibleTreeDefinitions) {
for (CompatibleMaterial material : treeDefinition.getLogMaterial()) {
if (material.equals(CompatibleMaterial.getMaterial(block))) {
for (XMaterial material : treeDefinition.getLogMaterial()) {
if (material == XMaterial.matchXMaterial(block.getType())) {
matchingTreeDefinitions.add(treeDefinition);
break;
}
@ -298,8 +274,8 @@ public class TreeDefinitionManager extends Manager {
break;
case LEAF:
for (TreeDefinition treeDefinition : possibleTreeDefinitions) {
for (CompatibleMaterial material : treeDefinition.getLeafMaterial()) {
if (material.equals(CompatibleMaterial.getMaterial(block))) {
for (XMaterial material : treeDefinition.getLeafMaterial()) {
if (material == XMaterial.matchXMaterial(block.getType())) {
matchingTreeDefinitions.add(treeDefinition);
break;
}
@ -319,8 +295,9 @@ public class TreeDefinitionManager extends Manager {
* @return True if the tool is allowed for toppling any trees
*/
public boolean isToolValidForAnyTreeDefinition(ItemStack tool) {
if (ConfigurationManager.Setting.IGNORE_REQUIRED_TOOLS.getBoolean())
if (!plugin.getMainConfig().getBoolean("Settings.Ignore Required Tools")) {
return true;
}
for (TreeDefinition treeDefinition : this.treeDefinitions) {
if (treeDefinition.isRequiredAxe() || isGlobalAxeRequired()) {
@ -350,9 +327,9 @@ public class TreeDefinitionManager extends Manager {
* @return True if the tool is allowed for toppling the given TreeDefinition
*/
public boolean isToolValidForTreeDefinition(TreeDefinition treeDefinition, ItemStack tool) {
if (ConfigurationManager.Setting.IGNORE_REQUIRED_TOOLS.getBoolean())
if (!plugin.getMainConfig().getBoolean("Settings.Ignore Required Tools")) {
return true;
}
// If the tree definition requires the custom axe, don't allow any other checks to pass.
if (treeDefinition.isRequiredAxe() || isGlobalAxeRequired()) {
@ -378,7 +355,7 @@ public class TreeDefinitionManager extends Manager {
* @param isForEntireTree If the loot is for the entire tree
*/
public void dropTreeLoot(TreeDefinition treeDefinition, ITreeBlock treeBlock, Player player, boolean hasSilkTouch, boolean isForEntireTree) {
boolean addToInventory = ConfigurationManager.Setting.ADD_ITEMS_TO_INVENTORY.getBoolean();
boolean addToInventory = plugin.getMainConfig().getBoolean("Settings.Add Items To Inventory");
boolean hasBonusChance = player.hasPermission("ultimatetimber.bonusloot");
List<ItemStack> lootedItems = new ArrayList<>();
List<String> lootedCommands = new ArrayList<>();
@ -389,10 +366,8 @@ public class TreeDefinitionManager extends Manager {
toTry.addAll(treeDefinition.getEntireTreeLoot());
toTry.addAll(this.globalEntireTreeLoot);
} else {
if (ConfigurationManager.Setting.APPLY_SILK_TOUCH.getBoolean() && hasSilkTouch) {
if (ConfigurationManager.Setting.HOOKS_APPLY_EXTRA_DROPS.getBoolean()
&& McMMOHook.hasWoodcuttingDoubleDrops(player))
lootedItems.addAll(BlockUtils.getBlockDrops(treeBlock));
// TODO: Add the mcMMO hook back.
if (plugin.getMainConfig().getBoolean("Settings.Apply Silk Touch") && hasSilkTouch) {
lootedItems.addAll(BlockUtils.getBlockDrops(treeBlock));
} else {
switch (treeBlock.getTreeBlockType()) {
@ -400,9 +375,6 @@ public class TreeDefinitionManager extends Manager {
toTry.addAll(treeDefinition.getLogLoot());
toTry.addAll(this.globalLogLoot);
if (treeDefinition.shouldDropOriginalLog()) {
if (ConfigurationManager.Setting.HOOKS_APPLY_EXTRA_DROPS.getBoolean()
&& McMMOHook.hasWoodcuttingDoubleDrops(player))
lootedItems.addAll(BlockUtils.getBlockDrops(treeBlock));
lootedItems.addAll(BlockUtils.getBlockDrops(treeBlock));
}
break;
@ -410,9 +382,6 @@ public class TreeDefinitionManager extends Manager {
toTry.addAll(treeDefinition.getLeafLoot());
toTry.addAll(this.globalLeafLoot);
if (treeDefinition.shouldDropOriginalLeaf()) {
if (ConfigurationManager.Setting.HOOKS_APPLY_EXTRA_DROPS.getBoolean()
&& McMMOHook.hasWoodcuttingDoubleDrops(player))
lootedItems.addAll(BlockUtils.getBlockDrops(treeBlock));
lootedItems.addAll(BlockUtils.getBlockDrops(treeBlock));
}
break;
@ -421,24 +390,22 @@ public class TreeDefinitionManager extends Manager {
}
// Roll the dice
double bonusLootMultiplier = ConfigurationManager.Setting.BONUS_LOOT_MULTIPLIER.getDouble();
double bonusLootMultiplier = plugin.getMainConfig().getDouble("Settings.Bonus Loot Multiplier");
for (TreeLoot treeLoot : toTry) {
if (treeLoot == null) continue;
double chance = hasBonusChance ? treeLoot.getChance() * bonusLootMultiplier : treeLoot.getChance();
if (this.random.nextDouble() > chance / 100)
if (treeLoot == null) {
continue;
}
double chance = hasBonusChance ? treeLoot.getChance() * bonusLootMultiplier : treeLoot.getChance();
if (ThreadLocalRandom.current().nextDouble() > chance / 100) {
continue;
}
if (treeLoot.hasItem()) {
if (ConfigurationManager.Setting.HOOKS_APPLY_EXTRA_DROPS.getBoolean()
&& McMMOHook.hasWoodcuttingDoubleDrops(player))
lootedItems.add(treeLoot.getItem());
lootedItems.add(treeLoot.getItem());
}
if (treeLoot.hasCommand()) {
if (ConfigurationManager.Setting.HOOKS_APPLY_EXTRA_DROPS.getBoolean()
&& McMMOHook.hasWoodcuttingDoubleDrops(player))
lootedCommands.add(treeLoot.getCommand());
lootedCommands.add(treeLoot.getCommand());
}
}
@ -446,15 +413,19 @@ public class TreeDefinitionManager extends Manager {
// Add to inventory or drop on ground
if (addToInventory && player.getWorld().equals(treeBlock.getLocation().getWorld())) {
List<ItemStack> extraItems = new ArrayList<>();
for (ItemStack lootedItem : lootedItems)
for (ItemStack lootedItem : lootedItems) {
extraItems.addAll(player.getInventory().addItem(lootedItem).values());
}
Location location = player.getLocation().clone().subtract(0.5, 0, 0.5);
for (ItemStack extraItem : extraItems)
for (ItemStack extraItem : extraItems) {
location.getWorld().dropItemNaturally(location, extraItem);
}
} else {
Location location = treeBlock.getLocation().clone().add(0.5, 0.5, 0.5);
for (ItemStack lootedItem : lootedItems)
for (ItemStack lootedItem : lootedItems) {
location.getWorld().dropItemNaturally(location, lootedItem);
}
}
// Run looted commands
@ -474,8 +445,8 @@ public class TreeDefinitionManager extends Manager {
*
* @return A Set of IBlockData of plantable soil
*/
public Set<CompatibleMaterial> getPlantableSoilMaterial(TreeDefinition treeDefinition) {
Set<CompatibleMaterial> plantableSoilBlockData = new HashSet<>();
public Set<XMaterial> getPlantableSoilMaterial(TreeDefinition treeDefinition) {
Set<XMaterial> plantableSoilBlockData = new HashSet<>();
plantableSoilBlockData.addAll(treeDefinition.getPlantableSoilMaterial());
plantableSoilBlockData.addAll(this.globalPlantableSoil);
return plantableSoilBlockData;
@ -491,11 +462,11 @@ public class TreeDefinitionManager extends Manager {
*/
private TreeLoot getTreeLootEntry(TreeBlockType treeBlockType, ConfigurationSection configurationSection) {
String material = configurationSection.getString("material");
CompatibleMaterial compatibleMaterial = material == null ? null : CompatibleMaterial.getMaterial(material);
XMaterial compatibleMaterial = material == null ? null : XMaterial.matchXMaterial(material).orElse(null);
ItemStack item = compatibleMaterial == null ? null : compatibleMaterial.getItem();
ItemStack item = compatibleMaterial == null ? null : compatibleMaterial.parseItem();
String command = configurationSection.getString("command");
double chance = configurationSection.getDouble("chance");
return new TreeLoot(treeBlockType, item, command, chance);
}
}
}

View File

@ -1,8 +1,8 @@
package com.songoda.ultimatetimber.manager;
package com.craftaro.ultimatetimber.managers;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.ultimatetimber.UltimateTimber;
import com.songoda.ultimatetimber.tree.*;
import com.craftaro.ultimatetimber.UltimateTimber;
import com.craftaro.ultimatetimber.tree.*;
import com.craftaro.core.third_party.com.cryptomorin.xseries.XMaterial;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
@ -10,57 +10,35 @@ import org.bukkit.util.Vector;
import java.util.*;
public class TreeDetectionManager extends Manager {
public class TreeDetectionManager {
private final Set<Vector> VALID_TRUNK_OFFSETS, VALID_BRANCH_OFFSETS, VALID_LEAF_OFFSETS;
private TreeDefinitionManager treeDefinitionManager;
private PlacedBlockManager placedBlockManager;
private int numLeavesRequiredForTree;
private boolean onlyBreakLogsUpwards, entireTreeBase, destroyLeaves;
public TreeDetectionManager(UltimateTimber ultimateTimber) {
super(ultimateTimber);
this.VALID_BRANCH_OFFSETS = new HashSet<>();
this.VALID_TRUNK_OFFSETS = new HashSet<>();
this.VALID_LEAF_OFFSETS = new HashSet<>();
private final UltimateTimber plugin;
private final Set<Vector> validTrunkOffsets = new HashSet<>(),
validBranchOffsets = new HashSet<>(),
validLeafOffsets = new HashSet<>();
public TreeDetectionManager(UltimateTimber plugin) {
this.plugin = plugin;
// 3x2x3 centered around log, excluding -y axis
for (int y = 0; y <= 1; y++)
for (int x = -1; x <= 1; x++)
for (int z = -1; z <= 1; z++)
this.VALID_BRANCH_OFFSETS.add(new Vector(x, y, z));
this.validBranchOffsets.add(new Vector(x, y, z));
// 3x3x3 centered around log
for (int y = -1; y <= 1; y++)
for (int x = -1; x <= 1; x++)
for (int z = -1; z <= 1; z++)
this.VALID_TRUNK_OFFSETS.add(new Vector(x, y, z));
this.validTrunkOffsets.add(new Vector(x, y, z));
// Adjacent blocks to log
for (int i = -1; i <= 1; i += 2) {
this.VALID_LEAF_OFFSETS.add(new Vector(i, 0, 0));
this.VALID_LEAF_OFFSETS.add(new Vector(0, i, 0));
this.VALID_LEAF_OFFSETS.add(new Vector(0, 0, i));
this.validLeafOffsets.add(new Vector(i, 0, 0));
this.validLeafOffsets.add(new Vector(0, i, 0));
this.validLeafOffsets.add(new Vector(0, 0, i));
}
}
@Override
public void reload() {
this.treeDefinitionManager = this.plugin.getTreeDefinitionManager();
this.placedBlockManager = this.plugin.getPlacedBlockManager();
this.numLeavesRequiredForTree = ConfigurationManager.Setting.LEAVES_REQUIRED_FOR_TREE.getInt();
this.onlyBreakLogsUpwards = ConfigurationManager.Setting.ONLY_DETECT_LOGS_UPWARDS.getBoolean();
this.entireTreeBase = ConfigurationManager.Setting.BREAK_ENTIRE_TREE_BASE.getBoolean();
this.destroyLeaves = ConfigurationManager.Setting.DESTROY_LEAVES.getBoolean();
}
@Override
public void disable() {
}
/**
* Detects a tree given an initial starting block
*
@ -72,10 +50,11 @@ public class TreeDetectionManager extends Manager {
TreeBlock initialTreeBlock = new TreeBlock(initialBlock, TreeBlockType.LOG);
TreeBlockSet<Block> detectedTreeBlocks = new TreeBlockSet<>(initialTreeBlock);
Set<TreeDefinition> possibleTreeDefinitions = this.treeDefinitionManager.getTreeDefinitionsForLog(initialBlock);
Set<TreeDefinition> possibleTreeDefinitions = plugin.getTreeDefinitionManager().getTreeDefinitionsForLog(initialBlock);
if (possibleTreeDefinitions.isEmpty())
if (possibleTreeDefinitions.isEmpty()) {
return null;
}
// Detect tree trunk
List<Block> trunkBlocks = new ArrayList<>();
@ -83,14 +62,14 @@ public class TreeDetectionManager extends Manager {
Block targetBlock = initialBlock;
while (this.isValidLogType(possibleTreeDefinitions, null, (targetBlock = targetBlock.getRelative(BlockFace.UP)))) {
trunkBlocks.add(targetBlock);
possibleTreeDefinitions.retainAll(this.treeDefinitionManager.narrowTreeDefinition(possibleTreeDefinitions, targetBlock, TreeBlockType.LOG));
possibleTreeDefinitions.retainAll(plugin.getTreeDefinitionManager().narrowTreeDefinition(possibleTreeDefinitions, targetBlock, TreeBlockType.LOG));
}
if (!this.onlyBreakLogsUpwards) {
if (!plugin.getMainConfig().getBoolean("Settings.Only Detect Logs Upwards")) {
targetBlock = initialBlock;
while (this.isValidLogType(possibleTreeDefinitions, null, (targetBlock = targetBlock.getRelative(BlockFace.DOWN)))) {
trunkBlocks.add(targetBlock);
possibleTreeDefinitions.retainAll(this.treeDefinitionManager.narrowTreeDefinition(possibleTreeDefinitions, targetBlock, TreeBlockType.LOG));
possibleTreeDefinitions.retainAll(plugin.getTreeDefinitionManager().narrowTreeDefinition(possibleTreeDefinitions, targetBlock, TreeBlockType.LOG));
}
}
@ -98,27 +77,31 @@ public class TreeDetectionManager extends Manager {
Collections.reverse(trunkBlocks);
// Detect branches off the main trunk
for (Block trunkBlock : trunkBlocks)
for (Block trunkBlock : trunkBlocks) {
this.recursiveBranchSearch(possibleTreeDefinitions, trunkBlocks, detectedTreeBlocks, trunkBlock, initialBlock.getLocation().getBlockY());
}
// Detect leaves off the trunk/branches
Set<ITreeBlock<Block>> branchBlocks = new HashSet<>(detectedTreeBlocks.getLogBlocks());
for (ITreeBlock<Block> branchBlock : branchBlocks)
for (ITreeBlock<Block> branchBlock : branchBlocks) {
this.recursiveLeafSearch(possibleTreeDefinitions, detectedTreeBlocks, branchBlock.getBlock(), new HashSet<>());
}
// Use the first tree definition in the set
TreeDefinition actualTreeDefinition = possibleTreeDefinitions.iterator().next();
// Trees need at least a certain number of leaves
if (detectedTreeBlocks.getLeafBlocks().size() < this.numLeavesRequiredForTree)
if (detectedTreeBlocks.getLeafBlocks().size() < plugin.getMainConfig().getInt("Settings.Leaves Required For Tree")) {
return null;
}
// Remove leaves if we don't care about the leaves
if (!this.destroyLeaves)
if (!plugin.getMainConfig().getBoolean("Settings.Destroy Leaves")) {
detectedTreeBlocks.removeAll(TreeBlockType.LEAF);
}
// Check that the tree isn't on the ground if enabled
if (this.entireTreeBase) {
if (plugin.getMainConfig().getBoolean("Settings.Break Entire Tree Base")) {
Set<Block> groundBlocks = new HashSet<>();
for (ITreeBlock<Block> treeBlock : detectedTreeBlocks.getLogBlocks())
if (treeBlock != detectedTreeBlocks.getInitialLogBlock() && treeBlock.getLocation().getBlockY() == initialBlock.getLocation().getBlockY())
@ -128,8 +111,8 @@ public class TreeDetectionManager extends Manager {
Block blockBelow = block.getRelative(BlockFace.DOWN);
boolean blockBelowIsLog = this.isValidLogType(possibleTreeDefinitions, null, blockBelow);
boolean blockBelowIsSoil = false;
for (CompatibleMaterial material : treeDefinitionManager.getPlantableSoilMaterial(actualTreeDefinition)) {
if (material.equals(CompatibleMaterial.getMaterial(blockBelow))) {
for (XMaterial material : treeDefinitionManager.getPlantableSoilMaterial(actualTreeDefinition)) {
if (material == XMaterial.matchXMaterial(blockBelow.getType())) {
blockBelowIsSoil = true;
break;
}
@ -153,13 +136,13 @@ public class TreeDetectionManager extends Manager {
* @param startingBlockY The Y coordinate of the initial block
*/
private void recursiveBranchSearch(Set<TreeDefinition> treeDefinitions, List<Block> trunkBlocks, TreeBlockSet<Block> treeBlocks, Block block, int startingBlockY) {
for (Vector offset : this.onlyBreakLogsUpwards ? this.VALID_BRANCH_OFFSETS : this.VALID_TRUNK_OFFSETS) {
for (Vector offset : plugin.getMainConfig().getBoolean("Settings.Only Detect Logs Upwards") ? this.validBranchOffsets : this.validTrunkOffsets) {
Block targetBlock = block.getRelative(offset.getBlockX(), offset.getBlockY(), offset.getBlockZ());
TreeBlock treeBlock = new TreeBlock(targetBlock, TreeBlockType.LOG);
if (this.isValidLogType(treeDefinitions, trunkBlocks, targetBlock) && !treeBlocks.contains(treeBlock)) {
treeBlocks.add(treeBlock);
treeDefinitions.retainAll(this.treeDefinitionManager.narrowTreeDefinition(treeDefinitions, targetBlock, TreeBlockType.LOG));
if (!this.onlyBreakLogsUpwards || targetBlock.getLocation().getBlockY() > startingBlockY)
treeDefinitions.retainAll(plugin.getTreeDefinitionManager().narrowTreeDefinition(treeDefinitions, targetBlock, TreeBlockType.LOG));
if (!plugin.getMainConfig().getBoolean("Settings.Only Detect Logs Upwards") || targetBlock.getLocation().getBlockY() > startingBlockY)
this.recursiveBranchSearch(treeDefinitions, trunkBlocks, treeBlocks, targetBlock, startingBlockY);
}
}
@ -175,7 +158,7 @@ public class TreeDetectionManager extends Manager {
private void recursiveLeafSearch(Set<TreeDefinition> treeDefinitions, TreeBlockSet<Block> treeBlocks, Block block, Set<Block> visitedBlocks) {
boolean detectLeavesDiagonally = treeDefinitions.stream().anyMatch(TreeDefinition::shouldDetectLeavesDiagonally);
for (Vector offset : !detectLeavesDiagonally ? this.VALID_LEAF_OFFSETS : this.VALID_TRUNK_OFFSETS) {
for (Vector offset : !detectLeavesDiagonally ? validLeafOffsets : validTrunkOffsets) {
Block targetBlock = block.getRelative(offset.getBlockX(), offset.getBlockY(), offset.getBlockZ());
if (visitedBlocks.contains(targetBlock))
continue;
@ -184,7 +167,7 @@ public class TreeDetectionManager extends Manager {
TreeBlock treeBlock = new TreeBlock(targetBlock, TreeBlockType.LEAF);
if (this.isValidLeafType(treeDefinitions, treeBlocks, targetBlock) && !treeBlocks.contains(treeBlock) && !this.doesLeafBorderInvalidLog(treeDefinitions, treeBlocks, targetBlock)) {
treeBlocks.add(treeBlock);
treeDefinitions.retainAll(this.treeDefinitionManager.narrowTreeDefinition(treeDefinitions, targetBlock, TreeBlockType.LEAF));
treeDefinitions.retainAll(plugin.getTreeDefinitionManager().narrowTreeDefinition(treeDefinitions, targetBlock, TreeBlockType.LEAF));
this.recursiveLeafSearch(treeDefinitions, treeBlocks, targetBlock, visitedBlocks);
}
}
@ -199,7 +182,7 @@ public class TreeDetectionManager extends Manager {
* @return True if the leaf borders an invalid log, otherwise false
*/
private boolean doesLeafBorderInvalidLog(Set<TreeDefinition> treeDefinitions, TreeBlockSet<Block> treeBlocks, Block block) {
for (Vector offset : this.VALID_TRUNK_OFFSETS) {
for (Vector offset : validTrunkOffsets) {
Block targetBlock = block.getRelative(offset.getBlockX(), offset.getBlockY(), offset.getBlockZ());
if (this.isValidLogType(treeDefinitions, null, targetBlock) && !treeBlocks.contains(new TreeBlock(targetBlock, TreeBlockType.LOG)))
return true;
@ -217,14 +200,14 @@ public class TreeDetectionManager extends Manager {
*/
private boolean isValidLogType(Set<TreeDefinition> treeDefinitions, List<Block> trunkBlocks, Block block) {
// Check if block is placed
if (this.placedBlockManager.isBlockPlaced(block))
if (plugin.getPlacedBlockManager().isBlockPlaced(block))
return false;
// Check if it matches the tree definition
boolean isCorrectType = false;
for (TreeDefinition treeDefinition : treeDefinitions) {
for (CompatibleMaterial material : treeDefinition.getLogMaterial()) {
if (material.equals(CompatibleMaterial.getMaterial(block))) {
for (XMaterial material : treeDefinition.getLogMaterial()) {
if (material == XMaterial.matchXMaterial(block.getType())) {
isCorrectType = true;
break;
}
@ -241,7 +224,7 @@ public class TreeDetectionManager extends Manager {
Location location = block.getLocation();
for (TreeDefinition treeDefinition : treeDefinitions) {
double maxDistance = treeDefinition.getMaxLogDistanceFromTrunk() * treeDefinition.getMaxLogDistanceFromTrunk();
if (!this.onlyBreakLogsUpwards) // Help detect logs more often if the tree isn't broken at the base
if (!plugin.getMainConfig().getBoolean("Settings.Only Detect Logs Upwards")) // Help detect logs more often if the tree isn't broken at the base
maxDistance *= 1.5;
for (Block trunkBlock : trunkBlocks)
if (location.distanceSquared(trunkBlock.getLocation()) < maxDistance)
@ -261,14 +244,14 @@ public class TreeDetectionManager extends Manager {
*/
private boolean isValidLeafType(Set<TreeDefinition> treeDefinitions, TreeBlockSet<Block> treeBlocks, Block block) {
// Check if block is placed
if (this.placedBlockManager.isBlockPlaced(block))
if (plugin.getPlacedBlockManager().isBlockPlaced(block))
return false;
// Check if it matches the tree definition
boolean isCorrectType = false;
for (TreeDefinition treeDefinition : treeDefinitions) {
for (CompatibleMaterial material : treeDefinition.getLeafMaterial()) {
if (material.equals(CompatibleMaterial.getMaterial(block))) {
for (XMaterial material : treeDefinition.getLeafMaterial()) {
if (material == XMaterial.matchXMaterial(block.getType())) {
isCorrectType = true;
break;
}
@ -286,4 +269,4 @@ public class TreeDetectionManager extends Manager {
return treeBlocks.getLogBlocks().stream().anyMatch(x -> x.getLocation().distanceSquared(block.getLocation()) < maxDistanceFromLog * maxDistanceFromLog);
}
}
}

View File

@ -1,18 +1,14 @@
package com.songoda.ultimatetimber.manager;
package com.craftaro.ultimatetimber.managers;
import com.songoda.core.compatibility.CompatibleHand;
import com.songoda.core.hooks.JobsHook;
import com.songoda.core.hooks.LogManager;
import com.songoda.core.hooks.McMMOHook;
import com.songoda.core.utils.ItemUtils;
import com.songoda.core.world.SItemStack;
import com.songoda.ultimatetimber.UltimateTimber;
import com.songoda.ultimatetimber.events.TreeFallEvent;
import com.songoda.ultimatetimber.events.TreeFellEvent;
import com.songoda.ultimatetimber.misc.OnlyToppleWhile;
import com.songoda.ultimatetimber.tree.DetectedTree;
import com.songoda.ultimatetimber.tree.ITreeBlock;
import com.songoda.ultimatetimber.tree.TreeBlockSet;
import com.craftaro.core.compatibility.CompatibleHand;
import com.craftaro.core.utils.ItemUtils;
import com.craftaro.core.world.SItemStack;
import com.craftaro.ultimatetimber.UltimateTimber;
import com.craftaro.ultimatetimber.misc.OnlyToppleWhile;
import com.craftaro.ultimatetimber.tree.DetectedTree;
import com.craftaro.ultimatetimber.tree.TreeBlockSet;
import com.craftaro.ultimatetimber.events.TreePostFallEvent;
import com.craftaro.ultimatetimber.events.TreePreFallEvent;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Material;
@ -25,25 +21,12 @@ import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.inventory.ItemStack;
import java.util.stream.Collectors;
public class TreeFallManager extends Manager implements Listener {
private int maxLogBlocksAllowed;
public TreeFallManager(UltimateTimber ultimateTimber) {
super(ultimateTimber);
Bukkit.getPluginManager().registerEvents(this, ultimateTimber);
}
@Override
public void reload() {
this.maxLogBlocksAllowed = ConfigurationManager.Setting.MAX_LOGS_PER_CHOP.getInt();
}
@Override
public void disable() {
public class TreeFallManager implements Listener {
private final UltimateTimber plugin;
public TreeFallManager(UltimateTimber plugin) {
this.plugin = plugin;
Bukkit.getPluginManager().registerEvents(this, plugin);
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@ -51,7 +34,6 @@ public class TreeFallManager extends Manager implements Listener {
TreeDefinitionManager treeDefinitionManager = this.plugin.getTreeDefinitionManager();
TreeDetectionManager treeDetectionManager = this.plugin.getTreeDetectionManager();
TreeAnimationManager treeAnimationManager = this.plugin.getTreeAnimationManager();
ChoppingManager choppingManager = this.plugin.getChoppingManager();
SaplingManager saplingManager = this.plugin.getSaplingManager();
Player player = event.getPlayer();
@ -67,22 +49,19 @@ public class TreeFallManager extends Manager implements Listener {
// Condition checks
boolean isValid = true;
if (ConfigurationManager.Setting.DISABLED_WORLDS.getStringList().contains(player.getWorld().getName()))
if (plugin.getMainConfig().getStringList("Settings.Disabled Worlds").contains(player.getWorld().getName()))
isValid = false;
if (!ConfigurationManager.Setting.ALLOW_CREATIVE_MODE.getBoolean() && player.getGameMode().equals(GameMode.CREATIVE))
if (!plugin.getMainConfig().getBoolean("Settings.Allow Creative Mode") && player.getGameMode() == GameMode.CREATIVE)
isValid = false;
if (!this.checkToppleWhile(player))
isValid = false;
if (ConfigurationManager.Setting.REQUIRE_CHOP_PERMISSION.getBoolean() && !player.hasPermission("ultimatetimber.chop"))
if (plugin.getMainConfig().getBoolean("Settings.Require Chop Permission") && !player.hasPermission("ultimatetimber.chop"))
isValid = false;
if (!choppingManager.isChopping(player))
isValid = false;
if (choppingManager.isInCooldown(player))
if (!plugin.getPlayerManager().canTopple(player))
isValid = false;
if (treeAnimationManager.isBlockInAnimation(block)) {
@ -93,11 +72,7 @@ public class TreeFallManager extends Manager implements Listener {
if (!treeDefinitionManager.isToolValidForAnyTreeDefinition(tool))
isValid = false;
if (ConfigurationManager.Setting.HOOKS_REQUIRE_ABILITY_ACTIVE.getBoolean()
&& !McMMOHook.isUsingTreeFeller(player))
isValid = false;
boolean alwaysReplantSapling = ConfigurationManager.Setting.ALWAYS_REPLANT_SAPLING.getBoolean();
boolean alwaysReplantSapling = plugin.getMainConfig().getBoolean("Settings.Always Replant Sapling");
if (!isValid && !alwaysReplantSapling)
return;
@ -117,12 +92,12 @@ public class TreeFallManager extends Manager implements Listener {
return;
short toolDamage = this.getToolDamage(detectedTree.getDetectedTreeBlocks(), tool.containsEnchantment(Enchantment.SILK_TOUCH));
if (ConfigurationManager.Setting.PROTECT_TOOL.getBoolean() && !ItemUtils.hasEnoughDurability(tool, toolDamage)) {
if (plugin.getMainConfig().getBoolean("Settings.Protect Tool") && !ItemUtils.hasEnoughDurability(tool, toolDamage)) {
return;
}
// Trigger fall event
TreeFallEvent treeFallEvent = new TreeFallEvent(player, detectedTree);
TreePreFallEvent treeFallEvent = new TreePreFallEvent(player, detectedTree);
Bukkit.getPluginManager().callEvent(treeFallEvent);
if (treeFallEvent.isCancelled())
return;
@ -130,39 +105,28 @@ public class TreeFallManager extends Manager implements Listener {
// Valid tree and meets all conditions past this point
event.setCancelled(true);
detectedTree.getDetectedTreeBlocks().sortAndLimit(maxLogBlocksAllowed);
choppingManager.cooldownPlayer(player);
detectedTree.getDetectedTreeBlocks().sortAndLimit(plugin.getMainConfig().getInt("Settings.Max Logs Per Chop"));
plugin.getPlayerManager().cooldownPlayer(player);
// Destroy initiated block if enabled
if (ConfigurationManager.Setting.DESTROY_INITIATED_BLOCK.getBoolean()) {
if (plugin.getMainConfig().getBoolean("Settings.Destroy Initiated Block")) {
detectedTree.getDetectedTreeBlocks().getInitialLogBlock().getBlock().setType(Material.AIR);
detectedTree.getDetectedTreeBlocks().remove(detectedTree.getDetectedTreeBlocks().getInitialLogBlock());
}
boolean isCreative = player.getGameMode().equals(GameMode.CREATIVE);
boolean isCreative = player.getGameMode().equals(GameMode.CREATIVE);
if (!isCreative) {
new SItemStack(tool).addDamage(player, toolDamage, true);
}
if (ConfigurationManager.Setting.HOOKS_APPLY_EXPERIENCE.getBoolean()) {
McMMOHook.addWoodcutting(player, detectedTree.getDetectedTreeBlocks().getAllTreeBlocks().stream()
.map(ITreeBlock::getBlock).collect(Collectors.toList()));
if (!isCreative && JobsHook.isEnabled())
for (ITreeBlock<Block> treeBlock : detectedTree.getDetectedTreeBlocks().getLogBlocks())
JobsHook.breakBlock(player, treeBlock.getBlock());
}
for (ITreeBlock<Block> treeBlock : detectedTree.getDetectedTreeBlocks().getAllTreeBlocks())
LogManager.logRemoval(player, treeBlock.getBlock());
// TODO: Add Jobs & mcMMO hook back here
treeAnimationManager.runAnimation(detectedTree, player);
treeDefinitionManager.dropTreeLoot(detectedTree.getTreeDefinition(), detectedTree.getDetectedTreeBlocks().getInitialLogBlock(), player, false, true);
// Trigger fell event
TreeFellEvent treeFellEvent = new TreeFellEvent(player, detectedTree);
TreePostFallEvent treeFellEvent = new TreePostFallEvent(player, detectedTree);
Bukkit.getPluginManager().callEvent(treeFellEvent);
}
@ -174,7 +138,7 @@ public class TreeFallManager extends Manager implements Listener {
* @return True if the check passes, otherwise false
*/
private boolean checkToppleWhile(Player player) {
switch (OnlyToppleWhile.fromString(ConfigurationManager.Setting.ONLY_TOPPLE_WHILE.getString())) {
switch (OnlyToppleWhile.fromString(plugin.getMainConfig().getString("Settings.Only Topple While"))) {
case SNEAKING:
return player.isSneaking();
case NOT_SNEAKING:
@ -185,13 +149,13 @@ public class TreeFallManager extends Manager implements Listener {
}
private short getToolDamage(TreeBlockSet<Block> treeBlocks, boolean hasSilkTouch) {
if (!ConfigurationManager.Setting.REALISTIC_TOOL_DAMAGE.getBoolean())
if (!plugin.getMainConfig().getBoolean("Settings.Realistic Tool Damage"))
return 1;
if (ConfigurationManager.Setting.APPLY_SILK_TOUCH_TOOL_DAMAGE.getBoolean() && hasSilkTouch) {
if (plugin.getMainConfig().getBoolean("Settings.Apply Silk Touch Tool Damage") && hasSilkTouch) {
return (short) treeBlocks.size();
} else {
return (short) treeBlocks.getLogBlocks().size();
}
}
}
}

View File

@ -1,4 +1,4 @@
package com.songoda.ultimatetimber.misc;
package com.craftaro.ultimatetimber.misc;
public enum OnlyToppleWhile {
SNEAKING,
@ -17,4 +17,4 @@ public enum OnlyToppleWhile {
return value;
return OnlyToppleWhile.ALWAYS;
}
}
}

View File

@ -0,0 +1,131 @@
package com.craftaro.ultimatetimber.players;
import com.craftaro.ultimatetimber.UltimateTimber;
import com.craftaro.core.database.Data;
import org.bukkit.entity.Player;
import java.time.Instant;
import java.util.*;
import java.util.function.Consumer;
public class PlayerManager {
private final UltimateTimber plugin;
private final Map<UUID, TimberPlayer> playerStorage = new HashMap<>();
public PlayerManager(UltimateTimber plugin) {
this.plugin = plugin;
}
/**
* Toggles a player's chopping status
*
* @param player The player to toggle
* @return True if the player has chopping enabled, or false if they have it disabled
*/
public boolean togglePlayer(Player player) {
TimberPlayer timberPlayer = playerStorage.get(player.getUniqueId());
if (timberPlayer == null) {
return false;
}
timberPlayer.setChoppingEnabled(!timberPlayer.isChoppingEnabled());
return timberPlayer.isChoppingEnabled();
}
/**
* Sets a player into cooldown
*
* @param player The player to cooldown
*/
public void cooldownPlayer(Player player) {
int cooldownTime = plugin.getMainConfig().getInt("Settings.Tree Topple Cooldown");
if (cooldownTime <= 0) {
return;
}
if (player.hasPermission("ultimatetimber.bypasscooldown")) {
return;
}
TimberPlayer timberPlayer = playerStorage.get(player.getUniqueId());
if (timberPlayer == null) {
return;
}
timberPlayer.setLastChoppingUse(Instant.now().getEpochSecond() + cooldownTime);
}
/**
* Checks if a player is in cooldown and if they can topple trees
*
* @param player The player to check
* @return True if the player can topple trees, otherwise false
*/
public boolean canTopple(Player player) {
TimberPlayer timberPlayer = playerStorage.get(player.getUniqueId());
if (timberPlayer == null) {
return false;
}
if (!timberPlayer.isChoppingEnabled()) {
return false;
}
int cooldownTime = plugin.getMainConfig().getInt("Settings.Tree Topple Cooldown");
if (cooldownTime <= 0) {
return true;
}
if (timberPlayer.getLastChoppingUse() >= Instant.now().getEpochSecond()) {
plugin.getLocaleManager().getMessage("event.onCooldown").sendMessage(player);
return false;
}
return true;
}
// Boring database stuff
/**
* Load the player into cache.
* @param player Player to load.
*/
public void loadPlayer(Player player) {
getPlayer(player, timberPlayer -> playerStorage.put(player.getUniqueId(), timberPlayer));
}
public void savePlayer(Player player) {
TimberPlayer timberPlayer = playerStorage.remove(player.getUniqueId());
if (timberPlayer == null) {
return;
}
plugin.getDataManager().save(timberPlayer);
}
public void saveAllPlayers() {
Collection<Data> dataToSave = new HashSet<>(playerStorage.values());
plugin.getDataManager().saveBatchSync(dataToSave);
}
private void getPlayer(Player player, Consumer<TimberPlayer> callback) {
if (playerStorage.containsKey(player.getUniqueId())) {
callback.accept(playerStorage.get(player.getUniqueId()));
return;
}
plugin.newChain().asyncFirst(() -> {
TimberPlayer timberPlayer = plugin.getDataManager().load(player.getUniqueId(), TimberPlayer.class, "players");
if (timberPlayer == null) {
timberPlayer = new TimberPlayer();
timberPlayer.setPlayer(player);
timberPlayer.setChoppingEnabled(true);
timberPlayer.setLastChoppingUse(0);
}
return timberPlayer;
}).abortIfNull()
.syncLast(callback::accept)
.execute();
}
}

View File

@ -0,0 +1,69 @@
package com.craftaro.ultimatetimber.players;
import com.craftaro.core.database.Data;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class TimberPlayer implements Data {
private Player player;
private boolean choppingEnabled;
private long lastChoppingUse;
public Player getPlayer() {
return player;
}
public boolean isChoppingEnabled() {
return choppingEnabled;
}
public long getLastChoppingUse() {
return lastChoppingUse;
}
protected void setPlayer(Player player) {
this.player = player;
}
public void setChoppingEnabled(boolean choppingEnabled) {
this.choppingEnabled = choppingEnabled;
}
public void setLastChoppingUse(long lastChoppingUse) {
this.lastChoppingUse = lastChoppingUse;
}
@Override
public UUID getUniqueId() {
return player.getUniqueId();
}
@Override
public Map<String, Object> serialize() {
Map<String, Object> serializedData = new HashMap<>();
serializedData.put("uuid", player.getUniqueId().toString());
serializedData.put("chopping_enabled", choppingEnabled);
serializedData.put("last_chopping_use", lastChoppingUse);
return serializedData;
}
@Override
public Data deserialize(Map<String, Object> map) {
this.player = Bukkit.getPlayer(UUID.fromString((String)map.get("uuid")));
this.choppingEnabled = (boolean)map.get("chopping_enabled");
this.lastChoppingUse = (long)map.get("last_chopping_use");
return this;
}
@Override
public String getTableName() {
return "players";
}
}

View File

@ -1,4 +1,5 @@
package com.songoda.ultimatetimber.tree;
package com.craftaro.ultimatetimber.tree;
import org.bukkit.block.Block;
@ -30,4 +31,4 @@ public class DetectedTree {
return this.detectedTreeBlocks;
}
}
}

View File

@ -1,4 +1,4 @@
package com.songoda.ultimatetimber.tree;
package com.craftaro.ultimatetimber.tree;
import org.bukkit.Location;
import org.bukkit.entity.FallingBlock;
@ -28,4 +28,4 @@ public class FallingTreeBlock implements ITreeBlock<FallingBlock> {
return this.treeBlockType;
}
}
}

View File

@ -1,4 +1,4 @@
package com.songoda.ultimatetimber.tree;
package com.craftaro.ultimatetimber.tree;
import org.bukkit.Location;
@ -25,4 +25,4 @@ public interface ITreeBlock<BlockType> {
*/
TreeBlockType getTreeBlockType();
}
}

View File

@ -1,4 +1,4 @@
package com.songoda.ultimatetimber.tree;
package com.craftaro.ultimatetimber.tree;
import org.bukkit.Location;
import org.bukkit.block.Block;
@ -43,4 +43,4 @@ public class TreeBlock implements ITreeBlock<Block> {
return oTreeBlock.block.equals(this.block) && oTreeBlock.treeBlockType.equals(this.treeBlockType);
}
}
}

View File

@ -1,15 +1,6 @@
package com.songoda.ultimatetimber.tree;
package com.craftaro.ultimatetimber.tree;
import org.bukkit.block.Block;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
public class TreeBlockSet<BlockType> implements Collection {
@ -219,4 +210,4 @@ public class TreeBlockSet<BlockType> implements Collection {
return treeBlocks.toArray();
}
}
}

View File

@ -1,4 +1,4 @@
package com.songoda.ultimatetimber.tree;
package com.craftaro.ultimatetimber.tree;
/**
* Represents a tree block type and whether it is a log or a leaf block
@ -6,4 +6,4 @@ package com.songoda.ultimatetimber.tree;
public enum TreeBlockType {
LOG,
LEAF
}
}

View File

@ -1,6 +1,6 @@
package com.songoda.ultimatetimber.tree;
package com.craftaro.ultimatetimber.tree;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.craftaro.core.third_party.com.cryptomorin.xseries.XMaterial;
import org.bukkit.inventory.ItemStack;
import java.util.Collections;
@ -9,8 +9,8 @@ import java.util.Set;
public class TreeDefinition {
private final String key;
private final Set<CompatibleMaterial> logMaterial, leafMaterial, plantableSoilMaterial;
private final CompatibleMaterial saplingMaterial;
private final Set<XMaterial> logMaterial, leafMaterial, plantableSoilMaterial;
private final XMaterial saplingMaterial;
private final double maxLogDistanceFromTrunk;
private final int maxLeafDistanceFromLog;
private final boolean detectLeavesDiagonally;
@ -19,8 +19,8 @@ public class TreeDefinition {
private final Set<ItemStack> requiredTools;
private final boolean requiredAxe;
public TreeDefinition(String key, Set<CompatibleMaterial> logMaterial, Set<CompatibleMaterial> leafMaterial, CompatibleMaterial saplingMaterial,
Set<CompatibleMaterial> plantableSoilMaterial, double maxLogDistanceFromTrunk, int maxLeafDistanceFromLog,
public TreeDefinition(String key, Set<XMaterial> logMaterial, Set<XMaterial> leafMaterial, XMaterial saplingMaterial,
Set<XMaterial> plantableSoilMaterial, double maxLogDistanceFromTrunk, int maxLeafDistanceFromLog,
boolean detectLeavesDiagonally, boolean dropOriginalLog, boolean dropOriginalLeaf, Set<TreeLoot> logLoot,
Set<TreeLoot> leafLoot, Set<TreeLoot> entireTreeLoot, Set<ItemStack> requiredTools, boolean requiredAxe) {
this.key = key;
@ -54,7 +54,7 @@ public class TreeDefinition {
*
* @return A Set of CompatibleMaterial
*/
public Set<CompatibleMaterial> getLogMaterial() {
public Set<XMaterial> getLogMaterial() {
return Collections.unmodifiableSet(this.logMaterial);
}
@ -63,7 +63,7 @@ public class TreeDefinition {
*
* @return A Set of CompatibleMaterial
*/
public Set<CompatibleMaterial> getLeafMaterial() {
public Set<XMaterial> getLeafMaterial() {
return Collections.unmodifiableSet(this.leafMaterial);
}
@ -72,7 +72,7 @@ public class TreeDefinition {
*
* @return An CompatibleMaterial instance for the sapling
*/
public CompatibleMaterial getSaplingMaterial() {
public XMaterial getSaplingMaterial() {
return this.saplingMaterial;
}
@ -81,7 +81,7 @@ public class TreeDefinition {
*
* @return A Set of CompatibleMaterial
*/
public Set<CompatibleMaterial> getPlantableSoilMaterial() {
public Set<XMaterial> getPlantableSoilMaterial() {
return Collections.unmodifiableSet(this.plantableSoilMaterial);
}
@ -174,4 +174,4 @@ public class TreeDefinition {
public boolean isRequiredAxe() {
return requiredAxe;
}
}
}

View File

@ -1,4 +1,4 @@
package com.songoda.ultimatetimber.tree;
package com.craftaro.ultimatetimber.tree;
import org.bukkit.inventory.ItemStack;
@ -79,4 +79,4 @@ public class TreeLoot {
", chance=" + chance +
'}';
}
}
}

View File

@ -1,8 +1,8 @@
package com.songoda.ultimatetimber.utils;
package com.craftaro.ultimatetimber.utils;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.ultimatetimber.tree.ITreeBlock;
import com.craftaro.core.compatibility.ServerVersion;
import com.craftaro.core.third_party.com.cryptomorin.xseries.XMaterial;
import com.craftaro.ultimatetimber.tree.ITreeBlock;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.entity.FallingBlock;
@ -16,18 +16,20 @@ public class BlockUtils {
public static Collection<ItemStack> getBlockDrops(ITreeBlock treeBlock) {
Set<ItemStack> drops = new HashSet<>();
XMaterial material = null;
if (treeBlock.getBlock() instanceof Block) {
Block block = (Block)treeBlock.getBlock();
CompatibleMaterial material = CompatibleMaterial.getMaterial(block);
if (material.isAir())
return drops;
drops.add(CompatibleMaterial.getMaterial(block).getItem());
material = XMaterial.matchXMaterial(block.getType());
} else if (treeBlock.getBlock() instanceof FallingBlock) {
CompatibleMaterial material = CompatibleMaterial.getMaterial((FallingBlock)treeBlock.getBlock());
if (material == null)
return drops;
drops.add(material.getItem());
material = XMaterial.matchXMaterial(((FallingBlock)treeBlock.getBlock()).getMaterial());
}
if (material == null || material == XMaterial.AIR) {
return drops;
}
drops.add(material.parseItem());
return drops;
}
@ -36,8 +38,8 @@ public class BlockUtils {
fallingBlock.setGravity(applyGravity);
}
public static FallingBlock spawnFallingBlock(Location location, CompatibleMaterial material) {
return location.getWorld().spawnFallingBlock(location, material.getMaterial(), material.getData());
public static FallingBlock spawnFallingBlock(Location location, XMaterial material) {
return location.getWorld().spawnFallingBlock(location, material.parseMaterial().createBlockData());
}
public static void configureFallingBlock(FallingBlock fallingBlock) {

View File

@ -1,8 +1,7 @@
package com.songoda.ultimatetimber.utils;
package com.craftaro.ultimatetimber.utils;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.ultimatetimber.tree.ITreeBlock;
import com.songoda.ultimatetimber.tree.TreeDefinition;
import com.craftaro.core.compatibility.ServerVersion;
import com.craftaro.ultimatetimber.tree.ITreeBlock;
import org.bukkit.Effect;
import org.bukkit.Location;
import org.bukkit.Particle;
@ -65,4 +64,4 @@ public class ParticleUtils {
}
}
}
}
}

View File

@ -1,8 +1,8 @@
package com.songoda.ultimatetimber.utils;
package com.craftaro.ultimatetimber.utils;
import com.songoda.core.compatibility.CompatibleSound;
import com.songoda.ultimatetimber.tree.ITreeBlock;
import com.songoda.ultimatetimber.tree.TreeBlockType;
import com.craftaro.core.third_party.com.cryptomorin.xseries.XSound;
import com.craftaro.ultimatetimber.tree.ITreeBlock;
import com.craftaro.ultimatetimber.tree.TreeBlockType;
import org.bukkit.Location;
public class SoundUtils {
@ -10,7 +10,7 @@ public class SoundUtils {
public static void playFallingSound(ITreeBlock block) {
Location location = block.getLocation();
if (location.getWorld() == null) return;
CompatibleSound.BLOCK_CHEST_OPEN.play(location.getWorld(), location, 2F, 0.1F);
XSound.BLOCK_CHEST_OPEN.play(location, 2F, 0.1F);
}
public static void playLandingSound(ITreeBlock block) {
@ -18,10 +18,10 @@ public class SoundUtils {
if (location.getWorld() == null) return;
if (block.getTreeBlockType().equals(TreeBlockType.LOG)) {
CompatibleSound.BLOCK_WOOD_FALL.play(location.getWorld(), location, 2F, 0.1F);
XSound.BLOCK_WOOD_FALL.play(location, 2F, 0.1F);
} else {
CompatibleSound.BLOCK_GRASS_BREAK.play(location.getWorld(), location, 0.5F, 0.75F);
XSound.BLOCK_GRASS_BREAK.play(location, 0.5F, 0.75F);
}
}
}
}

View File

@ -0,0 +1,88 @@
Settings:
# A list of worlds that the plugin is disabled in.
Disabled Worlds:
- disabled_world_name
# Allow toppling trees in creative mode
Allow Creative Mode: true
# The max number of logs that can be broken at one time
Max Logs Per Chop: 150
# Don't drop a block for the block that initiates the tree fall
Destroy Initiated Block: false
# Require the player to have the permission 'ultimatetimber.chop' to topple trees.
Require Chop Permission: false
## This sets the cooldown for toppling a tree.
## This cooldown is per-player.
## Set to -1 to disable.
Tree Topple Cooldown: -1
# The maximum number of blocks to keep track of in memory at once
# Use a lower number if this starts to take up too much memory or trees start taking too long to detect
# To disable, set it to -1.
Ignore Placed Blocks Memory Size: 5000
# Automatically replant saplings when a tree is toppled.
Replant Saplings: true
# Give fallen leaf blocks a chance to replant saplings when they hit the ground.
Falling Blocks Replant Saplings: true
# The percent chance that fallen leaves have of planting a sapling.
# Does nothing if falling-blocks-replant-saplings is false.
# The chance is out of 100 and may contain decimals.
Falling Blocks Replant Saplings Chance: 1
# How many seconds to prevent players from breaking replanted saplings?
# Set to 0 to disable.
# Does nothing if replant-saplings is false.
# The time is in seconds and must be a positive whole number.
Replant Saplings Cooldown: 3
# Allow players to topple trees regardless of what they are holding in their hand?
Ignore Required Tools: false
# Automatically add tree blocks to the player's inventory instead of dropping them?
Add Items To Inventory: false
# Use the silk touch enchantment if the tool has it?
# Logs and leaves will drop their original block 100% of the time.
Apply Silk Touch: true
# The bonus loot multiplier when a player has the permission ultimatetimber.bonusloot
# Multiplies the chance of tree drops by this value
# Decimal values are allowed
# Default: 2
Bonus Loot Multiplier: 2
# Only detect logs above the initiated block?
Only Detect Logs Upwards: true
# The minimum number of leaves required for something to be considered a tree.
Leaves Required For Tree: 5
# Should leaves be destroyed?
Destroy Leaves: true
# Require the entire base of the tree to be broken before it topples.
Break Entire Tree Base: false
# Use custom sounds when toppling trees?
Use Custom Sounds: true
# Use custom particles when toppling trees?
Use Custom Particles: true
# The type of animation to use for tree toppling
# Types: FANCY, DISINTEGRATE, CRUMBLE, NONE
Tree Animation Type: FANCY
# If a tree lands on these blocks they will be destroyed.
Fragile Blocks:
- GLASS
- ICE
- PACKED_ICE
- BLUE_ICE
# Make falling tree blocks deal damage to players if they get hit
Falling Blocks Deal Damage: true
# The amount of damage that falling tree blocks do.
# This does nothing if falling-blocks-deal-damage is false.
Falling Block Damage: 1
# If the tree-animation-type is FANCY or CRUMBLE, make the blocks stick to the ground
# Does nothing if tree-animation-type is not FANCY or CRUMBLE.
Scatter Tree Blocks On Ground: false
# Always replant saplings for base tree blocks, regardless of player permissions
Always Replant Sapling: false
# Protect the tool used to chop down the tree from breaking
# Prevents the tree from being toppled if the tool would break
Protect Tool: false
# Only topple trees while the player is doing something
# Valid values: SNEAKING, NOT_SNEAKING, ALWAYS
Only Topple While: ALWAYS
# Apply realistic damage to the tools based on the number of logs chopped
# If false, only one durability will be removed from the tool
Realistic Tool Damage: true
# Damage the tool extra for each leaf block broken, this is vanilla behavior but can be disabled here
# Does nothing if realistic-tool-damage is false
Apply Silk Touch Tool Damage: true

View File

@ -0,0 +1,23 @@
# Command Messages
command:
help:
- '<gold><bold>UltimateTimber 3'
- '<gray><italic>Using CraftaroCore 3'
- ''
- '<yellow>Commands:'
- '<gold>/ut giveaxe <Player>'
- '<gold>/ut toggle'
- '<gold>/ut reload'
give:
no-axe: '<red>The axe could not be loaded.'
given: '<green>Axe given to <gold>%player%'
toggle:
enabled: '<gray>Chopping Mode: <green>Enabled'
disabled: '<gray>Chopping Mode: <red>Disabled'
reload:
success: '<green>Configuration and locale files have been reloaded.'
# Event Messages
event:
onCooldown: '<red>You are on cooldown and cannot topple trees right now.'

View File

@ -0,0 +1,5 @@
name: UltimateTimber
version: 3.0.0
author: Craftaro
api-version: 1.13
main: com.craftaro.ultimatetimber.UltimateTimber

View File

@ -1,182 +1,3 @@
# ____ ___ __ __ __ __ ___________ __ ___
# | | \ |_/ |_|__| _____ _____ _/ |_ ___\__ ___/|__| _____\_ |__ ___________
# | | / |\ __\ |/ \\__ \\ __\/ __ \| | | |/ \| __ \_/ __ \_ __ \
# | | /| |_| | | | Y Y \/ __ \| | \ ___/| | | | Y Y \ \_\ \ ___/| | \/
# |______/ |____/__| |__|__|_| (____ /__| \___ |____| |__|__|_| /___ /\___ >__|
# The type of server you are running in relation to this plugin
# Do not change this value
# Default: CURRENT
server-type: CURRENT
# The locale to use in the /locale folder
# Default: en_US
locale: en_US
# A list of worlds that the plugin is disabled in
# Default:
# - disabled_world_name
disabled-worlds:
- disabled_world_name
# The max number of logs that can be broken at one time
# Default: 150
max-logs-per-chop: 150
# The minimum number of leaves required for something to be considered a tree
# Default: 5
leaves-required-for-tree: 5
# If leaves should be destroyed
# Default: true
destroy-leaves: true
# Apply realistic damage to the tools based on the number of logs chopped
# If false, only one durability will be removed from the tool
# Default: true
realistic-tool-damage: true
# Protect the tool used to chop down the tree from breaking
# Prevents the tree from being toppled if the tool would break
# Default: false
protect-tool: false
# Use the silk touch enchantment if the tool has it
# Logs and leaves will drop their original block 100% of the time
# Default: true
apply-silk-touch: true
# Damage the tool extra for each leaf block broken, this is vanilla behavior but can be disabled here
# Does nothing if realistic-tool-damage is false
# Default: true
apply-silk-touch-tool-damage: true
# Require the entire base of the tree to be broken before it topples
# Default: false
break-entire-tree-base: false
# Don't drop a block for the block that initiates the tree fall
# Default: false
destroy-initiated-block: false
# Only detect logs above the initiated block
# Default: true
only-detect-logs-upwards: true
# Only topple trees while the player is doing something
# Valid values: SNEAKING, NOT_SNEAKING, ALWAYS
# Default: ALWAYS
only-topple-while: ALWAYS
# Allow toppling trees in creative mode
# Default: true
allow-creative-mode: true
# Require the player to have the permission 'ultimatetimber.chop' to topple trees
# Default: false
require-chop-permission: false
# If a player should only be allowed to chop one tree per cooldown length
# Default: false
player-tree-topple-cooldown: false
# The amount of seconds a player has to wait before they can chop a tree again
# Does nothing if player-tree-topple-cooldown is false
# The time is in seconds and must be a postive whole number
# Default: 5
player-tree-topple-cooldown-length: 5
# Allow players to topple trees regardless of what they are holding in their hand
# Default: false
ignore-required-tools: false
# Automatically replant saplings when a tree is toppled
# Default: true
replant-saplings: true
# Always replant saplings for base tree blocks, regardless of player permissions
# Default: false
always-replant-sapling: false
# How many seconds to prevent players from breaking replanted saplings
# Set to 0 to disable
# Does nothing if replant-saplings is false
# The time is in seconds and must be a postive whole number
# Default: 3
replant-saplings-cooldown: 3
# Give fallen leaf blocks a chance to replant saplings when they hit the ground
# Default: true
falling-blocks-replant-saplings: true
# The percent chance that fallen leaves have of planting a sapling
# Does nothing if falling-blocks-replant-saplings is false
# The chance is out of 100 and may contain decimals
# Default: 1
falling-blocks-replant-saplings-chance: 1
# Make falling tree blocks deal damage to players if they get hit
# Default: true
falling-blocks-deal-damage: true
# The amount of damage that falling tree blocks do
# This does nothing if falling-blocks-deal-damage is false
# Default: 1
falling-block-damage: 1
# Automatically add tree blocks to the player's inventory instead of dropping them
# Default: false
add-items-to-inventory: false
# Use custom sounds when toppling trees
# Default: true
use-custom-sounds: true
# Use custom particles when toppling trees
# Default: true
use-custom-particles: true
# The bonus loot multiplier when a player has the permission ultimatetimber.bonusloot
# Multiplies the chance of tree drops by this value
# Decimal values are allowed
# Default: 2
bonus-loot-multiplier: 2
# If placed blocks should be ignored for toppling trees
# Note: This only keeps track of blocks placed during the current server load
# If your server restarts, the placed tree blocks could be toppled again
# Default: true
ignore-placed-blocks: true
# The maximum number of blocks to keep track of in memory at once
# Use a lower number if this starts to take up too much memory or trees start taking too long to detect
# Default: 5000
ignore-placed-blocks-memory-size: 5000
# Applies experience when using Jobs/mcMMO
# Only does something if Jobs or mcMMO is installed
# Default: true
hooks-apply-experience: true
# Applies extra drops passive ability when using mcMMO
# Only does something if mcMMO is installed
# Default: true
hooks-apply-extra-drops: true
# Requires the tree feller ability in mcMMO to be active to use timber
# Only does something if mcMMO is installed
# Default: false
hooks-require-ability-active: false
# The type of animation to use for tree toppling
# Types: FANCY, DISINTEGRATE, CRUMBLE, NONE
tree-animation-type: FANCY
# If the tree-animation-type is FANCY or CRUMBLE, make the blocks stick to the ground
# Does nothing if tree-animation-type is not FANCY or CRUMBLE
# Default: false
scatter-tree-blocks-on-ground: false
# Tree configuration
# Allows for extreme fine-tuning of tree detection and what are considered trees
# Multiple log and leaf types are allowed, only one sapling type is allowed
@ -535,11 +356,4 @@ required-axe:
- 'DURABILITY:3'
- 'DIG_SPEED:5'
# NBT to identify the axe by.
nbt: 'ultimatetimber_axe'
# If a tree lands on these blocks they will be destroyed.
fragile-blocks:
- GLASS
- ICE
- PACKED_ICE
- BLUE_ICE
nbt: 'ultimatetimber_axe'