Skip to content

Commit 5aea0f8

Browse files
Merge pull request #36 from TechnicallyCoded/dev
Fix SpigotImplementation runAtEntityTimer() & runAtEntityLater() & minor cleanups
2 parents 0f76d84 + 298050b commit 5aea0f8

File tree

3 files changed

+74
-13
lines changed

3 files changed

+74
-13
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.tcoded.folialib.type;
2+
3+
public class Ref<T> {
4+
5+
private T value;
6+
7+
public Ref() {
8+
this.value = null;
9+
}
10+
11+
public Ref(T value) {
12+
this.value = value;
13+
}
14+
15+
public T get() {
16+
return value;
17+
}
18+
19+
public void set(T value) {
20+
this.value = value;
21+
}
22+
23+
}

platform/folia/src/main/java/com/tcoded/folialib/impl/FoliaImplementation.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.tcoded.folialib.wrapper.task.WrappedTask;
99
import io.papermc.paper.threadedregions.scheduler.AsyncScheduler;
1010
import io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler;
11+
import io.papermc.paper.threadedregions.scheduler.RegionScheduler;
1112
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
1213
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
1314
import org.bukkit.Location;
@@ -35,11 +36,13 @@ public class FoliaImplementation implements PlatformScheduler {
3536

3637
private final Plugin plugin;
3738
private final GlobalRegionScheduler globalRegionScheduler;
39+
private final RegionScheduler regionScheduler;
3840
private final AsyncScheduler asyncScheduler;
3941

4042
public FoliaImplementation(FoliaLib foliaLib) {
4143
this.plugin = foliaLib.getPlugin();
4244
this.globalRegionScheduler = plugin.getServer().getGlobalRegionScheduler();
45+
this.regionScheduler = plugin.getServer().getRegionScheduler();
4346
this.asyncScheduler = plugin.getServer().getAsyncScheduler();
4447
}
4548

@@ -234,7 +237,7 @@ public void runTimerAsync(@NotNull Consumer<WrappedTask> consumer, long delay, l
234237
public @NotNull CompletableFuture<Void> runAtLocation(Location location, @NotNull Consumer<WrappedTask> consumer) {
235238
CompletableFuture<Void> future = new CompletableFuture<>();
236239

237-
this.plugin.getServer().getRegionScheduler().run(plugin, location, task -> {
240+
this.regionScheduler.run(plugin, location, task -> {
238241
consumer.accept(this.wrapTask(task));
239242
future.complete(null);
240243
});
@@ -249,7 +252,7 @@ public WrappedTask runAtLocationLater(Location location, @NotNull Runnable runna
249252
delay = 1;
250253
}
251254
return this.wrapTask(
252-
this.plugin.getServer().getRegionScheduler().runDelayed(plugin, location, task -> runnable.run(), delay)
255+
this.regionScheduler.runDelayed(plugin, location, task -> runnable.run(), delay)
253256
);
254257
}
255258

@@ -261,7 +264,7 @@ public WrappedTask runAtLocationLater(Location location, @NotNull Runnable runna
261264
InvalidTickDelayNotifier.notifyOnce(plugin.getLogger(), delay);
262265
delay = 1;
263266
}
264-
this.plugin.getServer().getRegionScheduler().runDelayed(plugin, location, task -> {
267+
this.regionScheduler.runDelayed(plugin, location, task -> {
265268
consumer.accept(this.wrapTask(task));
266269
future.complete(null);
267270
}, delay);
@@ -290,7 +293,7 @@ public WrappedTask runAtLocationTimer(Location location, @NotNull Runnable runna
290293
period = 1;
291294
}
292295
return this.wrapTask(
293-
this.plugin.getServer().getRegionScheduler().runAtFixedRate(plugin, location, task -> runnable.run(), delay, period)
296+
this.regionScheduler.runAtFixedRate(plugin, location, task -> runnable.run(), delay, period)
294297
);
295298
}
296299

@@ -304,7 +307,7 @@ public void runAtLocationTimer(Location location, @NotNull Consumer<WrappedTask>
304307
InvalidTickDelayNotifier.notifyOnce(plugin.getLogger(), period);
305308
period = 1;
306309
}
307-
this.plugin.getServer().getRegionScheduler().runAtFixedRate(plugin, location, task -> consumer.accept(this.wrapTask(task)), delay, period);
310+
this.regionScheduler.runAtFixedRate(plugin, location, task -> consumer.accept(this.wrapTask(task)), delay, period);
308311
}
309312

310313
@Override

platform/spigot/src/main/java/com/tcoded/folialib/impl/SpigotImplementation.java

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.tcoded.folialib.FoliaLib;
44
import com.tcoded.folialib.enums.EntityTaskResult;
5+
import com.tcoded.folialib.type.Ref;
56
import com.tcoded.folialib.util.TimeConverter;
67
import com.tcoded.folialib.wrapper.task.WrappedTask;
78
import com.tcoded.folialib.wrapper.task.WrappedBukkitTask;
@@ -289,18 +290,29 @@ public WrappedTask runAtEntityLater(Entity entity, @NotNull Runnable runnable, R
289290
public @NotNull CompletableFuture<Void> runAtEntityLater(Entity entity, @NotNull Consumer<WrappedTask> consumer, @Nullable Runnable fallback, long delay) {
290291
CompletableFuture<Void> future = new CompletableFuture<>();
291292

293+
// Entity is invalid. Complete the future and run the fallback if provided
292294
if (!isValid(entity)) {
295+
future.complete(null);
296+
293297
if (fallback != null) {
294298
fallback.run();
295-
future.complete(null);
296299
}
300+
301+
return future;
297302
}
298-
else {
299-
this.runLater(task -> {
300-
consumer.accept(this.wrapTask(task));
303+
304+
this.runLater(task -> {
305+
// Handle the case where the entity becomes invalid between scheduling and task execution
306+
if (!isValid(entity)) {
307+
if (fallback != null) fallback.run();
301308
future.complete(null);
302-
}, delay);
303-
}
309+
return;
310+
}
311+
312+
// Everything is healthy, run the consumer and complete the future
313+
consumer.accept(task);
314+
future.complete(null);
315+
}, delay);
304316

305317
return future;
306318
}
@@ -326,8 +338,31 @@ public WrappedTask runAtEntityTimer(Entity entity, @NotNull Runnable runnable, @
326338
if (fallback != null) fallback.run();
327339
return null;
328340
}
329-
return this.runTimer(runnable, delay, period);
330-
// return this.wrapTask(this.scheduler.runTaskTimer(plugin, runnable, delay, period)); // todo: remove old
341+
342+
// This is called a magic trick...
343+
// Close your eyes!
344+
Ref<WrappedTask> wtRef = new Ref<>();
345+
346+
WrappedTask task = this.runTimer(() -> {
347+
// Handle case where entity becomes invalid. The task should no longer run.
348+
// We first check if the WrappedTask is non-null, since we never want to call the fallback
349+
// multiple times: we need to be able to cancel the recurring task,
350+
WrappedTask wt = wtRef.get();
351+
if (wt != null && !isValid(entity)) {
352+
wt.cancel();
353+
// Run the fallback if provided
354+
if (fallback != null) fallback.run();
355+
return;
356+
}
357+
358+
// Everything is healthy, run the task.
359+
runnable.run();
360+
}, delay, period);
361+
362+
wtRef.set(task);
363+
// Ok, you can open your eyes again.
364+
365+
return task;
331366
}
332367

333368
@Override

0 commit comments

Comments
 (0)