Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7c9bf21ced | ||
![]() |
f4cb5f58e5 | ||
![]() |
3fde89e1ca | ||
![]() |
5701a20cc8 | ||
![]() |
97e17cba3f | ||
![]() |
8acef93d7d | ||
![]() |
353f97a5e8 | ||
![]() |
a3f0fcf5aa | ||
![]() |
cb10fa6720 | ||
![]() |
1c2d966791 | ||
![]() |
092aa33303 | ||
![]() |
a740b34e4e |
@ -9,4 +9,6 @@ search:
|
||||
searchRadiusY: 8
|
||||
searchRadiusZ: 8
|
||||
ghostClick: true
|
||||
capitator: true
|
||||
capitator: true
|
||||
capitatorHungerPerBlock: 0.03125
|
||||
capitatorMinHunger: 3
|
@ -1,5 +1,5 @@
|
||||
name: InventoryTweaks
|
||||
version: 1.4.0
|
||||
version: 1.4.1
|
||||
author: IKEA_Jesus
|
||||
main: dev.w1zzrd.invtweaks.InvTweaksPlugin
|
||||
api-version: 1.13
|
||||
@ -18,6 +18,10 @@ commands:
|
||||
description: Search for a given item in all nearby inventories
|
||||
usage: /<command> {item type}
|
||||
permission: invtweaks.search
|
||||
find:
|
||||
description: Show all chests that contain a given item
|
||||
usage: /<command> {item type}
|
||||
permission: invtweaks.find
|
||||
capitator:
|
||||
description: Toggle tree capitation for an axe in your main hand
|
||||
usage: /<command>
|
||||
@ -25,4 +29,12 @@ commands:
|
||||
chestname:
|
||||
description: Add a floating nametag to a chest
|
||||
usage: /<command> {name}
|
||||
permission: invtweaks.spawnfake
|
||||
permission: invtweaks.spawnfake
|
||||
growup:
|
||||
description: Age baby animals
|
||||
usage: /<command> [radius]
|
||||
permission: invtweaks.growup
|
||||
rewool:
|
||||
description: Put the wool back on sheep
|
||||
usage: /<command> [radius]
|
||||
permission: invtweaks.rewool
|
@ -41,7 +41,10 @@ public final class InvTweaksPlugin extends JavaPlugin {
|
||||
private MagnetCommandExecutor magnetCommandExecutor;
|
||||
private SearchCommandExecutor searchCommandExecutor;
|
||||
private NamedChestCommand namedChestCommandExecutor;
|
||||
private FindCommandExecutor findCommandExecutor;
|
||||
private CapitatorCommand capitatorCommand;
|
||||
private GrowUpCommand growUpCommand;
|
||||
private ReWoolCommand reWoolCommand;
|
||||
private PersistentData data;
|
||||
private NamedChestManager chestManager;
|
||||
private EnchantmentRegistryEntry<CapitatorEnchantment> capitatorEnchantment = null;
|
||||
@ -120,9 +123,14 @@ public final class InvTweaksPlugin extends JavaPlugin {
|
||||
pluginManager.registerEvents(new SortListener(), this);
|
||||
pluginManager.registerEvents(new MagnetismListener(magnetCommandExecutor), this);
|
||||
pluginManager.registerEvents(new TabCompletionListener(), this);
|
||||
pluginManager.registerEvents(new TreeCapitatorListener(activateCapitator ? capitatorEnchantment.getEnchantment() : null), this);
|
||||
pluginManager.registerEvents(new TreeCapitatorListener(
|
||||
activateCapitator ? capitatorEnchantment.getEnchantment() : null,
|
||||
getConfig().getDouble("capitatorHungerPerBlock"),
|
||||
getConfig().getInt("capitatorMinHunger")
|
||||
), this);
|
||||
pluginManager.registerEvents(new PlayerMoveRenderListener(chestManager), this);
|
||||
pluginManager.registerEvents(new ChestBreakListener(chestManager), this);
|
||||
pluginManager.registerEvents(new SignEditListener(), this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -143,6 +151,9 @@ public final class InvTweaksPlugin extends JavaPlugin {
|
||||
magnetCommandExecutor = new MagnetCommandExecutor(this, "magnet", getPersistentData());
|
||||
searchCommandExecutor = new SearchCommandExecutor(this, "search");
|
||||
namedChestCommandExecutor = new NamedChestCommand(chestManager);
|
||||
findCommandExecutor = new FindCommandExecutor(this);
|
||||
growUpCommand = new GrowUpCommand();
|
||||
reWoolCommand = new ReWoolCommand();
|
||||
|
||||
if (activateCapitator)
|
||||
capitatorCommand = new CapitatorCommand(capitatorEnchantment.getEnchantment());
|
||||
@ -152,6 +163,9 @@ public final class InvTweaksPlugin extends JavaPlugin {
|
||||
Objects.requireNonNull(getCommand("magnet")).setExecutor(magnetCommandExecutor);
|
||||
Objects.requireNonNull(getCommand("search")).setExecutor(searchCommandExecutor);
|
||||
Objects.requireNonNull(getCommand("chestname")).setExecutor(namedChestCommandExecutor);
|
||||
Objects.requireNonNull(getCommand("find")).setExecutor(findCommandExecutor);
|
||||
Objects.requireNonNull(getCommand("growup")).setExecutor(growUpCommand);
|
||||
Objects.requireNonNull(getCommand("rewool")).setExecutor(reWoolCommand);
|
||||
|
||||
if (activateCapitator)
|
||||
Objects.requireNonNull(getCommand("capitator")).setExecutor(capitatorCommand);
|
||||
@ -164,6 +178,7 @@ public final class InvTweaksPlugin extends JavaPlugin {
|
||||
magnetCommandExecutor.onDisable();
|
||||
|
||||
capitatorCommand = null;
|
||||
findCommandExecutor = null;
|
||||
namedChestCommandExecutor = null;
|
||||
searchCommandExecutor = null;
|
||||
magnetCommandExecutor = null;
|
||||
|
43
src/dev/w1zzrd/invtweaks/command/Commands.java
Normal file
43
src/dev/w1zzrd/invtweaks/command/Commands.java
Normal file
@ -0,0 +1,43 @@
|
||||
package dev.w1zzrd.invtweaks.command;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static dev.w1zzrd.spigot.wizcompat.command.CommandUtils.errorMessage;
|
||||
|
||||
public final class Commands {
|
||||
private Commands() { throw new UnsupportedOperationException("Functional class"); }
|
||||
|
||||
public static double getCommandRadius(final CommandSender sender, final String[] args, final int radiusIndex) {
|
||||
try {
|
||||
if (args.length > radiusIndex)
|
||||
return Double.parseDouble(args[radiusIndex]);
|
||||
} catch (NumberFormatException e) {
|
||||
sender.spigot().sendMessage(errorMessage(String.format("\"%s\" is not a number", args[radiusIndex])));
|
||||
}
|
||||
|
||||
return Double.NaN;
|
||||
}
|
||||
|
||||
public static <T extends Entity> Stream<T> getCommandEntityRadius(
|
||||
final CommandSender sender,
|
||||
final String[] args,
|
||||
final int radiusIndex,
|
||||
final Class<T> entityType
|
||||
) {
|
||||
final double radius = Commands.getCommandRadius(sender, args, 0);
|
||||
if (Double.compare(radius, Double.NaN) == 0)
|
||||
return null;
|
||||
|
||||
return
|
||||
(radius >= 0 ?
|
||||
((Player) sender).getNearbyEntities(radius, radius, radius).stream() :
|
||||
Bukkit.getWorlds().stream().flatMap(it -> it.getEntities().stream()))
|
||||
.filter(it -> entityType.isAssignableFrom(it.getClass()))
|
||||
.map(it -> (T) it);
|
||||
}
|
||||
}
|
98
src/dev/w1zzrd/invtweaks/command/FindCommandExecutor.java
Normal file
98
src/dev/w1zzrd/invtweaks/command/FindCommandExecutor.java
Normal file
@ -0,0 +1,98 @@
|
||||
package dev.w1zzrd.invtweaks.command;
|
||||
|
||||
import dev.w1zzrd.spigot.wizcompat.command.CommandUtils;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Container;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static dev.w1zzrd.invtweaks.listener.TabCompletionListener.getMaterialMatching;
|
||||
import static dev.w1zzrd.spigot.wizcompat.command.CommandUtils.assertTrue;
|
||||
import static dev.w1zzrd.spigot.wizcompat.packet.EntityCreator.*;
|
||||
|
||||
public final class FindCommandExecutor implements CommandExecutor {
|
||||
private static final int SEARCH_RADIUS = 3;
|
||||
private static final long DESPAWN_WAIT = 20 * 10;
|
||||
|
||||
private final Plugin plugin;
|
||||
|
||||
public FindCommandExecutor(final Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
Material targetMaterial;
|
||||
|
||||
if (assertTrue(sender instanceof Player, "Command can only be run by players", sender) ||
|
||||
assertTrue(args.length == 1, "Exactly one argument is expected", sender) ||
|
||||
assertTrue((targetMaterial = getMaterialMatching(args[0])) != null, String.format("Unknown item/block: %s", args[0]), sender))
|
||||
return true;
|
||||
|
||||
final Player player = (Player) sender;
|
||||
|
||||
final List<BlockState> matches = searchChunks(
|
||||
player.getLocation().getChunk(),
|
||||
SEARCH_RADIUS,
|
||||
Material.CHEST, Material.TRAPPED_CHEST, Material.SHULKER_BOX
|
||||
);
|
||||
|
||||
final List<Integer> entities = matches.stream()
|
||||
.filter(it -> Arrays.stream(((Container)it).getSnapshotInventory().getContents()).filter(Objects::nonNull).map(ItemStack::getType).anyMatch(targetMaterial::equals))
|
||||
.map(state -> spawnMarker(player, state.getLocation().add(0.5, 0.2, 0.5)))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (assertTrue(entities.size() > 0, "No containers neardby contain that item/block", sender))
|
||||
return true;
|
||||
|
||||
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
||||
entities.forEach(it -> sendEntityDespawnPacket(player, it));
|
||||
}, DESPAWN_WAIT);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int spawnMarker(final Player target, final Location location) {
|
||||
final Object entity = createFakeSlime(target);
|
||||
setSlimeSize(entity, 1);
|
||||
setEntityCollision(entity, false);
|
||||
setEntityInvisible(entity, true);
|
||||
setEntityInvulnerable(entity, true);
|
||||
setEntityGlowing(entity, true);
|
||||
setEntityLocation(entity, location.getX(), location.getY(), location.getZ(), 0f, 0f);
|
||||
|
||||
sendEntitySpawnPacket(target, entity);
|
||||
sendEntityMetadataPacket(target, entity);
|
||||
|
||||
return getEntityID(entity);
|
||||
}
|
||||
|
||||
private static List<BlockState> searchChunks(final Chunk middle, final int radius, final Material... targets) {
|
||||
final int xMin = middle.getX() - radius;
|
||||
final int xMax = middle.getX() + radius;
|
||||
final int zMin = middle.getZ() - radius;
|
||||
final int zMax = middle.getZ() + radius;
|
||||
|
||||
final World sourceWorld = middle.getWorld();
|
||||
|
||||
final List<Material> targetMaterials = Arrays.asList(targets);
|
||||
final ArrayList<BlockState> collect = new ArrayList<>();
|
||||
for (int x = xMin; x <= xMax; ++x)
|
||||
for (int z = zMin; z <= zMax; ++z)
|
||||
Arrays.stream(sourceWorld.getChunkAt(x, z).getTileEntities()).filter(it -> targetMaterials.contains(it.getType())).forEach(collect::add);
|
||||
|
||||
return collect;
|
||||
}
|
||||
}
|
28
src/dev/w1zzrd/invtweaks/command/GrowUpCommand.java
Normal file
28
src/dev/w1zzrd/invtweaks/command/GrowUpCommand.java
Normal file
@ -0,0 +1,28 @@
|
||||
package dev.w1zzrd.invtweaks.command;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Ageable;
|
||||
import org.bukkit.entity.Breedable;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static dev.w1zzrd.spigot.wizcompat.command.CommandUtils.assertTrue;
|
||||
|
||||
public class GrowUpCommand implements CommandExecutor {
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (assertTrue(args.length == 0 || sender instanceof Player, "Only players can run this command", sender))
|
||||
return true;
|
||||
|
||||
final Stream<Breedable> breedables = Commands.getCommandEntityRadius(sender, args, 0, Breedable.class);
|
||||
if (breedables == null)
|
||||
return true;
|
||||
|
||||
breedables.filter(it -> !it.getAgeLock() && !it.isAdult()).forEach(Ageable::setAdult);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
27
src/dev/w1zzrd/invtweaks/command/ReWoolCommand.java
Normal file
27
src/dev/w1zzrd/invtweaks/command/ReWoolCommand.java
Normal file
@ -0,0 +1,27 @@
|
||||
package dev.w1zzrd.invtweaks.command;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Sheep;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static dev.w1zzrd.spigot.wizcompat.command.CommandUtils.assertTrue;
|
||||
|
||||
public class ReWoolCommand implements CommandExecutor {
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (assertTrue(args.length == 0 || sender instanceof Player, "Only players can run this command", sender))
|
||||
return true;
|
||||
|
||||
final Stream<Sheep> sheep = Commands.getCommandEntityRadius(sender, args, 0, Sheep.class);
|
||||
if (sheep == null)
|
||||
return true;
|
||||
|
||||
sheep.forEach(it -> it.setSheared(false));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -3,10 +3,7 @@ package dev.w1zzrd.invtweaks.command;
|
||||
import dev.w1zzrd.invtweaks.InvTweaksPlugin;
|
||||
import dev.w1zzrd.invtweaks.serialization.SearchConfig;
|
||||
import dev.w1zzrd.spigot.wizcompat.command.ConfigurableCommandExecutor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.*;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@ -17,10 +14,8 @@ import org.bukkit.plugin.Plugin;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
import java.util.Comparator;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static dev.w1zzrd.invtweaks.listener.TabCompletionListener.getMaterialMatching;
|
||||
@ -54,23 +49,23 @@ public class SearchCommandExecutor extends ConfigurableCommandExecutor<SearchCon
|
||||
assertTrue((targetMaterial = getMaterialMatching(args[0])) != null, String.format(ERR_UNKNOWN, args[0]), sender)
|
||||
) return true;
|
||||
|
||||
assert targetMaterial != null;
|
||||
assert sender instanceof Player;
|
||||
final Player player = (Player) sender;
|
||||
final Location playerLocation = player.getLocation();
|
||||
|
||||
final SearchConfig config = getConfig();
|
||||
|
||||
final List<BlockState> matches = searchBlocks(
|
||||
player.getLocation(),
|
||||
player.getWorld(),
|
||||
config.getSearchRadiusX(), config.getSearchRadiusY(), config.getSearchRadiusZ(),
|
||||
Material.CHEST, Material.SHULKER_BOX
|
||||
final List<BlockState> matches = searchChunks(
|
||||
playerLocation.getChunk(),
|
||||
config.getSearchRadiusX(),
|
||||
Material.CHEST, Material.TRAPPED_CHEST, Material.SHULKER_BOX
|
||||
);
|
||||
|
||||
// Ensure we found inventory-holding blocks
|
||||
if (assertTrue(matches.size() != 0, ERR_NO_INVENTORIES, sender))
|
||||
return true;
|
||||
|
||||
matches.sort(Comparator.comparingDouble(state -> state.getLocation().distanceSquared(playerLocation)));
|
||||
|
||||
final InventoryHolder result;
|
||||
|
||||
FIND_RESULT:
|
||||
@ -152,7 +147,24 @@ public class SearchCommandExecutor extends ConfigurableCommandExecutor<SearchCon
|
||||
return true;
|
||||
}
|
||||
|
||||
private List<BlockState> searchBlocks(
|
||||
private static List<BlockState> searchChunks(final Chunk middle, final int radius, final Material... targets) {
|
||||
final int xMin = middle.getX() - radius;
|
||||
final int xMax = middle.getX() + radius;
|
||||
final int zMin = middle.getZ() - radius;
|
||||
final int zMax = middle.getZ() + radius;
|
||||
|
||||
final World sourceWorld = middle.getWorld();
|
||||
|
||||
final List<Material> targetMaterials = Arrays.asList(targets);
|
||||
final ArrayList<BlockState> collect = new ArrayList<>();
|
||||
for (int x = xMin; x <= xMax; ++x)
|
||||
for (int z = zMin; z <= zMax; ++z)
|
||||
Arrays.stream(sourceWorld.getChunkAt(x, z).getTileEntities()).filter(it -> targetMaterials.contains(it.getType())).forEach(collect::add);
|
||||
|
||||
return collect;
|
||||
}
|
||||
|
||||
private static List<BlockState> searchBlocks(
|
||||
final Location centre,
|
||||
final World world,
|
||||
final int rx,
|
||||
|
@ -1,6 +1,7 @@
|
||||
package dev.w1zzrd.invtweaks.feature;
|
||||
|
||||
import dev.w1zzrd.invtweaks.serialization.ChestNameConfig;
|
||||
import dev.w1zzrd.spigot.wizcompat.packet.EntityCreator;
|
||||
import dev.w1zzrd.spigot.wizcompat.serialization.PersistentData;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
@ -123,12 +124,13 @@ public final class NamedChestManager {
|
||||
if (chunk == null)
|
||||
return;
|
||||
|
||||
chunk.streamEntries().forEach(entry -> {
|
||||
final Object entity = entry.getEntity(() -> null);
|
||||
|
||||
if (entity != null)
|
||||
sendEntityDespawnPacket(target, getEntityID(entity));
|
||||
});
|
||||
sendEntityDespawnPackets(
|
||||
target,
|
||||
chunk.streamEntries()
|
||||
.map(entry -> entry.getEntity(() -> null))
|
||||
.filter(Objects::nonNull)
|
||||
.mapToInt(EntityCreator::getEntityID).toArray()
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@ -268,7 +270,7 @@ public final class NamedChestManager {
|
||||
.filter(chunk -> {
|
||||
final ChestNameConfig.ChestNameWorldEntry.ChestNameChunkEntry chestChunk = config.getChunkEntry(worldID, chunk.getRender().x(), chunk.getRender().z());
|
||||
|
||||
return chunk.getRender().x() < xMax ||
|
||||
return chunk.getRender().x() > xMax ||
|
||||
chunk.getRender().x() < xMin ||
|
||||
chunk.getRender().z() > zMax ||
|
||||
chunk.getRender().z() < zMin ||
|
||||
|
21
src/dev/w1zzrd/invtweaks/listener/SignEditListener.java
Normal file
21
src/dev/w1zzrd/invtweaks/listener/SignEditListener.java
Normal file
@ -0,0 +1,21 @@
|
||||
package dev.w1zzrd.invtweaks.listener;
|
||||
|
||||
import dev.w1zzrd.spigot.wizcompat.packet.Players;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class SignEditListener implements Listener {
|
||||
@EventHandler
|
||||
public void onSignClick(final PlayerInteractEvent event) {
|
||||
if(event.getAction() == Action.RIGHT_CLICK_BLOCK &&
|
||||
Objects.requireNonNull(event.getClickedBlock()).getState() instanceof Sign &&
|
||||
event.getPlayer().isSneaking()) { // Sneak-right-click to edit sign
|
||||
Players.openSignEditor(event.getPlayer(), event.getClickedBlock().getLocation());
|
||||
}
|
||||
}
|
||||
}
|
@ -112,9 +112,16 @@ public class TabCompletionListener implements Listener {
|
||||
public static Material getMaterialMatching(final String arg) {
|
||||
final List<Material> mats = getAllMaterialsMatching(arg).collect(Collectors.toList());
|
||||
|
||||
if (mats.size() == 0)
|
||||
return null;
|
||||
|
||||
if (mats.size() == 1)
|
||||
return mats.get(0);
|
||||
|
||||
return mats.stream()
|
||||
.filter(it -> multiNS ? arg.equals(it.getKey().toString()) : arg.equals(it.getKey().getKey()))
|
||||
.findFirst().orElse(mats.size() == 1 ? mats.get(0) : null);
|
||||
.filter(it -> multiNS || arg.contains(":") ? arg.equals(it.getKey().toString()) : arg.equals(it.getKey().getKey()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -12,9 +12,12 @@ import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.Damageable;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static dev.w1zzrd.spigot.wizcompat.command.CommandUtils.errorMessage;
|
||||
import static org.bukkit.Material.*;
|
||||
|
||||
public class TreeCapitatorListener implements Listener {
|
||||
@ -27,13 +30,38 @@ public class TreeCapitatorListener implements Listener {
|
||||
JUNGLE_LOG,
|
||||
DARK_OAK_LOG,
|
||||
SPRUCE_LOG,
|
||||
CRIMSON_STEM,
|
||||
WARPED_STEM,
|
||||
ACACIA_WOOD,
|
||||
OAK_WOOD,
|
||||
BIRCH_WOOD,
|
||||
JUNGLE_WOOD,
|
||||
DARK_OAK_WOOD,
|
||||
SPRUCE_WOOD,
|
||||
CRIMSON_STEM,
|
||||
WARPED_STEM,
|
||||
CRIMSON_HYPHAE,
|
||||
WARPED_HYPHAE,
|
||||
STRIPPED_ACACIA_LOG,
|
||||
STRIPPED_OAK_LOG,
|
||||
STRIPPED_BIRCH_LOG,
|
||||
STRIPPED_JUNGLE_LOG,
|
||||
STRIPPED_DARK_OAK_LOG,
|
||||
STRIPPED_SPRUCE_LOG,
|
||||
STRIPPED_CRIMSON_STEM,
|
||||
STRIPPED_WARPED_STEM,
|
||||
STRIPPED_CRIMSON_HYPHAE,
|
||||
STRIPPED_WARPED_HYPHAE,
|
||||
|
||||
ACACIA_LEAVES,
|
||||
OAK_LEAVES,
|
||||
BIRCH_LEAVES,
|
||||
JUNGLE_LEAVES,
|
||||
DARK_OAK_LEAVES,
|
||||
SPRUCE_LEAVES
|
||||
SPRUCE_LEAVES,
|
||||
NETHER_WART_BLOCK,
|
||||
WARPED_WART_BLOCK,
|
||||
SHROOMLIGHT
|
||||
);
|
||||
|
||||
private static final List<Material> leaves = Arrays.asList(
|
||||
@ -42,13 +70,20 @@ public class TreeCapitatorListener implements Listener {
|
||||
BIRCH_LEAVES,
|
||||
JUNGLE_LEAVES,
|
||||
DARK_OAK_LEAVES,
|
||||
SPRUCE_LEAVES
|
||||
SPRUCE_LEAVES,
|
||||
NETHER_WART_BLOCK,
|
||||
WARPED_WART_BLOCK,
|
||||
SHROOMLIGHT
|
||||
);
|
||||
|
||||
private final Enchantment capitatorEnchantment;
|
||||
private final double hungerPerBlock;
|
||||
private final int minHunger;
|
||||
|
||||
public TreeCapitatorListener(final Enchantment capitatorEnchantment) {
|
||||
public TreeCapitatorListener(final Enchantment capitatorEnchantment, final double hungerPerBlock, final int minHunger) {
|
||||
this.capitatorEnchantment = capitatorEnchantment;
|
||||
this.hungerPerBlock = hungerPerBlock;
|
||||
this.minHunger = minHunger;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@ -57,6 +92,12 @@ public class TreeCapitatorListener implements Listener {
|
||||
if (event.isCancelled() || !handTool.containsEnchantment(capitatorEnchantment))
|
||||
return;
|
||||
|
||||
// Check if capitator functionality is prevented by hunger
|
||||
if (event.getPlayer().getFoodLevel() < minHunger) {
|
||||
event.getPlayer().spigot().sendMessage(errorMessage("You are too tired to fell the tree"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (handTool.getItemMeta() instanceof final Damageable tool) {
|
||||
if (!leaves.contains(event.getBlock().getType()) && targetMaterials.contains(event.getBlock().getType())) {
|
||||
int logBreakCount = 0;
|
||||
@ -76,6 +117,11 @@ public class TreeCapitatorListener implements Listener {
|
||||
event.getPlayer().playSound(event.getPlayer().getLocation(), Sound.ENTITY_ITEM_BREAK, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
if (event.getPlayer().getGameMode() == GameMode.ADVENTURE || event.getPlayer().getGameMode() == GameMode.SURVIVAL) {
|
||||
final int hunger = (int) Math.round(hungerPerBlock * logBreakCount);
|
||||
event.getPlayer().setFoodLevel(Math.max(0, event.getPlayer().getFoodLevel() - hunger));
|
||||
}
|
||||
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
276
test_env.sh
276
test_env.sh
@ -1,276 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
MIN_JAVA_VERSION=15
|
||||
[ -z "$JAVA_PATH" ] && JAVA_PATH=$(which java)
|
||||
[ -z "$PYTHON_PATH" ] && PYTHON_PATH=$(which python3)
|
||||
[ -z "$SHELL" ] && SHELL=/bin/bash
|
||||
|
||||
SCRIPT_RUN_NAME="start.sh"
|
||||
SCRIPT_DEBUG_NAME="start_debug.sh"
|
||||
|
||||
# JVM options graciously "borrowed" from the PaperMC Timings JVM Tuning page
|
||||
# https://aikar.co/2018/07/02/tuning-the-jvm-g1gc-garbage-collector-flags-for-minecraft/
|
||||
MC_AUTORUN_FLAGS="-XX:+UnlockExperimentalVMOptions -Xmx1G -Xms512M -XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 -XX:+DisableExplicitGC -XX:+AlwaysPreTouch -XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 -XX:G1HeapRegionSize=8M -XX:G1ReservePercent=20 -XX:G1HeapWastePercent=5 -XX:G1MixedGCCountTarget=4 -XX:InitiatingHeapOccupancyPercent=15 -XX:G1MixedGCLiveThresholdPercent=90 -XX:G1RSetUpdatingPauseTimePercent=5 -XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem -XX:MaxTenuringThreshold=1"
|
||||
MC_VERSION="1.16"
|
||||
ENV_DIR="$(pwd)/server"
|
||||
PAPER_JAR_FILE="paper.jar"
|
||||
PLUGIN_PATH=""
|
||||
UPDATE_PAPER=true
|
||||
AUTORUN=""
|
||||
EULA=false
|
||||
DEPS=""
|
||||
CLEAR_PLUGINS=0
|
||||
|
||||
print_help() {
|
||||
echo -e "Paper test server deployment script\nArguments:"
|
||||
echo " -v [VERSION] - Specify minecraft version to download"
|
||||
echo " -p [PATH] - Path to plugin to debug"
|
||||
echo " -d [PATH] - Path to directory where server will be deployed"
|
||||
echo " -j [PATH] - Java executable path"
|
||||
echo " --python [PATH] - Python3 executable path"
|
||||
echo " --no-update - Don't download updates for Paper if jar file already exists"
|
||||
echo " -n - Same as --no-update"
|
||||
echo " -s [type] - Autorun server after deployment. Type is \"debug\" to start with remote debugging, else \"run\""
|
||||
echo " -e - Accepts the EULA for the deployed server (user must accept it in a provided prompt)"
|
||||
echo " --deps [PATH] - Path for plugin dependencies needed to load plugin"
|
||||
echo " -c - Delete existing plugins directory on autorun"
|
||||
echo " -h - Show this help prompt"
|
||||
echo -e "Example:\n $0 -v 1.16 -p out/plugin.jar -s debug -e"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo "[ERROR] $1" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
print_info() {
|
||||
if [ $# -eq 2 ]
|
||||
then
|
||||
echo -e "$1" "[TEST_ENV] $2"
|
||||
else
|
||||
echo -e "[TEST_ENV] $1"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
SKIP=false
|
||||
CUR=""
|
||||
TARGET=""
|
||||
for arg in "$@"
|
||||
do
|
||||
if $SKIP
|
||||
then
|
||||
eval "$TARGET"="$arg"
|
||||
SKIP=false
|
||||
continue
|
||||
fi
|
||||
|
||||
CUR="$arg"
|
||||
|
||||
case "$arg" in
|
||||
"-h")
|
||||
print_help
|
||||
exit
|
||||
;;
|
||||
|
||||
"-v")
|
||||
TARGET="MC_VERSION"
|
||||
SKIP=true
|
||||
;;
|
||||
|
||||
"-p")
|
||||
TARGET="PLUGIN_PATH"
|
||||
SKIP=true
|
||||
;;
|
||||
|
||||
"-d")
|
||||
TARGET="ENV_DIR"
|
||||
SKIP=true
|
||||
;;
|
||||
|
||||
"-j")
|
||||
TARGET="JAVA_PATH"
|
||||
SKIP=true
|
||||
;;
|
||||
|
||||
"--python")
|
||||
TARGET="PYTHON_PATH"
|
||||
SKIP=true
|
||||
;;
|
||||
|
||||
"-n" | "--no-update")
|
||||
UPDATE_PAPER=false
|
||||
;;
|
||||
|
||||
"-s")
|
||||
TARGET="AUTORUN"
|
||||
SKIP=true
|
||||
;;
|
||||
|
||||
"-e")
|
||||
EULA=true
|
||||
;;
|
||||
|
||||
"--deps")
|
||||
TARGET="DEPS"
|
||||
SKIP=true
|
||||
;;
|
||||
|
||||
"-c")
|
||||
CLEAR_PLUGINS=1
|
||||
;;
|
||||
|
||||
*)
|
||||
print_error "Unknown argument: $arg"
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if $SKIP
|
||||
then
|
||||
print_error "Malformed parameter $CUR"
|
||||
exit
|
||||
fi
|
||||
|
||||
case "$AUTORUN" in
|
||||
"run")
|
||||
AUTORUN="$SCRIPT_RUN_NAME"
|
||||
;;
|
||||
"debug")
|
||||
AUTORUN="$SCRIPT_DEBUG_NAME"
|
||||
;;
|
||||
*)
|
||||
print_error "Unknown autorun argument \"$AUTORUN\""
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
|
||||
check_java_version() {
|
||||
version=$("$JAVA_PATH" -version 2>&1 | head -n 1 | sed "s/java version \"\\([0-9]*\\)\\..*/\\1/g")
|
||||
if [ "$version" -lt "$MIN_JAVA_VERSION" ]
|
||||
then
|
||||
print_error "Java version is too low! Minimum is $MIN_JAVA_VERSION (found $version)"
|
||||
return 1
|
||||
fi
|
||||
print_info "Found Java version $version"
|
||||
return 0
|
||||
}
|
||||
|
||||
ensure_python3() {
|
||||
if [ -z "$PYTHON_PATH" ]
|
||||
then
|
||||
print_error "Could not locate Python3 which is required for automatic server deployment: please install it"
|
||||
return 1
|
||||
fi
|
||||
print_info "Found Python3 binary"
|
||||
return 0
|
||||
}
|
||||
|
||||
get_paper() {
|
||||
|
||||
print_info "Polling all versions of paper for MC $MC_VERSION"
|
||||
|
||||
link=$(curl -s "https://papermc.io/api/v2/projects/paper/version_group/$MC_VERSION/builds" | python3 -c "import sys, json; versions=json.load(sys.stdin); print('https://papermc.io/api/v2/projects/paper/versions/' + str(versions['builds'][-1]['version']) + '/builds/' + str(versions['builds'][-1]['build']) + '/downloads/' + str(versions['builds'][-1]['downloads']['application']['name']))")
|
||||
|
||||
if [ -f "new_$PAPER_JAR_FILE" ]
|
||||
then
|
||||
rm -f "new_$PAPER_JAR_FILE"
|
||||
fi
|
||||
|
||||
print_info "Downloading from pulled link: $link"
|
||||
|
||||
result=$(curl -o "new_$PAPER_JAR_FILE" -s -w "%{http_code}" "$link")
|
||||
|
||||
if [ "$result" -eq 200 ] && [ -f "new_$PAPER_JAR_FILE" ]
|
||||
then
|
||||
rm -f "$PAPER_JAR_FILE"
|
||||
mv "new_$PAPER_JAR_FILE" "$PAPER_JAR_FILE"
|
||||
print_info "Downloaded latest version of paper"
|
||||
return 1
|
||||
else
|
||||
print_info "Could not download new version of paper"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
check_java_version || exit
|
||||
ensure_python3 || exit
|
||||
|
||||
|
||||
if [ -d "$ENV_DIR/plugins" ] && [ $CLEAR_PLUGINS -eq 1 ]
|
||||
then
|
||||
print_info "Found existing plugins directory. Clearing it..."
|
||||
rm -r "$ENV_DIR/plugins"
|
||||
fi
|
||||
|
||||
mkdir -p "$ENV_DIR/plugins" || (print_error "Could not create server directory at $ENV_DIR" && exit)
|
||||
|
||||
if [ -n "$PLUGIN_PATH" ]
|
||||
then
|
||||
print_info "Copying plugin to server directory..."
|
||||
cp "$PLUGIN_PATH" "$ENV_DIR/plugins" || (print_error "Could not copy targeted plugin to test environment" && exit)
|
||||
fi
|
||||
|
||||
if [ -n "$DEPS" ]
|
||||
then
|
||||
if [ -d "$DEPS" ]
|
||||
then
|
||||
print_info "Copying dependencies..."
|
||||
cp "$DEPS"/* "$ENV_DIR/plugins"
|
||||
else
|
||||
print_error "Dependencies directory does not exist!"
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
|
||||
cd "$ENV_DIR" || (print_error "Could not enter directory $ENV_DIR" && exit)
|
||||
{ ! [ -f "$PAPER_JAR_FILE" ] || $UPDATE_PAPER; } && get_paper && { ! [ -f "$PAPER_JAR_FILE" ]; } && exit
|
||||
|
||||
[ -f "$PAPER_JAR_FILE" ] || exit
|
||||
|
||||
if ! [ -f "$SCRIPT_RUN_NAME" ]
|
||||
then
|
||||
echo -e "#!/bin/bash\njava $MC_AUTORUN_FLAGS -jar \"$PAPER_JAR_FILE\" nogui" > "$SCRIPT_RUN_NAME"
|
||||
fi
|
||||
|
||||
if ! [ -f "$SCRIPT_DEBUG_NAME" ]
|
||||
then
|
||||
echo -e "#!/bin/bash\njava -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 -jar \"$PAPER_JAR_FILE\" nogui" > "$SCRIPT_DEBUG_NAME"
|
||||
fi
|
||||
|
||||
print_info "Test environment successfully prepared!"
|
||||
|
||||
# Disable case-sensitivity for conditional expressions
|
||||
shopt -s nocaseglob
|
||||
|
||||
# No need to ask user to accept EULA if it is already accepted
|
||||
if $EULA && ! { [ -f "eula.txt" ] && [[ "$(cat eula.txt)" =~ eula=true ]]; }
|
||||
then
|
||||
print_info -n "Do you accept the terms of the Minecraft End User License Agreement? (https://account.mojang.com/documents/minecraft_eula) [y/N]: "
|
||||
read -r ACCEPTS
|
||||
|
||||
case "$ACCEPTS" in
|
||||
"y"* | "Y"*)
|
||||
echo "eula=true" > eula.txt
|
||||
;;
|
||||
*)
|
||||
print_info "EULA was not accepted"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Re-enable case-sensitivity, just in case
|
||||
shopt -u nocaseglob
|
||||
|
||||
if [ -n "$AUTORUN" ]
|
||||
then
|
||||
print_info "Autorun was specified. Attempting to kill active server processes..."
|
||||
|
||||
kill -9 $(fuser 25565/tcp | sed "s/.*\\s\\(.*\\)/\\1/g") > /dev/null 2>&1
|
||||
|
||||
print_info "Starting server..."
|
||||
|
||||
"$SHELL" "$AUTORUN"
|
||||
fi
|
Loading…
x
Reference in New Issue
Block a user