From aad12c2f6af09919772fdc7dfe8ede0b93f62d6e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 09:04:15 +0000 Subject: [PATCH 1/3] Initial plan From db6928d0fbce70776c34dce4400b0444c20efdcc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 09:08:46 +0000 Subject: [PATCH 2/3] Remove spawn cycle skip behavior during stack updates Changed tryLock() to lock() in two locations: 1. When acquiring dataLock to read spawn timing (line 109) 2. When re-acquiring lootGenerationLock for update phase (line 168) This ensures spawn/loot cycles continue even when spawner stack is being updated, instead of skipping the cycle. Co-authored-by: ptthanh02 <73684260+ptthanh02@users.noreply.github.com> --- .../spawner/lootgen/SpawnerLootGenerator.java | 22 ++++--------------- 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/core/src/main/java/github/nighter/smartspawner/spawner/lootgen/SpawnerLootGenerator.java b/core/src/main/java/github/nighter/smartspawner/spawner/lootgen/SpawnerLootGenerator.java index 2abbc756..139a80c0 100644 --- a/core/src/main/java/github/nighter/smartspawner/spawner/lootgen/SpawnerLootGenerator.java +++ b/core/src/main/java/github/nighter/smartspawner/spawner/lootgen/SpawnerLootGenerator.java @@ -105,19 +105,8 @@ public void spawnLootToSpawner(SpawnerData spawner) { try { // Acquire dataLock to safely read spawn timing and configuration values - // Use tryLock with short timeout to avoid blocking - boolean dataLockAcquired = false; - try { - dataLockAcquired = spawner.getDataLock().tryLock(50, java.util.concurrent.TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return; - } - - if (!dataLockAcquired) { - // dataLock is held (likely stack size change), skip this cycle - return; - } + // Wait for the lock instead of skipping to ensure spawn cycles continue even during stack updates + spawner.getDataLock().lock(); // Declare variables outside the try block so they're accessible in the async lambda final long currentTime = System.currentTimeMillis(); @@ -175,11 +164,8 @@ public void spawnLootToSpawner(SpawnerData spawner) { // Re-acquire the lock for the update phase // This ensures the spawner hasn't been modified (like stack size changes) // between our async calculations and now - boolean updateLockAcquired = spawner.getLootGenerationLock().tryLock(); - if (!updateLockAcquired) { - // Lock is held, stack size is changing, skip this update - return; - } + // Wait for the lock instead of skipping to ensure loot is applied + spawner.getLootGenerationLock().lock(); try { // Modified approach: Handle items and exp separately From d83de63dbc5e882e345ad25ae9340bb1c6531c0f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Nov 2025 09:22:37 +0000 Subject: [PATCH 3/3] Improve timer sync by using 500ms timeout instead of blocking lock Changed from blocking lock() to tryLock(500ms) to maintain better timer synchronization with SpawnerGuiViewManager while still waiting for stack updates to complete. This prevents indefinite blocking that could cause timer display issues. Co-authored-by: ptthanh02 <73684260+ptthanh02@users.noreply.github.com> --- .../spawner/lootgen/SpawnerLootGenerator.java | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/github/nighter/smartspawner/spawner/lootgen/SpawnerLootGenerator.java b/core/src/main/java/github/nighter/smartspawner/spawner/lootgen/SpawnerLootGenerator.java index 139a80c0..166bea72 100644 --- a/core/src/main/java/github/nighter/smartspawner/spawner/lootgen/SpawnerLootGenerator.java +++ b/core/src/main/java/github/nighter/smartspawner/spawner/lootgen/SpawnerLootGenerator.java @@ -105,8 +105,19 @@ public void spawnLootToSpawner(SpawnerData spawner) { try { // Acquire dataLock to safely read spawn timing and configuration values - // Wait for the lock instead of skipping to ensure spawn cycles continue even during stack updates - spawner.getDataLock().lock(); + // Use longer timeout to wait for stack updates while maintaining timer sync + boolean dataLockAcquired = false; + try { + dataLockAcquired = spawner.getDataLock().tryLock(500, java.util.concurrent.TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return; + } + + if (!dataLockAcquired) { + // dataLock still held after timeout, skip this cycle to avoid blocking + return; + } // Declare variables outside the try block so they're accessible in the async lambda final long currentTime = System.currentTimeMillis(); @@ -164,8 +175,19 @@ public void spawnLootToSpawner(SpawnerData spawner) { // Re-acquire the lock for the update phase // This ensures the spawner hasn't been modified (like stack size changes) // between our async calculations and now - // Wait for the lock instead of skipping to ensure loot is applied - spawner.getLootGenerationLock().lock(); + // Use longer timeout to wait for concurrent operations while avoiding indefinite blocking + boolean updateLockAcquired = false; + try { + updateLockAcquired = spawner.getLootGenerationLock().tryLock(500, java.util.concurrent.TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return; + } + + if (!updateLockAcquired) { + // Lock still held after timeout, skip this update to avoid blocking main thread + return; + } try { // Modified approach: Handle items and exp separately