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; + } + } +}