Merge branch 'development'

This commit is contained in:
Brianna 2020-11-24 15:51:04 -06:00
commit fdd4286195
10 changed files with 273 additions and 14 deletions

View File

@ -3,7 +3,7 @@
<parent>
<groupId>com.songoda</groupId>
<artifactId>UltimateTimber</artifactId>
<version>2.1.1</version>
<version>2.2</version>
<relativePath>../../</relativePath>
</parent>

View File

@ -17,11 +17,12 @@ public class TreeDefinition {
private final boolean dropOriginalLog, dropOriginalLeaf;
private final Set<TreeLoot> logLoot, leafLoot, entireTreeLoot;
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,
boolean detectLeavesDiagonally, boolean dropOriginalLog, boolean dropOriginalLeaf, Set<TreeLoot> logLoot,
Set<TreeLoot> leafLoot, Set<TreeLoot> entireTreeLoot, Set<ItemStack> requiredTools) {
Set<TreeLoot> leafLoot, Set<TreeLoot> entireTreeLoot, Set<ItemStack> requiredTools, boolean requiredAxe) {
this.key = key;
this.logMaterial = logMaterial;
this.leafMaterial = leafMaterial;
@ -36,6 +37,7 @@ public class TreeDefinition {
this.leafLoot = leafLoot;
this.entireTreeLoot = entireTreeLoot;
this.requiredTools = requiredTools;
this.requiredAxe = requiredAxe;
}
/**
@ -164,4 +166,12 @@ public class TreeDefinition {
return Collections.unmodifiableSet(this.requiredTools);
}
/**
* Returns whether or not does this TreeDefinition require a custom axe.
*
* @return True if the TreeDefinition requires a custom axe
*/
public boolean isRequiredAxe() {
return requiredAxe;
}
}

View File

@ -3,7 +3,7 @@
<parent>
<groupId>com.songoda</groupId>
<artifactId>UltimateTimber</artifactId>
<version>2.1.1</version>
<version>2.2</version>
<relativePath>../../</relativePath>
</parent>

View File

@ -207,6 +207,7 @@ trees:
chance: 0.5
entire-tree-loot: []
required-tools: []
required-axe: false
spruce:
logs:
- SPRUCE_LOG
@ -229,6 +230,7 @@ trees:
chance: 5
entire-tree-loot: []
required-tools: []
required-axe: false
birch:
logs:
- BIRCH_LOG
@ -251,6 +253,7 @@ trees:
chance: 5
entire-tree-loot: []
required-tools: []
required-axe: false
jungle:
logs:
- JUNGLE_LOG
@ -273,6 +276,7 @@ trees:
chance: 2.5
entire-tree-loot: []
required-tools: []
required-axe: false
acacia:
logs:
- ACACIA_LOG
@ -295,6 +299,7 @@ trees:
chance: 5
entire-tree-loot: []
required-tools: []
required-axe: false
dark_oak:
logs:
- DARK_OAK_LOG
@ -320,6 +325,7 @@ trees:
chance: 0.5
entire-tree-loot: []
required-tools: []
required-axe: false
brown_mushroom:
logs:
- MUSHROOM_STEM
@ -340,6 +346,7 @@ trees:
chance: 25
entire-tree-loot: []
required-tools: []
required-axe: false
red_mushroom:
logs:
- MUSHROOM_STEM
@ -360,6 +367,7 @@ trees:
chance: 25
entire-tree-loot: []
required-tools: []
required-axe: false
huge_crimson_fungus:
logs:
- CRIMSON_STEM
@ -381,6 +389,7 @@ trees:
leaf-loot: []
entire-tree-loot: []
required-tools: []
required-axe: false
huge_warpped_fungus:
logs:
- WARPED_STEM
@ -402,6 +411,7 @@ trees:
leaf-loot: []
entire-tree-loot: []
required-tools: []
required-axe: false
# All soil types that the tree type's saplings can be planted on
global-plantable-soil:
@ -457,3 +467,20 @@ global-required-tools:
- GOLDEN_AXE
- DIAMOND_AXE
- NETHERITE_AXE
# Require the custom axe
# Applies to all tree types
global-required-axe: false
# Axe item
required-axe:
type: DIAMOND_AXE
name: '&aAn Epic Axe'
lore:
- "&7This axe... it's awesome."
- "&7It can chop down trees real fast."
enchants:
- 'DURABILITY:3'
- 'DIG_SPEED:5'
# NBT to identify the axe by.
nbt: 'ultimatetimber_axe'

