From 73f9d3a15513d4174a147f355c0c8da910c63479 Mon Sep 17 00:00:00 2001 From: Big Pappa Date: Sun, 7 Jun 2026 12:11:50 -0500 Subject: [PATCH] Initial RS-MobStand commit --- .gitignore | 14 + pom.xml | 82 ++ .../mobstand/RSMobStandPlugin.java | 94 ++ .../mobstand/commands/RSMSCommand.java | 81 ++ .../mobstand/commands/RSMSTabCompleter.java | 33 + .../mobstand/config/ConfigManager.java | 278 +++++ .../mobstand/data/MobFilterData.java | 45 + .../mobstand/gui/AdultFilterMenu.java | 326 ++++++ .../mobstand/gui/BabyFilterMenu.java | 326 ++++++ .../mobstand/gui/ConversionMenu.java | 77 ++ .../mobstand/gui/LeaveAliveMenu.java | 181 +++ .../rsscripting/mobstand/gui/RSAdminMenu.java | 225 ++++ .../mobstand/gui/RSMenuHolder.java | 32 + .../rsscripting/mobstand/gui/RadiusMenu.java | 179 +++ .../rsscripting/mobstand/gui/StandMenu.java | 369 ++++++ .../listeners/ArmorStandBreakListener.java | 39 + .../listeners/ArmorStandListener.java | 113 ++ .../mobstand/listeners/ChunkLoadListener.java | 47 + .../mobstand/listeners/MenuListener.java | 1003 +++++++++++++++++ .../mobstand/managers/StandManager.java | 794 +++++++++++++ .../mobstand/tasks/SlaughterTask.java | 380 +++++++ .../mobstand/utils/VersionChecker.java | 148 +++ src/main/resources/config.yml | 91 ++ src/main/resources/configs/adult-mobs.yml | 131 +++ src/main/resources/configs/baby-mobs.yml | 73 ++ src/main/resources/plugin.yml | 27 + src/main/resources/updates.txt | 15 + 27 files changed, 5203 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/com/rsscripting/mobstand/RSMobStandPlugin.java create mode 100644 src/main/java/com/rsscripting/mobstand/commands/RSMSCommand.java create mode 100644 src/main/java/com/rsscripting/mobstand/commands/RSMSTabCompleter.java create mode 100644 src/main/java/com/rsscripting/mobstand/config/ConfigManager.java create mode 100644 src/main/java/com/rsscripting/mobstand/data/MobFilterData.java create mode 100644 src/main/java/com/rsscripting/mobstand/gui/AdultFilterMenu.java create mode 100644 src/main/java/com/rsscripting/mobstand/gui/BabyFilterMenu.java create mode 100644 src/main/java/com/rsscripting/mobstand/gui/ConversionMenu.java create mode 100644 src/main/java/com/rsscripting/mobstand/gui/LeaveAliveMenu.java create mode 100644 src/main/java/com/rsscripting/mobstand/gui/RSAdminMenu.java create mode 100644 src/main/java/com/rsscripting/mobstand/gui/RSMenuHolder.java create mode 100644 src/main/java/com/rsscripting/mobstand/gui/RadiusMenu.java create mode 100644 src/main/java/com/rsscripting/mobstand/gui/StandMenu.java create mode 100644 src/main/java/com/rsscripting/mobstand/listeners/ArmorStandBreakListener.java create mode 100644 src/main/java/com/rsscripting/mobstand/listeners/ArmorStandListener.java create mode 100644 src/main/java/com/rsscripting/mobstand/listeners/ChunkLoadListener.java create mode 100644 src/main/java/com/rsscripting/mobstand/listeners/MenuListener.java create mode 100644 src/main/java/com/rsscripting/mobstand/managers/StandManager.java create mode 100644 src/main/java/com/rsscripting/mobstand/tasks/SlaughterTask.java create mode 100644 src/main/java/com/rsscripting/mobstand/utils/VersionChecker.java create mode 100644 src/main/resources/config.yml create mode 100644 src/main/resources/configs/adult-mobs.yml create mode 100644 src/main/resources/configs/baby-mobs.yml create mode 100644 src/main/resources/plugin.yml create mode 100644 src/main/resources/updates.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..63032fe --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# IntelliJ IDEA +.idea/ +*.iml + +# Maven build output +target/ + +# OS files +.DS_Store +Thumbs.db + +# Logs +*.log +logs/ \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d9f6419 --- /dev/null +++ b/pom.xml @@ -0,0 +1,82 @@ + + + + 4.0.0 + + + + + + + com.rsscripting + rs-mobstand + 1.0.0 + + RS-MobStand + + + 21 + UTF-8 + + + + + + + + + + + papermc-repo + https://repo.papermc.io/repository/maven-public/ + + + + + + + + + + + + + io.papermc.paper + paper-api + 1.21.1-R0.1-SNAPSHOT + provided + + + + + + + + + + + + RS-MobStand-1.0.0 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + + ${java.version} + ${java.version} + + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/RSMobStandPlugin.java b/src/main/java/com/rsscripting/mobstand/RSMobStandPlugin.java new file mode 100644 index 0000000..1641727 --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/RSMobStandPlugin.java @@ -0,0 +1,94 @@ +package com.rsscripting.mobstand; + +import com.rsscripting.mobstand.commands.RSMSCommand; +import com.rsscripting.mobstand.commands.RSMSTabCompleter; +import com.rsscripting.mobstand.tasks.SlaughterTask; +import com.rsscripting.mobstand.config.ConfigManager; +import com.rsscripting.mobstand.listeners.ChunkLoadListener; +import com.rsscripting.mobstand.listeners.ArmorStandBreakListener; +import com.rsscripting.mobstand.listeners.ArmorStandListener; +import com.rsscripting.mobstand.listeners.MenuListener; +import com.rsscripting.mobstand.managers.StandManager; +import com.rsscripting.mobstand.utils.VersionChecker; + +import org.bukkit.plugin.java.JavaPlugin; + +public class RSMobStandPlugin extends JavaPlugin { + + private StandManager standManager; + private ConfigManager configManager; + + @Override + public void onEnable() { + + saveDefaultConfig(); + + this.standManager = new StandManager(this); + + this.configManager = new ConfigManager(this); + + getCommand("rsms").setExecutor( + new RSMSCommand(this) + ); + + getCommand("rsms").setTabCompleter( + new RSMSTabCompleter() + ); + + getServer().getPluginManager().registerEvents( + new ArmorStandListener( + this, + standManager + ), + this + ); + + getServer().getPluginManager().registerEvents( + new ArmorStandBreakListener(this), + this + ); + + getServer().getPluginManager().registerEvents( + new MenuListener(this), + this + ); + + long scanInterval = getConfig().getLong("scan-interval"); + + new SlaughterTask(this).runTaskTimer( + this, + 20L, + scanInterval + ); + + getServer().getPluginManager().registerEvents( + new ChunkLoadListener(standManager), + this + ); + + new VersionChecker(this).checkVersion(); + + getLogger().info("RS Mob Stand enabled."); + + } + + @Override + public void onDisable() { + + getLogger().info("RS Mob Stand disabled."); + + } + + public StandManager getStandManager() { + + return standManager; + + } + + public ConfigManager getConfigManager() { + + return configManager; + + } + +} \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/commands/RSMSCommand.java b/src/main/java/com/rsscripting/mobstand/commands/RSMSCommand.java new file mode 100644 index 0000000..e4a03ef --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/commands/RSMSCommand.java @@ -0,0 +1,81 @@ +package com.rsscripting.mobstand.commands; + +import com.rsscripting.mobstand.RSMobStandPlugin; + +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; + +public class RSMSCommand implements CommandExecutor { + + private final RSMobStandPlugin plugin; + + public RSMSCommand( + RSMobStandPlugin plugin + ) { + + this.plugin = plugin; + + } + + @Override + public boolean onCommand( + CommandSender sender, + Command command, + String label, + String[] args + ) { + + if (!sender.hasPermission( + "rsmobstand.admin" + )) { + + sender.sendMessage( + ChatColor.RED + + "You do not have permission." + ); + + return true; + + } + + if (args.length == 0) { + + sender.sendMessage( + ChatColor.YELLOW + + "/rsms reload" + ); + + return true; + + } + + if (args[0].equalsIgnoreCase( + "reload" + )) { + + plugin.reloadConfig(); + + plugin.getConfigManager() + .loadConfigs(); + + sender.sendMessage( + ChatColor.GREEN + + "RS MobStand configuration reloaded." + ); + + return true; + + } + + sender.sendMessage( + ChatColor.RED + + "Unknown subcommand." + ); + + return true; + + } + +} \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/commands/RSMSTabCompleter.java b/src/main/java/com/rsscripting/mobstand/commands/RSMSTabCompleter.java new file mode 100644 index 0000000..3037e8a --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/commands/RSMSTabCompleter.java @@ -0,0 +1,33 @@ +package com.rsscripting.mobstand.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; + +import java.util.ArrayList; +import java.util.List; + +public class RSMSTabCompleter implements TabCompleter { + + @Override + public List onTabComplete( + CommandSender sender, + Command command, + String alias, + String[] args + ) { + + List completions = + new ArrayList<>(); + + if (args.length == 1) { + + completions.add("reload"); + + } + + return completions; + + } + +} \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/config/ConfigManager.java b/src/main/java/com/rsscripting/mobstand/config/ConfigManager.java new file mode 100644 index 0000000..7186b18 --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/config/ConfigManager.java @@ -0,0 +1,278 @@ +package com.rsscripting.mobstand.config; + +import com.rsscripting.mobstand.RSMobStandPlugin; +import com.rsscripting.mobstand.data.MobFilterData; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; + +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; + +import java.io.File; +import java.util.Map; +import java.util.HashMap; + +import java.util.List; + +public class ConfigManager { + + private final RSMobStandPlugin plugin; + + private final Map adultMobData = + new HashMap<>(); + + private final Map babyMobData = + new HashMap<>(); + + private FileConfiguration adultConfig; + + private FileConfiguration babyConfig; + + public ConfigManager(RSMobStandPlugin plugin) { + + this.plugin = plugin; + + loadConfigs(); + + } + + +// Loads all plugin configs. + + public void loadConfigs() { + + File configFolder = new File( + plugin.getDataFolder(), + "configs" + ); + + if (!configFolder.exists()) { + + if (!configFolder.mkdirs()) { + + plugin.getLogger().warning( + "Failed to create configs folder." + ); + + } + + } + + loadAdultConfig(); + loadAdultMobData(); + + loadBabyConfig(); + loadBabyMobData(); + + } + + +// Loads adult mob config. + + private void loadAdultConfig() { + + File file = new File( + plugin.getDataFolder(), + "configs/adult-mobs.yml" + ); + + if (!file.exists()) { + + plugin.saveResource("configs/adult-mobs.yml", false); + + } + + adultConfig = YamlConfiguration.loadConfiguration(file); + + } + + +//Loads baby mob config. + + private void loadBabyConfig() { + + File file = new File( + plugin.getDataFolder(), + "configs/baby-mobs.yml" + ); + + if (!file.exists()) { + + plugin.saveResource("configs/baby-mobs.yml", false); + + } + + babyConfig = YamlConfiguration.loadConfiguration(file); + + } + +// Gets allowed adult mobs. + + public void loadBabyMobData() { + + babyMobData.clear(); + + ConfigurationSection section = + babyConfig.getConfigurationSection( + "baby-mobs" + ); + + if (section == null) { + return; + } + + for (String mobName : section.getKeys(false)) { + + String path = + "baby-mobs." + mobName; + + String iconName = + babyConfig.getString( + path + ".icon" + ); + + boolean enabled = + babyConfig.getBoolean( + path + ".enabled-by-default" + ); + + boolean killAll = + babyConfig.getBoolean( + path + ".kill-all", + false + ); + + if (iconName == null) { + + plugin.getLogger().warning( + "Missing icon for mob: " + + mobName + ); + + continue; + + } + + Material icon = + Material.matchMaterial(iconName); + + if (icon == null) { + + plugin.getLogger().warning( + "Invalid icon material for mob: " + + mobName + ); + + continue; + + } + + babyMobData.put( + mobName, + new MobFilterData( + icon, + enabled, + killAll + ) + ); + + } + + } + +// Gets allowed adult mobs. + + public void loadAdultMobData() { + + adultMobData.clear(); + + ConfigurationSection section = + adultConfig.getConfigurationSection( + "adult-mobs" + ); + + if (section == null) { + return; + } + + for (String mobName : section.getKeys(false)) { + + String path = + "adult-mobs." + mobName; + + String iconName = + adultConfig.getString( + path + ".icon" + ); + + boolean enabled = + adultConfig.getBoolean( + path + ".enabled-by-default" + ); + + boolean killAll = + adultConfig.getBoolean( + path + ".kill-all", + false + ); + + if (iconName == null) { + + plugin.getLogger().warning( + "Missing icon for mob: " + + mobName + ); + + continue; + + } + + Material icon = + Material.matchMaterial(iconName); + + if (icon == null) { + + plugin.getLogger().warning( + "Invalid icon material for mob: " + + mobName + ); + + continue; + + } + + adultMobData.put( + mobName, + new MobFilterData( + icon, + enabled, + killAll + ) + ); + + } + + } + + +// Gets allowed baby mobs. + + public List getBabyMobs() { + + return babyConfig.getStringList("baby-mobs"); + + } + + public Map getAdultMobData() { + + return adultMobData; + + } + + public Map getBabyMobData() { + + return babyMobData; + + } + +} \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/data/MobFilterData.java b/src/main/java/com/rsscripting/mobstand/data/MobFilterData.java new file mode 100644 index 0000000..05a4cc9 --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/data/MobFilterData.java @@ -0,0 +1,45 @@ +package com.rsscripting.mobstand.data; + +import org.bukkit.Material; + +public class MobFilterData { + + private final Material icon; + + private final boolean enabledByDefault; + + private final boolean killAll; + + public MobFilterData( + Material icon, + boolean enabledByDefault, + boolean killAll + ) { + + this.icon = icon; + + this.enabledByDefault = enabledByDefault; + + this.killAll = killAll; + + } + + public Material getIcon() { + + return icon; + + } + + public boolean isKillAll() { + + return killAll; + + } + + public boolean isEnabledByDefault() { + + return enabledByDefault; + + } + +} \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/gui/AdultFilterMenu.java b/src/main/java/com/rsscripting/mobstand/gui/AdultFilterMenu.java new file mode 100644 index 0000000..2f30d6a --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/gui/AdultFilterMenu.java @@ -0,0 +1,326 @@ +package com.rsscripting.mobstand.gui; + +import com.rsscripting.mobstand.RSMobStandPlugin; +import com.rsscripting.mobstand.data.MobFilterData; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class AdultFilterMenu { + + public static final String MENU_TITLE = + ChatColor.BLUE + "Adult Filters"; + + private static final int ITEMS_PER_PAGE = 45; + + public static void open( + RSMobStandPlugin plugin, + Player player, + ArmorStand armorStand, + int page + ) { + + Map mobData = + plugin.getConfigManager() + .getAdultMobData(); + + List mobs = + new ArrayList<>(mobData.keySet()); + + Collections.sort(mobs); + + List disabledMobs = + plugin.getStandManager() + .getDisabledAdultMobs( + armorStand + ); + + int startIndex = + page * ITEMS_PER_PAGE; + + int endIndex = + Math.min( + startIndex + ITEMS_PER_PAGE, + mobs.size() + ); + + int visibleItemCount = + endIndex - startIndex; + + int contentRows = + (int) Math.ceil( + visibleItemCount / 9.0 + ); + + contentRows = + Math.max(contentRows, 1); + + int totalRows = + contentRows + 1; + + int inventorySize = + totalRows * 9; + + Inventory inventory = + Bukkit.createInventory( + new RSMenuHolder( + "ADULTFILTER" + ), + inventorySize, + MENU_TITLE + + " (Page " + + (page + 1) + + ")" + ); + + ItemStack filler = + new ItemStack(Material.WHITE_STAINED_GLASS_PANE); + + ItemMeta fillerMeta = + filler.getItemMeta(); + + if (fillerMeta != null) { + + fillerMeta.setDisplayName(" "); + + filler.setItemMeta(fillerMeta); + + } + + for (int i = 0; i < inventory.getSize(); i++) { + + inventory.setItem(i, filler); + + } + + List filterItems = + new ArrayList<>(); + + for (int i = startIndex; i < endIndex; i++) { + + String mobName = mobs.get(i); + + MobFilterData data = + mobData.get(mobName); + + boolean forcedEnabled = + data.isKillAll(); + + boolean enabled = + forcedEnabled + || !disabledMobs.contains( + mobName + ); + + ItemStack item = + new ItemStack( + enabled + ? data.getIcon() + : Material.RED_STAINED_GLASS_PANE + ); + + ItemMeta meta = + item.getItemMeta(); + + if (meta != null) { + + meta.setDisplayName( + enabled + ? ChatColor.GREEN + mobName + : ChatColor.YELLOW + + mobName + + " (Disabled)" + ); + + java.util.List lore = + new java.util.ArrayList<>(); + + if (forcedEnabled) { + + lore.add( + ChatColor.YELLOW + + "Overridden by Server Admin" + ); + + } + + meta.setLore(lore); + + item.setItemMeta(meta); + + } + + filterItems.add(item); + + } + + int currentRow = 0; + int rowStart = 0; + + while (rowStart < filterItems.size()) { + + int remainingItems = + filterItems.size() - rowStart; + + int itemsThisRow = + Math.min(9, remainingItems); + + boolean isLastPartialRow = + itemsThisRow < 9; + + int rowBaseSlot = + currentRow * 9; + + List rowSlots = + new ArrayList<>(); + + if (isLastPartialRow) { + + if (itemsThisRow % 2 == 0) { + + switch (itemsThisRow) { + + case 2 -> rowSlots = List.of(3, 5); + + case 4 -> rowSlots = List.of(2, 3, 5, 6); + + case 6 -> rowSlots = List.of(1, 2, 3, 5, 6, 7); + + case 8 -> rowSlots = List.of(0, 1, 2, 3, 5, 6, 7, 8); + + } + + } else { + + int startSlot = + (9 - itemsThisRow) / 2; + + for (int i = 0; i < itemsThisRow; i++) { + + rowSlots.add(startSlot + i); + + } + + } + + } else { + + for (int i = 0; i < 9; i++) { + + rowSlots.add(i); + + } + + } + + for (int i = 0; i < itemsThisRow; i++) { + + inventory.setItem( + rowBaseSlot + rowSlots.get(i), + filterItems.get(rowStart + i) + ); + + } + + rowStart += itemsThisRow; + currentRow++; + + } + + int navigationRow = + inventorySize - 9; + +// Previous page + if (page > 0) { + + ItemStack previous = + new ItemStack(Material.ARROW); + + ItemMeta previousMeta = + previous.getItemMeta(); + + if (previousMeta != null) { + + previousMeta.setDisplayName( + ChatColor.YELLOW + + "Previous Page" + ); + + previous.setItemMeta(previousMeta); + + } + + inventory.setItem( + navigationRow, + previous + ); + + } + + +// Back button + ItemStack back = + new ItemStack(Material.OAK_DOOR); + + ItemMeta backMeta = + back.getItemMeta(); + + if (backMeta != null) { + + backMeta.setDisplayName( + ChatColor.YELLOW + "Back" + ); + + back.setItemMeta(backMeta); + + } + + inventory.setItem( + navigationRow + 4, + back + ); + + + +// Next page + if (endIndex < mobs.size()) { + + ItemStack next = + new ItemStack(Material.ARROW); + + ItemMeta nextMeta = + next.getItemMeta(); + + if (nextMeta != null) { + + nextMeta.setDisplayName( + ChatColor.YELLOW + + "Next Page" + ); + + next.setItemMeta(nextMeta); + + } + + inventory.setItem( + navigationRow + 8, + next + ); + + } + player.openInventory(inventory); + + } + +} diff --git a/src/main/java/com/rsscripting/mobstand/gui/BabyFilterMenu.java b/src/main/java/com/rsscripting/mobstand/gui/BabyFilterMenu.java new file mode 100644 index 0000000..3e52fac --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/gui/BabyFilterMenu.java @@ -0,0 +1,326 @@ +package com.rsscripting.mobstand.gui; + +import com.rsscripting.mobstand.RSMobStandPlugin; +import com.rsscripting.mobstand.data.MobFilterData; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class BabyFilterMenu { + + public static final String MENU_TITLE = + ChatColor.BLUE + "Baby Filters"; + + private static final int ITEMS_PER_PAGE = 45; + + public static void open( + RSMobStandPlugin plugin, + Player player, + ArmorStand armorStand, + int page + ) { + + Map mobData = + plugin.getConfigManager() + .getBabyMobData(); + + List mobs = + new ArrayList<>(mobData.keySet()); + + Collections.sort(mobs); + + List disabledMobs = + plugin.getStandManager() + .getDisabledBabyMobs( + armorStand + ); + + int startIndex = + page * ITEMS_PER_PAGE; + + int endIndex = + Math.min( + startIndex + ITEMS_PER_PAGE, + mobs.size() + ); + + int visibleItemCount = + endIndex - startIndex; + + int contentRows = + (int) Math.ceil( + visibleItemCount / 9.0 + ); + + contentRows = + Math.max(contentRows, 1); + + int totalRows = + contentRows + 1; + + int inventorySize = + totalRows * 9; + + Inventory inventory = + Bukkit.createInventory( + new RSMenuHolder( + "BABYFILTER" + ), + inventorySize, + MENU_TITLE + + " (Page " + + (page + 1) + + ")" + ); + + ItemStack filler = + new ItemStack(Material.WHITE_STAINED_GLASS_PANE); + + ItemMeta fillerMeta = + filler.getItemMeta(); + + if (fillerMeta != null) { + + fillerMeta.setDisplayName(" "); + + filler.setItemMeta(fillerMeta); + + } + + for (int i = 0; i < inventory.getSize(); i++) { + + inventory.setItem(i, filler); + + } + + List filterItems = + new ArrayList<>(); + + for (int i = startIndex; i < endIndex; i++) { + + String mobName = mobs.get(i); + + MobFilterData data = + mobData.get(mobName); + + boolean forcedEnabled = + data.isKillAll(); + + boolean enabled = + forcedEnabled + || !disabledMobs.contains( + mobName + ); + + ItemStack item = + new ItemStack( + enabled + ? data.getIcon() + : Material.RED_STAINED_GLASS_PANE + ); + + ItemMeta meta = + item.getItemMeta(); + + if (meta != null) { + + meta.setDisplayName( + enabled + ? ChatColor.GREEN + mobName + : ChatColor.YELLOW + + mobName + + " (Disabled)" + ); + + java.util.List lore = + new java.util.ArrayList<>(); + + if (forcedEnabled) { + + lore.add( + ChatColor.YELLOW + + "Overridden by Server Admin" + ); + + } + + meta.setLore(lore); + + item.setItemMeta(meta); + + } + + filterItems.add(item); + + } + + int currentRow = 0; + int rowStart = 0; + + while (rowStart < filterItems.size()) { + + int remainingItems = + filterItems.size() - rowStart; + + int itemsThisRow = + Math.min(9, remainingItems); + + boolean isLastPartialRow = + itemsThisRow < 9; + + int rowBaseSlot = + currentRow * 9; + + List rowSlots = + new ArrayList<>(); + + if (isLastPartialRow) { + + if (itemsThisRow % 2 == 0) { + + switch (itemsThisRow) { + + case 2 -> rowSlots = List.of(3, 5); + + case 4 -> rowSlots = List.of(2, 3, 5, 6); + + case 6 -> rowSlots = List.of(1, 2, 3, 5, 6, 7); + + case 8 -> rowSlots = List.of(0, 1, 2, 3, 5, 6, 7, 8); + + } + + } else { + + int startSlot = + (9 - itemsThisRow) / 2; + + for (int i = 0; i < itemsThisRow; i++) { + + rowSlots.add(startSlot + i); + + } + + } + + } else { + + for (int i = 0; i < 9; i++) { + + rowSlots.add(i); + + } + + } + + for (int i = 0; i < itemsThisRow; i++) { + + inventory.setItem( + rowBaseSlot + rowSlots.get(i), + filterItems.get(rowStart + i) + ); + + } + + rowStart += itemsThisRow; + currentRow++; + + } + + int navigationRow = + inventorySize - 9; + +// Previous page + if (page > 0) { + + ItemStack previous = + new ItemStack(Material.ARROW); + + ItemMeta previousMeta = + previous.getItemMeta(); + + if (previousMeta != null) { + + previousMeta.setDisplayName( + ChatColor.YELLOW + + "Previous Page" + ); + + previous.setItemMeta(previousMeta); + + } + + inventory.setItem( + navigationRow, + previous + ); + + } + + +// Back button + ItemStack back = + new ItemStack(Material.OAK_DOOR); + + ItemMeta backMeta = + back.getItemMeta(); + + if (backMeta != null) { + + backMeta.setDisplayName( + ChatColor.YELLOW + "Back" + ); + + back.setItemMeta(backMeta); + + } + + inventory.setItem( + navigationRow + 4, + back + ); + + + +// Next page + if (endIndex < mobs.size()) { + + ItemStack next = + new ItemStack(Material.ARROW); + + ItemMeta nextMeta = + next.getItemMeta(); + + if (nextMeta != null) { + + nextMeta.setDisplayName( + ChatColor.YELLOW + + "Next Page" + ); + + next.setItemMeta(nextMeta); + + } + + inventory.setItem( + navigationRow + 8, + next + ); + + } + player.openInventory(inventory); + + } + +} diff --git a/src/main/java/com/rsscripting/mobstand/gui/ConversionMenu.java b/src/main/java/com/rsscripting/mobstand/gui/ConversionMenu.java new file mode 100644 index 0000000..652f803 --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/gui/ConversionMenu.java @@ -0,0 +1,77 @@ +package com.rsscripting.mobstand.gui; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.Collections; + +public class ConversionMenu { + + public static final String MENU_TITLE = + ChatColor.BLUE + + "Convert to RS-MobStand"; + + public static void open(Player player) { + + Inventory inventory = + Bukkit.createInventory( + new RSMenuHolder( + "CONVERT" + ), + 9, + MENU_TITLE + ); + + ItemStack filler = + new ItemStack(Material.WHITE_STAINED_GLASS_PANE); + + ItemMeta fillerMeta = + filler.getItemMeta(); + + if (fillerMeta != null) { + + fillerMeta.setDisplayName(" "); + + filler.setItemMeta(fillerMeta); + + } + + for (int i = 0; i < inventory.getSize(); i++) { + + inventory.setItem(i, filler); + + } + + ItemStack convertItem = new ItemStack(Material.CRAFTING_TABLE); + + ItemMeta meta = convertItem.getItemMeta(); + + if (meta != null) { + + meta.setDisplayName(ChatColor.GREEN + "Convert to RS MobStand"); + + meta.setLore(Collections.singletonList( + ChatColor.YELLOW + "Convert this armor stand into an RS MobStand." + )); + + meta.addItemFlags( + ItemFlag.HIDE_ATTRIBUTES + ); + + convertItem.setItemMeta(meta); + + } + + inventory.setItem(4, convertItem); + + player.openInventory(inventory); + + } + +} \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/gui/LeaveAliveMenu.java b/src/main/java/com/rsscripting/mobstand/gui/LeaveAliveMenu.java new file mode 100644 index 0000000..e18dfa7 --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/gui/LeaveAliveMenu.java @@ -0,0 +1,181 @@ +package com.rsscripting.mobstand.gui; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.List; + +public class LeaveAliveMenu { + + public static final String MENU_TITLE = + ChatColor.BLUE + + "Leave Alive: "; + + public void open( + Player player, + int leaveAlive + ) { + + Inventory inventory = + Bukkit.createInventory( + new RSMenuHolder( + "LEAVEALIVE" + ), + 18, + MENU_TITLE + + leaveAlive + ); + + ItemStack filler = + new ItemStack(Material.WHITE_STAINED_GLASS_PANE); + + ItemMeta fillerMeta = + filler.getItemMeta(); + + if (fillerMeta != null) { + + fillerMeta.setDisplayName(" "); + + filler.setItemMeta(fillerMeta); + + } + + for (int i = 0; i < inventory.getSize(); i++) { + + inventory.setItem(i, filler); + + } + + inventory.setItem( + 4, + createItem( + Material.OAK_DOOR, + "§eBack", + List.of( + "§7Return to previous menu." + ), + 1 + ) + ); + + inventory.setItem( + 10, + createItem( + Material.RED_WOOL, + "§cRemove 10", + List.of( + "§7Decrease by 10." + ), + 10 + ) + ); + + inventory.setItem( + 11, + createItem( + Material.RED_WOOL, + "§cRemove 5", + List.of( + "§7Decrease by 5." + ), + 5 + ) + ); + + inventory.setItem( + 12, + createItem( + Material.RED_WOOL, + "§cRemove 1", + List.of( + "§7Decrease by 1." + ), + 1 + ) + ); + + inventory.setItem( + 13, + createItem( + Material.GRAY_STAINED_GLASS_PANE, + " ", + List.of(), + 1 + ) + ); + + inventory.setItem( + 14, + createItem( + Material.GREEN_WOOL, + "§aAdd 1", + List.of( + "§7Increase by 1." + ), + 1 + ) + ); + + inventory.setItem( + 15, + createItem( + Material.GREEN_WOOL, + "§aAdd 5", + List.of( + "§7Increase by 5." + ), + 5 + ) + ); + + inventory.setItem( + 16, + createItem( + Material.GREEN_WOOL, + "§aAdd 10", + List.of( + "§7Increase by 10." + ), + 10 + ) + ); + + player.openInventory(inventory); + + } + + private ItemStack createItem( + Material material, + String name, + List lore, + int amount + ) { + + ItemStack item = + new ItemStack( + material, + amount + ); + + ItemMeta meta = + item.getItemMeta(); + + if (meta == null) { + return item; + } + + meta.setDisplayName(name); + + meta.setLore(lore); + + item.setItemMeta(meta); + + return item; + + } +} \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/gui/RSAdminMenu.java b/src/main/java/com/rsscripting/mobstand/gui/RSAdminMenu.java new file mode 100644 index 0000000..c2ad644 --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/gui/RSAdminMenu.java @@ -0,0 +1,225 @@ +package com.rsscripting.mobstand.gui; + +import com.rsscripting.mobstand.RSMobStandPlugin; +import com.rsscripting.mobstand.utils.VersionChecker; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.Collections; + +public class RSAdminMenu { + + public static final String MENU_TITLE = + ChatColor.GOLD + "Admin"; + + public static void open( + Player player + ) { + + Inventory inventory = + Bukkit.createInventory( + new RSMenuHolder( + "ADMIN" + ), + 18, + MENU_TITLE + ); + + /* + |-------------------------------------------------------------------------- + | FILLER + |-------------------------------------------------------------------------- + */ + + ItemStack filler = + new ItemStack( + Material.WHITE_STAINED_GLASS_PANE + ); + + ItemMeta fillerMeta = + filler.getItemMeta(); + + if (fillerMeta != null) { + + fillerMeta.setDisplayName(" "); + + filler.setItemMeta(fillerMeta); + + } + + for (int i = 0; i < inventory.getSize(); i++) { + + inventory.setItem(i, filler); + + } + + /* + |-------------------------------------------------------------------------- + | RELOAD CONFIG + |-------------------------------------------------------------------------- + */ + + ItemStack reloadItem = + new ItemStack( + Material.ENCHANTED_BOOK + ); + + ItemMeta reloadMeta = + reloadItem.getItemMeta(); + + if (reloadMeta != null) { + + reloadMeta.setDisplayName( + ChatColor.GREEN + + "Reload Config" + ); + + reloadMeta.setLore( + Collections.singletonList( + ChatColor.GRAY + + "Reload plugin configuration." + ) + ); + + reloadMeta.addItemFlags( + ItemFlag.HIDE_ENCHANTS + ); + + reloadItem.setItemMeta( + reloadMeta + ); + + } + + inventory.setItem( + 12, + reloadItem + ); + + /* + |-------------------------------------------------------------------------- + | Back Button + |-------------------------------------------------------------------------- + */ + + ItemStack backItem = + new ItemStack( + Material.OAK_DOOR + ); + + ItemMeta backMeta = + backItem.getItemMeta(); + + if (backMeta != null) { + + backMeta.setDisplayName( + ChatColor.YELLOW + + "Back" + ); + + backItem.setItemMeta( + backMeta + ); + + } + + inventory.setItem( + 4, + backItem + ); + + /* + |-------------------------------------------------------------------------- + | VERSION + |-------------------------------------------------------------------------- + */ + + ItemStack versionItem = + new ItemStack( + Material.BOOK + ); + + ItemMeta versionMeta = + versionItem.getItemMeta(); + + if (versionMeta != null) { + + versionMeta.setDisplayName( + ChatColor.AQUA + + "Plugin Version" + ); + + String currentVersion = + Bukkit.getPluginManager() + .getPlugin("RS-MobStand") + .getDescription() .getVersion(); + + String latestVersion = + VersionChecker.getLatestVersion(); + + java.util.List lore = + new java.util.ArrayList<>(); + + lore.add( + ChatColor.GRAY + + "Current Version: " + + ChatColor.WHITE + + currentVersion + ); + + if (!currentVersion.equalsIgnoreCase( + latestVersion + )) { + + lore.add( + ChatColor.GRAY + + "Latest Version: " + + ChatColor.WHITE + + latestVersion + ); + + lore.add(""); + + lore.add( + ChatColor.GREEN + + "Update Available!" + ); + + } + + else { + + lore.add( + ChatColor.YELLOW + + "Plugin Up To Date" + ); + + } + + versionMeta.setLore(lore); + + versionItem.setItemMeta( + versionMeta + ); + + } + + inventory.setItem( + 14, + versionItem + ); + + player.openInventory( + inventory + ); + + } + +} \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/gui/RSMenuHolder.java b/src/main/java/com/rsscripting/mobstand/gui/RSMenuHolder.java new file mode 100644 index 0000000..8cf111d --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/gui/RSMenuHolder.java @@ -0,0 +1,32 @@ +package com.rsscripting.mobstand.gui; + +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; + +public class RSMenuHolder + implements InventoryHolder { + + private final String menuId; + + public RSMenuHolder( + String menuId + ) { + + this.menuId = menuId; + + } + + public String getMenuId() { + + return menuId; + + } + + @Override + public Inventory getInventory() { + + return null; + + } + +} \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/gui/RadiusMenu.java b/src/main/java/com/rsscripting/mobstand/gui/RadiusMenu.java new file mode 100644 index 0000000..607919a --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/gui/RadiusMenu.java @@ -0,0 +1,179 @@ +package com.rsscripting.mobstand.gui; + +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.ChatColor; + +import java.util.List; + +public class RadiusMenu { + public static final String MENU_TITLE = + ChatColor.BLUE + + "Radius: "; + + public void open( + Player player, + int radius + ) { + + Inventory inventory = + Bukkit.createInventory( + new RSMenuHolder( + "RADIUS" + ), + 18, + MENU_TITLE + radius + ); + + ItemStack filler = + new ItemStack(Material.WHITE_STAINED_GLASS_PANE); + + ItemMeta fillerMeta = + filler.getItemMeta(); + + if (fillerMeta != null) { + + fillerMeta.setDisplayName(" "); + + filler.setItemMeta(fillerMeta); + + } + + for (int i = 0; i < inventory.getSize(); i++) { + + inventory.setItem(i, filler); + + } + + inventory.setItem( + 4, + createItem( + Material.OAK_DOOR, + "§eBack", + List.of( + "§7Return to previous menu." + ), + 1 + ) + ); + + inventory.setItem( + 10, + createItem( + Material.RED_WOOL, + "§cRemove 10", + List.of( + "§7Decrease radius by 10." + ), + 10 + ) + ); + + inventory.setItem( + 11, + createItem( + Material.RED_WOOL, + "§cRemove 5", + List.of( + "§7Decrease radius by 5." + ), + 5 + ) + ); + + inventory.setItem( + 12, + createItem( + Material.RED_WOOL, + "§cRemove 1", + List.of( + "§7Decrease radius by 1." + ), + 1 + ) + ); + + inventory.setItem( + 13, + createItem( + Material.GRAY_STAINED_GLASS_PANE, + " ", + List.of(), + 1 + ) + ); + + inventory.setItem( + 14, + createItem( + Material.GREEN_WOOL, + "§aAdd 1", + List.of( + "§7Increase radius by 1." + ), + 1 + ) + ); + + inventory.setItem( + 15, + createItem( + Material.GREEN_WOOL, + "§aAdd 5", + List.of( + "§7Increase radius by 5." + ), + 5 + ) + ); + + inventory.setItem( + 16, + createItem( + Material.GREEN_WOOL, + "§aAdd 10", + List.of( + "§7Increase radius by 10." + ), + 10 + ) + ); + + player.openInventory(inventory); + + } + + private ItemStack createItem( + Material material, + String name, + List lore, + int amount + ) { + + ItemStack item = + new ItemStack( + material, + amount + ); + + ItemMeta meta = + item.getItemMeta(); + + if (meta == null) { + return item; + } + + meta.setDisplayName(name); + + meta.setLore(lore); + + item.setItemMeta(meta); + + return item; + + } +} \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/gui/StandMenu.java b/src/main/java/com/rsscripting/mobstand/gui/StandMenu.java new file mode 100644 index 0000000..a947628 --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/gui/StandMenu.java @@ -0,0 +1,369 @@ +package com.rsscripting.mobstand.gui; + +import com.rsscripting.mobstand.RSMobStandPlugin; +import com.rsscripting.mobstand.managers.StandManager; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemFlag; + +import java.util.Collections; +import java.util.List; + +public class StandMenu { + + public static final String MENU_TITLE = + ChatColor.BLUE + "RS MobStand"; + + public static void open( + RSMobStandPlugin plugin, + Player player, + ArmorStand armorStand + ) { + + Inventory inventory = + Bukkit.createInventory( + new RSMenuHolder( + "MAIN" + ), + 18, + MENU_TITLE + ); + + StandManager standManager = + plugin.getStandManager(); + + double radius = + standManager.getRadius(armorStand); + + int maxRadius = + plugin.getConfig() + .getInt( + "max-player-scan-radius" + ); + + radius = + Math.min( + radius, + maxRadius + ); + + standManager.setRadius( + armorStand, + radius + ); + + boolean gravity = + standManager.hasGravity(armorStand); + + boolean paused = + standManager.isPaused(armorStand); + + ItemStack filler = + new ItemStack(Material.WHITE_STAINED_GLASS_PANE); + + ItemMeta fillerMeta = + filler.getItemMeta(); + + if (fillerMeta != null) { + + fillerMeta.setDisplayName(" "); + + filler.setItemMeta(fillerMeta); + + } + + for (int i = 0; i < inventory.getSize(); i++) { + + inventory.setItem(i, filler); + + } + +// Convert back item + ItemStack revertItem = + new ItemStack(Material.COMPOSTER); + + ItemMeta revertMeta = + revertItem.getItemMeta(); + + if (revertMeta != null) { + + revertMeta.setDisplayName( + ChatColor.RED + + "Convert Back to Armor Stand" + ); + + revertMeta.setLore( + Collections.singletonList( + ChatColor.GRAY + + "Remove MobStand functionality." + ) + ); + + revertItem.setItemMeta(revertMeta); + + } + + inventory.setItem(2, revertItem); + + /* + |-------------------------------------------------------------------------- + | ADMIN MENU + |-------------------------------------------------------------------------- + */ + + if (player.isOp()) { + + ItemStack adminItem = + new ItemStack( + Material.COMMAND_BLOCK + ); + + ItemMeta adminMeta = + adminItem.getItemMeta(); + + if (adminMeta != null) { + + adminMeta.setDisplayName( + ChatColor.GOLD + + "Admin" + ); + + adminMeta.setLore( + java.util.Collections.singletonList( + "§7Administrative options." + ) + ); + + adminItem.setItemMeta( + adminMeta + ); + + } + + inventory.setItem( + 4, + adminItem + ); + + } + +// Pause item + ItemStack pauseItem = + new ItemStack( + paused + ? Material.RED_DYE + : Material.GREEN_DYE + ); + + ItemMeta pauseMeta = + pauseItem.getItemMeta(); + + if (pauseMeta != null) { + + pauseMeta.setDisplayName( + paused + ? ChatColor.GREEN + "Enable Processing" + : ChatColor.RED + "Disable Processing" + ); + + pauseMeta.setLore(List.of( + paused + ? ChatColor.GRAY + + "Click to resume processing." + : ChatColor.GRAY + + "Click to pause processing." + )); + + pauseMeta.addItemFlags( + ItemFlag.HIDE_ATTRIBUTES + ); + + pauseItem.setItemMeta(pauseMeta); + + } + + inventory.setItem(6, pauseItem); + + + + +// Adult filters item + ItemStack adultFilters = + new ItemStack(Material.BEEF); + + ItemMeta adultMeta = + adultFilters.getItemMeta(); + + if (adultMeta != null) { + + adultMeta.setDisplayName( + ChatColor.YELLOW + + "Adult Filters" + ); + + adultMeta.setLore(List.of( + ChatColor.YELLOW + + "Configure adult mob filters." + )); + + adultFilters.setItemMeta(adultMeta); + + } + + inventory.setItem(15, adultFilters); + +// Baby filters item + ItemStack babyFilters = + new ItemStack(Material.BEE_SPAWN_EGG); + + ItemMeta babyMeta = + babyFilters.getItemMeta(); + + if (babyMeta != null) { + + babyMeta.setDisplayName( + ChatColor.YELLOW + + "Baby Filters" + ); + + babyMeta.setLore(List.of( + ChatColor.YELLOW + + "Configure baby mob filters." + )); + + babyFilters.setItemMeta(babyMeta); + + } + + inventory.setItem(17, babyFilters); + + + // Leave Alive item + int leaveAlive = + standManager.getLeaveAlive( + armorStand + ); + + ItemStack leaveAliveItem = + new ItemStack( + Material.TOTEM_OF_UNDYING + ); + + ItemMeta leaveAliveMeta = + leaveAliveItem.getItemMeta(); + + if (leaveAliveMeta != null) { + + leaveAliveMeta.setDisplayName( + ChatColor.YELLOW + + "Leave Alive:" + ); + + leaveAliveMeta.setLore(List.of( + ChatColor.GRAY + + "Current: " + + ChatColor.WHITE + + leaveAlive, + "", + ChatColor.YELLOW + + "Click to adjust." + )); + + leaveAliveItem.setItemMeta(leaveAliveMeta); + + } + + inventory.setItem(13, leaveAliveItem); + + + +// Radius item + ItemStack radiusItem = + new ItemStack( + Material.COMPASS + ); + + ItemMeta radiusMeta = + radiusItem.getItemMeta(); + + if (radiusMeta != null) { + + radiusMeta.setDisplayName( + ChatColor.YELLOW + + "Scan Radius" + ); + + radiusMeta.setLore(List.of( + ChatColor.GRAY + + "Current: " + + ChatColor.WHITE + + (int) radius, + "", + ChatColor.YELLOW + + "Click to adjust radius." + )); + + radiusItem.setItemMeta(radiusMeta); + + } + + inventory.setItem(9, radiusItem); + + ItemStack gravityItem = + new ItemStack(Material.FEATHER); + + ItemMeta gravityMeta = + gravityItem.getItemMeta(); + + if (gravityMeta != null) { + + gravityMeta.setDisplayName( + (gravity + ? ChatColor.GREEN + : ChatColor.RED) + + "Gravity" + ); + + gravityMeta.setLore(List.of( + ChatColor.GRAY + "Current: " + + (gravity + ? ChatColor.GREEN + "Enabled" + : ChatColor.RED + "Disabled"), + "", + ChatColor.YELLOW + "Left Click: Toggle" + )); + +// Add enchant glow if gravity enabled + if (gravity) { + + gravityMeta.addEnchant( + Enchantment.UNBREAKING, + 1, + true + ); + + gravityMeta.addItemFlags( + ItemFlag.HIDE_ENCHANTS + ); + + } + + gravityItem.setItemMeta(gravityMeta); + + } + + inventory.setItem(11, gravityItem); + + player.openInventory(inventory); + + } + +} \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/listeners/ArmorStandBreakListener.java b/src/main/java/com/rsscripting/mobstand/listeners/ArmorStandBreakListener.java new file mode 100644 index 0000000..99b12f8 --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/listeners/ArmorStandBreakListener.java @@ -0,0 +1,39 @@ +package com.rsscripting.mobstand.listeners; + +import com.rsscripting.mobstand.RSMobStandPlugin; +import com.rsscripting.mobstand.managers.StandManager; + +import org.bukkit.entity.ArmorStand; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageEvent; + +public class ArmorStandBreakListener implements Listener { + + private final StandManager standManager; + + public ArmorStandBreakListener(RSMobStandPlugin plugin) { + + this.standManager = plugin.getStandManager(); + + } + + @EventHandler + public void onArmorStandDamage(EntityDamageEvent event) { + +// Must be armor stand + if (!(event.getEntity() instanceof ArmorStand armorStand)) { + return; + } + +// Only manage MobStands + if (!standManager.isMobStand(armorStand)) { + return; + } + +// Completely block ALL vanilla damage + event.setCancelled(true); + + } + +} \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/listeners/ArmorStandListener.java b/src/main/java/com/rsscripting/mobstand/listeners/ArmorStandListener.java new file mode 100644 index 0000000..05e0e8e --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/listeners/ArmorStandListener.java @@ -0,0 +1,113 @@ +package com.rsscripting.mobstand.listeners; + +import com.rsscripting.mobstand.RSMobStandPlugin; +import com.rsscripting.mobstand.gui.ConversionMenu; +import com.rsscripting.mobstand.gui.StandMenu; +import com.rsscripting.mobstand.managers.StandManager; + +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import org.bukkit.inventory.ItemStack; + +public class ArmorStandListener implements Listener { + + private final StandManager standManager; + + private final RSMobStandPlugin plugin; + + public ArmorStandListener( + RSMobStandPlugin plugin, + StandManager standManager + ) { + + this.plugin = plugin; + + this.standManager = standManager; + + } + + @EventHandler + public void onArmorStandInteract(PlayerInteractAtEntityEvent event) { + +// Only armor stands + if (!(event.getRightClicked() instanceof ArmorStand armorStand)) { + return; + } + + Player player = event.getPlayer(); + +// Must be sneaking + if (!player.isSneaking()) { + return; + } + + ItemStack item = + player.getInventory() + .getItemInMainHand(); + + if (item == null || + item.getType() != Material.STICK) { + + return; + } + +// Existing MobStand + if (standManager.isMobStand(armorStand)) { + +// Track selected stand + standManager.setSelectedArmorStand( + player.getUniqueId(), + armorStand.getUniqueId() + ); + +// Owner check + if (!standManager.isOwner( + armorStand, + player + ) + && !player.hasPermission( + "rsmobstand.admin" + )) { + + player.sendMessage( + ChatColor.RED + + "You do not own this MobStand." + ); + + return; + + } + +// Cancel normal interaction + event.setCancelled(true); + + StandMenu.open( + plugin, + player, + armorStand + ); + + return; + + } + +// Track selected stand + standManager.setSelectedArmorStand( + player.getUniqueId(), + armorStand.getUniqueId() + ); + + // Cancel normal interaction + event.setCancelled(true); + +// Open conversion menu + ConversionMenu.open(player); + + } + +} \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/listeners/ChunkLoadListener.java b/src/main/java/com/rsscripting/mobstand/listeners/ChunkLoadListener.java new file mode 100644 index 0000000..2df1aa3 --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/listeners/ChunkLoadListener.java @@ -0,0 +1,47 @@ +package com.rsscripting.mobstand.listeners; + +import com.rsscripting.mobstand.managers.StandManager; + +import org.bukkit.Chunk; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.world.ChunkLoadEvent; + +public class ChunkLoadListener implements Listener { + + private final StandManager standManager; + + public ChunkLoadListener(StandManager standManager) { + + this.standManager = standManager; + + } + + @EventHandler + public void onChunkLoad(ChunkLoadEvent event) { + + Chunk chunk = event.getChunk(); + + for (Entity entity : chunk.getEntities()) { + + if (!(entity instanceof ArmorStand armorStand)) { + continue; + } + + if (!standManager.isMobStand(armorStand)) { + continue; + } + + armorStand.setInvulnerable(true); + + standManager.getActiveStands().add( + armorStand.getUniqueId() + ); + + } + + } + +} \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/listeners/MenuListener.java b/src/main/java/com/rsscripting/mobstand/listeners/MenuListener.java new file mode 100644 index 0000000..62d802d --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/listeners/MenuListener.java @@ -0,0 +1,1003 @@ +package com.rsscripting.mobstand.listeners; + +import com.rsscripting.mobstand.RSMobStandPlugin; +import com.rsscripting.mobstand.data.MobFilterData; +import com.rsscripting.mobstand.gui.*; +import com.rsscripting.mobstand.managers.StandManager; +import com.rsscripting.mobstand.gui.RSAdminMenu; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; + +import java.util.Map; +import java.util.UUID; + +public class MenuListener implements Listener { + + private final StandManager standManager; + + private final RSMobStandPlugin plugin; + + public MenuListener(RSMobStandPlugin plugin) { + + this.plugin = plugin; + + this.standManager = plugin.getStandManager(); + + } + + @EventHandler + public void onInventoryClick(InventoryClickEvent event) { + + if (!(event.getWhoClicked() instanceof Player player)) { + return; + } + + String title = event.getView().getTitle(); + +// Only listen to inventories +// using RSMenuHolder. + if (!(event.getInventory() + .getHolder() + instanceof RSMenuHolder)) { + + return; + + } + + if (event.getInventory() + .getHolder() + instanceof RSMenuHolder holder + && holder.getMenuId() + .equals( + "LEAVEALIVE" + )) { + + event.setCancelled(true); + + UUID standUUID = + standManager.getSelectedArmorStand( + player.getUniqueId() + ); + + if (standUUID == null) { + + player.closeInventory(); + + return; + } + + ArmorStand armorStand = + (ArmorStand) Bukkit.getEntity( + standUUID + ); + + if (armorStand == null) { + + player.closeInventory(); + + return; + } + + int leaveAlive = + standManager.getLeaveAlive( + armorStand + ); + + int slot = + event.getRawSlot(); + + switch (slot) { + + case 10 -> leaveAlive -= 10; + + case 11 -> leaveAlive -= 5; + + case 12 -> leaveAlive -= 1; + + case 14 -> leaveAlive += 1; + + case 15 -> leaveAlive += 5; + + case 16 -> leaveAlive += 10; + + case 4 -> { + + StandMenu.open( + plugin, + player, + armorStand + ); + + return; + } + + default -> { + return; + } + } + + int minLeaveAlive = + plugin.getConfig() + .getInt( + "min-leave-alive" + ); + + int maxleaveAlive = + plugin.getConfig() + .getInt( + "max-leave-alive" + ); + + leaveAlive = + Math.max( + minLeaveAlive, + Math.min( + maxleaveAlive, + leaveAlive + ) + ); + + standManager.setLeaveAlive( + armorStand, + (int) leaveAlive + ); + + LeaveAliveMenu leaveAliveMenu = + new LeaveAliveMenu(); + + leaveAliveMenu.open( + player, + (int) leaveAlive + ); + + return; + } + + if (event.getInventory() + .getHolder() + instanceof RSMenuHolder holder + && holder.getMenuId() + .equals( + "RADIUS" + )) { + + event.setCancelled(true); + + + UUID standUUID = + standManager.getSelectedArmorStand( + player.getUniqueId() + ); + + if (standUUID == null) { + + player.closeInventory(); + + return; + } + + ArmorStand armorStand = + (ArmorStand) Bukkit.getEntity( + standUUID + ); + + if (armorStand == null) { + + player.closeInventory(); + + return; + } + + double radius = + standManager.getRadius( + armorStand + ); + + int slot = + event.getRawSlot(); + + switch (slot) { + + case 10 -> radius -= 10; + + case 11 -> radius -= 5; + + case 12 -> radius -= 1; + + case 14 -> radius += 1; + + case 15 -> radius += 5; + + case 16 -> radius += 10; + + case 4 -> { + + StandMenu.open( + plugin, + player, + armorStand + ); + + return; + } + + default -> { + return; + } + } + + int maxRadius = + plugin.getConfig() + .getInt( + "max-player-scan-radius" + ); + + radius = + Math.max( + 1.0, + Math.min( + maxRadius, + radius + ) + ); + + standManager.setRadius( + armorStand, + (int) radius + ); + + RadiusMenu radiusMenu = + new RadiusMenu(); + + radiusMenu.open( + player, + (int) radius + ); + + return; + } + +// Adult Filter Menu + if (event.getInventory() + .getHolder() + instanceof RSMenuHolder holder + && holder.getMenuId() + .equals( + "ADULTFILTER" + )) { + + event.setCancelled(true); + + String[] split = + title.split("Page "); + + int currentPage = 0; + + if (split.length > 1) { + + try { + + currentPage = + Integer.parseInt( + split[1] + ) - 1; + + } catch (NumberFormatException ignored) { + } + + } + + UUID standUUID = + standManager.getSelectedArmorStand( + player.getUniqueId() + ); + + if (standUUID == null) { + + player.closeInventory(); + + return; + + } + + ArmorStand armorStand = + (ArmorStand) Bukkit.getEntity( + standUUID + ); + + if (armorStand == null) { + + player.closeInventory(); + + return; + + } + + int navigationRow = + event.getInventory().getSize() - 9; + + int previousSlot = + navigationRow; + + int backSlot = + navigationRow + 4; + + int nextSlot = + navigationRow + 8; + +// Previous page + if (event.getSlot() == previousSlot) { + + if (currentPage > 0) { + + AdultFilterMenu.open( + plugin, + player, + armorStand, + currentPage - 1 + ); + + } + + return; + + } + +// Next page + if (event.getSlot() == nextSlot) { + + Map mobData = + plugin.getConfigManager() + .getAdultMobData(); + + int maxPage = + (int) Math.ceil( + mobData.size() / 45.0 + ) - 1; + + if (currentPage < maxPage) { + + AdultFilterMenu.open( + plugin, + player, + armorStand, + currentPage + 1 + ); + + } + + return; + + } + +// Back button + if (event.getSlot() == backSlot) { + + StandMenu.open( + plugin, + player, + armorStand + ); + + return; + + } + +// Ignore navigation row + if (event.getSlot() >= navigationRow) { + return; + } + + if (event.getCurrentItem() == null || + !event.getCurrentItem().hasItemMeta() || + event.getCurrentItem().getItemMeta() == null || + !event.getCurrentItem().getItemMeta().hasDisplayName()) { + + return; + } + + String mobName = + ChatColor.stripColor( + event.getCurrentItem() + .getItemMeta() + .getDisplayName() + ); + + mobName = + mobName.replace(" (Disabled)", ""); + + MobFilterData data = + plugin.getConfigManager() + .getAdultMobData() + .get(mobName); + + if (data != null && data.isKillAll()) { + + return; + + } + + standManager.toggleAdultMobFilter( + armorStand, + mobName + ); + + AdultFilterMenu.open( + plugin, + player, + armorStand, + currentPage + ); + + return; + + } + +// Baby Filter Menu + if (event.getInventory() + .getHolder() + instanceof RSMenuHolder holder + && holder.getMenuId() + .equals( + "BABYFILTER" + )) { + + event.setCancelled(true); + + String[] split = + title.split("Page "); + + int currentPage = 0; + + if (split.length > 1) { + + try { + + currentPage = + Integer.parseInt( + split[1] + ) - 1; + + } catch (NumberFormatException ignored) { + } + + } + + UUID standUUID = + standManager.getSelectedArmorStand( + player.getUniqueId() + ); + + if (standUUID == null) { + + player.closeInventory(); + + return; + + } + + ArmorStand armorStand = + (ArmorStand) Bukkit.getEntity( + standUUID + ); + + if (armorStand == null) { + + player.closeInventory(); + + return; + + } + + int navigationRow = + event.getInventory().getSize() - 9; + + int previousSlot = + navigationRow; + + int backSlot = + navigationRow + 4; + + int nextSlot = + navigationRow + 8; + +// Previous page + if (event.getSlot() == previousSlot) { + + if (currentPage > 0) { + + BabyFilterMenu.open( + plugin, + player, + armorStand, + currentPage - 1 + ); + + } + + return; + + } + +// Next page + if (event.getSlot() == nextSlot) { + + Map mobData = + plugin.getConfigManager() + .getBabyMobData(); + + int maxPage = + (int) Math.ceil( + mobData.size() / 45.0 + ) - 1; + + if (currentPage < maxPage) { + + BabyFilterMenu.open( + plugin, + player, + armorStand, + currentPage + 1 + ); + + } + + return; + + } + +// Back button + if (event.getSlot() == backSlot) { + + StandMenu.open( + plugin, + player, + armorStand + ); + + return; + + } + +// Ignore navigation row + if (event.getSlot() >= navigationRow) { + return; + } + + if (event.getCurrentItem() == null || + !event.getCurrentItem().hasItemMeta() || + event.getCurrentItem().getItemMeta() == null || + !event.getCurrentItem().getItemMeta().hasDisplayName()) { + + return; + } + + String mobName = + ChatColor.stripColor( + event.getCurrentItem() + .getItemMeta() + .getDisplayName() + ); + + mobName = + mobName.replace(" (Disabled)", ""); + + MobFilterData data = + plugin.getConfigManager() + .getBabyMobData() + .get(mobName); + + if (data != null && + data.isKillAll()) { + + return; + + } + + standManager.toggleBabyMobFilter( + armorStand, + mobName + ); + + BabyFilterMenu.open( + plugin, + player, + armorStand, + currentPage + ); + + return; + + } + +// Conversion Menu + if (event.getInventory() + .getHolder() + instanceof RSMenuHolder holder + && holder.getMenuId() + .equals( + "CONVERT" + )) { + + event.setCancelled(true); + + if (event.getCurrentItem() == null) { + return; + } + + UUID standUUID = standManager.getSelectedArmorStand( + player.getUniqueId() + ); + + if (standUUID == null) { + + player.closeInventory(); + + return; + } + + ArmorStand armorStand = (ArmorStand) Bukkit.getEntity(standUUID); + + if (armorStand == null) { + + player.closeInventory(); + + return; + } + + boolean converted = + standManager.convertToMobStand( + armorStand, + player + ); + + standManager.setSelectedArmorStand( + player.getUniqueId(), + armorStand.getUniqueId() + ); + + UUID selectedUUID = + standManager.getSelectedArmorStand( + player.getUniqueId() + ); + + standManager.setSelectedArmorStand( + player.getUniqueId(), + armorStand.getUniqueId() + ); + + if (converted) { + + player.sendMessage( + ChatColor.GREEN + + "Converted to RS MobStand. Reopen the stand to adjust settings." + ); + + } + + player.closeInventory(); + + standManager.clearSelectedArmorStand( + player.getUniqueId() + ); + + return; + + } + +// Stand Menu + if (event.getInventory() + .getHolder() + instanceof RSMenuHolder holder + && holder.getMenuId() + .equals( + "MAIN" + )) { + + event.setCancelled(true); + + UUID standUUID = + standManager.getSelectedArmorStand( + player.getUniqueId() + ); + + if (standUUID == null) { + + player.closeInventory(); + + return; + + } + + ArmorStand armorStand = + (ArmorStand) Bukkit.getEntity( + standUUID + ); + + if (armorStand == null) { + + player.closeInventory(); + + return; + + } + +// Adult Filters + if (event.getSlot() == 15) { + + AdultFilterMenu.open( + plugin, + player, + armorStand, + 0 + ); + + return; + + } + +// Baby Filters + if (event.getSlot() == 17) { + + BabyFilterMenu.open( + plugin, + player, + armorStand, + 0 + ); + + return; + + } + + if (event.getCurrentItem() == null) { + return; + } + +// Convert back button + if (event.getSlot() == 2) { + + standManager.revertToNormalStand(armorStand); + + standManager.clearSelectedArmorStand( + player.getUniqueId() + ); + + player.sendMessage( + ChatColor.GREEN + + "Converted back to normal Armor Stand." + ); + + player.closeInventory(); + + return; + + } + + /* + |-------------------------------------------------------------------------- + | ADMIN MENU + |-------------------------------------------------------------------------- + */ + + if (event.getRawSlot() == 4) { + + if (!player.isOp()) { + return; + } + + RSAdminMenu.open(player); + + return; + + } + +// Pause toggle + if (event.getSlot() == 6) { + + boolean paused = + standManager.isPaused(armorStand); + + paused = !paused; + + standManager.setPaused( + armorStand, + paused + ); + + player.sendMessage( + paused + ? ChatColor.GREEN + + "MobStand paused." + : ChatColor.GREEN + + "MobStand resumed." + ); + + StandMenu.open( + plugin, + player, + armorStand + ); + + return; + + } +// Open leave Alive Menu + if (event.getSlot() == 13) { + + LeaveAliveMenu leaveAliveMenu = + new LeaveAliveMenu(); + + leaveAliveMenu.open( + player, + standManager.getLeaveAlive(armorStand) + ); + + return; + } + +// Open Radius Menu + if (event.getSlot() == 9) { + + RadiusMenu radiusMenu = + new RadiusMenu(); + + radiusMenu.open( + player, + (int) standManager.getRadius(armorStand) + ); + + return; + } + +// Gravity toggle + if (event.getSlot() == 11) { + + boolean gravity = + standManager.hasGravity(armorStand); + + gravity = !gravity; + + standManager.setGravity( + armorStand, + gravity + ); + + player.sendMessage( + ChatColor.GREEN + + "Gravity " + + (gravity + ? ChatColor.GREEN + "Enabled" + : ChatColor.GREEN + "Disabled") + ); + + StandMenu.open( + plugin, + player, + armorStand + ); + + return; + + } + } + + /* + |-------------------------------------------------------------------------- + | ADMIN MENU + |-------------------------------------------------------------------------- + */ + + if (event.getInventory() + .getHolder() + instanceof RSMenuHolder holder + && holder.getMenuId() + .equals( + "ADMIN" + )) { + + event.setCancelled(true); + + if (event.getCurrentItem() == null) { + return; + } + + /* + |-------------------------------------------------------------------------- + | BACK BUTTON + |-------------------------------------------------------------------------- + */ + + if (event.getRawSlot() == 4) { + + UUID standUUID = + standManager.getSelectedArmorStand( + player.getUniqueId() + ); + + if (standUUID == null) { + + player.closeInventory(); + + return; + + } + + ArmorStand armorStand = + (ArmorStand) Bukkit.getEntity( + standUUID + ); + + if (armorStand == null) { + + player.closeInventory(); + + return; + + } + + StandMenu.open( + plugin, + player, + armorStand + ); + + return; + + } + + + /* + |-------------------------------------------------------------------------- + | RELOAD CONFIG + |-------------------------------------------------------------------------- + */ + + if (event.getRawSlot() == 12) { + + plugin.reloadConfig(); + + plugin.getConfigManager() + .loadConfigs(); + + player.sendMessage( + ChatColor.GREEN + + "RS MobStand Configuration Reloaded." + ); + + RSAdminMenu.open(player); + + return; + + } + + /* + |-------------------------------------------------------------------------- + | VERSION DISPLAY + |-------------------------------------------------------------------------- + */ + + if (event.getRawSlot() == 14) { + + player.sendMessage( + ChatColor.GREEN + + "§bRS MobStand Version: §f" + + Bukkit.getPluginManager() + .getPlugin("RS-MobStand") + .getDescription() + .getVersion() + + ); + + } + + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/managers/StandManager.java b/src/main/java/com/rsscripting/mobstand/managers/StandManager.java new file mode 100644 index 0000000..7e55801 --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/managers/StandManager.java @@ -0,0 +1,794 @@ +package com.rsscripting.mobstand.managers; + +import com.rsscripting.mobstand.RSMobStandPlugin; + +import org.bukkit.NamespacedKey; +import org.bukkit.entity.ArmorStand; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.Set; +import java.util.HashSet; + +public class StandManager { + + private final RSMobStandPlugin plugin; + + private final NamespacedKey mobStandKey; + + private final NamespacedKey ownerKey; + + private final NamespacedKey radiusKey; + + private final NamespacedKey gravityKey; + + private final NamespacedKey pausedKey; + + private final NamespacedKey disabledAdultMobsKey; + + private final NamespacedKey disabledBabyMobsKey; + + private final Map selectedArmorStands = new HashMap<>(); + + private final NamespacedKey leaveAliveKey; + + private final Set activeStands = new HashSet<>(); + + public StandManager(RSMobStandPlugin plugin) { + + this.plugin = plugin; + + this.mobStandKey = new NamespacedKey(plugin, "mobstand"); + + this.ownerKey = new NamespacedKey(plugin, "owner"); + + this.radiusKey = new NamespacedKey(plugin, "radius"); + + this.leaveAliveKey = new NamespacedKey(plugin, "leaveAlive"); + + this.gravityKey = new NamespacedKey(plugin, "gravity"); + + this.pausedKey = new NamespacedKey(plugin, "paused"); + + this.disabledAdultMobsKey = + new NamespacedKey( + plugin, + "disabled_adult_mobs" + ); + + this.disabledBabyMobsKey = + new NamespacedKey( + plugin, + "disabled_baby_mobs" + ); + + } + +// counts stands on server. + public int getPlayerStandCount(UUID ownerUUID) { + + int count = 0; + + for (UUID standUUID : activeStands) { + + Entity entity = + Bukkit.getEntity(standUUID); + + if (!(entity instanceof ArmorStand armorStand)) { + continue; + } + + UUID standOwner = + getOwnerUUID(armorStand); + + if (ownerUUID.equals(standOwner)) { + count++; + } + + } + + return count; + + } + +// Converts an armor stand into a MobStand. + + public boolean convertToMobStand(ArmorStand armorStand, Player owner) { + + if (!isArmorStandEmpty(armorStand)) { + + owner.sendMessage( + ChatColor.RED + + "Remove all equipment first." + ); + + return false; + + } + + if (!owner.hasPermission( + "rsmobstand.bypasslimits" + )) { + +// Server limit + int maxTotalStands = + plugin.getConfig() + .getInt( + "max-total-stands" + ); + + if (maxTotalStands > 0 && + activeStands.size() + >= maxTotalStands) { + + owner.sendMessage( + ChatColor.RED + + "Server mob stand limit reached." + ); + + return false; + + } + +// Player limit + int maxPlayerStands = + plugin.getConfig() + .getInt( + "max-stands-per-player" + ); + + int playerStandCount = + getPlayerStandCount( + owner.getUniqueId() + ); + + if (maxPlayerStands > 0 && + playerStandCount + >= maxPlayerStands) { + + owner.sendMessage( + ChatColor.RED + + "You have reached your mob stand limit." + ); + + return false; + + } + + } + + armorStand.getPersistentDataContainer().set( + pausedKey, + PersistentDataType.BYTE, + (byte) 0 + ); + + armorStand.getPersistentDataContainer().set( + mobStandKey, + PersistentDataType.BYTE, + (byte) 1 + ); + + armorStand.getPersistentDataContainer().set( + ownerKey, + PersistentDataType.STRING, + owner.getUniqueId().toString() + ); + + double defaultRadius = plugin.getConfig().getDouble( + "default-scan-radius" + ); + + armorStand.getPersistentDataContainer().set( + radiusKey, + PersistentDataType.DOUBLE, + defaultRadius + ); + + boolean defaultGravity = plugin.getConfig().getBoolean( + "default-gravity" + ); + + int defaultLeaveAlive = + plugin.getConfig().getInt( + "default-leave-alive" + ); + + armorStand.getPersistentDataContainer().set( + leaveAliveKey, + PersistentDataType.INTEGER, + defaultLeaveAlive + ); + + armorStand.getPersistentDataContainer().set( + gravityKey, + PersistentDataType.BYTE, + (byte) (defaultGravity ? 1 : 0) + ); + + armorStand.setGravity(defaultGravity); + + armorStand.setCustomName("§cRS MobStand"); + armorStand.setCustomNameVisible(true); + armorStand.setInvulnerable(true); + activeStands.add(armorStand.getUniqueId()); + + // Initialize adult disabled filters + List disabledAdultMobs = + new ArrayList<>(); + + plugin.getConfigManager() + .getAdultMobData() + .forEach((mobName, data) -> { + + if (!data.isEnabledByDefault()) { + + disabledAdultMobs.add( + mobName + ); + + } + + }); + + setDisabledAdultMobs( + armorStand, + disabledAdultMobs + ); + +// Initialize baby disabled filters + List disabledBabyMobs = + new ArrayList<>(); + + plugin.getConfigManager() + .getBabyMobData() + .forEach((mobName, data) -> { + + if (!data.isEnabledByDefault()) { + + disabledBabyMobs.add( + mobName + ); + + } + + }); + + setDisabledBabyMobs( + armorStand, + disabledBabyMobs + ); + + return true; + + } + + +// Removes MobStand data. + + public void revertToNormalStand(ArmorStand armorStand) { + + armorStand.getPersistentDataContainer().remove(mobStandKey); + + armorStand.getPersistentDataContainer().remove(radiusKey); + + armorStand.getPersistentDataContainer().remove(gravityKey); + + armorStand.getPersistentDataContainer().remove(pausedKey); + + armorStand.getPersistentDataContainer().remove(leaveAliveKey); + + armorStand.getPersistentDataContainer().remove(disabledAdultMobsKey); + + armorStand.getPersistentDataContainer().remove(disabledBabyMobsKey); + + clearOwnership(armorStand); + + activeStands.remove(armorStand.getUniqueId()); + + armorStand.setInvulnerable(false); + + armorStand.setCustomName(null); + + armorStand.setCustomNameVisible(false); + + armorStand.setGravity(true); + + } + + +// Checks if armor stand is a MobStand. + + public boolean isMobStand(ArmorStand armorStand) { + + Byte value = armorStand.getPersistentDataContainer().get( + mobStandKey, + PersistentDataType.BYTE + ); + + return value != null && value == (byte) 1; + + } + + +// Stores selected armor stand for player. + + public void setSelectedArmorStand(UUID playerUUID, UUID armorStandUUID) { + + selectedArmorStands.put(playerUUID, armorStandUUID); + + } + + +// Gets selected armor stand UUID. + + public UUID getSelectedArmorStand(UUID playerUUID) { + + return selectedArmorStands.get(playerUUID); + + } + + +// Removes selected armor stand tracking. + + public void clearSelectedArmorStand(UUID playerUUID) { + + selectedArmorStands.remove(playerUUID); + + } + + +// Checks if player owns this stand. + + public boolean isOwner(ArmorStand armorStand, Player player) { + + String ownerUUID = armorStand.getPersistentDataContainer().get( + ownerKey, + PersistentDataType.STRING + ); + + if (ownerUUID == null) { + return false; + } + + return ownerUUID.equals(player.getUniqueId().toString()); + + } + + public UUID getOwnerUUID( + ArmorStand armorStand + ) { + + String ownerUUID = + armorStand + .getPersistentDataContainer() + .get( + ownerKey, + PersistentDataType.STRING + ); + + if (ownerUUID == null) { + return null; + } + + return UUID.fromString(ownerUUID); + + } + + +// Removes ownership data. + + public void clearOwnership(ArmorStand armorStand) { + + armorStand.getPersistentDataContainer().remove(ownerKey); + + } + + +// Gets all active Mob stands. + + public Set getActiveStands() { + + return activeStands; + + } + + +// Reloads all MobStands from loaded worlds. + + public void loadExistingStands() { + + activeStands.clear(); + + for (World world : Bukkit.getWorlds()) { + + for (Entity entity : world.getEntities()) { + +// Must be armor stand + if (!(entity instanceof ArmorStand armorStand)) { + continue; + } + + Byte storedValue = armorStand.getPersistentDataContainer().get( + mobStandKey, + PersistentDataType.BYTE + ); + +// Must be MobStand + if (!isMobStand(armorStand)) { + continue; + } + +// Restore invulnerability + armorStand.setInvulnerable(true); + +// Re-register stand + activeStands.add(armorStand.getUniqueId()); + + } + + } + + plugin.getLogger().info( + "Recovered " + + activeStands.size() + + " MobStands." + ); + + } + + public int getLeaveAlive( + ArmorStand armorStand + ) { + + Integer leaveAlive = + armorStand + .getPersistentDataContainer() + .get( + leaveAliveKey, + PersistentDataType.INTEGER + ); + + if (leaveAlive == null) { + + return plugin.getConfig().getInt( + "default-leave-alive" + ); + + } + + return leaveAlive; + + } + + public double getRadius(ArmorStand armorStand) { + + Double radius = armorStand.getPersistentDataContainer().get( + radiusKey, + PersistentDataType.DOUBLE + ); + + if (radius == null) { + + return plugin.getConfig().getDouble( + "default-scan-radius" + ); + + } + + return radius; + + } + + public void setRadius( + ArmorStand armorStand, + double radius + ) { + + double maxRadius = plugin.getConfig().getDouble( + "max-player-scan-radius" + ); + +// Clamp radius + if (radius < 0) { + radius = 0; + } + + if (radius > maxRadius) { + radius = maxRadius; + } + + armorStand.getPersistentDataContainer().set( + radiusKey, + PersistentDataType.DOUBLE, + radius + ); + + } + + public void setLeaveAlive( + ArmorStand armorStand, + int leaveAlive + ) { + + int minLeaveAlive = + plugin.getConfig() + .getInt( + "min-leave-alive" + ); + + int maxLeaveAlive = + plugin.getConfig() + .getInt( + "max-leave-alive" + ); + +// Clamp leaveAlive + if (leaveAlive < minLeaveAlive) { + leaveAlive = minLeaveAlive; + } + + if (leaveAlive > maxLeaveAlive) { + leaveAlive = maxLeaveAlive; + } + + armorStand.getPersistentDataContainer().set( + leaveAliveKey, + PersistentDataType.INTEGER, + leaveAlive + ); + + } + + public boolean hasGravity(ArmorStand armorStand) { + + Byte value = armorStand.getPersistentDataContainer().get( + gravityKey, + PersistentDataType.BYTE + ); + + if (value == null) { + + return plugin.getConfig().getBoolean( + "default-gravity" + ); + + } + + return value == (byte) 1; + + } + + public void setGravity( + ArmorStand armorStand, + boolean gravity + ) { + + armorStand.getPersistentDataContainer().set( + gravityKey, + PersistentDataType.BYTE, + (byte) (gravity ? 1 : 0) + ); + + armorStand.setGravity(gravity); + + } + + public boolean isPaused(ArmorStand armorStand) { + + Byte value = armorStand.getPersistentDataContainer().get( + pausedKey, + PersistentDataType.BYTE + ); + + if (value == null) { + return false; + } + + return value == (byte) 1; + + } + + public void setPaused( + ArmorStand armorStand, + boolean paused + ) { + + armorStand.getPersistentDataContainer().set( + pausedKey, + PersistentDataType.BYTE, + (byte) (paused ? 1 : 0) + ); + + } + +// Get disabled Adult Mobs + public List getDisabledAdultMobs( + ArmorStand armorStand + ) { + + String stored = + armorStand + .getPersistentDataContainer() + .get( + disabledAdultMobsKey, + PersistentDataType.STRING + ); + + if (stored == null || stored.isEmpty()) { + + return new ArrayList<>(); + + } + + return new ArrayList<>( + Arrays.asList( + stored.split(",") + ) + ); + + } + + public List getDisabledBabyMobs( + ArmorStand armorStand + ) { + + String stored = + armorStand + .getPersistentDataContainer() + .get( + disabledBabyMobsKey, + PersistentDataType.STRING + ); + + if (stored == null || stored.isEmpty()) { + + return new ArrayList<>(); + + } + + return new ArrayList<>( + Arrays.asList( + stored.split(",") + ) + ); + + } + + public void setDisabledAdultMobs( + ArmorStand armorStand, + List mobs + ) { + + String stored = + String.join(",", mobs); + + armorStand + .getPersistentDataContainer() + .set( + disabledAdultMobsKey, + PersistentDataType.STRING, + stored + ); + + } + + public void setDisabledBabyMobs( + ArmorStand armorStand, + List mobs + ) { + + String stored = + String.join(",", mobs); + + armorStand + .getPersistentDataContainer() + .set( + disabledBabyMobsKey, + PersistentDataType.STRING, + stored + ); + + } + + public void toggleAdultMobFilter( + ArmorStand armorStand, + String mobName + ) { + + List disabled = + getDisabledAdultMobs( + armorStand + ); + + if (disabled.contains(mobName)) { + + disabled.remove(mobName); + + } else { + + disabled.add(mobName); + + } + + setDisabledAdultMobs( + armorStand, + disabled + ); + + } + + private boolean isArmorStandEmpty( + ArmorStand armorStand + ) { + + return armorStand.getEquipment() + .getHelmet() + .getType() + .isAir() + + && armorStand.getEquipment() + .getChestplate() + .getType() + .isAir() + + && armorStand.getEquipment() + .getLeggings() + .getType() + .isAir() + + && armorStand.getEquipment() + .getBoots() + .getType() + .isAir() + + && armorStand.getEquipment() + .getItemInMainHand() + .getType() + .isAir() + + && armorStand.getEquipment() + .getItemInOffHand() + .getType() + .isAir(); + + } + + public void toggleBabyMobFilter( + ArmorStand armorStand, + String mobName + ) { + + List disabled = + getDisabledBabyMobs( + armorStand + ); + + if (disabled.contains(mobName)) { + + disabled.remove(mobName); + + } else { + + disabled.add(mobName); + + } + + setDisabledBabyMobs( + armorStand, + disabled + ); + + } + +} \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/tasks/SlaughterTask.java b/src/main/java/com/rsscripting/mobstand/tasks/SlaughterTask.java new file mode 100644 index 0000000..6a55842 --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/tasks/SlaughterTask.java @@ -0,0 +1,380 @@ +package com.rsscripting.mobstand.tasks; + +import com.rsscripting.mobstand.RSMobStandPlugin; +import com.rsscripting.mobstand.managers.StandManager; + +import org.bukkit.Bukkit; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.entity.Ageable; +import org.bukkit.entity.EntityType; +import org.bukkit.Location; + +import java.util.UUID; +import java.util.List; + +public class SlaughterTask extends BukkitRunnable { + + private final RSMobStandPlugin plugin; + + private final StandManager standManager; + + public SlaughterTask(RSMobStandPlugin plugin) { + + this.plugin = plugin; + + this.standManager = plugin.getStandManager(); + + } + + @Override + public void run() { + + long start = System.nanoTime(); + + boolean debugEnabled = + plugin.getConfig().getBoolean("debug.enabled"); + + boolean performanceLogging = + plugin.getConfig().getBoolean( + "debug.logging.performance" + ); + + boolean entityKillLogging = + plugin.getConfig().getBoolean( + "debug.logging.entity-kills" + ); + + Integer killedThisCycle = + entityKillLogging ? 0 : null; + + Location lastStandLocation = null; + + var configManager = plugin.getConfigManager(); + + var adultMobs = + configManager + .getAdultMobData() + .keySet(); + + var babyMobs = + configManager + .getBabyMobData() + .keySet(); + + for (UUID uuid : standManager.getActiveStands()) { + + Entity entity = Bukkit.getEntity(uuid); + +// Stand no longer exists + if (!(entity instanceof ArmorStand armorStand)) { + continue; + } + +// Skip paused stands + if (standManager.isPaused(armorStand)) { + continue; + } + +// Scan nearby entities + double radius = standManager.getRadius(armorStand); + + int leaveAlive = + standManager.getLeaveAlive( + armorStand + ); + + lastStandLocation = + armorStand.getLocation(); + + java.util.Map> adultTargets = + new java.util.HashMap<>(); + + java.util.Map> babyTargets = + new java.util.HashMap<>(); + + List killAllTargets = + new java.util.ArrayList<>(); + + for (Entity nearby : armorStand.getNearbyEntities( + radius, + radius, + radius + )) { + +// Ignore players + if (nearby instanceof Player) { + continue; + } + +// Ignore armor stands + if (nearby instanceof ArmorStand) { + continue; + } + +// Must be living entity + if (!(nearby instanceof LivingEntity livingEntity)) { + continue; + } + + EntityType entityType = livingEntity.getType(); + + String entityName = entityType.name(); + + boolean killAll = false; + + boolean shouldKill; + +// Ageable mobs + if (livingEntity instanceof Ageable ageable) { + +// Adult mob + if (ageable.isAdult()) { + + List disabledAdultMobs = + standManager.getDisabledAdultMobs( + armorStand + ); + + shouldKill = + !disabledAdultMobs.contains( + entityName + ); + + if (configManager + .getAdultMobData() + .containsKey(entityName)) { + + killAll = + configManager + .getAdultMobData() + .get(entityName) + .isKillAll(); + + } + + } + +// Baby mob + else { + + List disabledBabyMobs = + standManager.getDisabledBabyMobs( + armorStand + ); + + shouldKill = + !disabledBabyMobs.contains( + entityName + ); + + if (configManager + .getBabyMobData() + .containsKey(entityName)) { + + killAll = + configManager + .getBabyMobData() + .get(entityName) + .isKillAll(); + + } + + } + + } + +// Non-ageable mobs + else { + + List disabledAdultMobs = + standManager.getDisabledAdultMobs( + armorStand + ); + + shouldKill = + !disabledAdultMobs.contains( + entityName + ); + + if (configManager + .getAdultMobData() + .containsKey(entityName)) { + + killAll = + configManager + .getAdultMobData() + .get(entityName) + .isKillAll(); + + } + + } + +// Not allowed + if (!shouldKill) { + continue; + } + +// Ignore named mobs + if (livingEntity.customName() != null) { + continue; + } + + if (killAll) { + + killAllTargets.add(livingEntity); + + } else { + + if (livingEntity instanceof Ageable ageable) { + + if (ageable.isAdult()) { + + adultTargets + .computeIfAbsent( + entityName, + k -> new java.util.ArrayList<>() + ) + .add(livingEntity); + + } else { + + babyTargets + .computeIfAbsent( + entityName, + k -> new java.util.ArrayList<>() + ) + .add(livingEntity); + + } + + } else { + + adultTargets + .computeIfAbsent( + entityName, + k -> new java.util.ArrayList<>() + ) + .add(livingEntity); + + } + + } + +// Damage amount + double damage = + plugin.getConfig() + .getDouble( + "damage-amount" + ); + +// Kill all targets first + for (LivingEntity target : killAllTargets) { + + target.damage(damage); + + if (entityKillLogging) { + killedThisCycle++; + } + + } + +// Leave alive logic +// Adult targets + for (List mobList : adultTargets.values()) { + + int allowedKills = + mobList.size() - leaveAlive; + + if (allowedKills > 0) { + + for (int i = 0; i < allowedKills; i++) { + + LivingEntity target = + mobList.get(i); + + target.damage(damage); + + if (entityKillLogging) { + killedThisCycle++; + } + + } + + } + + } + +// Baby targets + for (List mobList : babyTargets.values()) { + + int allowedKills = + mobList.size() - leaveAlive; + + if (allowedKills > 0) { + + for (int i = 0; i < allowedKills; i++) { + + LivingEntity target = + mobList.get(i); + + target.damage(damage); + + if (entityKillLogging) { + killedThisCycle++; + } + + } + + } + + } + + } + + } + + long duration = System.nanoTime() - start; + double ms = duration / 1_000_000.0; + + if (debugEnabled && performanceLogging) { + + if (ms >= 5.0) { + + Location location = + lastStandLocation; + + if (location == null) { + return; + } + + plugin.getLogger().warning( + "Slow cycle: " + + String.format("%.2f", ms) + + "ms" + + ( + entityKillLogging + ? " | Killed: " + killedThisCycle + : "" + ) + + " | " + + location.getWorld().getName() + + " " + + location.getBlockX() + + " " + + location.getBlockY() + + " " + + location.getBlockZ() + ); + + } + + } + + } + +} \ No newline at end of file diff --git a/src/main/java/com/rsscripting/mobstand/utils/VersionChecker.java b/src/main/java/com/rsscripting/mobstand/utils/VersionChecker.java new file mode 100644 index 0000000..76a97e0 --- /dev/null +++ b/src/main/java/com/rsscripting/mobstand/utils/VersionChecker.java @@ -0,0 +1,148 @@ +package com.rsscripting.mobstand.utils; + +import com.rsscripting.mobstand.RSMobStandPlugin; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; + +public class VersionChecker { + + private final RSMobStandPlugin plugin; + + private static String latestVersion = + "Unknown"; + + private static final String VERSION_URL = + "https://raw.githubusercontent.com/russelburgraymond/RS-MobStand/main/version.txt"; + + public VersionChecker( + RSMobStandPlugin plugin + ) { + + this.plugin = plugin; + + } + + public void checkVersion() { + + plugin.getServer() + .getScheduler() + .runTaskAsynchronously( + + plugin, + + () -> { + + try { + + /* + |-------------------------------------------------------------------------- + | READ VERSION FILE + |-------------------------------------------------------------------------- + */ + + URL url = + new URL( + VERSION_URL + ); + + BufferedReader reader = + new BufferedReader( + new InputStreamReader( + url.openStream() + ) + ); + + latestVersion = + reader.readLine(); + + reader.close(); + + /* + |-------------------------------------------------------------------------- + | CURRENT VERSION + |-------------------------------------------------------------------------- + */ + + String currentVersion = + plugin.getDescription() + .getVersion(); + + /* + |-------------------------------------------------------------------------- + | UPDATE AVAILABLE + |-------------------------------------------------------------------------- + */ + + if (!currentVersion.equalsIgnoreCase( + latestVersion + )) { + + plugin.getLogger().warning( + "=================================================" + ); + + plugin.getLogger().warning( + "A new version of RS-MobStand is available!" + ); + + plugin.getLogger().warning( + "Current Version: " + + currentVersion + ); + + plugin.getLogger().warning( + "Latest Version: " + + latestVersion + ); + + plugin.getLogger().warning( + "=================================================" + ); + + } + + /* + |-------------------------------------------------------------------------- + | UP TO DATE + |-------------------------------------------------------------------------- + */ + + else { + + plugin.getLogger().info( + "RS-MobStand is up to date." + ); + + } + + } + + /* + |-------------------------------------------------------------------------- + | FAILED + |-------------------------------------------------------------------------- + */ + + catch (Exception exception) { + + plugin.getLogger().warning( + "Could not check for updates." + ); + + } + + } + + ); + + } + + public static String getLatestVersion() { + + return latestVersion; + + } + +} \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..9a3b450 --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,91 @@ +# ========================================= +# RS MobStand Configuration +# RS MobStand by Big_Pappa +# ========================================= + +config-version: 1 + + +########################################################## +# Plugin Settings # +########################################################## + +# How often MobStands scan for mobs. Measured in ticks. +# 20 ticks = 1 second +scan-interval: 1200 + +# Default gravity state for new MobStands. +# true = Stand will fall until sitting on top of a block +# false = Stand will not fall if block below it is broken. +default-gravity: true + +# Damage dealt to mobs. +damage-amount: 1000.0 + + +########################################################## +# Scan Settings # +# Recommended maximum radius: # +# 32 for normal servers # +# 48 for large/high-performance servers # +########################################################## + +# Default radius new MobStands begin with. +default-scan-radius: 10 + +# Maximum radius players may set their MobStand to. +# Recommended maximum radius: +# 32 for normal servers +# 48 for large/high-performance servers +# Excessive values may impact performance heavily. +max-player-scan-radius: 32 + + +########################################################## +# Stand Count Settings # +########################################################## + +# Maximum number of stands a player may place at one time. +# 0 = Unlimited +max-stands-per-player: 5 + +# Maximum number of stands that may be placed on the server at one time. +# 0 = Unlimited +max-total-stands: 200 + + +########################################################## +# Settings below are for leaving mobs alive by default. # +########################################################## + +# Default setting when new stands are created. +default-leave-alive: 2 + +# Minimum amount users may set their stands to leave alive each +# scan and kill cycle. NOTE: Named mobs DO NOT count as the +# RS Mob Stand ignores those completely. +min-leave-alive: 0 + +# Minimum amount users may set their stands to leave alive each +# scan and kill cycle. NOTE: Named mobs DO NOT count as the +# RS Mob Stand ignores those completely. +max-leave-alive: 30 + + +########################################################## +# Debugging # +# Debugging options below this line are intended for # +# development/testing and should be left disabled on # +# production servers. # +########################################################## + +debug: + enabled: false # Override all options below. + + logging: + performance: true # Enables performance log entries + entity-kills: true # Adds kill count to performance entries (Requires performance: true) + + performance: + warning-ms: 100.0 + summary-interval-seconds: 300 diff --git a/src/main/resources/configs/adult-mobs.yml b/src/main/resources/configs/adult-mobs.yml new file mode 100644 index 0000000..4d799e5 --- /dev/null +++ b/src/main/resources/configs/adult-mobs.yml @@ -0,0 +1,131 @@ +# ========================================= +# RS MobStand Adult Mob Settings +# ========================================= +# Add as many as you like. The menus will +# Center, add rows, and pagenate them +# automatically. +# ========================================= + +#========================================== +# available items +# icon: icon that will show for that mob in the menu +# enabled-by-default: wether or not will be killed by default +# kill-all: true Kills all these mob types regardless of user settings +# - Named mobs will still be ignored +#================================================================ +# Kills all these mob types regardless of user settings +# kill-all: true +# - Named mobs will still be ignored +#================================================================ +adult-mobs: + + BLAZE: + icon: BLAZE_ROD + enabled-by-default: true + # true: Stand will kill all regardless of settings. + # false: (or not existing for mob) will follow players setting. + # Ignores per-stand settings. + kill-all: false + CAVE_SPIDER: + icon: SPIDER_EYE + enabled-by-default: true + + CHICKEN: + icon: FEATHER + enabled-by-default: true + + COW: + icon: LEATHER + enabled-by-default: true + + CREEPER: + icon: GUNPOWDER + enabled-by-default: true + + DROWNED: + icon: COPPER_INGOT + enabled-by-default: true + + ENDERMAN: + icon: ENDER_PEARL + enabled-by-default: true + + GHAST: + icon: GHAST_TEAR + enabled-by-default: true + + GUARDIAN: + icon: PRISMARINE_SHARD + enabled-by-default: true + + HOGLIN: + icon: PORKCHOP + enabled-by-default: true + + HUSK: + icon: ROTTEN_FLESH + enabled-by-default: true + + MAGMA_CUBE: + icon: MAGMA_CREAM + enabled-by-default: true + + PHANTOM: + icon: PHANTOM_MEMBRANE + enabled-by-default: true + + PIG: + icon: PORKCHOP + enabled-by-default: true + + PIGLIN: + icon: GOLD_NUGGET + enabled-by-default: true + + RABBIT: + icon: RABBIT_HIDE + enabled-by-default: true + + SHEEP: + icon: WHITE_WOOL + enabled-by-default: true + + SHULKER: + icon: SHULKER_SHELL + enabled-by-default: true + + SILVERFISH: + icon: STONE + enabled-by-default: true + + SKELETON: + icon: BONE + enabled-by-default: true + + SLIME: + icon: SLIME_BALL + enabled-by-default: true + + SPIDER: + icon: STRING + enabled-by-default: true + + WITCH: + icon: GLASS_BOTTLE + enabled-by-default: true + + ZOGLIN: + icon: ROTTEN_FLESH + enabled-by-default: true + + ZOMBIE: + icon: ROTTEN_FLESH + enabled-by-default: true + + ZOMBIE_VILLAGER: + icon: EMERALD + enabled-by-default: true + + ZOMBIFIED_PIGLIN: + icon: GOLD_INGOT + enabled-by-default: true \ No newline at end of file diff --git a/src/main/resources/configs/baby-mobs.yml b/src/main/resources/configs/baby-mobs.yml new file mode 100644 index 0000000..780e0c0 --- /dev/null +++ b/src/main/resources/configs/baby-mobs.yml @@ -0,0 +1,73 @@ +# ========================================= +# RS MobStand baby Mob Settings +# ========================================= +# Add as many as you like. The menus will +# Center, add rows, and pagenate them +# automatically. +# ========================================= + +#========================================== +# available items +# icon: icon that will show for that mob in the menu +# enabled-by-default: wether or not will be killed by default +# kill-all: Kills all these mob types regardless of user settings +# - Named mobs will still be ignored +#================================================================ + +baby-mobs: + + CHICKEN: + icon: FEATHER + enabled-by-default: false + # true: Stand will kill all regardless of players settings. + # false: (or not existing for mob) will follow players setting. + # Ignores per-stand settings. + kill-all: false + + COW: + icon: LEATHER + enabled-by-default: false + + DROWNED: + icon: COPPER_INGOT + enabled-by-default: true + + HOGLIN: + icon: PORKCHOP + enabled-by-default: true + + HUSK: + icon: ROTTEN_FLESH + enabled-by-default: true + + PIG: + icon: PORKCHOP + enabled-by-default: false + + PIGLIN: + icon: GOLD_NUGGET + enabled-by-default: true + + RABBIT: + icon: RABBIT_HIDE + enabled-by-default: false + + SHEEP: + icon: WHITE_WOOL + enabled-by-default: false + + ZOGLIN: + icon: ROTTEN_FLESH + enabled-by-default: true + + ZOMBIE: + icon: ROTTEN_FLESH + enabled-by-default: true + + ZOMBIE_VILLAGER: + icon: EMERALD + enabled-by-default: true + + ZOMBIFIED_PIGLIN: + icon: GOLD_INGOT + enabled-by-default: true diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..19ce4fb --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,27 @@ +name: RS-MobStand +prefix: RS-MobStand +version: 1.0.0 +main: com.rsscripting.mobstand.RSMobStandPlugin +api-version: '1.21' + +author: RSScripting + +commands: + rsms: + description: RS MobStand main command + usage: /rsms reload + permission: rsmobstand.admin + +permissions: + + rsmobstand.use: + description: Allows use of RS MobStand + default: true + + rsmobstand.admin: + description: Admin access for RS MobStand + default: op + + rsmobstand.bypasslimits: + description: Bypass MobStand placement limits + default: op \ No newline at end of file diff --git a/src/main/resources/updates.txt b/src/main/resources/updates.txt new file mode 100644 index 0000000..65fcf37 --- /dev/null +++ b/src/main/resources/updates.txt @@ -0,0 +1,15 @@ +========================================= +1.0.0 (05/28/2026) +========================================= + +[ADDED] +- Added kill-all support to adult and baby configs. + +[FIXED] +- Fixed admin reload not reloading mob configs. +- Fixed adult/baby filters toggle bug. +- Fixed kill-all mobs appearing disabled in menus. + +[CHANGED] +- Kill-all mobs now remain visually enabled. +- Added admin override lore to forced-enabled mobs. \ No newline at end of file