diff --git a/res/plugin.yml b/res/plugin.yml index da058f7..808c757 100644 --- a/res/plugin.yml +++ b/res/plugin.yml @@ -19,4 +19,8 @@ commands: capitator: description: Toggle tree capitation for an axe in your main hand usage: / - permission: invtweaks.capitator \ No newline at end of file + permission: invtweaks.capitator + chestname: + description: Add a floating nametag to a chest + usage: / {name} + permission: invtweaks.spawnfake \ No newline at end of file diff --git a/src/dev/w1zzrd/invtweaks/InvTweaksPlugin.java b/src/dev/w1zzrd/invtweaks/InvTweaksPlugin.java index 0559fbe..ee5581a 100644 --- a/src/dev/w1zzrd/invtweaks/InvTweaksPlugin.java +++ b/src/dev/w1zzrd/invtweaks/InvTweaksPlugin.java @@ -1,9 +1,6 @@ package dev.w1zzrd.invtweaks; -import dev.w1zzrd.invtweaks.command.CapitatorCommand; -import dev.w1zzrd.invtweaks.command.MagnetCommandExecutor; -import dev.w1zzrd.invtweaks.command.SearchCommandExecutor; -import dev.w1zzrd.invtweaks.command.SortCommandExecutor; +import dev.w1zzrd.invtweaks.command.*; import dev.w1zzrd.invtweaks.enchantment.CapitatorEnchantment; import dev.w1zzrd.invtweaks.listener.*; import dev.w1zzrd.invtweaks.serialization.MagnetConfig; @@ -42,6 +39,7 @@ public final class InvTweaksPlugin extends JavaPlugin { private SortCommandExecutor sortCommandExecutor; private MagnetCommandExecutor magnetCommandExecutor; private SearchCommandExecutor searchCommandExecutor; + private NamedChestCommand namedChestCommandExecutor; private CapitatorCommand capitatorCommand; private DataStore data; private NamespacedKey capitatorEnchantmentKey; @@ -172,6 +170,7 @@ public final class InvTweaksPlugin extends JavaPlugin { sortCommandExecutor = new SortCommandExecutor(); magnetCommandExecutor = new MagnetCommandExecutor(this, "magnet", getPersistentData()); searchCommandExecutor = new SearchCommandExecutor(this, "search"); + namedChestCommandExecutor = new NamedChestCommand(this); if (activateCapitator) capitatorCommand = new CapitatorCommand(capitatorEnchantment); @@ -180,6 +179,7 @@ public final class InvTweaksPlugin extends JavaPlugin { Objects.requireNonNull(getCommand("sort")).setExecutor(sortCommandExecutor); Objects.requireNonNull(getCommand("magnet")).setExecutor(magnetCommandExecutor); Objects.requireNonNull(getCommand("search")).setExecutor(searchCommandExecutor); + Objects.requireNonNull(getCommand("chestname")).setExecutor(namedChestCommandExecutor); if (activateCapitator) Objects.requireNonNull(getCommand("capitator")).setExecutor(capitatorCommand); @@ -192,6 +192,7 @@ public final class InvTweaksPlugin extends JavaPlugin { magnetCommandExecutor.onDisable(); capitatorCommand = null; + namedChestCommandExecutor = null; searchCommandExecutor = null; magnetCommandExecutor = null; sortCommandExecutor = null; diff --git a/src/dev/w1zzrd/invtweaks/command/NamedChestCommand.java b/src/dev/w1zzrd/invtweaks/command/NamedChestCommand.java new file mode 100644 index 0000000..8c0efc0 --- /dev/null +++ b/src/dev/w1zzrd/invtweaks/command/NamedChestCommand.java @@ -0,0 +1,89 @@ +package dev.w1zzrd.invtweaks.command; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.Chest; +import org.bukkit.block.DoubleChest; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.plugin.Plugin; + +import java.util.Objects; + +import static dev.w1zzrd.invtweaks.command.CommandUtils.assertTrue; +import static dev.w1zzrd.invtweaks.entity.EntityCreator.*; + +public class NamedChestCommand implements CommandExecutor { + + private final Plugin plugin; + + public NamedChestCommand(final Plugin plugin) { + this.plugin = plugin; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (assertTrue(sender instanceof Player && ((Player) sender).isOnline(), "Command can only be run by a player!", sender)) + return true; + + if (assertTrue(args.length == 0, "Expected a name for the chest", sender)) + return true; + + if (assertTrue(args.length > 1, "Too many arguments for command", sender)) + return true; + + assert sender instanceof Player; + final Player player = (Player) sender; + + final Block block = player.getTargetBlockExact(10); + + if (assertTrue(block != null && (block.getType() == Material.CHEST || block.getType() == Material.TRAPPED_CHEST), "You must be targeting a chest", sender)) + return true; + + assert block != null; + + final Location loc = getCenterChestLocation(block); + + final Object entity = createFakeSlime(player); + setSlimeSize(entity, 1); + + setEntityCollision(entity, false); + setEntityCustomName(entity, args[0]); + setEntityInvulnerable(entity, true); + setEntityLocation(entity, loc.getX(), loc.getY(), loc.getZ(), 0f, 0f); + setEntityCustomNameVisible(entity, true); + + sendEntitySpawnPacket(player, entity); + sendEntityMetadataPacket(player, entity); + + final int entityID = getEntityID(entity); + + Bukkit.getScheduler().runTaskLater(plugin, () -> { + sendEntityDespawnPacket(player, entityID); + }, 60); + + return true; + } + + private static Location getCenterChestLocation(final Block chestBlock) { + final InventoryHolder holder = Objects.requireNonNull(((Chest) chestBlock.getState()).getBlockInventory().getHolder()).getInventory().getHolder(); + + if (holder instanceof final DoubleChest dChest) { + final Location left = getBlockCenter(Objects.requireNonNull((Chest)dChest.getLeftSide()).getBlock()); + final Location right = getBlockCenter(Objects.requireNonNull((Chest)dChest.getRightSide()).getBlock()); + + return new Location(left.getWorld(), (left.getX() + right.getX()) / 2.0, left.getY() + 0.2, (left.getZ() + right.getZ()) / 2.0); + } else { + return getBlockCenter(chestBlock).add(0.0, 0.2, 0.0); + } + } + + private static Location getBlockCenter(final Block block) { + return block.getLocation().add(0.5, 0, 0.5); + } +} diff --git a/src/dev/w1zzrd/invtweaks/serialization/ChestNameConfig.java b/src/dev/w1zzrd/invtweaks/serialization/ChestNameConfig.java new file mode 100644 index 0000000..1b33736 --- /dev/null +++ b/src/dev/w1zzrd/invtweaks/serialization/ChestNameConfig.java @@ -0,0 +1,17 @@ +package dev.w1zzrd.invtweaks.serialization; + +import java.util.Map; + +public class ChestNameConfig extends SimpleReflectiveConfigItem { + + private Map locs; + + /** + * Required constructor for deserializing data + * + * @param mappings Data to deserialize + */ + public ChestNameConfig(Map mappings) { + super(mappings); + } +}