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
Expand Up @@ -371,6 +371,10 @@ public SpawnerStorageUI getSpawnerStorageUI() {
return spawnerStorageUI;
}

public FilterConfigUI getFilterConfigUI() {
return filterConfigUI;
}

public GuiLayoutConfig getGuiLayoutConfig() {
return guiLayoutConfig;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import github.nighter.smartspawner.SmartSpawner;
import github.nighter.smartspawner.spawner.gui.main.SpawnerMenuHolder;
import github.nighter.smartspawner.spawner.gui.storage.StoragePageHolder;
import github.nighter.smartspawner.spawner.gui.storage.filter.FilterConfigHolder;
import github.nighter.smartspawner.spawner.gui.main.SpawnerMenuUI;
import github.nighter.smartspawner.spawner.gui.storage.SpawnerStorageUI;
import github.nighter.smartspawner.spawner.gui.layout.GuiLayout;
Expand Down Expand Up @@ -63,6 +64,9 @@ public class SpawnerGuiViewManager implements Listener {
private final Map<UUID, SpawnerViewerInfo> playerToSpawnerMap;
private final Map<String, Set<UUID>> spawnerToPlayersMap;
private final Set<Class<? extends InventoryHolder>> validHolderTypes;

// Additional tracking for filter GUI viewers to prevent duplication exploits
private final Map<String, Set<UUID>> spawnerToFilterViewersMap;

// NEW: Separate tracking for main menu viewers only (for timer updates)
private final Map<UUID, SpawnerViewerInfo> mainMenuViewers = new ConcurrentHashMap<>();
Expand Down Expand Up @@ -102,7 +106,8 @@ private static class SpawnerViewerInfo {
// Enum to track different viewer types
private enum ViewerType {
MAIN_MENU, // SpawnerMenuHolder - needs timer updates
STORAGE // StoragePageHolder - no timer updates needed
STORAGE, // StoragePageHolder - no timer updates needed
FILTER // FilterConfigHolder - no timer updates needed
}

public SpawnerGuiViewManager(SmartSpawner plugin) {
Expand All @@ -112,10 +117,12 @@ public SpawnerGuiViewManager(SmartSpawner plugin) {
this.spawnerMenuUI = plugin.getSpawnerMenuUI();
this.playerToSpawnerMap = new ConcurrentHashMap<>();
this.spawnerToPlayersMap = new ConcurrentHashMap<>();
this.spawnerToFilterViewersMap = new ConcurrentHashMap<>();
this.isTaskRunning = false;
this.validHolderTypes = Set.of(
SpawnerMenuHolder.class,
StoragePageHolder.class
StoragePageHolder.class,
FilterConfigHolder.class
);

// Preload commonly used strings to avoid repeated lookups
Expand Down Expand Up @@ -257,6 +264,12 @@ public void trackViewer(UUID playerId, SpawnerData spawner, ViewerType viewerTyp
spawnerToMainMenuViewers.computeIfAbsent(spawner.getSpawnerId(), k -> ConcurrentHashMap.newKeySet())
.add(playerId);
}

// Separately track filter GUI viewers to prevent duplication exploits
if (viewerType == ViewerType.FILTER) {
spawnerToFilterViewersMap.computeIfAbsent(spawner.getSpawnerId(), k -> ConcurrentHashMap.newKeySet())
.add(playerId);
}

// Start update task if we have any viewers (for pending updates processing)
if (!isTaskRunning && !playerToSpawnerMap.isEmpty()) {
Expand Down Expand Up @@ -295,6 +308,18 @@ public void untrackViewer(UUID playerId) {
}
}
}

// Also remove from filter viewer tracking if present
if (info != null) {
String spawnerId = info.spawnerData.getSpawnerId();
Set<UUID> filterViewers = spawnerToFilterViewersMap.get(spawnerId);
if (filterViewers != null) {
filterViewers.remove(playerId);
if (filterViewers.isEmpty()) {
spawnerToFilterViewersMap.remove(spawnerId);
}
}
}

// Also remove from pending updates and performance tracking
pendingUpdates.remove(playerId);
Expand Down Expand Up @@ -335,6 +360,7 @@ public void clearAllTrackedGuis() {
spawnerToPlayersMap.clear();
mainMenuViewers.clear();
spawnerToMainMenuViewers.clear();
spawnerToFilterViewersMap.clear();
pendingUpdates.clear();
updateFlags.clear();
lastTimerUpdate.clear();
Expand Down Expand Up @@ -437,6 +463,9 @@ public void onInventoryOpen(InventoryOpenEvent event) {
} else if (holder instanceof StoragePageHolder storageHolder) {
spawnerData = storageHolder.getSpawnerData();
viewerType = ViewerType.STORAGE;
} else if (holder instanceof FilterConfigHolder filterHolder) {
spawnerData = filterHolder.getSpawnerData();
viewerType = ViewerType.FILTER;
}

if (spawnerData != null && viewerType != null) {
Expand Down Expand Up @@ -1347,6 +1376,25 @@ public void closeAllViewersInventory(SpawnerData spawner) {
}
}
}

// Force close filter GUI viewers to prevent duplication exploits
Set<UUID> filterViewers = spawnerToFilterViewersMap.get(spawnerId);
if (filterViewers != null && !filterViewers.isEmpty()) {
// Create a copy to avoid concurrent modification
Set<UUID> filterViewersCopy = new HashSet<>(filterViewers);
for (UUID viewerId : filterViewersCopy) {
Player viewer = Bukkit.getPlayer(viewerId);
if (viewer != null && viewer.isOnline()) {
// Check if they actually have a filter GUI open for this spawner
Inventory openInventory = viewer.getOpenInventory().getTopInventory();
if (openInventory != null && openInventory.getHolder(false) instanceof FilterConfigHolder filterHolder) {
if (filterHolder.getSpawnerData().getSpawnerId().equals(spawnerId)) {
viewer.closeInventory();
}
}
}
}
}

// Check for stacker viewers if that functionality exists
if (plugin.getSpawnerStackerHandler() != null) {
Expand Down