Skip to content

Commit 2988db6

Browse files
Folia support
1 parent 7f789a6 commit 2988db6

11 files changed

Lines changed: 79 additions & 49 deletions

File tree

invui/src/main/java/xyz/xenondevs/invui/gui/AbstractGui.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package xyz.xenondevs.invui.gui;
22

33
import io.papermc.paper.datacomponent.DataComponentTypes;
4+
import io.papermc.paper.threadedregions.scheduler.EntityScheduler;
45
import org.bukkit.GameMode;
56
import org.bukkit.entity.Player;
67
import org.bukkit.event.inventory.InventoryAction;
@@ -633,7 +634,7 @@ public void closeForAllViewers() {
633634
}
634635

635636
@Override
636-
public void playAnimation(Animation animation) {
637+
public void playAnimation(Animation animation, @Nullable EntityScheduler scheduler) {
637638
if (this.animation != null)
638639
cancelAnimation();
639640

@@ -665,7 +666,7 @@ public void playAnimation(Animation animation) {
665666
}
666667
});
667668

668-
animState.start();
669+
animState.start(scheduler);
669670
}
670671

671672
@Override

invui/src/main/java/xyz/xenondevs/invui/gui/AnimationImpl.java

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package xyz.xenondevs.invui.gui;
22

3+
import io.papermc.paper.threadedregions.scheduler.EntityScheduler;
34
import org.bukkit.Bukkit;
4-
import org.bukkit.scheduler.BukkitTask;
55
import org.jspecify.annotations.Nullable;
66
import xyz.xenondevs.invui.InvUI;
77
import xyz.xenondevs.invui.internal.util.MathUtils;
@@ -47,7 +47,7 @@ final class StateImpl implements State {
4747
private final Set<Slot> remainingSlots = new HashSet<>();
4848
private final Gui gui;
4949

50-
private @Nullable BukkitTask task;
50+
private @Nullable Runnable cancelTask;
5151
private int currentFrame;
5252

5353
public StateImpl(
@@ -73,13 +73,19 @@ public StateImpl(
7373
/**
7474
* Starts the animation task timer;
7575
*/
76-
public void start() {
76+
public void start(@Nullable EntityScheduler scheduler) {
7777
if (isFinished())
7878
throw new IllegalStateException("Animation is already completed");
79-
if (task != null)
79+
if (cancelTask != null)
8080
throw new IllegalStateException("Animation is already running");
8181

82-
task = Bukkit.getScheduler().runTaskTimer(InvUI.getInstance().getPlugin(), this::handleTick, 0, tickDelay);
82+
if (scheduler != null) {
83+
var task = scheduler.runAtFixedRate(InvUI.getInstance().getPlugin(), x -> handleTick(), null, 1, tickDelay);
84+
cancelTask = task != null ? task::cancel : null;
85+
} else {
86+
var task = Bukkit.getScheduler().runTaskTimer(InvUI.getInstance().getPlugin(), this::handleTick, 0, tickDelay);
87+
cancelTask = task::cancel;
88+
}
8389
}
8490

8591
private void handleTick() {
@@ -95,8 +101,8 @@ private void handleTick() {
95101
}
96102

97103
public void cancel() {
98-
if (task != null) {
99-
task.cancel();
104+
if (cancelTask != null) {
105+
cancelTask.run();
100106
finishHandler.accept(this);
101107
extraFinishHandler.run();
102108
}

invui/src/main/java/xyz/xenondevs/invui/gui/Gui.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package xyz.xenondevs.invui.gui;
22

3+
import io.papermc.paper.threadedregions.scheduler.EntityScheduler;
34
import org.bukkit.entity.Player;
45
import org.bukkit.inventory.ItemStack;
56
import org.jetbrains.annotations.Unmodifiable;
@@ -674,11 +675,24 @@ default void notifyWindows(char key1, char key2) {
674675

675676
/**
676677
* Plays an {@link Animation}.
678+
* <p>
679+
* For Folia, use {@link #playAnimation(Animation, EntityScheduler)} instead.
677680
*
678681
* @param animation The {@link Animation} to play.
679682
* @throws IllegalStateException If the {@link Animation} is already playing or was already played.
680683
*/
681-
void playAnimation(Animation animation);
684+
default void playAnimation(Animation animation) {
685+
playAnimation(animation, null);
686+
}
687+
688+
/**
689+
* Plays an {@link Animation}, ticked by the given {@link EntityScheduler}.
690+
*
691+
* @param animation The {@link Animation} to play.
692+
* @param scheduler The {@link EntityScheduler} that will be used to tick the animation.
693+
* If this is null, the default Bukkit scheduler will be used (fails on Folia).
694+
*/
695+
void playAnimation(Animation animation, @Nullable EntityScheduler scheduler);
682696

683697
/**
684698
* Checks whether an {@link Animation} is currently running.

invui/src/main/java/xyz/xenondevs/invui/internal/menu/CustomContainerMenu.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
import net.minecraft.world.item.ItemStack;
3333
import net.minecraft.world.item.Items;
3434
import net.minecraft.world.item.component.BundleContents;
35-
import org.bukkit.Bukkit;
3635
import org.bukkit.craftbukkit.entity.CraftPlayer;
3736
import org.bukkit.craftbukkit.inventory.CraftInventory;
3837
import org.bukkit.craftbukkit.inventory.CraftItemStack;
@@ -45,10 +44,10 @@
4544
import xyz.xenondevs.invui.Click;
4645
import xyz.xenondevs.invui.InvUI;
4746
import xyz.xenondevs.invui.internal.network.PacketListener;
47+
import xyz.xenondevs.invui.internal.util.FakeInventoryView;
4848
import xyz.xenondevs.invui.internal.util.InventoryUtils;
4949
import xyz.xenondevs.invui.internal.util.MathUtils;
5050
import xyz.xenondevs.invui.internal.util.PingData;
51-
import xyz.xenondevs.invui.internal.util.FakeInventoryView;
5251
import xyz.xenondevs.invui.window.Window;
5352

5453
import java.time.Duration;
@@ -397,9 +396,11 @@ public void handlePongAsync(ServerboundPongPacket packet) {
397396
var data = pendingPongs.remove(packet.getId());
398397
if (data == null)
399398
return; // ignore unknown pongs, unrelated to InvUI
400-
Bukkit.getScheduler().runTask(
399+
400+
player.getScheduler().run(
401401
InvUI.getInstance().getPlugin(),
402-
() -> getWindowEvents().handlePong(data.id())
402+
x -> getWindowEvents().handlePong(data.id()),
403+
null
403404
);
404405
}
405406

invui/src/main/java/xyz/xenondevs/invui/internal/network/PacketListener.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class PacketListener implements Listener {
3030
private static final PacketListener INSTANCE = new PacketListener();
3131

3232
private final String invuiPacketHandlerName;
33-
private final Map<UUID, PacketHandler> packetHandlers = new HashMap<>();
33+
private final Map<UUID, PacketHandler> packetHandlers = new ConcurrentHashMap<>();
3434

3535
private PacketListener() {
3636
invuiPacketHandlerName = "invui_packet_handler_" + InvUI.getInstance().getPlugin().getName();
@@ -101,7 +101,7 @@ private void injectChannelHandler(Player player) {
101101
throw new IllegalStateException("A packet handler is already registered for this player");
102102

103103
var channel = ((CraftPlayer) player).getHandle().connection.connection.channel;
104-
var packetHandler = new PacketHandler(channel);
104+
var packetHandler = new PacketHandler(player, channel);
105105
packetHandlers.put(player.getUniqueId(), packetHandler);
106106
channel.pipeline().addBefore(MC_PACKET_HANDLER_NAME, invuiPacketHandlerName, packetHandler);
107107
}
@@ -117,9 +117,11 @@ private static class PacketHandler extends ChannelDuplexHandler {
117117
private final Map<Class<? extends Packet<? super ServerGamePacketListener>>, Consumer<Packet<? super ServerGamePacketListener>>> redirections = new ConcurrentHashMap<>();
118118
private final Map<Class<? extends Packet<? super ServerGamePacketListener>>, Consumer<Packet<? super ServerGamePacketListener>>> listeners = new ConcurrentHashMap<>();
119119
private final Set<Class<? extends Packet<ClientGamePacketListener>>> discardRules = Collections.newSetFromMap(new ConcurrentHashMap<>());
120+
private final Player player;
120121
private final Channel channel;
121122

122-
public PacketHandler(Channel channel) {
123+
public PacketHandler(Player player, Channel channel) {
124+
this.player = player;
123125
this.channel = channel;
124126
}
125127

@@ -187,9 +189,10 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
187189

188190
var redirectHandler = redirections.get(msg.getClass());
189191
if (redirectHandler != null) {
190-
Bukkit.getScheduler().runTask(
192+
player.getScheduler().run(
191193
InvUI.getInstance().getPlugin(),
192-
() -> redirectHandler.accept((Packet<ServerGamePacketListener>) msg)
194+
x -> redirectHandler.accept((Packet<ServerGamePacketListener>) msg),
195+
null
193196
);
194197
} else {
195198
super.channelRead(ctx, msg);

invui/src/main/java/xyz/xenondevs/invui/inventory/ReferencingInventory.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
package xyz.xenondevs.invui.inventory;
22

3+
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
34
import org.bukkit.Bukkit;
45
import org.bukkit.event.inventory.InventoryAction;
56
import org.bukkit.event.inventory.InventoryClickEvent;
67
import org.bukkit.event.inventory.InventoryType;
78
import org.bukkit.inventory.Inventory;
89
import org.bukkit.inventory.ItemStack;
910
import org.bukkit.inventory.PlayerInventory;
10-
import org.bukkit.scheduler.BukkitTask;
1111
import org.jspecify.annotations.Nullable;
1212
import xyz.xenondevs.invui.Click;
1313
import xyz.xenondevs.invui.InvUI;
@@ -17,6 +17,7 @@
1717
import xyz.xenondevs.invui.util.TriConsumer;
1818

1919
import java.util.Arrays;
20+
import java.util.concurrent.TimeUnit;
2021
import java.util.function.BiFunction;
2122
import java.util.function.Function;
2223

@@ -36,7 +37,7 @@ public sealed class ReferencingInventory extends xyz.xenondevs.invui.inventory.I
3637
protected final TriConsumer<Inventory, Integer, @Nullable ItemStack> itemSetter;
3738
protected final int[] maxStackSizes;
3839

39-
private @Nullable BukkitTask updateTask;
40+
private @Nullable ScheduledTask updateTask;
4041

4142
/**
4243
* Constructs a new {@link ReferencingInventory}.
@@ -136,10 +137,12 @@ protected void setDirectBackingItem(int slot, @Nullable ItemStack itemStack) {
136137
public void addObserver(Observer who, int what, int how) {
137138
super.addObserver(who, what, how);
138139
if (updateTask == null) {
139-
updateTask = Bukkit.getScheduler().runTaskTimer(
140+
updateTask = Bukkit.getAsyncScheduler().runAtFixedRate(
140141
InvUI.getInstance().getPlugin(),
141-
() -> notifyWindows(),
142-
0, 1
142+
x -> notifyWindows(),
143+
0,
144+
50,
145+
TimeUnit.MILLISECONDS
143146
);
144147
}
145148
}

invui/src/main/java/xyz/xenondevs/invui/inventory/VirtualInventoryManager.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,9 @@ public List<VirtualInventory> getAllInventories() {
137137
*/
138138
public void remove(VirtualInventory inventory) {
139139
inventories.remove(inventory.getUuid(), inventory);
140-
Bukkit.getScheduler().runTaskAsynchronously(
140+
Bukkit.getAsyncScheduler().runNow(
141141
InvUI.getInstance().getPlugin(),
142-
() -> getSaveFile(inventory).delete()
142+
x -> getSaveFile(inventory).delete()
143143
);
144144
}
145145

invui/src/main/java/xyz/xenondevs/invui/item/CustomBoundItem.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package xyz.xenondevs.invui.item;
22

3+
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
34
import org.bukkit.Bukkit;
45
import org.bukkit.entity.Player;
56
import org.bukkit.event.inventory.ClickType;
6-
import org.bukkit.scheduler.BukkitTask;
77
import org.jspecify.annotations.NonNull;
88
import org.jspecify.annotations.Nullable;
99
import xyz.xenondevs.invui.Click;
@@ -18,6 +18,7 @@
1818

1919
import java.util.List;
2020
import java.util.concurrent.CompletableFuture;
21+
import java.util.concurrent.TimeUnit;
2122
import java.util.concurrent.atomic.AtomicReference;
2223
import java.util.function.*;
2324

@@ -30,7 +31,7 @@ class CustomBoundItem<G extends Gui> extends AbstractBoundItem {
3031
private final BiConsumer<? super Item, ? super G> bindHandler;
3132
private final BiConsumer<? super Item, ? super G> unbindHandler;
3233
private final int updatePeriod;
33-
private @Nullable BukkitTask updateTask;
34+
private @Nullable ScheduledTask updateTask;
3435

3536
public CustomBoundItem(
3637
Class<? extends Gui> guiClass,
@@ -90,11 +91,12 @@ public void handleBundleSelect(Player player, int bundleSlot) {
9091
public void addObserver(Observer who, int what, int how) {
9192
super.addObserver(who, what, how);
9293
if (updatePeriod > 0 && updateTask == null) {
93-
updateTask = Bukkit.getScheduler().runTaskTimer(
94+
updateTask = Bukkit.getAsyncScheduler().runAtFixedRate(
9495
InvUI.getInstance().getPlugin(),
95-
this::notifyWindows,
96+
x -> notifyWindows(),
9697
0,
97-
updatePeriod
98+
updatePeriod * 50L,
99+
TimeUnit.MILLISECONDS
98100
);
99101
}
100102
}
@@ -249,9 +251,9 @@ public BoundItem build() {
249251
);
250252

251253
if (asyncSupplier != null) {
252-
Bukkit.getScheduler().runTaskAsynchronously(
254+
Bukkit.getAsyncScheduler().runNow(
253255
InvUI.getInstance().getPlugin(),
254-
() -> {
256+
x -> {
255257
var itemProvider = asyncSupplier.get();
256258
customItem.itemProvider = (viewer, gui) -> itemProvider;
257259
customItem.notifyWindows();

invui/src/main/java/xyz/xenondevs/invui/item/CustomItem.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package xyz.xenondevs.invui.item;
22

3+
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
34
import org.bukkit.Bukkit;
45
import org.bukkit.entity.Player;
56
import org.bukkit.event.inventory.ClickType;
6-
import org.bukkit.scheduler.BukkitTask;
77
import org.jspecify.annotations.Nullable;
88
import xyz.xenondevs.invui.Click;
99
import xyz.xenondevs.invui.InvUI;
@@ -12,6 +12,7 @@
1212

1313
import java.util.List;
1414
import java.util.concurrent.CompletableFuture;
15+
import java.util.concurrent.TimeUnit;
1516
import java.util.function.BiConsumer;
1617
import java.util.function.Consumer;
1718
import java.util.function.Function;
@@ -23,7 +24,7 @@ class CustomItem extends AbstractItem {
2324
private final TriConsumer<? super Item, ? super Player, ? super Integer> selectHandler;
2425
private volatile Function<? super Player, ? extends ItemProvider> itemProvider;
2526
private final int updatePeriod;
26-
private @Nullable BukkitTask updateTask;
27+
private @Nullable ScheduledTask updateTask;
2728

2829
public CustomItem(
2930
BiConsumer<? super Item, ? super Click> clickHandler,
@@ -56,11 +57,12 @@ public void handleBundleSelect(Player player, int bundleSlot) {
5657
public void addObserver(Observer who, int what, int how) {
5758
super.addObserver(who, what, how);
5859
if (updatePeriod > 0 && updateTask == null) {
59-
updateTask = Bukkit.getScheduler().runTaskTimer(
60+
updateTask = Bukkit.getAsyncScheduler().runAtFixedRate(
6061
InvUI.getInstance().getPlugin(),
61-
this::notifyWindows,
62+
x -> notifyWindows(),
6263
0,
63-
updatePeriod
64+
updatePeriod * 50L,
65+
TimeUnit.MILLISECONDS
6466
);
6567
}
6668
}
@@ -175,9 +177,9 @@ public Item build() {
175177
);
176178

177179
if (asyncSupplier != null) {
178-
Bukkit.getScheduler().runTaskAsynchronously(
180+
Bukkit.getAsyncScheduler().runNow(
179181
InvUI.getInstance().getPlugin(),
180-
() -> {
182+
x -> {
181183
var itemProvider = asyncSupplier.get();
182184
customItem.itemProvider = (viewer -> itemProvider);
183185
customItem.notifyWindows();

invui/src/main/java/xyz/xenondevs/invui/window/AbstractWindow.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package xyz.xenondevs.invui.window;
22

3+
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
34
import it.unimi.dsi.fastutil.ints.IntArrayList;
45
import it.unimi.dsi.fastutil.ints.IntLinkedOpenHashSet;
56
import it.unimi.dsi.fastutil.ints.IntSet;
@@ -72,6 +73,7 @@ non-sealed abstract class AbstractWindow<M extends CustomContainerMenu> implemen
7273
private final int size;
7374
private final List<List<SlotElement>> elementsDisplayed;
7475
private final BitSet dirtySlots;
76+
private @Nullable ScheduledTask tickTask;
7577

7678
private @Nullable Component activeTitle;
7779

@@ -469,6 +471,7 @@ public void open() {
469471

470472
// track window and elements
471473
WindowManager.getInstance().addWindow(this);
474+
tickTask = getViewer().getScheduler().runAtFixedRate(InvUI.getInstance().getPlugin(), x -> handleTick(), null, 1, 1);
472475
registerAsViewer();
473476

474477
// init items
@@ -502,6 +505,8 @@ public void handleClose(Reason cause) {
502505
return;
503506

504507
WindowManager.getInstance().removeWindow(this);
508+
if (tickTask != null)
509+
tickTask.cancel();
505510
unregisterAsViewer();
506511
menu.handleClosed();
507512
isOpen = false;

0 commit comments

Comments
 (0)