Implement tree capitator
This commit is contained in:
parent
4a602b42f6
commit
0d37534eed
@ -15,4 +15,8 @@ commands:
|
|||||||
search:
|
search:
|
||||||
description: Search for a given item in all nearby inventories
|
description: Search for a given item in all nearby inventories
|
||||||
usage: /<command> {item type}
|
usage: /<command> {item type}
|
||||||
permission: invtweaks.search
|
permission: invtweaks.search
|
||||||
|
capitator:
|
||||||
|
description: Toggle tree capitation for an axe in your main hand
|
||||||
|
usage: /<command>
|
||||||
|
permission: invtweaks.capitator
|
@ -1,22 +1,25 @@
|
|||||||
package dev.w1zzrd.invtweaks;
|
package dev.w1zzrd.invtweaks;
|
||||||
|
|
||||||
|
import dev.w1zzrd.invtweaks.command.CapitatorCommand;
|
||||||
import dev.w1zzrd.invtweaks.command.MagnetCommandExecutor;
|
import dev.w1zzrd.invtweaks.command.MagnetCommandExecutor;
|
||||||
import dev.w1zzrd.invtweaks.command.SearchCommandExecutor;
|
import dev.w1zzrd.invtweaks.command.SearchCommandExecutor;
|
||||||
import dev.w1zzrd.invtweaks.command.SortCommandExecutor;
|
import dev.w1zzrd.invtweaks.command.SortCommandExecutor;
|
||||||
import dev.w1zzrd.invtweaks.listener.MagnetismListener;
|
import dev.w1zzrd.invtweaks.enchantment.CapitatorEnchantment;
|
||||||
import dev.w1zzrd.invtweaks.listener.TabCompletionListener;
|
import dev.w1zzrd.invtweaks.listener.*;
|
||||||
import dev.w1zzrd.invtweaks.serialization.MagnetConfig;
|
import dev.w1zzrd.invtweaks.serialization.MagnetConfig;
|
||||||
import dev.w1zzrd.invtweaks.listener.SortListener;
|
|
||||||
import dev.w1zzrd.invtweaks.listener.StackReplaceListener;
|
|
||||||
import dev.w1zzrd.invtweaks.serialization.MagnetData;
|
import dev.w1zzrd.invtweaks.serialization.MagnetData;
|
||||||
import dev.w1zzrd.invtweaks.serialization.SearchConfig;
|
import dev.w1zzrd.invtweaks.serialization.SearchConfig;
|
||||||
import dev.w1zzrd.invtweaks.serialization.UUIDList;
|
import dev.w1zzrd.invtweaks.serialization.UUIDList;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.configuration.serialization.ConfigurationSerialization;
|
import org.bukkit.configuration.serialization.ConfigurationSerialization;
|
||||||
|
import org.bukkit.enchantments.Enchantment;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.bukkit.plugin.PluginManager;
|
import org.bukkit.plugin.PluginManager;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@ -31,18 +34,24 @@ public final class InvTweaksPlugin extends JavaPlugin {
|
|||||||
public static final String LOG_PLUGIN_NAME = "[InventoryTweaks]";
|
public static final String LOG_PLUGIN_NAME = "[InventoryTweaks]";
|
||||||
private static final String PERSISTENT_DATA_NAME = "data";
|
private static final String PERSISTENT_DATA_NAME = "data";
|
||||||
|
|
||||||
|
private static final String ENCHANTMENT_CAPITATOR_NAME = "Capitator";
|
||||||
|
|
||||||
private final Logger logger = Bukkit.getLogger();
|
private final Logger logger = Bukkit.getLogger();
|
||||||
|
|
||||||
// Command executor references in case I need them or something idk
|
// Command executor references in case I need them or something idk
|
||||||
private SortCommandExecutor sortCommandExecutor;
|
private SortCommandExecutor sortCommandExecutor;
|
||||||
private MagnetCommandExecutor magnetCommandExecutor;
|
private MagnetCommandExecutor magnetCommandExecutor;
|
||||||
private SearchCommandExecutor searchCommandExecutor;
|
private SearchCommandExecutor searchCommandExecutor;
|
||||||
|
private CapitatorCommand capitatorCommand;
|
||||||
private DataStore data;
|
private DataStore data;
|
||||||
|
private NamespacedKey capitatorEnchantmentKey;
|
||||||
|
private Enchantment capitatorEnchantment;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
logger.fine(LOG_PLUGIN_NAME + " Plugin enabled");
|
logger.fine(LOG_PLUGIN_NAME + " Plugin enabled");
|
||||||
|
|
||||||
|
initEnchantments();
|
||||||
enablePersistentData();
|
enablePersistentData();
|
||||||
initCommands();
|
initCommands();
|
||||||
initEvents();
|
initEvents();
|
||||||
@ -55,6 +64,7 @@ public final class InvTweaksPlugin extends JavaPlugin {
|
|||||||
disableEvents();
|
disableEvents();
|
||||||
disableCommands();
|
disableCommands();
|
||||||
disablePersistentData();
|
disablePersistentData();
|
||||||
|
disableEnchantments();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -78,18 +88,43 @@ public final class InvTweaksPlugin extends JavaPlugin {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void initEnchantments() {
|
||||||
* Initialize commands registered by this plugin
|
capitatorEnchantmentKey = new NamespacedKey(this, ENCHANTMENT_CAPITATOR_NAME);
|
||||||
*/
|
capitatorEnchantment = new CapitatorEnchantment(ENCHANTMENT_CAPITATOR_NAME, capitatorEnchantmentKey);
|
||||||
private void initCommands() {
|
|
||||||
sortCommandExecutor = new SortCommandExecutor();
|
|
||||||
magnetCommandExecutor = new MagnetCommandExecutor(this, "magnet", getPersistentData());
|
|
||||||
searchCommandExecutor = new SearchCommandExecutor(this, "search");
|
|
||||||
|
|
||||||
// TODO: Bind command by annotation
|
try {
|
||||||
Objects.requireNonNull(getCommand("sort")).setExecutor(sortCommandExecutor);
|
final Field acceptingField = Enchantment.class.getDeclaredField("acceptingNew");
|
||||||
Objects.requireNonNull(getCommand("magnet")).setExecutor(magnetCommandExecutor);
|
acceptingField.setAccessible(true);
|
||||||
Objects.requireNonNull(getCommand("search")).setExecutor(searchCommandExecutor);
|
|
||||||
|
acceptingField.set(null, true);
|
||||||
|
|
||||||
|
Enchantment.registerEnchantment(capitatorEnchantment);
|
||||||
|
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disableEnchantments() {
|
||||||
|
try {
|
||||||
|
final Field byKeyField = Enchantment.class.getDeclaredField("byKey");
|
||||||
|
final Field byNameField = Enchantment.class.getDeclaredField("byName");
|
||||||
|
|
||||||
|
byKeyField.setAccessible(true);
|
||||||
|
byNameField.setAccessible(true);
|
||||||
|
|
||||||
|
final Object byKey = byKeyField.get(null);
|
||||||
|
final Object byName = byNameField.get(null);
|
||||||
|
|
||||||
|
if (byKey instanceof final Map<?, ?> byKeyMap && byName instanceof final Map<?, ?> byNameMap) {
|
||||||
|
byKeyMap.remove(capitatorEnchantmentKey);
|
||||||
|
byNameMap.remove(ENCHANTMENT_CAPITATOR_NAME);
|
||||||
|
}
|
||||||
|
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
capitatorEnchantment = null;
|
||||||
|
capitatorEnchantmentKey = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,17 +137,7 @@ public final class InvTweaksPlugin extends JavaPlugin {
|
|||||||
pluginManager.registerEvents(new SortListener(), this);
|
pluginManager.registerEvents(new SortListener(), this);
|
||||||
pluginManager.registerEvents(new MagnetismListener(magnetCommandExecutor), this);
|
pluginManager.registerEvents(new MagnetismListener(magnetCommandExecutor), this);
|
||||||
pluginManager.registerEvents(new TabCompletionListener(), this);
|
pluginManager.registerEvents(new TabCompletionListener(), this);
|
||||||
}
|
pluginManager.registerEvents(new TreeCapitatorListener(capitatorEnchantment), this);
|
||||||
|
|
||||||
/**
|
|
||||||
* Do whatever is necessary to disable commands and their execution
|
|
||||||
*/
|
|
||||||
private void disableCommands() {
|
|
||||||
magnetCommandExecutor.onDisable();
|
|
||||||
|
|
||||||
sortCommandExecutor = null;
|
|
||||||
magnetCommandExecutor = null;
|
|
||||||
searchCommandExecutor = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -123,6 +148,34 @@ public final class InvTweaksPlugin extends JavaPlugin {
|
|||||||
HandlerList.unregisterAll(this);
|
HandlerList.unregisterAll(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize commands registered by this plugin
|
||||||
|
*/
|
||||||
|
private void initCommands() {
|
||||||
|
sortCommandExecutor = new SortCommandExecutor();
|
||||||
|
magnetCommandExecutor = new MagnetCommandExecutor(this, "magnet", getPersistentData());
|
||||||
|
searchCommandExecutor = new SearchCommandExecutor(this, "search");
|
||||||
|
capitatorCommand = new CapitatorCommand(capitatorEnchantment);
|
||||||
|
|
||||||
|
// TODO: Bind command by annotation
|
||||||
|
Objects.requireNonNull(getCommand("sort")).setExecutor(sortCommandExecutor);
|
||||||
|
Objects.requireNonNull(getCommand("magnet")).setExecutor(magnetCommandExecutor);
|
||||||
|
Objects.requireNonNull(getCommand("search")).setExecutor(searchCommandExecutor);
|
||||||
|
Objects.requireNonNull(getCommand("capitator")).setExecutor(capitatorCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do whatever is necessary to disable commands and their execution
|
||||||
|
*/
|
||||||
|
private void disableCommands() {
|
||||||
|
magnetCommandExecutor.onDisable();
|
||||||
|
|
||||||
|
capitatorCommand = null;
|
||||||
|
searchCommandExecutor = null;
|
||||||
|
magnetCommandExecutor = null;
|
||||||
|
sortCommandExecutor = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register type serializers/deserializers for configurations and YAML files
|
* Register type serializers/deserializers for configurations and YAML files
|
||||||
*
|
*
|
||||||
|
37
src/dev/w1zzrd/invtweaks/command/CapitatorCommand.java
Normal file
37
src/dev/w1zzrd/invtweaks/command/CapitatorCommand.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package dev.w1zzrd.invtweaks.command;
|
||||||
|
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.enchantments.Enchantment;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
public class CapitatorCommand implements CommandExecutor {
|
||||||
|
private final Enchantment capitatorEnchantment;
|
||||||
|
|
||||||
|
public CapitatorCommand(final Enchantment capitatorEnchantment) {
|
||||||
|
this.capitatorEnchantment = capitatorEnchantment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
if (sender instanceof final Player caller) {
|
||||||
|
final ItemStack stack = caller.getInventory().getItemInMainHand();
|
||||||
|
|
||||||
|
if (stack.getType().name().endsWith("_AXE")) {
|
||||||
|
if (stack.containsEnchantment(capitatorEnchantment)) {
|
||||||
|
stack.removeEnchantment(capitatorEnchantment);
|
||||||
|
sender.spigot().sendMessage(CommandUtils.successMessage("Item is now a regular axe"));
|
||||||
|
} else {
|
||||||
|
stack.addEnchantment(capitatorEnchantment, 1);
|
||||||
|
sender.spigot().sendMessage(CommandUtils.successMessage("Item is now a capitator axe"));
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
sender.spigot().sendMessage(CommandUtils.errorMessage("Only axes can be tree capitators!"));
|
||||||
|
} else
|
||||||
|
sender.spigot().sendMessage(CommandUtils.errorMessage("Only players can create tree capitators!"));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package dev.w1zzrd.invtweaks.command;
|
package dev.w1zzrd.invtweaks.command;
|
||||||
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
@ -16,4 +17,16 @@ public final class CommandUtils {
|
|||||||
|
|
||||||
return !condition;
|
return !condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BaseComponent errorMessage(final String message) {
|
||||||
|
final BaseComponent component = new TextComponent(message);
|
||||||
|
component.setColor(ChatColor.DARK_RED);
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BaseComponent successMessage(final String message) {
|
||||||
|
final BaseComponent component = new TextComponent(message);
|
||||||
|
component.setColor(ChatColor.GREEN);
|
||||||
|
return component;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
package dev.w1zzrd.invtweaks.enchantment;
|
||||||
|
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.enchantments.Enchantment;
|
||||||
|
import org.bukkit.enchantments.EnchantmentTarget;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
public final class CapitatorEnchantment extends Enchantment {
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public CapitatorEnchantment(String name, NamespacedKey key) {
|
||||||
|
super(key);
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxLevel() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStartLevel() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnchantmentTarget getItemTarget() {
|
||||||
|
return EnchantmentTarget.TOOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTreasure() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCursed() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean conflictsWith(Enchantment other) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canEnchantItem(ItemStack item) {
|
||||||
|
return item.getType().name().endsWith("_AXE");
|
||||||
|
}
|
||||||
|
}
|
211
src/dev/w1zzrd/invtweaks/listener/TreeCapitatorListener.java
Normal file
211
src/dev/w1zzrd/invtweaks/listener/TreeCapitatorListener.java
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
package dev.w1zzrd.invtweaks.listener;
|
||||||
|
|
||||||
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.enchantments.Enchantment;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.block.BlockBreakEvent;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.Damageable;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.bukkit.Material.*;
|
||||||
|
|
||||||
|
public class TreeCapitatorListener implements Listener {
|
||||||
|
|
||||||
|
private static final int MAX_SEARCH_BLOCKS = 69420;
|
||||||
|
private static final List<Material> targetMaterials = Arrays.asList(
|
||||||
|
ACACIA_LOG,
|
||||||
|
OAK_LOG,
|
||||||
|
BIRCH_LOG,
|
||||||
|
JUNGLE_LOG,
|
||||||
|
DARK_OAK_LOG,
|
||||||
|
SPRUCE_LOG,
|
||||||
|
|
||||||
|
ACACIA_LEAVES,
|
||||||
|
OAK_LEAVES,
|
||||||
|
BIRCH_LEAVES,
|
||||||
|
JUNGLE_LEAVES,
|
||||||
|
DARK_OAK_LEAVES,
|
||||||
|
SPRUCE_LEAVES
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final List<Material> leaves = Arrays.asList(
|
||||||
|
ACACIA_LEAVES,
|
||||||
|
OAK_LEAVES,
|
||||||
|
BIRCH_LEAVES,
|
||||||
|
JUNGLE_LEAVES,
|
||||||
|
DARK_OAK_LEAVES,
|
||||||
|
SPRUCE_LEAVES
|
||||||
|
);
|
||||||
|
|
||||||
|
private final Enchantment capitatorEnchantment;
|
||||||
|
|
||||||
|
public TreeCapitatorListener(final Enchantment capitatorEnchantment) {
|
||||||
|
this.capitatorEnchantment = capitatorEnchantment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onBlockBreak(final BlockBreakEvent event) {
|
||||||
|
final ItemStack handTool = event.getPlayer().getInventory().getItemInMainHand();
|
||||||
|
if (event.isCancelled() || !handTool.containsEnchantment(capitatorEnchantment))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (handTool.getItemMeta() instanceof final Damageable tool) {
|
||||||
|
if (!leaves.contains(event.getBlock().getType()) && targetMaterials.contains(event.getBlock().getType())) {
|
||||||
|
int logBreakCount = 0;
|
||||||
|
|
||||||
|
for (final Block found : findAdjacent(event.getBlock(), getMaxUses(handTool, tool)))
|
||||||
|
if (event.getPlayer().getGameMode() == GameMode.CREATIVE)
|
||||||
|
found.setType(AIR);
|
||||||
|
else {
|
||||||
|
if (!leaves.contains(found.getType()))
|
||||||
|
++logBreakCount;
|
||||||
|
|
||||||
|
found.breakNaturally(handTool);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.getPlayer().getGameMode() != GameMode.CREATIVE && !applyDamage(handTool, logBreakCount)) {
|
||||||
|
event.getPlayer().getInventory().setItemInMainHand(new ItemStack(AIR));
|
||||||
|
event.getPlayer().playSound(event.getPlayer().getLocation(), Sound.ENTITY_ITEM_BREAK, 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getMaxUses(final ItemStack stack, final Damageable tool) {
|
||||||
|
return ((stack.getEnchantmentLevel(Enchantment.DURABILITY) + 1) * (stack.getType().getMaxDurability()) - tool.getDamage());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean applyDamage(final ItemStack stack, final int brokenBlocks) {
|
||||||
|
final ItemMeta meta = stack.getItemMeta();
|
||||||
|
|
||||||
|
if (meta instanceof final Damageable toolMeta) {
|
||||||
|
|
||||||
|
final int unbreakingDivider = stack.getEnchantmentLevel(Enchantment.DURABILITY) + 1;
|
||||||
|
final int round = brokenBlocks % unbreakingDivider;
|
||||||
|
final int dmg = (brokenBlocks / unbreakingDivider) + (round != 0 ? 1 : 0);
|
||||||
|
|
||||||
|
if (dmg > (stack.getType().getMaxDurability() - toolMeta.getDamage()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
toolMeta.setDamage(toolMeta.getDamage() + dmg);
|
||||||
|
|
||||||
|
stack.setItemMeta(meta);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Block> findAdjacent(final Block start, final int softMax) {
|
||||||
|
List<Block> frontier = new ArrayList<>();
|
||||||
|
final List<Block> matches = new ArrayList<>();
|
||||||
|
|
||||||
|
frontier.add(start);
|
||||||
|
matches.add(start);
|
||||||
|
|
||||||
|
int total = 1;
|
||||||
|
int softMaxCount = 1;
|
||||||
|
|
||||||
|
// Keep finding blocks until we have no new matches
|
||||||
|
while (frontier.size() > 0 && total < MAX_SEARCH_BLOCKS && softMaxCount < softMax) {
|
||||||
|
final long result = addAdjacents(frontier, matches, total, softMaxCount, softMax);
|
||||||
|
total = (int) (result >>> 32);
|
||||||
|
softMaxCount = (int) (result & 0xFFFFFFFFL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long addAdjacents(final List<Block> frontier, final List<Block> collect, int total, int softMax, final int softMaxCap) {
|
||||||
|
final List<Block> newFrontier = new ArrayList<>();
|
||||||
|
|
||||||
|
OUTER:
|
||||||
|
for (final Block check : frontier)
|
||||||
|
for (int x = -1; x <= 1; ++x)
|
||||||
|
for (int y = -1; y <= 1; ++y)
|
||||||
|
for (int z = -1; z <= 1; ++z)
|
||||||
|
if ((x | y | z) != 0) {
|
||||||
|
final Block offset = offset(collect, check, x, y, z);
|
||||||
|
|
||||||
|
if (offset != null && !binaryContains(newFrontier, offset)) {
|
||||||
|
binaryInsert(collect, offset);
|
||||||
|
binaryInsert(newFrontier, offset);
|
||||||
|
|
||||||
|
if (!leaves.contains(offset.getType())) {
|
||||||
|
++softMax;
|
||||||
|
|
||||||
|
if (softMax >= softMaxCap)
|
||||||
|
break OUTER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Short-circuit for max search
|
||||||
|
++total;
|
||||||
|
if (total == MAX_SEARCH_BLOCKS)
|
||||||
|
break OUTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
frontier.clear();
|
||||||
|
frontier.addAll(newFrontier);
|
||||||
|
|
||||||
|
return (((long)total) << 32) | (((long) softMax) & 0xFFFFFFFFL);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Block offset(final List<Block> checked, final Block source, int x, int y, int z) {
|
||||||
|
final Block offset = source.getWorld().getBlockAt(source.getLocation().add(x, y, z));
|
||||||
|
|
||||||
|
if (targetMaterials.contains(offset.getType()) && (!leaves.contains(source.getType()) || !leaves.contains(offset.getType())) && !binaryContains(checked, offset))
|
||||||
|
return offset;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean binaryContains(final List<Block> collection, final Block find) {
|
||||||
|
return binarySearchBlock(collection, find) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void binaryInsert(final List<Block> collection, final Block insert) {
|
||||||
|
final int index = binarySearchBlock(collection, insert);
|
||||||
|
|
||||||
|
if (index >= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
collection.add(-(index + 1), insert);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void binaryRemove(final List<Block> collection, final Block remove) {
|
||||||
|
final int index = binarySearchBlock(collection, remove);
|
||||||
|
|
||||||
|
if (index < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
collection.remove(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int binarySearchBlock(final List<Block> collection, final Block find) {
|
||||||
|
return Collections.binarySearch(collection, find, TreeCapitatorListener::blockCompare);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int blockCompare(final Block b1, final Block b2) {
|
||||||
|
return coordinateCompare(b1.getX(), b1.getY(), b1.getZ(), b2.getX(), b2.getY(), b2.getZ());
|
||||||
|
}
|
||||||
|
private static int coordinateCompare(final int x1, final int y1, final int z1, final int x2, final int y2, final int z2) {
|
||||||
|
final int x = Integer.compare(x1, x2);
|
||||||
|
if (x != 0)
|
||||||
|
return x;
|
||||||
|
|
||||||
|
final int y = Integer.compare(y1, y2);
|
||||||
|
if (y != 0)
|
||||||
|
return y;
|
||||||
|
|
||||||
|
return Integer.compare(z1, z2);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user