22
33import com .tcoded .folialib .FoliaLib ;
44import com .tcoded .folialib .enums .EntityTaskResult ;
5+ import com .tcoded .folialib .type .Ref ;
56import com .tcoded .folialib .util .TimeConverter ;
67import com .tcoded .folialib .wrapper .task .WrappedTask ;
78import 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