From eb695414e3e1664d691ab4a6e69c92b2e796839d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 04:16:24 +0000 Subject: [PATCH 1/2] Initial plan From 9dc3ec13ca7b33482e82b338917924c6d0f63d81 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 04:21:23 +0000 Subject: [PATCH 2/2] Optimize hopper restart during spawner loading Co-authored-by: ptthanh02 <73684260+ptthanh02@users.noreply.github.com> --- .../spawner/data/SpawnerFileHandler.java | 14 +++++++++----- .../spawner/data/WorldEventHandler.java | 13 +++++++++++++ .../spawner/properties/SpawnerData.java | 11 ++++++++--- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/github/nighter/smartspawner/spawner/data/SpawnerFileHandler.java b/core/src/main/java/github/nighter/smartspawner/spawner/data/SpawnerFileHandler.java index ae28dfe0..87339b13 100644 --- a/core/src/main/java/github/nighter/smartspawner/spawner/data/SpawnerFileHandler.java +++ b/core/src/main/java/github/nighter/smartspawner/spawner/data/SpawnerFileHandler.java @@ -234,8 +234,8 @@ public Map loadAllSpawnersRaw() { for (String spawnerId : spawnersSection.getKeys(false)) { try { - // Use non-logging version to suppress "World not found" errors during startup - SpawnerData spawner = loadSpawnerFromConfig(spawnerId, false); + // Use non-logging version and skip hopper restart during batch load + SpawnerData spawner = loadSpawnerFromConfig(spawnerId, false, false); // Add to map even if null (world not loaded) loadedSpawners.put(spawnerId, spawner); } catch (Exception e) { @@ -266,10 +266,14 @@ public String getRawLocationString(String spawnerId) { } private SpawnerData loadSpawnerFromConfig(String spawnerId) { - return loadSpawnerFromConfig(spawnerId, true); + return loadSpawnerFromConfig(spawnerId, true, true); } private SpawnerData loadSpawnerFromConfig(String spawnerId, boolean logErrors) { + return loadSpawnerFromConfig(spawnerId, logErrors, true); + } + + private SpawnerData loadSpawnerFromConfig(String spawnerId, boolean logErrors, boolean restartHopper) { String path = "spawners." + spawnerId; String locationString = spawnerData.getString(path + ".location"); @@ -341,7 +345,7 @@ private SpawnerData loadSpawnerFromConfig(String spawnerId, boolean logErrors) { spawner.setMaxStoredExp(Integer.parseInt(settings[6])); spawner.setMinMobs(Integer.parseInt(settings[7])); spawner.setMaxMobs(Integer.parseInt(settings[8])); - spawner.setStackSize(Integer.parseInt(settings[9])); + spawner.setStackSize(Integer.parseInt(settings[9]), restartHopper); spawner.setMaxStackSize(Integer.parseInt(settings[10])); spawner.setLastSpawnTime(Long.parseLong(settings[11])); spawner.setIsAtCapacity(Boolean.parseBoolean(settings[12])); @@ -356,7 +360,7 @@ private SpawnerData loadSpawnerFromConfig(String spawnerId, boolean logErrors) { spawner.setMaxStoredExp(Integer.parseInt(settings[6])); spawner.setMinMobs(Integer.parseInt(settings[7])); spawner.setMaxMobs(Integer.parseInt(settings[8])); - spawner.setStackSize(Integer.parseInt(settings[9])); + spawner.setStackSize(Integer.parseInt(settings[9]), restartHopper); spawner.setLastSpawnTime(Long.parseLong(settings[10])); spawner.setIsAtCapacity(false); } diff --git a/core/src/main/java/github/nighter/smartspawner/spawner/data/WorldEventHandler.java b/core/src/main/java/github/nighter/smartspawner/spawner/data/WorldEventHandler.java index 22984c6f..d934414e 100644 --- a/core/src/main/java/github/nighter/smartspawner/spawner/data/WorldEventHandler.java +++ b/core/src/main/java/github/nighter/smartspawner/spawner/data/WorldEventHandler.java @@ -149,6 +149,13 @@ public void attemptInitialSpawnerLoad() { // Initialize chunk spawner limits after spawners are loaded plugin.getChunkSpawnerLimiter().reloadConfig(); + + // Restart all hoppers after batch loading is complete + // This is more efficient than restarting hopper for each spawner individually + if (loadedCount > 0 && plugin.getHopperHandler() != null) { + plugin.getHopperHandler().restartAllHoppers(); + plugin.debug("Restarted all hoppers after batch spawner load"); + } } /** @@ -185,6 +192,12 @@ private void loadPendingSpawnersForWorld(String worldName) { // Reinitialize chunk spawner limits after loading pending spawners plugin.getChunkSpawnerLimiter().reloadConfig(); + + // Restart hoppers for the spawners in this world + if (plugin.getHopperHandler() != null) { + plugin.getHopperHandler().restartAllHoppers(); + plugin.debug("Restarted hoppers after loading pending spawners for world: " + worldName); + } } } diff --git a/core/src/main/java/github/nighter/smartspawner/spawner/properties/SpawnerData.java b/core/src/main/java/github/nighter/smartspawner/spawner/properties/SpawnerData.java index 407ee1be..6f7a39d3 100644 --- a/core/src/main/java/github/nighter/smartspawner/spawner/properties/SpawnerData.java +++ b/core/src/main/java/github/nighter/smartspawner/spawner/properties/SpawnerData.java @@ -198,6 +198,10 @@ private void createHologram() { } public void setStackSize(int stackSize) { + setStackSize(stackSize, true); + } + + public void setStackSize(int stackSize, boolean restartHopper) { // Acquire locks in consistent order to prevent deadlocks: // 1. dataLock - for metadata changes // 2. inventoryLock - to prevent inventory operations during virtual inventory replacement @@ -206,7 +210,7 @@ public void setStackSize(int stackSize) { try { inventoryLock.lock(); try { - updateStackSize(stackSize); + updateStackSize(stackSize, restartHopper); } finally { inventoryLock.unlock(); } @@ -215,7 +219,7 @@ public void setStackSize(int stackSize) { } } - private void updateStackSize(int newStackSize) { + private void updateStackSize(int newStackSize, boolean restartHopper) { if (newStackSize <= 0) { this.stackSize = 1; plugin.getLogger().warning("Invalid stack size. Setting to 1"); @@ -251,7 +255,8 @@ private void updateStackSize(int newStackSize) { // Restart hopper task if hopper integration is enabled // This ensures hopper continues to work after stack size changes - if (plugin.getHopperHandler() != null) { + // Skip during batch loading to avoid performance bottleneck + if (restartHopper && plugin.getHopperHandler() != null) { plugin.getHopperHandler().restartHopperForSpawner(this.spawnerLocation); } }