Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package github.nighter.smartspawner.api.events;

import lombok.Getter;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;

public class SpawnerOpenGUIEvent extends SpawnerEvent implements Cancellable {
@Getter
private final Player player;
@Getter
private final EntityType entityType;
@Getter
private final boolean isRefresh;
private boolean cancelled = false;

private static final HandlerList handlers = new HandlerList();

public SpawnerOpenGUIEvent(Player player, Location location, EntityType entityType, int stackSize, boolean isRefresh) {
super(location, stackSize);
this.player = player;
this.entityType = entityType;
this.isRefresh = isRefresh;
}

@Override
public boolean isCancelled() {
return cancelled;
}

@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}

@Override
public @NotNull HandlerList getHandlers() {
return handlers;
}

public static @NotNull HandlerList getHandlerList() {
return handlers;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,11 @@ public void reload() {
// Clear spawner info slot cache since layout may have changed
spawnerGuiViewManager.clearSlotCache();

// Clear GUI item cache since layout/config may have changed
if (spawnerMenuUI != null) {
spawnerMenuUI.clearCache();
}

spawnerStorageAction.reload();
spawnerStorageUI.reload();
filterConfigUI.reload();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,12 @@ private boolean loadButton(FileConfiguration config, GuiLayout layout, String bu
// Load actions
Map<String, String> actions = new HashMap<>();
ConfigurationSection actionsSection = config.getConfigurationSection(path + ".actions");
if (actionsSection != null) {
if (actionsSection != null && !actionsSection.getKeys(false).isEmpty()) {
for (String actionKey : actionsSection.getKeys(false)) {
actions.put(actionKey, actionsSection.getString(actionKey));
String actionValue = actionsSection.getString(actionKey);
if (actionValue != null && !actionValue.equals("none")) {
actions.put(actionKey, actionValue);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ private boolean handleLayoutAction(Player player, SpawnerData spawner, int slot,
spawnerStackerUI.openStackerGui(player, spawner);
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1.0f, 1.0f);
return true;
case "sell_inventory":
case "sell_and_exp":
if (isClickTooFrequent(player)) {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,14 @@ private List<ButtonInfo> collectAvailableButtons(GuiLayout layout, Player player
buttons.add(new ButtonInfo("open_stacker", text, "https://static.wikia.nocookie.net/minecraft_gamepedia/images/c/cf/Spawner_with_fire.png/revision/latest?cb=20190925003048"));
}

// Check for sell_inventory button (Claim XP and Sell All)
// Check for sell_and_exp button (Claim XP and Sell All)
if (hasShopPermission) {
GuiButton sellInventoryButton = layout.getButton("spawner_info_with_shop");
if (sellInventoryButton != null && sellInventoryButton.isEnabled() &&
sellInventoryButton.getAction("left_click") != null &&
sellInventoryButton.getAction("left_click").equals("sell_inventory")) {
String text = languageManager.getGuiItemName("bedrock_gui.buttons.sell_inventory", placeholders);
buttons.add(new ButtonInfo("sell_inventory", text, "https://img.icons8.com/?size=100&id=12815&format=png&color=FFD700"));
sellInventoryButton.getAction("left_click").equals("sell_and_exp")) {
String text = languageManager.getGuiItemName("bedrock_gui.buttons.sell_and_exp", placeholders);
buttons.add(new ButtonInfo("sell_and_exp", text, "https://img.icons8.com/?size=100&id=12815&format=png&color=FFD700"));
}

// Check for sell_all button (Sell items only)
Expand Down Expand Up @@ -259,7 +259,7 @@ private void handleButtonAction(Player player, SpawnerData spawner, String actio
case "open_stacker":
handleSpawnerInfo(player, spawner);
break;
case "sell_inventory":
case "sell_and_exp":
handleSellInventory(player, spawner);
break;
case "sell_all":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import github.nighter.smartspawner.spawner.properties.SpawnerData;
import github.nighter.smartspawner.spawner.properties.VirtualInventory;
import github.nighter.smartspawner.language.LanguageManager;
import github.nighter.smartspawner.api.events.SpawnerOpenGUIEvent;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Sound;
Expand Down Expand Up @@ -37,6 +38,11 @@ public class SpawnerMenuUI {
private final String lootItemFormat;
private final String emptyLootMessage;

// Cache for GUI items - cleared when spawner data changes
private final Map<String, ItemStack> itemCache = new HashMap<>();
private final Map<String, Long> cacheTimestamps = new HashMap<>();
private static final long CACHE_EXPIRY_TIME_MS = 30000; // 30 seconds

public SpawnerMenuUI(SmartSpawner plugin) {
this.plugin = plugin;
this.languageManager = plugin.getLanguageManager();
Expand All @@ -46,7 +52,36 @@ public SpawnerMenuUI(SmartSpawner plugin) {
this.emptyLootMessage = languageManager.getGuiItemName(EMPTY_LOOT_MESSAGE_KEY, EMPTY_PLACEHOLDERS);
}

public void clearCache() {
itemCache.clear();
cacheTimestamps.clear();
}

public void invalidateSpawnerCache(String spawnerId) {
itemCache.entrySet().removeIf(entry -> entry.getKey().startsWith(spawnerId + "|"));
cacheTimestamps.entrySet().removeIf(entry -> entry.getKey().startsWith(spawnerId + "|"));
}

private boolean isCacheEntryExpired(String cacheKey) {
Long timestamp = cacheTimestamps.get(cacheKey);
return timestamp == null || System.currentTimeMillis() - timestamp > CACHE_EXPIRY_TIME_MS;
}

public void openSpawnerMenu(Player player, SpawnerData spawner, boolean refresh) {
// Fire SpawnerOpenGUI API event
SpawnerOpenGUIEvent openEvent = new SpawnerOpenGUIEvent(
player,
spawner.getSpawnerLocation(),
spawner.getEntityType(),
spawner.getStackSize(),
refresh
);
Bukkit.getPluginManager().callEvent(openEvent);

if (openEvent.isCancelled()) {
return;
}

Inventory menu = createMenu(spawner);
GuiLayout layout = plugin.getGuiLayoutConfig().getCurrentMainLayout();

Expand Down Expand Up @@ -114,10 +149,19 @@ private Inventory createMenu(SpawnerData spawner) {
}

public ItemStack createLootStorageItem(SpawnerData spawner) {
// Get important data upfront
// Generate cache key based on spawner state
VirtualInventory virtualInventory = spawner.getVirtualInventory();
int currentItems = virtualInventory.getUsedSlots();
int maxSlots = spawner.getMaxSpawnerLootSlots();
String cacheKey = spawner.getSpawnerId() + "|storage|" + currentItems + "|" + maxSlots + "|" + virtualInventory.hashCode();

// Check cache first
ItemStack cachedItem = itemCache.get(cacheKey);
if (cachedItem != null && !isCacheEntryExpired(cacheKey)) {
return cachedItem.clone();
}

// Get important data upfront
int percentStorage = calculatePercentage(currentItems, maxSlots);

// Not in cache, create new item
Expand Down Expand Up @@ -146,6 +190,10 @@ public ItemStack createLootStorageItem(SpawnerData spawner) {
chestMeta.setLore(lore);
chestItem.setItemMeta(chestMeta);

// Cache the result
itemCache.put(cacheKey, chestItem.clone());
cacheTimestamps.put(cacheKey, System.currentTimeMillis());

return chestItem;
}

Expand Down Expand Up @@ -333,6 +381,12 @@ public ItemStack createExpItem(SpawnerData spawner) {
// Create cache key for this specific spawner's exp state
String cacheKey = spawner.getSpawnerId() + "|exp|" + currentExp + "|" + maxExp;

// Check cache first
ItemStack cachedItem = itemCache.get(cacheKey);
if (cachedItem != null && !isCacheEntryExpired(cacheKey)) {
return cachedItem.clone();
}

// Not in cache, create the ItemStack
ItemStack expItem = new ItemStack(Material.EXPERIENCE_BOTTLE);
ItemMeta expMeta = expItem.getItemMeta();
Expand All @@ -357,6 +411,10 @@ public ItemStack createExpItem(SpawnerData spawner) {

expItem.setItemMeta(expMeta);

// Cache the result
itemCache.put(cacheKey, expItem.clone());
cacheTimestamps.put(cacheKey, System.currentTimeMillis());

return expItem;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,11 @@ public void updateSpawnerMenuViewers(SpawnerData spawner) {
Set<UUID> viewers = spawnerToPlayersMap.get(spawner.getSpawnerId());
if (viewers == null || viewers.isEmpty()) return;

// Invalidate cache for this spawner
if (plugin.getSpawnerMenuUI() != null) {
plugin.getSpawnerMenuUI().invalidateSpawnerCache(spawner.getSpawnerId());
}

int viewerCount = viewers.size();
if (viewerCount > 10) {
plugin.debug(viewerCount + " spawner menu viewers to update for " + spawner.getSpawnerId() + " (batch update)");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@ public void recalculateAfterConfigReload() {
recreateVirtualInventory();
}
updateHologramData();

// Invalidate GUI cache after config reload
if (plugin.getSpawnerMenuUI() != null) {
plugin.getSpawnerMenuUI().invalidateSpawnerCache(this.spawnerId);
}
}

private void calculateStackBasedValues() {
Expand Down Expand Up @@ -195,6 +200,11 @@ private void updateStackSize(int newStackSize) {

this.lastSpawnTime = System.currentTimeMillis();
updateHologramData();

// Invalidate GUI cache when stack size changes
if (plugin.getSpawnerMenuUI() != null) {
plugin.getSpawnerMenuUI().invalidateSpawnerCache(this.spawnerId);
}
}

private void recreateVirtualInventory() {
Expand Down Expand Up @@ -227,6 +237,11 @@ private void transferItemsToNewInventory(Map<VirtualInventory.ItemSignature, Lon
public void setSpawnerExp(int exp) {
this.spawnerExp = Math.min(Math.max(0, exp), maxStoredExp);
updateHologramData();

// Invalidate GUI cache when experience changes
if (plugin.getSpawnerMenuUI() != null) {
plugin.getSpawnerMenuUI().invalidateSpawnerCache(this.spawnerId);
}
}

public void setSpawnerExpData(int exp) {
Expand Down