View File

@ -15,6 +15,10 @@ command:
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

View File

@ -5,9 +5,18 @@ 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.*;
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;
@ -49,8 +58,10 @@ public class UltimateTimber extends SongodaPlugin {
// Setup plugin commands
this.commandManager = new com.songoda.core.commands.CommandManager(this);
this.commandManager.addMainCommand("ut")
.addSubCommands(new CommandReload(this),
new CommandToggle(this)
.addSubCommands(
new CommandReload(this),
new CommandToggle(this),
new CommandGiveAxe(this)
);
// Register managers

View File

@ -0,0 +1,80 @@
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,7 +1,12 @@
package com.songoda.ultimatetimber.manager;
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.nms.NmsManager;
import com.songoda.core.nms.nbt.NBTItem;
import com.songoda.core.utils.TextUtils;
import com.songoda.ultimatetimber.UltimateTimber;
import com.songoda.ultimatetimber.tree.ITreeBlock;
import com.songoda.ultimatetimber.tree.TreeBlockType;
@ -10,13 +15,17 @@ 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 java.util.*;
import java.util.stream.Collectors;
public class TreeDefinitionManager extends Manager {
@ -26,6 +35,10 @@ public class TreeDefinitionManager extends Manager {
private final Set<TreeLoot> globalLogLoot, globalLeafLoot, globalEntireTreeLoot;
private final Set<ItemStack> globalRequiredTools;
private boolean globalAxeRequired;
private ItemStack requiredAxe;
private String requiredAxeKey;
public TreeDefinitionManager(UltimateTimber ultimateTimber) {
super(ultimateTimber);
this.random = new Random();
@ -68,6 +81,7 @@ public class TreeDefinitionManager extends Manager {
Set<TreeLoot> leafLoot = new HashSet<>();
Set<TreeLoot> entireTreeLoot = new HashSet<>();
Set<ItemStack> requiredTools = new HashSet<>();
boolean requiredAxe;
for (String materialString : tree.getStringList("logs")) {
CompatibleMaterial material = CompatibleMaterial.getMaterial(materialString);
@ -116,8 +130,10 @@ public class TreeDefinitionManager extends Manager {
requiredTools.add(material.getItem());
}
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));
maxLeafDistanceFromLog, detectLeavesDiagonally, dropOriginalLog, dropOriginalLeaf, logLoot, leafLoot, entireTreeLoot, requiredTools, requiredAxe));
}
// Load global plantable soil
@ -148,6 +164,95 @@ public class TreeDefinitionManager extends Manager {
if (tool == null) continue;
this.globalRequiredTools.add(tool);
}
this.globalAxeRequired = config.getBoolean("global-required-axe", false);
// Load required axe
if (config.contains("required-axe"))
loadAxe(config);
}
private void loadAxe(YamlConfiguration 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;
String typeString = config.getString("required-axe.type");
if (Strings.isNullOrEmpty(typeString)) {
plugin.getLogger().warning("Required-axe has to have a material set.");
return;
}
CompatibleMaterial material = CompatibleMaterial.getMaterial(typeString);
if (material == null) {
plugin.getLogger().warning("Material " + typeString + " is invalid.");
return;
}
ItemStack item = material.getItem();
// 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)
.collect(Collectors.toList());
ItemMeta meta = item.getItemMeta();
meta.setDisplayName(displayName);
meta.setLore(lore);
// Enchants
for (String enchantString : config.getStringList("required-axe.enchants")) {
String[] arr = enchantString.split(":");
int level = arr.length > 1 ? Math.max(1, parseInt(arr[1])) : 1;
// Enchantment#getKey is not present on versions below 1.13
Enchantment enchantment;
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)) {
NamespacedKey key = NamespacedKey.minecraft(arr[0].trim().toLowerCase());
enchantment = Enchantment.getByKey(key);
// Try to fall back to #getByName() if someone uses the old names.
if (enchantment == null)
enchantment = Enchantment.getByName(arr[0].trim());
} else
enchantment = Enchantment.getByName(arr[0].trim());
if (enchantment == null) {
plugin.getLogger().warning("Enchantment " + arr[0].trim() + " is invalid.");
continue;
}
meta.addEnchant(enchantment, level, true);
}
item.setItemMeta(meta);
// Apply NBT
NBTItem nbtItem = NmsManager.getNbt().of(item);
nbtItem.set(requiredAxeKey, true);
item = nbtItem.finish();
this.requiredAxe = item;
}
private int parseInt(String str) {
try {
return Integer.parseInt(str.trim());
} catch (NumberFormatException e) {
return -1;
}
}
public ItemStack getRequiredAxe() {
return this.requiredAxe;
}
public boolean isGlobalAxeRequired() {
return globalAxeRequired;
}
@Override
@ -210,13 +315,24 @@ public class TreeDefinitionManager extends Manager {
public boolean isToolValidForAnyTreeDefinition(ItemStack tool) {
if (ConfigurationManager.Setting.IGNORE_REQUIRED_TOOLS.getBoolean())
return true;
for (TreeDefinition treeDefinition : this.treeDefinitions) {
if (treeDefinition.isRequiredAxe() || isGlobalAxeRequired()) {
NBTItem nbtItem = NmsManager.getNbt().of(tool);
if (nbtItem.has(requiredAxeKey))
return true;
}
}
for (TreeDefinition treeDefinition : this.treeDefinitions)
for (ItemStack requiredTool : treeDefinition.getRequiredTools())
if (requiredTool.getType().equals(tool.getType()))
return true;
for (ItemStack requiredTool : this.globalRequiredTools)
if (requiredTool.getType().equals(tool.getType()))
return true;
return false;
}
@ -228,11 +344,20 @@ 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())
return true;
// If the tree definition requires the custom axe, don't allow any other checks to pass.
if (treeDefinition.isRequiredAxe() || isGlobalAxeRequired()) {
NBTItem nbtItem = NmsManager.getNbt().of(tool);
return nbtItem.has(requiredAxeKey);
}
for (ItemStack requiredTool : treeDefinition.getRequiredTools())
if (requiredTool.getType().equals(tool.getType()))
return true;
for (ItemStack requiredTool : this.globalRequiredTools)
if (requiredTool.getType().equals(tool.getType()))
return true;

