From 9d39e4cc7a21e25cd5f77ba2d11333dc6b3bd76b Mon Sep 17 00:00:00 2001 From: Teriuihi Date: Sat, 19 Oct 2024 19:10:37 +0200 Subject: [PATCH] Add GiveSpawner command and enhance spawner functionalities Implemented the GiveSpawner command to allow players to receive specific mob spawners. Added validation and namespaced key handling for mob types and entities to ensure proper functionality when placing spawners. Refactored existing code to use the new EntityTypeChecker utility. --- src/main/java/com/alttd/custommobs/Main.java | 17 ++- .../custommobs/commands/CommandManager.java | 7 +- .../commands/subcommands/GiveSpawner.java | 105 ++++++++++++++++++ .../commands/subcommands/Spawn.java | 19 +--- .../com/alttd/custommobs/config/Messages.java | 30 +++++ .../custommobs/listeners/SpawnerListener.java | 58 +++++++++- .../custommobs/utility/EntityTypeChecker.java | 24 ++++ 7 files changed, 234 insertions(+), 26 deletions(-) create mode 100644 src/main/java/com/alttd/custommobs/commands/subcommands/GiveSpawner.java create mode 100644 src/main/java/com/alttd/custommobs/utility/EntityTypeChecker.java diff --git a/src/main/java/com/alttd/custommobs/Main.java b/src/main/java/com/alttd/custommobs/Main.java index 8fa4f31..b6ab07b 100644 --- a/src/main/java/com/alttd/custommobs/Main.java +++ b/src/main/java/com/alttd/custommobs/Main.java @@ -6,6 +6,7 @@ import com.alttd.custommobs.config.Messages; import com.alttd.custommobs.config.MobTypes; import com.alttd.custommobs.listeners.SpawnerListener; import lombok.extern.slf4j.Slf4j; +import org.bukkit.NamespacedKey; import org.bukkit.plugin.java.JavaPlugin; @Slf4j @@ -15,16 +16,20 @@ public class Main extends JavaPlugin { public void onEnable() { log.info("Plugin enabled!"); reloadConfigs(); - registerEvents(); - registerCommands(); + + NamespacedKey mobTypeKey = new NamespacedKey(this, "mob-type"); + NamespacedKey entityKey = new NamespacedKey(this, "entity-type"); + + registerEvents(mobTypeKey, entityKey); + registerCommands(mobTypeKey, entityKey); } - private void registerCommands() { - new CommandManager(this); + private void registerCommands(NamespacedKey mobTypeKey, NamespacedKey entityKey) { + new CommandManager(this, mobTypeKey, entityKey); } - private void registerEvents() { - getServer().getPluginManager().registerEvents(new SpawnerListener(this), this); + private void registerEvents(NamespacedKey mobTypeKey, NamespacedKey entityKey) { + getServer().getPluginManager().registerEvents(new SpawnerListener(this, mobTypeKey, entityKey), this); } public void reloadConfigs() { diff --git a/src/main/java/com/alttd/custommobs/commands/CommandManager.java b/src/main/java/com/alttd/custommobs/commands/CommandManager.java index aee5464..86ff5ce 100644 --- a/src/main/java/com/alttd/custommobs/commands/CommandManager.java +++ b/src/main/java/com/alttd/custommobs/commands/CommandManager.java @@ -1,10 +1,12 @@ package com.alttd.custommobs.commands; import com.alttd.custommobs.Main; +import com.alttd.custommobs.commands.subcommands.GiveSpawner; import com.alttd.custommobs.commands.subcommands.Spawn; import com.alttd.custommobs.config.Messages; import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import org.bukkit.NamespacedKey; import org.bukkit.command.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -19,7 +21,7 @@ import java.util.stream.Collectors; public class CommandManager implements CommandExecutor, TabExecutor { private final List subCommands; - public CommandManager(Main main) { + public CommandManager(Main main, @NotNull NamespacedKey mobTypeKey, @NotNull NamespacedKey entityKey) { PluginCommand command = main.getCommand("custommobs"); if (command == null) { subCommands = null; @@ -31,7 +33,8 @@ public class CommandManager implements CommandExecutor, TabExecutor { command.setAliases(List.of("cm")); subCommands = Arrays.asList( - new Spawn(main) + new Spawn(main), + new GiveSpawner(main, mobTypeKey, entityKey) ); } diff --git a/src/main/java/com/alttd/custommobs/commands/subcommands/GiveSpawner.java b/src/main/java/com/alttd/custommobs/commands/subcommands/GiveSpawner.java new file mode 100644 index 0000000..75f647f --- /dev/null +++ b/src/main/java/com/alttd/custommobs/commands/subcommands/GiveSpawner.java @@ -0,0 +1,105 @@ +package com.alttd.custommobs.commands.subcommands; + +import com.alttd.custommobs.Main; +import com.alttd.custommobs.abilities.MobType; +import com.alttd.custommobs.commands.SubCommand; +import com.alttd.custommobs.config.Messages; +import com.alttd.custommobs.config.MobTypes; +import com.alttd.custommobs.utility.EntityTypeChecker; +import lombok.extern.slf4j.Slf4j; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +@Slf4j +public class GiveSpawner extends SubCommand { + + private final Main main; + private final NamespacedKey mobTypeKey; + private final NamespacedKey entityKey; + + public GiveSpawner(Main main, @NotNull NamespacedKey mobTypeKey, @NotNull NamespacedKey entityKey) { + this.main = main; + this.mobTypeKey = mobTypeKey; + this.entityKey = entityKey; + } + + @Override + public boolean onCommand(CommandSender commandSender, String[] args) { + if (!(commandSender instanceof Player player)) { + commandSender.sendRichMessage(Messages.GENERIC.PLAYER_ONLY); + return true; + } + if (args.length != 3) { + return false; + } + Optional optionalMobType = MobTypes.MOB_TYPES.get(args[1]); + if (optionalMobType.isEmpty()) { + return false; + } + + try { + EntityType entityType = EntityType.valueOf(args[2]); + if (!entityType.isSpawnable() || !EntityTypeChecker.isMob(entityType)) { + return false; + } + } catch (IllegalArgumentException e) { + log.info("DEBUG: Invalid mob type {}", args[2]); + return false; + } + + ItemStack spawner = new ItemStack(Material.SPAWNER); + ItemMeta meta = spawner.getItemMeta(); + meta.displayName(MiniMessage.miniMessage().deserialize(Messages.GIVE_SPAWNER.SPAWNER_NAME, TagResolver.resolver( + Placeholder.parsed("entity", args[2]), + Placeholder.parsed("mob_type", args[1]) + ))); + PersistentDataContainer persistentDataContainer = meta.getPersistentDataContainer(); + persistentDataContainer.set(mobTypeKey, PersistentDataType.STRING, args[1]); + persistentDataContainer.set(entityKey, PersistentDataType.STRING, args[2]); + spawner.setItemMeta(meta); + + if (!player.getInventory().addItem(spawner).isEmpty()) { + player.sendRichMessage(Messages.GIVE_SPAWNER.FULL_INVENTORY); + return true; + } + player.sendRichMessage(Messages.GIVE_SPAWNER.GIVEN, TagResolver.resolver( + Placeholder.parsed("entity", args[2]), + Placeholder.parsed("mob_type", args[1]) + )); + return true; + } + + @Override + public String getName() { + return "give_spawner"; + } + + @Override + public List getTabComplete(CommandSender commandSender, String[] args) { + return switch (args.length) { + case 2 -> MobTypes.MOB_TYPES.getAllMobTypes(); + case 3 -> Arrays.stream(EntityType.values()).map(EntityType::name).toList(); + default -> List.of(); + }; + } + + @Override + public String getHelpMessage() { + return Messages.HELP.GIVE_SPAWNER; + } +} diff --git a/src/main/java/com/alttd/custommobs/commands/subcommands/Spawn.java b/src/main/java/com/alttd/custommobs/commands/subcommands/Spawn.java index ddb4787..29fa99e 100644 --- a/src/main/java/com/alttd/custommobs/commands/subcommands/Spawn.java +++ b/src/main/java/com/alttd/custommobs/commands/subcommands/Spawn.java @@ -6,6 +6,7 @@ import com.alttd.custommobs.abilities.MobTypeApplier; import com.alttd.custommobs.commands.SubCommand; import com.alttd.custommobs.config.Messages; import com.alttd.custommobs.config.MobTypes; +import com.alttd.custommobs.utility.EntityTypeChecker; import com.alttd.custommobs.utility.SpawnableTargetBlock; import lombok.extern.slf4j.Slf4j; import org.bukkit.Bukkit; @@ -46,7 +47,7 @@ public class Spawn extends SubCommand { log.info("DEBUG: Invalid mob type {}", args[2]); return false; } - if (!entityType.isSpawnable() || !isMob(entityType)) { + if (!entityType.isSpawnable() || !EntityTypeChecker.isMob(entityType)) { return false; } @@ -87,22 +88,6 @@ public class Spawn extends SubCommand { } } - public boolean isMob(EntityType entityType) { - if (entityType == null) { - return false; - } - try { - Class entityClass = entityType.getEntityClass(); - if (entityClass == null) { - return false; - } - Class mobEntityClass = Class.forName("org.bukkit.entity." + entityClass.getSimpleName()); - return Mob.class.isAssignableFrom(mobEntityClass); - } catch (ClassNotFoundException e) { - return false; - } - } - private void spawnMob(World world, Location location, EntityType entityType, MobType mobType) { if (entityType.getEntityClass() == null) { log.warn("Tried to spawn entity with null entity class {}", entityType.name()); diff --git a/src/main/java/com/alttd/custommobs/config/Messages.java b/src/main/java/com/alttd/custommobs/config/Messages.java index 0c8298d..a99de6c 100644 --- a/src/main/java/com/alttd/custommobs/config/Messages.java +++ b/src/main/java/com/alttd/custommobs/config/Messages.java @@ -1,6 +1,7 @@ package com.alttd.custommobs.config; import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; import java.io.File; @@ -29,12 +30,14 @@ public class Messages extends AbstractConfig { public static String HELP_MESSAGE_WRAPPER = "Main help:\n"; public static String HELP_MESSAGE = "Show this menu: /cm help"; public static String SPAWN = "Spawn a mob of a specific type: /cm spawn [ ]"; + public static String GIVE_SPAWNER = "Give a mob spawner for a mob of a specific type: /cm givespawner "; @SuppressWarnings("unused") private static void load() { HELP_MESSAGE_WRAPPER = config.getString(prefix, "help-wrapper", HELP_MESSAGE_WRAPPER); HELP_MESSAGE = config.getString(prefix, "help", HELP_MESSAGE); SPAWN = config.getString(prefix, "spawn", SPAWN); + GIVE_SPAWNER = config.getString(prefix, "give-spawner", GIVE_SPAWNER); } } @@ -52,4 +55,31 @@ public class Messages extends AbstractConfig { PLAYER_NOT_FOUND = config.getString(prefix, "player-only", PLAYER_NOT_FOUND); } } + + public static class GIVE_SPAWNER { + private static final String prefix = "give-spawner."; + + public static String FULL_INVENTORY = "You inventory is full so the spawner was not given"; + public static String GIVEN = "You have been given a spawner for type "; + public static String SPAWNER_NAME = " spawner"; + + @SuppressWarnings("unused") + private static void load() { + FULL_INVENTORY = config.getString(prefix, "full-inventory", FULL_INVENTORY); + GIVEN = config.getString(prefix, "given", GIVEN); + SPAWNER_NAME = config.getString(prefix, "spawner-name", SPAWNER_NAME); + } + } + + public static class PLACE_SPAWNER { + private static final String prefix = "place-spawner."; + public static String INVALID_MOB_TYPE = "This spawner has an invalid mob type ()"; + public static String INVALID_ENTITY_TYPE = "This spawner has an invalid entity type ()"; + + @SuppressWarnings("unused") + private static void load() { + INVALID_MOB_TYPE = config.getString(prefix, "invalid-mob-type", INVALID_MOB_TYPE); + INVALID_ENTITY_TYPE = config.getString(prefix, "invalid-entity-type", INVALID_ENTITY_TYPE); + } + } } diff --git a/src/main/java/com/alttd/custommobs/listeners/SpawnerListener.java b/src/main/java/com/alttd/custommobs/listeners/SpawnerListener.java index 7548214..1acfec1 100644 --- a/src/main/java/com/alttd/custommobs/listeners/SpawnerListener.java +++ b/src/main/java/com/alttd/custommobs/listeners/SpawnerListener.java @@ -3,14 +3,26 @@ package com.alttd.custommobs.listeners; import com.alttd.custommobs.Main; import com.alttd.custommobs.abilities.MobType; import com.alttd.custommobs.abilities.MobTypeApplier; +import com.alttd.custommobs.config.Messages; import com.alttd.custommobs.config.MobTypes; +import com.alttd.custommobs.utility.EntityTypeChecker; +import io.papermc.paper.persistence.PersistentDataContainerView; import lombok.extern.slf4j.Slf4j; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import org.bukkit.NamespacedKey; +import org.bukkit.block.Block; import org.bukkit.block.CreatureSpawner; +import org.bukkit.block.Sign; +import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.SpawnerSpawnEvent; +import org.bukkit.inventory.ItemStack; import org.bukkit.metadata.MetadataValue; +import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.Optional; @@ -19,9 +31,13 @@ import java.util.Optional; public class SpawnerListener implements Listener { private final MobTypeApplier mobTypeApplier; + private final NamespacedKey mobTypeKey; + private final NamespacedKey entityKey; - public SpawnerListener(Main main) { + public SpawnerListener(Main main, @NotNull NamespacedKey mobTypeKey, @NotNull NamespacedKey entityKey) { mobTypeApplier = new MobTypeApplier(main); + this.mobTypeKey = mobTypeKey; + this.entityKey = entityKey; } @EventHandler @@ -48,4 +64,44 @@ public class SpawnerListener implements Listener { mobTypeApplier.apply(livingEntity, mobType); } + @EventHandler + public void onSpawnerPlace(BlockPlaceEvent event) { + ItemStack itemInHand = event.getItemInHand(); + if (!itemInHand.getType().equals(org.bukkit.Material.SPAWNER)) { + return; + } + PersistentDataContainerView persistentDataContainer = itemInHand.getPersistentDataContainer(); + if (!persistentDataContainer.has(mobTypeKey) || !persistentDataContainer.has(entityKey)) { + return; + } + String mobType = persistentDataContainer.get(mobTypeKey, PersistentDataType.STRING); + String entityTypeName = persistentDataContainer.get(entityKey, PersistentDataType.STRING); + if (mobType == null || entityTypeName == null) { + return; + } + + Optional optionalMobType = MobTypes.MOB_TYPES.get(mobType); + if (optionalMobType.isEmpty()) { + event.getPlayer().sendRichMessage(Messages.PLACE_SPAWNER.INVALID_MOB_TYPE, Placeholder.parsed("mob-type", mobType)); + return; + } + EntityType entityType; + try { + entityType = EntityType.valueOf(entityTypeName); + if (!entityType.isSpawnable() || !EntityTypeChecker.isMob(entityType)) { + event.getPlayer().sendRichMessage(Messages.PLACE_SPAWNER.INVALID_ENTITY_TYPE, Placeholder.parsed("entity-type", entityTypeName)); + return; + } + } catch (IllegalArgumentException e) { + log.info("DEBUG: Invalid mob type {}", entityTypeName); + return; + } + + if (event.getBlock().getState() instanceof CreatureSpawner spawner) { + spawner.setSpawnedType(entityType); + } else { + log.info("Actual bock state {}", event.getBlock().getState().getClass().getName()); + } + } + } diff --git a/src/main/java/com/alttd/custommobs/utility/EntityTypeChecker.java b/src/main/java/com/alttd/custommobs/utility/EntityTypeChecker.java new file mode 100644 index 0000000..a59b4ea --- /dev/null +++ b/src/main/java/com/alttd/custommobs/utility/EntityTypeChecker.java @@ -0,0 +1,24 @@ +package com.alttd.custommobs.utility; + +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Mob; + +public class EntityTypeChecker { + + public static boolean isMob(EntityType entityType) { + if (entityType == null) { + return false; + } + try { + Class entityClass = entityType.getEntityClass(); + if (entityClass == null) { + return false; + } + Class mobEntityClass = Class.forName("org.bukkit.entity." + entityClass.getSimpleName()); + return Mob.class.isAssignableFrom(mobEntityClass); + } catch (ClassNotFoundException e) { + return false; + } + } +}