Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Folia support #224

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.frankheijden.insights.api.concurrent;

import dev.frankheijden.insights.api.InsightsPlugin;
import dev.frankheijden.insights.api.utils.SchedulingUtils;
import io.papermc.lib.PaperLib;
import java.util.concurrent.CompletableFuture;
import org.bukkit.HeightMap;
Expand All @@ -21,28 +22,29 @@ public ChunkTeleport(InsightsPlugin plugin) {
*/
public CompletableFuture<Result> teleportPlayerToChunk(Player player, World world, int x, int z, boolean gen) {
CompletableFuture<Result> resultFuture = new CompletableFuture<>();
PaperLib.getChunkAtAsync(world, x, z, gen).whenComplete((chunk, chunkErr) -> {
if (chunkErr != null) {
resultFuture.completeExceptionally(chunkErr);
return;
} else if (chunk == null) {
resultFuture.complete(Result.NOT_GENERATED);
return;
}

plugin.getServer().getScheduler().runTask(plugin, () -> {
SchedulingUtils.runImmediatelyAtChunk(plugin, world, x, z, () -> {
PaperLib.getChunkAtAsync(world, x, z, gen).whenComplete((chunk, chunkErr) -> {
if (chunkErr != null) {
resultFuture.completeExceptionally(chunkErr);
return;
} else if (chunk == null) {
resultFuture.complete(Result.NOT_GENERATED);
return;
}
int blockX = (x << 4) + 8;
int blockZ = (z << 4) + 8;
int blockY = world.getHighestBlockYAt(blockX, blockZ, HeightMap.MOTION_BLOCKING) + 1;
var loc = new Location(world, blockX + .5, blockY, blockZ + .5);
PaperLib.teleportAsync(player, loc).whenComplete((success, tpErr) -> {
if (tpErr != null) {
resultFuture.completeExceptionally(tpErr);
} else if (Boolean.FALSE.equals(success)) {
resultFuture.complete(Result.FAILED);
} else {
resultFuture.complete(Result.SUCCESS);
}
SchedulingUtils.runImmediatelyAtEntityIfFolia(plugin, player, () -> {
PaperLib.teleportAsync(player, loc).whenComplete((success, tpErr) -> {
if (tpErr != null) {
resultFuture.completeExceptionally(tpErr);
} else if (Boolean.FALSE.equals(success)) {
resultFuture.complete(Result.FAILED);
} else {
resultFuture.complete(Result.SUCCESS);
}
});
});
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package dev.frankheijden.insights.api.concurrent.count;

import dev.frankheijden.insights.api.InsightsPlugin;
import org.bukkit.scheduler.BukkitTask;
import dev.frankheijden.insights.api.utils.SchedulingUtils;
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

Expand All @@ -12,7 +13,7 @@ public class TickResetCount<T> {
private final int size;
private final Map<T, IntegerCount> counts;
private final ResetTask resetTask;
private BukkitTask bukkitTask = null;
private ScheduledTask scheduledTask = null;

/**
* Constructs a new TickResetCount.
Expand All @@ -30,14 +31,14 @@ public TickResetCount(InsightsPlugin plugin, int intervalTicks, int size) {
* @throws IllegalStateException If the task is already running.
*/
public void start() {
if (bukkitTask != null) {
if (scheduledTask != null) {
throw new IllegalStateException("ResetTask is already running!");
}

this.bukkitTask = plugin.getServer().getScheduler().runTaskTimerAsynchronously(
this.scheduledTask = SchedulingUtils.runTaskTimerAsynchronously(
plugin,
resetTask,
0,
1L,
intervalTicks
);
}
Expand All @@ -47,12 +48,12 @@ public void start() {
* @throws IllegalStateException If the task is not running.
*/
public void stop() {
if (bukkitTask == null) {
if (scheduledTask == null) {
throw new IllegalStateException("ResetTask is not running!");
}

this.bukkitTask.cancel();
this.bukkitTask = null;
this.scheduledTask.cancel();
this.scheduledTask = null;
}

public int getCurrentTick() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import dev.frankheijden.insights.api.InsightsPlugin;
import dev.frankheijden.insights.api.config.Messages;
import dev.frankheijden.insights.api.utils.SchedulingUtils;
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.bossbar.BossBar;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitTask;
import java.util.LinkedList;
import java.util.Queue;

Expand All @@ -20,7 +21,7 @@ public class BossBarNotification implements Notification {
protected final Queue<Audience> viewers = new LinkedList<>();
protected final int ticks;
protected final Runnable bossBarClearer;
protected BukkitTask task;
protected ScheduledTask task;

protected BossBarNotification(InsightsPlugin plugin, BossBar bossBar, Messages.Message content, int ticks) {
this.plugin = plugin;
Expand Down Expand Up @@ -55,7 +56,11 @@ public void send() {
audience.showBossBar(bossBar);
viewers.add(audience);
}
task = Bukkit.getScheduler().runTaskLater(plugin, bossBarClearer, ticks);
task = Bukkit.getGlobalRegionScheduler().runDelayed(
plugin,
SchedulingUtils.wrapRunnable(bossBarClearer),
ticks
);
}
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import dev.frankheijden.insights.api.objects.wrappers.ScanObject;
import dev.frankheijden.insights.api.tasks.ScanTask;
import dev.frankheijden.insights.api.utils.ChunkUtils;
import dev.frankheijden.insights.api.utils.SchedulingUtils;
import dev.frankheijden.insights.api.utils.StringUtils;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import org.bukkit.Chunk;
Expand Down Expand Up @@ -57,12 +58,14 @@ protected void handleModification(Location location, Material material, int amou
}

protected void handleModification(Location location, Consumer<Storage> storageConsumer) {
UUID worldUid = location.getWorld().getUID();
long chunkKey = ChunkUtils.getKey(location);
plugin.getWorldStorage().getWorld(worldUid).get(chunkKey).ifPresent(storageConsumer);
plugin.getAddonManager().getRegion(location)
.flatMap(region -> plugin.getAddonStorage().get(region.getKey()))
.ifPresent(storageConsumer);
SchedulingUtils.runImmediatelyAtLocationIfFolia(plugin, location, () -> {
UUID worldUid = location.getWorld().getUID();
long chunkKey = ChunkUtils.getKey(location);
plugin.getWorldStorage().getWorld(worldUid).get(chunkKey).ifPresent(storageConsumer);
plugin.getAddonManager().getRegion(location)
.flatMap(region -> plugin.getAddonStorage().get(region.getKey()))
.ifPresent(storageConsumer);
});
}

protected void handleModification(Location location, Material from, Material to, int amount) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@
import dev.frankheijden.insights.api.objects.wrappers.ScanObject;
import dev.frankheijden.insights.api.util.TriConsumer;
import dev.frankheijden.insights.api.utils.EnumUtils;
import dev.frankheijden.insights.api.utils.SchedulingUtils;
import dev.frankheijden.insights.api.utils.StringUtils;
import io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler;
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
import java.time.Duration;
import java.util.Comparator;
import java.util.Iterator;
Expand Down Expand Up @@ -51,7 +52,7 @@ public class ScanTask<R> implements Runnable {
private final AtomicBoolean completedExceptionally = new AtomicBoolean();
private final int chunkCount;
private long lastInfo = 0;
private BukkitTask task;
private ScheduledTask task;

/**
* Creates a new ScanTask to scan a collection of ChunkPart's.
Expand Down Expand Up @@ -370,8 +371,13 @@ public static void scanAndDisplayGroupedByChunk(
}

private void start() {
BukkitScheduler scheduler = plugin.getServer().getScheduler();
task = scheduler.runTaskTimer(plugin, this, 0, plugin.getSettings().SCANS_ITERATION_INTERVAL_TICKS);
GlobalRegionScheduler scheduler = plugin.getServer().getGlobalRegionScheduler();
task = scheduler.runAtFixedRate(
plugin,
SchedulingUtils.wrapRunnable(this),
1L, // At least 1 tick for Folia schedulers
plugin.getSettings().SCANS_ITERATION_INTERVAL_TICKS
);
}

private void cancel() {
Expand Down Expand Up @@ -416,35 +422,39 @@ public void run() {
var loc = chunkPart.getChunkLocation();
var world = loc.getWorld();

CompletableFuture<Storage> storageFuture;
if (world.isChunkLoaded(loc.getX(), loc.getZ())) {
storageFuture = executor.submit(
world.getChunkAt(loc.getX(), loc.getZ()),
chunkPart.getChunkCuboid(),
options
);
} else {
storageFuture = executor.submit(
loc.getWorld(),
loc.getX(),
loc.getZ(),
chunkPart.getChunkCuboid(),
options
);
}
int chunkX = loc.getX();
int chunkZ = loc.getZ();
SchedulingUtils.runImmediatelyAtChunkIfFolia(plugin, world, chunkX, chunkZ, () -> {
CompletableFuture<Storage> storageFuture;
if (world.isChunkLoaded(loc.getX(), loc.getZ())) {
storageFuture = executor.submit(
world.getChunkAt(loc.getX(), loc.getZ()),
chunkPart.getChunkCuboid(),
options
);
} else {
storageFuture = executor.submit(
loc.getWorld(),
loc.getX(),
loc.getZ(),
chunkPart.getChunkCuboid(),
options
);
}

storageFuture
.thenAccept(storage -> resultMerger.accept(storage, loc, result))
.thenRun(() -> {
iterationChunks.incrementAndGet();
chunks.incrementAndGet();
})
.exceptionally(th -> {
if (!completedExceptionally.getAndSet(true)) {
plugin.getLogger().log(Level.SEVERE, th, th::getMessage);
}
return null;
});
storageFuture
.thenAccept(storage -> resultMerger.accept(storage, loc, result))
.thenRun(() -> {
iterationChunks.incrementAndGet();
chunks.incrementAndGet();
})
.exceptionally(th -> {
if (!completedExceptionally.getAndSet(true)) {
plugin.getLogger().log(Level.SEVERE, th, th::getMessage);
}
return null;
});
});
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package dev.frankheijden.insights.api.utils;

public class ClassUtils {

private ClassUtils() {}

public static boolean isClassLoaded(String className) {
try {
Class.forName(className);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package dev.frankheijden.insights.api.utils;

import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.plugin.Plugin;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

public class SchedulingUtils {
public static final boolean IS_FOLIA = ClassUtils.isClassLoaded(
"io.papermc.paper.threadedregions.RegionizedServer"
);
public static final long TICK_TO_MILLISECONDS = 50L;
private static final long FOLIA_MINIMUM_DELAY = 1L;

public static void runImmediatelyAtEntityIfFolia(Plugin plugin, Entity entity, Runnable task) {
if (IS_FOLIA) {
entity.getScheduler().execute(plugin, task, null, FOLIA_MINIMUM_DELAY);
} else {
task.run();
}
}

public static void runImmediatelyAtChunkIfFolia(Plugin plugin, World world, int chunkX, int chunkZ, Runnable task) {
if (IS_FOLIA) {
plugin.getServer().getRegionScheduler().execute(plugin, world, chunkX, chunkZ, task);
} else {
task.run();
}
}

public static void runImmediatelyAtChunk(Plugin plugin, World world, int chunkX, int chunkZ, Runnable task) {
plugin.getServer().getRegionScheduler().execute(plugin, world, chunkX, chunkZ, task);
}

public static void runImmediatelyAtLocationIfFolia(Plugin plugin, Location location, Runnable task) {
if (IS_FOLIA) {
plugin.getServer().getRegionScheduler().execute(plugin, location, task);
} else {
task.run();
}
}

public static ScheduledTask runTaskTimerAsynchronously(
Plugin plugin, Runnable runnable, long delayTicks, long periodTicks
) {
return plugin.getServer().getAsyncScheduler().runAtFixedRate(
plugin,
wrapRunnable(runnable),
delayTicks * TICK_TO_MILLISECONDS,
periodTicks * TICK_TO_MILLISECONDS,
TimeUnit.MILLISECONDS
);
}

public static Consumer<ScheduledTask> wrapRunnable(Runnable runnable) {
return task -> runnable.run();
}
}
1 change: 1 addition & 0 deletions Insights-NMS/Current/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
dependencies {
paperweight.paperDevBundle("1.21.3-R0.1-SNAPSHOT")
compileOnly(project(":Insights-API"))
}
Loading