View File

@ -12,7 +12,6 @@ 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.songoda.ultimatetimber.tree.TreeBlockType;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Material;
@ -135,17 +134,20 @@ public class TreeFallManager extends Manager implements Listener {
detectedTree.getDetectedTreeBlocks().remove(detectedTree.getDetectedTreeBlocks().getInitialLogBlock());
}
if (!player.getGameMode().equals(GameMode.CREATIVE))
boolean isCreative = player.getGameMode().equals(GameMode.CREATIVE);
if (!isCreative)
ItemUtils.addDamage(tool, toolDamage);
McMMOHook.addWoodcutting(player, detectedTree.getDetectedTreeBlocks().getAllTreeBlocks().stream()
.map(ITreeBlock::getBlock).collect(Collectors.toList()));
for (ITreeBlock<Block> treeBlock : detectedTree.getDetectedTreeBlocks().getAllTreeBlocks()) {
if (JobsHook.isEnabled() && treeBlock.getTreeBlockType() == TreeBlockType.LOG)
JobsHook.breakBlock(player, block);
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());
}
treeAnimationManager.runAnimation(detectedTree, player);
treeDefinitionManager.dropTreeLoot(detectedTree.getTreeDefinition(), detectedTree.getDetectedTreeBlocks().getInitialLogBlock(), player, false, true);

View File

@ -2,7 +2,7 @@
<groupId>com.songoda</groupId>
<artifactId>UltimateTimber</artifactId>
<version>2.1.1</version>
<version>2.2</version>
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>