diff --git a/core/build.gradle b/core/build.gradle index dd745d3d..714f7568 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -50,9 +50,9 @@ jar { archiveVersion.set("${version}") from { project(':api').sourceSets.main.output } - from { project(':NMS:v1_21').sourceSets.main.output } - from { project(':NMS:v1_21_4').sourceSets.main.output } - from { project(':NMS:v1_21_6').sourceSets.main.output } + from { project(':nms:v1_21').sourceSets.main.output } + from { project(':nms:v1_21_4').sourceSets.main.output } + from { project(':nms:v1_21_6').sourceSets.main.output } from sourceSets.main.output duplicatesStrategy = DuplicatesStrategy.EXCLUDE exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA' diff --git a/core/src/main/java/github/nighter/smartspawner/commands/list/ListSubCommand.java b/core/src/main/java/github/nighter/smartspawner/commands/list/ListSubCommand.java index 2d6d7c93..8b790fc1 100644 --- a/core/src/main/java/github/nighter/smartspawner/commands/list/ListSubCommand.java +++ b/core/src/main/java/github/nighter/smartspawner/commands/list/ListSubCommand.java @@ -15,6 +15,12 @@ import github.nighter.smartspawner.spawner.properties.SpawnerManager; import github.nighter.smartspawner.spawner.utils.SpawnerMobHeadTexture; import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.datacomponent.DataComponentType; +import io.papermc.paper.datacomponent.DataComponentTypes; +import io.papermc.paper.datacomponent.item.TooltipDisplay; +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.keys.DataComponentTypeKeys; import org.bukkit.*; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; @@ -27,6 +33,9 @@ import java.util.stream.Collectors; public class ListSubCommand extends BaseSubCommand { + private static final Set HIDDEN_TOOLTIP_COMPONENTS = Set.of( + RegistryAccess.registryAccess().getRegistry(RegistryKey.DATA_COMPONENT_TYPE).get(DataComponentTypeKeys.BLOCK_ENTITY_DATA) + ); private final SpawnerManager spawnerManager; private final LanguageManager languageManager; private final MessageService messageService; @@ -447,8 +456,12 @@ private ItemStack createNavigationButton(Material material, String namePath) { return button; } + private static void hideTooltip(ItemStack item) { + item.setData(DataComponentTypes.TOOLTIP_DISPLAY, + TooltipDisplay.tooltipDisplay().hiddenComponents(HIDDEN_TOOLTIP_COMPONENTS).build()); + } + private ItemStack createSpawnerInfoItem(SpawnerData spawner) { - // Get the custom head for the spawner's entity type EntityType entityType = spawner.getEntityType(); ItemStack spawnerItem; ItemMeta meta; @@ -456,27 +469,18 @@ private ItemStack createSpawnerInfoItem(SpawnerData spawner) { spawnerItem = new ItemStack(Material.SPAWNER); meta = spawnerItem.getItemMeta(); if (meta == null) return spawnerItem; - meta.addItemFlags(ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_ATTRIBUTES, - ItemFlag.HIDE_ADDITIONAL_TOOLTIP, ItemFlag.HIDE_UNBREAKABLE); + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_UNBREAKABLE); } else { spawnerItem = SpawnerMobHeadTexture.getCustomHead(entityType); meta = spawnerItem.getItemMeta(); if (meta == null) return spawnerItem; } Location loc = spawner.getSpawnerLocation(); - - // Set display name with formatted spawner ID Map placeholders = new HashMap<>(); placeholders.put("id", String.valueOf(spawner.getSpawnerId())); meta.setDisplayName(languageManager.getGuiItemName("spawner_item_list.name", placeholders)); - - // Add entity type placeholders.put("entity", languageManager.getFormattedMobName(entityType)); - - // Add stack size placeholders.put("size", String.valueOf(spawner.getStackSize())); - - // Add status if (spawner.getSpawnerStop().get()) { placeholders.put("status_color", "&#ff6b6b"); placeholders.put("status_text", "Inactive"); @@ -484,35 +488,21 @@ private ItemStack createSpawnerInfoItem(SpawnerData spawner) { placeholders.put("status_color", "�E689"); placeholders.put("status_text", "Active"); } - - // Add location placeholders.put("x", String.valueOf(loc.getBlockX())); placeholders.put("y", String.valueOf(loc.getBlockY())); placeholders.put("z", String.valueOf(loc.getBlockZ())); - - // Add last interacted player String lastPlayer = spawner.getLastInteractedPlayer(); placeholders.put("last_player", lastPlayer != null ? lastPlayer : "None"); - - // Get the lore with placeholders replaced List lore = Arrays.asList(languageManager.getGuiItemLore("spawner_item_list.lore", placeholders)); - - // Set lore and apply meta meta.setLore(lore); spawnerItem.setItemMeta(meta); + hideTooltip(spawnerItem); return spawnerItem; } - /** - * Opens the spawner management GUI for a specific spawner - */ public void openSpawnerManagementGUI(Player player, String spawnerId, String worldName, int listPage) { spawnerManagementGUI.openManagementMenu(player, spawnerId, worldName, listPage); } - - /** - * Gets the user's current filter preference for a world - */ public FilterOption getUserFilter(Player player, String worldName) { return userPreferenceCache.getUserFilter(player, worldName); } diff --git a/core/src/main/java/github/nighter/smartspawner/commands/list/gui/adminstacker/AdminStackerUI.java b/core/src/main/java/github/nighter/smartspawner/commands/list/gui/adminstacker/AdminStackerUI.java index 07dce9e5..328fdf82 100644 --- a/core/src/main/java/github/nighter/smartspawner/commands/list/gui/adminstacker/AdminStackerUI.java +++ b/core/src/main/java/github/nighter/smartspawner/commands/list/gui/adminstacker/AdminStackerUI.java @@ -3,6 +3,12 @@ import github.nighter.smartspawner.SmartSpawner; import github.nighter.smartspawner.spawner.properties.SpawnerData; import github.nighter.smartspawner.language.LanguageManager; +import io.papermc.paper.datacomponent.DataComponentType; +import io.papermc.paper.datacomponent.DataComponentTypes; +import io.papermc.paper.datacomponent.item.TooltipDisplay; +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.keys.DataComponentTypeKeys; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -13,11 +19,9 @@ import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.Arrays; -/** - * Admin version of the spawner stacker GUI that doesn't require actual spawner items - */ public class AdminStackerUI { private static final int GUI_SIZE = 27; private static final int[] DECREASE_SLOTS = {9, 10, 11}; @@ -25,6 +29,9 @@ public class AdminStackerUI { private static final int SPAWNER_INFO_SLOT = 13; private static final int BACK_SLOT = 22; private static final int[] STACK_AMOUNTS = {64, 10, 1}; + private static final Set HIDDEN_TOOLTIP_COMPONENTS = Set.of( + RegistryAccess.registryAccess().getRegistry(RegistryKey.DATA_COMPONENT_TYPE).get(DataComponentTypeKeys.BLOCK_ENTITY_DATA) + ); private final SmartSpawner plugin; private final LanguageManager languageManager; @@ -38,42 +45,28 @@ public void openAdminStackerGui(Player player, SpawnerData spawner, String world if (player == null || spawner == null) { return; } - String title = languageManager.getGuiTitle("gui_title_stacker"); Inventory gui = Bukkit.createInventory(new AdminStackerHolder(spawner, worldName, listPage), GUI_SIZE, title); - - // Fill GUI with modifier buttons and spawner info populateStackerGui(gui, spawner); - player.openInventory(gui); } private void populateStackerGui(Inventory gui, SpawnerData spawner) { - // Add decrease buttons for (int i = 0; i < STACK_AMOUNTS.length; i++) { gui.setItem(DECREASE_SLOTS[i], createActionButton("remove", spawner, STACK_AMOUNTS[i])); } - - // Add increase buttons for (int i = 0; i < STACK_AMOUNTS.length; i++) { gui.setItem(INCREASE_SLOTS[i], createActionButton("add", spawner, STACK_AMOUNTS[i])); } - - // Add spawner info button gui.setItem(SPAWNER_INFO_SLOT, createSpawnerInfoButton(spawner)); - - // Add back button to return to management GUI gui.setItem(BACK_SLOT, createBackButton()); } private ItemStack createActionButton(String action, SpawnerData spawner, int amount) { Map placeholders = createPlaceholders(spawner, amount); - String name = languageManager.getGuiItemName("button_" + action + ".name", placeholders); String[] lore = languageManager.getGuiItemLore("button_" + action + ".lore", placeholders); - Material material = action.equals("add") ? Material.LIME_STAINED_GLASS_PANE : Material.RED_STAINED_GLASS_PANE; - ItemStack button = createButton(material, name, lore); button.setAmount(Math.max(1, Math.min(amount, 64))); return button; @@ -81,17 +74,14 @@ private ItemStack createActionButton(String action, SpawnerData spawner, int amo private ItemStack createSpawnerInfoButton(SpawnerData spawner) { Map placeholders = createPlaceholders(spawner, 0); - String name = languageManager.getGuiItemName("button_spawner.name", placeholders); String[] lore = languageManager.getGuiItemLore("button_spawner.lore", placeholders); - return createButton(Material.SPAWNER, name, lore); } private ItemStack createBackButton() { String name = languageManager.getGuiItemName("spawner_management.back.name"); String[] lore = languageManager.getGuiItemLore("spawner_management.back.lore"); - return createButton(Material.RED_STAINED_GLASS_PANE, name, lore); } @@ -106,20 +96,23 @@ private Map createPlaceholders(SpawnerData spawner, int amount) return placeholders; } + private static void hideTooltip(ItemStack item) { + item.setData(DataComponentTypes.TOOLTIP_DISPLAY, + TooltipDisplay.tooltipDisplay().hiddenComponents(HIDDEN_TOOLTIP_COMPONENTS).build()); + } + private ItemStack createButton(Material material, String name, String[] lore) { ItemStack button = new ItemStack(material); ItemMeta meta = button.getItemMeta(); - if (meta != null) { meta.setDisplayName(name); if (lore != null && lore.length > 0) { meta.setLore(Arrays.asList(lore)); } - meta.addItemFlags(ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_ATTRIBUTES, - ItemFlag.HIDE_ADDITIONAL_TOOLTIP, ItemFlag.HIDE_UNBREAKABLE); + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_UNBREAKABLE); button.setItemMeta(meta); } - + hideTooltip(button); return button; } } \ No newline at end of file diff --git a/core/src/main/java/github/nighter/smartspawner/commands/list/gui/management/SpawnerManagementGUI.java b/core/src/main/java/github/nighter/smartspawner/commands/list/gui/management/SpawnerManagementGUI.java index 394f45f4..a6ffd802 100644 --- a/core/src/main/java/github/nighter/smartspawner/commands/list/gui/management/SpawnerManagementGUI.java +++ b/core/src/main/java/github/nighter/smartspawner/commands/list/gui/management/SpawnerManagementGUI.java @@ -5,8 +5,12 @@ import github.nighter.smartspawner.language.MessageService; import github.nighter.smartspawner.spawner.properties.SpawnerData; import github.nighter.smartspawner.spawner.properties.SpawnerManager; +import io.papermc.paper.datacomponent.DataComponentType; import io.papermc.paper.datacomponent.DataComponentTypes; import io.papermc.paper.datacomponent.item.TooltipDisplay; +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.keys.DataComponentTypeKeys; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.Sound; @@ -20,6 +24,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; public class SpawnerManagementGUI { private static final int INVENTORY_SIZE = 27; @@ -28,6 +33,9 @@ public class SpawnerManagementGUI { private static final int STACK_SLOT = 14; private static final int REMOVE_SLOT = 16; private static final int BACK_SLOT = 26; + private static final Set HIDDEN_TOOLTIP_COMPONENTS = Set.of( + RegistryAccess.registryAccess().getRegistry(RegistryKey.DATA_COMPONENT_TYPE).get(DataComponentTypeKeys.BLOCK_ENTITY_DATA) + ); private final SmartSpawner plugin; private final LanguageManager languageManager; @@ -47,29 +55,25 @@ public void openManagementMenu(Player player, String spawnerId, String worldName messageService.sendMessage(player, "spawner_not_found"); return; } - String title = languageManager.getGuiTitle("spawner_management.title"); - Inventory inv = Bukkit.createInventory( new SpawnerManagementHolder(spawnerId, worldName, listPage), INVENTORY_SIZE, title ); - player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1.0f, 1.0f); - - // Create action items with better materials and positioning createActionItem(inv, TELEPORT_SLOT, "spawner_management.teleport", Material.ENDER_PEARL); createActionItem(inv, OPEN_SPAWNER_SLOT, "spawner_management.open_spawner", Material.ENDER_EYE); createActionItem(inv, STACK_SLOT, "spawner_management.stack", Material.SPAWNER); createActionItem(inv, REMOVE_SLOT, "spawner_management.remove", Material.BARRIER); createActionItem(inv, BACK_SLOT, "spawner_management.back", Material.RED_STAINED_GLASS_PANE); - - // Fill empty slots with glass panes - // fillEmptySlots(inv); - player.openInventory(inv); } + private static void hideTooltip(ItemStack item) { + item.setData(DataComponentTypes.TOOLTIP_DISPLAY, + TooltipDisplay.tooltipDisplay().hiddenComponents(HIDDEN_TOOLTIP_COMPONENTS).build()); + } + private void createActionItem(Inventory inv, int slot, String langKey, Material material) { ItemStack item = new ItemStack(material); ItemMeta meta = item.getItemMeta(); @@ -77,25 +81,10 @@ private void createActionItem(Inventory inv, int slot, String langKey, Material meta.setDisplayName(languageManager.getGuiItemName(langKey + ".name")); List lore = Arrays.asList(languageManager.getGuiItemLore(langKey + ".lore")); meta.setLore(lore); - meta.addItemFlags(ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_ATTRIBUTES, - ItemFlag.HIDE_ADDITIONAL_TOOLTIP, ItemFlag.HIDE_UNBREAKABLE); + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_UNBREAKABLE); item.setItemMeta(meta); } + hideTooltip(item); inv.setItem(slot, item); } - -// private void fillEmptySlots(Inventory inv) { -// ItemStack glass = new ItemStack(Material.GRAY_STAINED_GLASS_PANE); -// ItemMeta meta = glass.getItemMeta(); -// if (meta != null) { -// meta.setDisplayName(" "); -// glass.setItemMeta(meta); -// } -// -// for (int i = 0; i < inv.getSize(); i++) { -// if (inv.getItem(i) == null) { -// inv.setItem(i, glass); -// } -// } -// } } \ No newline at end of file diff --git a/core/src/main/java/github/nighter/smartspawner/spawner/gui/stacker/SpawnerStackerUI.java b/core/src/main/java/github/nighter/smartspawner/spawner/gui/stacker/SpawnerStackerUI.java index fbac1ed6..3e318492 100644 --- a/core/src/main/java/github/nighter/smartspawner/spawner/gui/stacker/SpawnerStackerUI.java +++ b/core/src/main/java/github/nighter/smartspawner/spawner/gui/stacker/SpawnerStackerUI.java @@ -3,6 +3,12 @@ import github.nighter.smartspawner.SmartSpawner; import github.nighter.smartspawner.spawner.properties.SpawnerData; import github.nighter.smartspawner.language.LanguageManager; +import io.papermc.paper.datacomponent.DataComponentType; +import io.papermc.paper.datacomponent.DataComponentTypes; +import io.papermc.paper.datacomponent.item.TooltipDisplay; +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.keys.DataComponentTypeKeys; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -13,6 +19,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.Arrays; public class SpawnerStackerUI { @@ -21,6 +28,9 @@ public class SpawnerStackerUI { private static final int[] INCREASE_SLOTS = {17, 16, 15}; private static final int SPAWNER_INFO_SLOT = 13; private static final int[] STACK_AMOUNTS = {64, 10, 1}; + private static final Set HIDDEN_TOOLTIP_COMPONENTS = Set.of( + RegistryAccess.registryAccess().getRegistry(RegistryKey.DATA_COMPONENT_TYPE).get(DataComponentTypeKeys.BLOCK_ENTITY_DATA) + ); private final SmartSpawner plugin; private final LanguageManager languageManager; @@ -34,14 +44,9 @@ public void openStackerGui(Player player, SpawnerData spawner) { if (player == null || spawner == null) { return; } - String title = languageManager.getGuiTitle("gui_title_stacker"); Inventory gui = Bukkit.createInventory(new SpawnerStackerHolder(spawner), GUI_SIZE, title); - - // Fill GUI with modifier buttons and spawner info populateStackerGui(gui, spawner); - - // Log stacker GUI opening if (plugin.getSpawnerActionLogger() != null) { plugin.getSpawnerActionLogger().log(github.nighter.smartspawner.logging.SpawnerEventType.SPAWNER_STACKER_OPEN, builder -> builder.player(player.getName(), player.getUniqueId()) @@ -51,33 +56,24 @@ public void openStackerGui(Player player, SpawnerData spawner) { .metadata("max_stack_size", spawner.getMaxStackSize()) ); } - player.openInventory(gui); } private void populateStackerGui(Inventory gui, SpawnerData spawner) { - // Add decrease buttons for (int i = 0; i < STACK_AMOUNTS.length; i++) { gui.setItem(DECREASE_SLOTS[i], createActionButton("remove", spawner, STACK_AMOUNTS[i])); } - - // Add increase buttons for (int i = 0; i < STACK_AMOUNTS.length; i++) { gui.setItem(INCREASE_SLOTS[i], createActionButton("add", spawner, STACK_AMOUNTS[i])); } - - // Add spawner info button gui.setItem(SPAWNER_INFO_SLOT, createSpawnerInfoButton(spawner)); } private ItemStack createActionButton(String action, SpawnerData spawner, int amount) { Map placeholders = createPlaceholders(spawner, amount); - String name = languageManager.getGuiItemName("button_" + action + ".name", placeholders); String[] lore = languageManager.getGuiItemLore("button_" + action + ".lore", placeholders); - Material material = action.equals("add") ? Material.LIME_STAINED_GLASS_PANE : Material.RED_STAINED_GLASS_PANE; - ItemStack button = createButton(material, name, lore); button.setAmount(Math.max(1, Math.min(amount, 64))); return button; @@ -85,10 +81,8 @@ private ItemStack createActionButton(String action, SpawnerData spawner, int amo private ItemStack createSpawnerInfoButton(SpawnerData spawner) { Map placeholders = createPlaceholders(spawner, 0); - String name = languageManager.getGuiItemName("button_spawner.name", placeholders); String[] lore = languageManager.getGuiItemLore("button_spawner.lore", placeholders); - return createButton(Material.SPAWNER, name, lore); } @@ -103,20 +97,23 @@ private Map createPlaceholders(SpawnerData spawner, int amount) return placeholders; } + private static void hideTooltip(ItemStack item) { + item.setData(DataComponentTypes.TOOLTIP_DISPLAY, + TooltipDisplay.tooltipDisplay().hiddenComponents(HIDDEN_TOOLTIP_COMPONENTS).build()); + } + private ItemStack createButton(Material material, String name, String[] lore) { ItemStack button = new ItemStack(material); ItemMeta meta = button.getItemMeta(); - if (meta != null) { meta.setDisplayName(name); if (lore != null && lore.length > 0) { meta.setLore(Arrays.asList(lore)); } - meta.addItemFlags(ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_ATTRIBUTES, - ItemFlag.HIDE_ADDITIONAL_TOOLTIP, ItemFlag.HIDE_UNBREAKABLE); + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_UNBREAKABLE); button.setItemMeta(meta); } - + hideTooltip(button); return button; } } \ No newline at end of file diff --git a/core/src/main/java/github/nighter/smartspawner/spawner/item/SpawnerItemFactory.java b/core/src/main/java/github/nighter/smartspawner/spawner/item/SpawnerItemFactory.java index e615ce0e..72821e86 100644 --- a/core/src/main/java/github/nighter/smartspawner/spawner/item/SpawnerItemFactory.java +++ b/core/src/main/java/github/nighter/smartspawner/spawner/item/SpawnerItemFactory.java @@ -25,24 +25,20 @@ import java.util.*; import java.util.concurrent.TimeUnit; -/** - * Factory class for creating spawner items with optimized caching - */ public class SpawnerItemFactory { + private static final long CACHE_EXPIRY_TIME_MS = TimeUnit.MINUTES.toMillis(30); + private static final int MAX_CACHE_SIZE = 100; + private static final Set HIDDEN_TOOLTIP_COMPONENTS = Set.of( + RegistryAccess.registryAccess().getRegistry(RegistryKey.DATA_COMPONENT_TYPE).get(DataComponentTypeKeys.BLOCK_ENTITY_DATA) + ); + private final SmartSpawner plugin; private final LanguageManager languageManager; private EntityLootRegistry entityLootRegistry; - private static NamespacedKey VANILLA_SPAWNER_KEY; - // private static NamespacedKey SMART_SPAWNER_KEY; private final Map spawnerItemCache = new HashMap<>(); private final Map cacheTimestamps = new HashMap<>(); - - // Cache configuration - private static final long CACHE_EXPIRY_TIME_MS = TimeUnit.MINUTES.toMillis(30); // Cache expires after 30 minutes - private static final int MAX_CACHE_SIZE = 100; // Maximum number of cached spawner items - private long lastCacheCleanup = System.currentTimeMillis(); public SpawnerItemFactory(SmartSpawner plugin) { @@ -50,39 +46,25 @@ public SpawnerItemFactory(SmartSpawner plugin) { this.languageManager = plugin.getLanguageManager(); this.entityLootRegistry = plugin.getEntityLootRegistry(); VANILLA_SPAWNER_KEY = new NamespacedKey(plugin, "vanilla_spawner"); - // SMART_SPAWNER_KEY = new NamespacedKey(plugin, "smart_spawner"); } public void reload() { this.entityLootRegistry = plugin.getEntityLootRegistry(); - // Clear caches on reload clearAllCaches(); } - /** - * Clears all caches in the factory - */ public void clearAllCaches() { spawnerItemCache.clear(); cacheTimestamps.clear(); lastCacheCleanup = System.currentTimeMillis(); } - /** - * Clean expired cache entries if needed - */ private void cleanupCacheIfNeeded() { long currentTime = System.currentTimeMillis(); - - // Only clean up once every minute to avoid performance overhead if (currentTime - lastCacheCleanup < TimeUnit.MINUTES.toMillis(1)) { return; } - - // Mark this cleanup lastCacheCleanup = currentTime; - - // Remove expired entries Iterator> iterator = cacheTimestamps.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = iterator.next(); @@ -94,153 +76,97 @@ private void cleanupCacheIfNeeded() { } } - /** - * Creates a spawner item for the given entity type - */ + private static void hideTooltip(ItemStack item) { + item.setData(DataComponentTypes.TOOLTIP_DISPLAY, + TooltipDisplay.tooltipDisplay().hiddenComponents(HIDDEN_TOOLTIP_COMPONENTS).build()); + } + public ItemStack createSpawnerItem(EntityType entityType) { return createSpawnerItem(entityType, 1); } - /** - * Creates a spawner item for the given entity type and amount - */ public ItemStack createSpawnerItem(EntityType entityType, int amount) { - // Check if we need to clean up the cache cleanupCacheIfNeeded(); - - // For single-item spawners, we can use the cache if (amount == 1) { ItemStack cachedItem = spawnerItemCache.get(entityType); - if (cachedItem != null) { - // Return a clone of the cached item to prevent modification of the cached instance return cachedItem.clone(); } } ItemStack spawner = new ItemStack(Material.SPAWNER, amount); ItemMeta meta = spawner.getItemMeta(); - if (meta != null && entityType != null && entityType != EntityType.UNKNOWN) { - // Apply block state for the spawner if (meta instanceof BlockStateMeta blockMeta) { BlockState blockState = blockMeta.getBlockState(); - if (blockState instanceof CreatureSpawner cs) { cs.setSpawnedType(entityType); blockMeta.setBlockState(cs); } } - - // Get entity name - now using LanguageManager's cached method String entityTypeName = languageManager.getFormattedMobName(entityType); - // Use LanguageManager's small caps method String entityTypeNameSmallCaps = languageManager.getSmallCaps(entityTypeName); - EntityLootConfig lootConfig = entityLootRegistry.getLootConfig(entityType); List lootItems = lootConfig != null ? lootConfig.getAllItems() : Collections.emptyList(); - - // Create placeholders map with both regular and small caps entity names Map placeholders = new HashMap<>(); placeholders.put("entity", entityTypeName); placeholders.put("ᴇɴᴛɪᴛʏ", entityTypeNameSmallCaps); placeholders.put("exp", String.valueOf(lootConfig != null ? lootConfig.getExperience() : 0)); - - // Sort the loot items for consistent ordering List sortedLootItems = new ArrayList<>(lootItems); - // Sort by material name to ensure consistent order sortedLootItems.sort(Comparator.comparing(item -> item.getMaterial().name())); - // Sort by material name in reverse order (Z to A) - if (!sortedLootItems.isEmpty()) { - // Get the custom loot format from the config String lootFormat = languageManager.getItemName("custom_item.spawner.loot_items", placeholders); - StringBuilder lootItemsBuilder = new StringBuilder(); for (LootItem item : sortedLootItems) { - // Use LanguageManager's cached method String itemName = languageManager.getVanillaItemName(item.getMaterial()); - // Use LanguageManager's small caps method String itemNameSmallCaps = languageManager.getSmallCaps(itemName); - String amountRange = item.getMinAmount() == item.getMaxAmount() ? String.valueOf(item.getMinAmount()) : item.getMinAmount() + "-" + item.getMaxAmount(); String chance = String.format("%.1f", item.getChance()); - - // Create placeholders specific to this item with both regular and small caps versions Map itemPlaceholders = new HashMap<>(placeholders); itemPlaceholders.put("item_name", itemName); itemPlaceholders.put("ɪᴛᴇᴍ_ɴᴀᴍᴇ", itemNameSmallCaps); itemPlaceholders.put("amount", amountRange); itemPlaceholders.put("chance", chance); - - // Apply the custom format for each item using the language manager String formattedItem = languageManager.applyPlaceholdersAndColors(lootFormat, itemPlaceholders); - lootItemsBuilder.append(formattedItem).append("\n"); } - - // Remove the last newline character if (!lootItemsBuilder.isEmpty()) { lootItemsBuilder.setLength(lootItemsBuilder.length() - 1); } placeholders.put("loot_items", lootItemsBuilder.toString()); } else { - // If no loot items, set a default message placeholders.put("loot_items", languageManager.getItemName("custom_item.spawner.loot_items_empty", placeholders)); } - - // Get the localized name and lore using enhanced placeholder system String displayName = languageManager.getItemName("custom_item.spawner.name", placeholders); meta.setDisplayName(displayName); - - // Use our method to handle multi-line placeholders List lore = languageManager.getItemLoreWithMultilinePlaceholders("custom_item.spawner.lore", placeholders); if (lore != null && !lore.isEmpty()) { meta.setLore(lore); } - - // Hide enchants and attributes meta.addItemFlags(ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_UNBREAKABLE); - - // Add hidden tag to identify as smart spawner -// meta.getPersistentDataContainer().set( -// SMART_SPAWNER_KEY, -// PersistentDataType.BOOLEAN, -// true -// ); spawner.setItemMeta(meta); } - - // Cache the item for future use (only for single items) if (amount == 1) { spawnerItemCache.put(entityType, spawner.clone()); cacheTimestamps.put(entityType, System.currentTimeMillis()); - - // Manage cache size if (spawnerItemCache.size() > MAX_CACHE_SIZE) { - // Find oldest entry EntityType oldestEntity = null; long oldestTime = Long.MAX_VALUE; - for (Map.Entry entry : cacheTimestamps.entrySet()) { if (entry.getValue() < oldestTime) { oldestTime = entry.getValue(); oldestEntity = entry.getKey(); } } - - // Remove oldest entry if found if (oldestEntity != null) { spawnerItemCache.remove(oldestEntity); cacheTimestamps.remove(oldestEntity); } } } - Set hiddenComponent = new HashSet<>(); - hiddenComponent.add(RegistryAccess.registryAccess().getRegistry(RegistryKey.DATA_COMPONENT_TYPE).get(DataComponentTypeKeys.BLOCK_ENTITY_DATA)); - spawner.setData(DataComponentTypes.TOOLTIP_DISPLAY, TooltipDisplay.tooltipDisplay().hiddenComponents(hiddenComponent).build()); + hideTooltip(spawner); return spawner; } @@ -251,57 +177,35 @@ public ItemStack createVanillaSpawnerItem(EntityType entityType) { public ItemStack createVanillaSpawnerItem(EntityType entityType, int amount) { ItemStack spawner = new ItemStack(Material.SPAWNER, amount); ItemMeta meta = spawner.getItemMeta(); - if (meta != null && entityType != null && entityType != EntityType.UNKNOWN) { - // Apply block state for the spawner if (meta instanceof BlockStateMeta blockMeta) { BlockState blockState = blockMeta.getBlockState(); - if (blockState instanceof CreatureSpawner cs) { cs.setSpawnedType(entityType); blockMeta.setBlockState(cs); } } - - // Get entity name String entityTypeName = languageManager.getFormattedMobName(entityType); - - // Create placeholders map with entity name Map placeholders = new HashMap<>(); placeholders.put("entity", entityTypeName); placeholders.put("ᴇɴᴛɪᴛʏ", languageManager.getSmallCaps(entityTypeName)); - - // Get vanilla-specific display name from config String displayName = languageManager.getItemName("custom_item.vanilla_spawner.name", placeholders); - - // Only set display name if it's not null or empty if (displayName != null && !displayName.isEmpty() && !displayName.equals("custom_item.vanilla_spawner.name")) { meta.setDisplayName(displayName); } - - // Get vanilla-specific lore from config List lore = languageManager.getItemLoreWithMultilinePlaceholders("custom_item.vanilla_spawner.lore", placeholders); - - // Only set lore if it's not null or empty if (lore != null && !lore.isEmpty()) { meta.setLore(lore); - - // If we have custom lore, then also add the item flags to hide attributes meta.addItemFlags(ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_UNBREAKABLE); } - - // Add hidden tag to identify as vanilla spawner meta.getPersistentDataContainer().set( VANILLA_SPAWNER_KEY, PersistentDataType.BOOLEAN, true ); - spawner.setItemMeta(meta); } - Set hiddenComponent = new HashSet<>(); - hiddenComponent.add(RegistryAccess.registryAccess().getRegistry(RegistryKey.DATA_COMPONENT_TYPE).get(DataComponentTypeKeys.BLOCK_ENTITY_DATA)); - spawner.setData(DataComponentTypes.TOOLTIP_DISPLAY, TooltipDisplay.tooltipDisplay().hiddenComponents(hiddenComponent).build()); + hideTooltip(spawner); return spawner; } } \ No newline at end of file diff --git a/core/src/main/java/github/nighter/smartspawner/spawner/utils/SpawnerMobHeadTexture.java b/core/src/main/java/github/nighter/smartspawner/spawner/utils/SpawnerMobHeadTexture.java index d2e8320d..2b9881fd 100644 --- a/core/src/main/java/github/nighter/smartspawner/spawner/utils/SpawnerMobHeadTexture.java +++ b/core/src/main/java/github/nighter/smartspawner/spawner/utils/SpawnerMobHeadTexture.java @@ -2,6 +2,12 @@ import github.nighter.smartspawner.SmartSpawner; import github.nighter.smartspawner.nms.TextureWrapper; +import io.papermc.paper.datacomponent.DataComponentType; +import io.papermc.paper.datacomponent.DataComponentTypes; +import io.papermc.paper.datacomponent.item.TooltipDisplay; +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.keys.DataComponentTypeKeys; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.entity.EntityType; @@ -16,10 +22,14 @@ import java.net.URL; import java.util.EnumMap; import java.util.Map; +import java.util.Set; import java.util.UUID; public class SpawnerMobHeadTexture { private static final Map HEAD_CACHE = new EnumMap<>(EntityType.class); + private static final Set HIDDEN_TOOLTIP_COMPONENTS = Set.of( + RegistryAccess.registryAccess().getRegistry(RegistryKey.DATA_COMPONENT_TYPE).get(DataComponentTypeKeys.BLOCK_ENTITY_DATA) + ); static { TextureWrapper.initializeCommonTextures(); @@ -34,6 +44,11 @@ private static boolean isBedrockPlayer(Player player) { return plugin.getIntegrationManager().getFloodgateHook().isBedrockPlayer(player); } + private static void hideTooltip(ItemStack item) { + item.setData(DataComponentTypes.TOOLTIP_DISPLAY, + TooltipDisplay.tooltipDisplay().hiddenComponents(HIDDEN_TOOLTIP_COMPONENTS).build()); + } + public static ItemStack getCustomHead(EntityType entityType, Player player) { if (entityType == null) { return createItemStack(Material.SPAWNER); @@ -50,35 +65,27 @@ public static ItemStack getCustomHead(EntityType entityType, Player player) { case PIGLIN, PIGLIN_BRUTE: return new ItemStack(Material.PIGLIN_HEAD); } - if (isBedrockPlayer(player)) { return new ItemStack(Material.SPAWNER); } - if (HEAD_CACHE.containsKey(entityType)) { return HEAD_CACHE.get(entityType).clone(); } - if (!TextureWrapper.hasTexture(entityType)) { return new ItemStack(Material.SPAWNER); } ItemStack head = new ItemStack(Material.PLAYER_HEAD); SkullMeta meta = (SkullMeta) head.getItemMeta(); - try { String texture = TextureWrapper.getTexture(entityType); - PlayerProfile profile = Bukkit.createPlayerProfile(UUID.randomUUID()); PlayerTextures textures = profile.getTextures(); URL url = new URL("http://textures.minecraft.net/texture/" + texture); textures.setSkin(url); profile.setTextures(textures); meta.setOwnerProfile(profile); - head.setItemMeta(meta); - HEAD_CACHE.put(entityType, head.clone()); - return head; } catch (Exception e) { e.printStackTrace(); @@ -102,48 +109,41 @@ public static ItemStack getCustomHead(EntityType entityType) { case PIGLIN, PIGLIN_BRUTE: return new ItemStack(Material.PIGLIN_HEAD); } - if (HEAD_CACHE.containsKey(entityType)) { return HEAD_CACHE.get(entityType).clone(); } - if (!TextureWrapper.hasTexture(entityType)) { return new ItemStack(Material.SPAWNER); } - ItemStack head = new ItemStack(Material.PLAYER_HEAD); SkullMeta meta = (SkullMeta) head.getItemMeta(); - try { String texture = TextureWrapper.getTexture(entityType); - PlayerProfile profile = Bukkit.createPlayerProfile(UUID.randomUUID()); PlayerTextures textures = profile.getTextures(); URL url = new URL("http://textures.minecraft.net/texture/" + texture); textures.setSkin(url); profile.setTextures(textures); meta.setOwnerProfile(profile); - head.setItemMeta(meta); - HEAD_CACHE.put(entityType, head.clone()); - return head; } catch (Exception e) { e.printStackTrace(); - return new ItemStack(Material.SPAWNER); + return createItemStack(Material.SPAWNER); } } public static ItemStack createItemStack(Material material) { ItemStack itemStack = new ItemStack(material); ItemMeta meta = itemStack.getItemMeta(); - meta.addItemFlags(ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_UNBREAKABLE, ItemFlag.HIDE_ADDITIONAL_TOOLTIP); + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_UNBREAKABLE); itemStack.setItemMeta(meta); + hideTooltip(itemStack); return itemStack; } public static void clearCache() { HEAD_CACHE.clear(); } -} +} \ No newline at end of file diff --git a/NMS/build.gradle b/nms/build.gradle similarity index 100% rename from NMS/build.gradle rename to nms/build.gradle diff --git a/NMS/v1_21/build.gradle b/nms/v1_21/build.gradle similarity index 100% rename from NMS/v1_21/build.gradle rename to nms/v1_21/build.gradle diff --git a/NMS/v1_21/src/main/java/github/nighter/smartspawner/v1_21/MaterialInitializer.java b/nms/v1_21/src/main/java/github/nighter/smartspawner/v1_21/MaterialInitializer.java similarity index 100% rename from NMS/v1_21/src/main/java/github/nighter/smartspawner/v1_21/MaterialInitializer.java rename to nms/v1_21/src/main/java/github/nighter/smartspawner/v1_21/MaterialInitializer.java diff --git a/NMS/v1_21/src/main/java/github/nighter/smartspawner/v1_21/ParticleInitializer.java b/nms/v1_21/src/main/java/github/nighter/smartspawner/v1_21/ParticleInitializer.java similarity index 100% rename from NMS/v1_21/src/main/java/github/nighter/smartspawner/v1_21/ParticleInitializer.java rename to nms/v1_21/src/main/java/github/nighter/smartspawner/v1_21/ParticleInitializer.java diff --git a/NMS/v1_21/src/main/java/github/nighter/smartspawner/v1_21/SpawnerInitializer.java b/nms/v1_21/src/main/java/github/nighter/smartspawner/v1_21/SpawnerInitializer.java similarity index 100% rename from NMS/v1_21/src/main/java/github/nighter/smartspawner/v1_21/SpawnerInitializer.java rename to nms/v1_21/src/main/java/github/nighter/smartspawner/v1_21/SpawnerInitializer.java diff --git a/NMS/v1_21/src/main/java/github/nighter/smartspawner/v1_21/TextureInitializer.java b/nms/v1_21/src/main/java/github/nighter/smartspawner/v1_21/TextureInitializer.java similarity index 100% rename from NMS/v1_21/src/main/java/github/nighter/smartspawner/v1_21/TextureInitializer.java rename to nms/v1_21/src/main/java/github/nighter/smartspawner/v1_21/TextureInitializer.java diff --git a/NMS/v1_21_4/build.gradle b/nms/v1_21_4/build.gradle similarity index 100% rename from NMS/v1_21_4/build.gradle rename to nms/v1_21_4/build.gradle diff --git a/NMS/v1_21_4/src/main/java/github/nighter/smartspawner/v1_21_4/MaterialInitializer.java b/nms/v1_21_4/src/main/java/github/nighter/smartspawner/v1_21_4/MaterialInitializer.java similarity index 100% rename from NMS/v1_21_4/src/main/java/github/nighter/smartspawner/v1_21_4/MaterialInitializer.java rename to nms/v1_21_4/src/main/java/github/nighter/smartspawner/v1_21_4/MaterialInitializer.java diff --git a/NMS/v1_21_4/src/main/java/github/nighter/smartspawner/v1_21_4/ParticleInitializer.java b/nms/v1_21_4/src/main/java/github/nighter/smartspawner/v1_21_4/ParticleInitializer.java similarity index 100% rename from NMS/v1_21_4/src/main/java/github/nighter/smartspawner/v1_21_4/ParticleInitializer.java rename to nms/v1_21_4/src/main/java/github/nighter/smartspawner/v1_21_4/ParticleInitializer.java diff --git a/NMS/v1_21_4/src/main/java/github/nighter/smartspawner/v1_21_4/SpawnerInitializer.java b/nms/v1_21_4/src/main/java/github/nighter/smartspawner/v1_21_4/SpawnerInitializer.java similarity index 100% rename from NMS/v1_21_4/src/main/java/github/nighter/smartspawner/v1_21_4/SpawnerInitializer.java rename to nms/v1_21_4/src/main/java/github/nighter/smartspawner/v1_21_4/SpawnerInitializer.java diff --git a/NMS/v1_21_4/src/main/java/github/nighter/smartspawner/v1_21_4/TextureInitializer.java b/nms/v1_21_4/src/main/java/github/nighter/smartspawner/v1_21_4/TextureInitializer.java similarity index 100% rename from NMS/v1_21_4/src/main/java/github/nighter/smartspawner/v1_21_4/TextureInitializer.java rename to nms/v1_21_4/src/main/java/github/nighter/smartspawner/v1_21_4/TextureInitializer.java diff --git a/NMS/v1_21_6/build.gradle b/nms/v1_21_6/build.gradle similarity index 100% rename from NMS/v1_21_6/build.gradle rename to nms/v1_21_6/build.gradle diff --git a/NMS/v1_21_6/src/main/java/github/nighter/smartspawner/v1_21_6/MaterialInitializer.java b/nms/v1_21_6/src/main/java/github/nighter/smartspawner/v1_21_6/MaterialInitializer.java similarity index 100% rename from NMS/v1_21_6/src/main/java/github/nighter/smartspawner/v1_21_6/MaterialInitializer.java rename to nms/v1_21_6/src/main/java/github/nighter/smartspawner/v1_21_6/MaterialInitializer.java diff --git a/NMS/v1_21_6/src/main/java/github/nighter/smartspawner/v1_21_6/ParticleInitializer.java b/nms/v1_21_6/src/main/java/github/nighter/smartspawner/v1_21_6/ParticleInitializer.java similarity index 100% rename from NMS/v1_21_6/src/main/java/github/nighter/smartspawner/v1_21_6/ParticleInitializer.java rename to nms/v1_21_6/src/main/java/github/nighter/smartspawner/v1_21_6/ParticleInitializer.java diff --git a/NMS/v1_21_6/src/main/java/github/nighter/smartspawner/v1_21_6/SpawnerInitializer.java b/nms/v1_21_6/src/main/java/github/nighter/smartspawner/v1_21_6/SpawnerInitializer.java similarity index 100% rename from NMS/v1_21_6/src/main/java/github/nighter/smartspawner/v1_21_6/SpawnerInitializer.java rename to nms/v1_21_6/src/main/java/github/nighter/smartspawner/v1_21_6/SpawnerInitializer.java diff --git a/NMS/v1_21_6/src/main/java/github/nighter/smartspawner/v1_21_6/TextureInitializer.java b/nms/v1_21_6/src/main/java/github/nighter/smartspawner/v1_21_6/TextureInitializer.java similarity index 100% rename from NMS/v1_21_6/src/main/java/github/nighter/smartspawner/v1_21_6/TextureInitializer.java rename to nms/v1_21_6/src/main/java/github/nighter/smartspawner/v1_21_6/TextureInitializer.java diff --git a/settings.gradle b/settings.gradle index 8cbf2fcb..daddbe00 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,6 @@ rootProject.name = 'SmartSpawner' include 'core' include 'api' -include 'NMS:v1_21' -include 'NMS:v1_21_4' -include 'NMS:v1_21_6' \ No newline at end of file +include 'nms:v1_21' +include 'nms:v1_21_4' +include 'nms:v1_21_6' \ No newline at end of file