Skip to content
This repository was archived by the owner on Nov 20, 2025. It is now read-only.

Commit e9a11d9

Browse files
committed
Add debounce support for sync and async tasks
1 parent 95cc589 commit e9a11d9

1 file changed

Lines changed: 48 additions & 8 deletions

File tree

src/main/java/net/opmasterleo/combat/util/SchedulerUtil.java

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,16 @@ public final class SchedulerUtil {
4444
private static final ThreadPoolManager THREAD_POOL = new ThreadPoolManager();
4545
private static final AtomicInteger activeAsyncTasks = new AtomicInteger(0);
4646
private static final int MAX_CONCURRENT_ASYNC_TASKS = Math.max(4, AVAILABLE_PROCESSORS);
47+
private static final ConcurrentHashMap<String, BukkitTask> SYNC_DEBOUNCE = new ConcurrentHashMap<>();
48+
private static final ConcurrentHashMap<String, java.util.concurrent.ScheduledFuture<?>> ASYNC_DEBOUNCE = new ConcurrentHashMap<>();
49+
private static final java.util.concurrent.ScheduledThreadPoolExecutor SCHEDULED_EXECUTOR = new java.util.concurrent.ScheduledThreadPoolExecutor(1, r -> {
50+
Thread t = new Thread(r, "MasterCombat-Scheduler");
51+
t.setDaemon(true);
52+
return t;
53+
});
4754

4855
static {
56+
SCHEDULED_EXECUTOR.setRemoveOnCancelPolicy(true);
4957
scheduleCleanupTask();
5058
}
5159

@@ -138,6 +146,11 @@ public static void setShuttingDown(boolean shuttingDown) {
138146
isShuttingDown.set(shuttingDown);
139147
if (shuttingDown) {
140148
THREAD_POOL.shutdown();
149+
SCHEDULED_EXECUTOR.shutdownNow();
150+
SYNC_DEBOUNCE.values().forEach(task -> { try { if (task != null && !task.isCancelled()) task.cancel(); } catch (Exception ignored) {} });
151+
SYNC_DEBOUNCE.clear();
152+
ASYNC_DEBOUNCE.values().forEach(f -> { try { if (f != null) f.cancel(false); } catch (Exception ignored) {} });
153+
ASYNC_DEBOUNCE.clear();
141154
}
142155
}
143156

@@ -152,6 +165,41 @@ public static void cancelAllTasks(Plugin plugin) {
152165
});
153166
}
154167

168+
public static void debounceSync(Plugin plugin, String key, Runnable task, long delayTicks) {
169+
if (shouldSkip(plugin)) return;
170+
BukkitTask existing = SYNC_DEBOUNCE.remove(key);
171+
if (existing != null) {
172+
try { existing.cancel(); } catch (Exception ignored) {}
173+
}
174+
Runnable wrapped = wrapTask(() -> {
175+
try { task.run(); } finally { SYNC_DEBOUNCE.remove(key); }
176+
}, plugin, "debounce-sync");
177+
BukkitTask newTask;
178+
if (IS_ARCLIGHT) {
179+
newTask = Bukkit.getScheduler().runTaskLater(plugin, wrapArclightTask(wrapped), delayTicks);
180+
} else {
181+
newTask = Bukkit.getScheduler().runTaskLater(plugin, wrapped, delayTicks);
182+
}
183+
SYNC_DEBOUNCE.put(key, newTask);
184+
}
185+
186+
public static void debounceAsync(Plugin plugin, String key, Runnable task, long delayTicks) {
187+
if (shouldSkip(plugin)) return;
188+
java.util.concurrent.ScheduledFuture<?> prev = ASYNC_DEBOUNCE.remove(key);
189+
if (prev != null) {
190+
try { prev.cancel(false); } catch (Exception ignored) {}
191+
}
192+
long delayMs = Math.max(0L, delayTicks * 50L);
193+
java.util.concurrent.ScheduledFuture<?> future = SCHEDULED_EXECUTOR.schedule(() -> {
194+
try {
195+
runTaskAsync(plugin, task);
196+
} finally {
197+
ASYNC_DEBOUNCE.remove(key);
198+
}
199+
}, delayMs, TimeUnit.MILLISECONDS);
200+
ASYNC_DEBOUNCE.put(key, future);
201+
}
202+
155203
private static boolean shouldSkip(Plugin plugin) {
156204
return isShuttingDown.get() || plugin == null || !plugin.isEnabled();
157205
}
@@ -257,11 +305,9 @@ public static BukkitTask runTask(Plugin plugin, Runnable task) {
257305
return null;
258306
} else if (IS_ARCLIGHT) {
259307
BukkitTask bukkitTask = Bukkit.getScheduler().runTask(plugin, wrapArclightTask(wrapped));
260-
trackTask(bukkitTask);
261308
return bukkitTask;
262309
} else {
263310
BukkitTask bukkitTask = Bukkit.getScheduler().runTask(plugin, wrapped);
264-
trackTask(bukkitTask);
265311
return bukkitTask;
266312
}
267313
}
@@ -288,11 +334,9 @@ public static BukkitTask runTaskAsync(Plugin plugin, Runnable task) {
288334
return null;
289335
} else if (IS_ARCLIGHT) {
290336
BukkitTask bukkitTask = Bukkit.getScheduler().runTaskAsynchronously(plugin, wrapArclightAsyncTask(wrapped));
291-
trackTask(bukkitTask);
292337
return bukkitTask;
293338
} else {
294339
BukkitTask bukkitTask = Bukkit.getScheduler().runTaskAsynchronously(plugin, wrapped);
295-
trackTask(bukkitTask);
296340
return bukkitTask;
297341
}
298342
}
@@ -307,11 +351,9 @@ public static BukkitTask runTaskLater(Plugin plugin, Runnable task, long delay)
307351
return null;
308352
} else if (IS_ARCLIGHT) {
309353
BukkitTask bukkitTask = Bukkit.getScheduler().runTaskLater(plugin, wrapArclightTask(wrapped), delay);
310-
trackTask(bukkitTask);
311354
return bukkitTask;
312355
} else {
313356
BukkitTask bukkitTask = Bukkit.getScheduler().runTaskLater(plugin, wrapped, delay);
314-
trackTask(bukkitTask);
315357
return bukkitTask;
316358
}
317359
}
@@ -349,11 +391,9 @@ public static BukkitTask runTaskLaterAsync(Plugin plugin, Runnable task, long de
349391
return null;
350392
} else if (IS_ARCLIGHT) {
351393
BukkitTask bukkitTask = Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, wrapArclightAsyncTask(wrapped), delay);
352-
trackTask(bukkitTask);
353394
return bukkitTask;
354395
} else {
355396
BukkitTask bukkitTask = Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, wrapped, delay);
356-
trackTask(bukkitTask);
357397
return bukkitTask;
358398
}
359399
}

0 commit comments

Comments
 (0)