Skip to content
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
Binary file added Dynmap-3.9.jar
Binary file not shown.
84 changes: 62 additions & 22 deletions spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,15 @@ public int isSignAt(String wname, int x, int y, int z) {

@Override
public void scheduleServerTask(Runnable run, long delay) {
getServer().getScheduler().scheduleSyncDelayedTask(DynmapPlugin.this, run, delay);
if (FoliaUtil.isFolia()) {
if (delay <= 0) {
FoliaUtil.runGlobalSync(DynmapPlugin.this, run);
} else {
FoliaUtil.runGlobalDelayed(DynmapPlugin.this, run, delay);
}
} else {
getServer().getScheduler().scheduleSyncDelayedTask(DynmapPlugin.this, run, delay);
}
}
@Override
public DynmapPlayer[] getOnlinePlayers() {
Expand Down Expand Up @@ -292,8 +300,12 @@ public Set<String> getIPBans() {
}
@Override
public <T> Future<T> callSyncMethod(Callable<T> task) {
if(DynmapPlugin.this.isEnabled())
if(DynmapPlugin.this.isEnabled()) {
if (FoliaUtil.isFolia()) {
return FoliaUtil.callGlobalSync(DynmapPlugin.this, task);
}
return getServer().getScheduler().callSyncMethod(DynmapPlugin.this, task);
}
else
return null;
}
Expand Down Expand Up @@ -372,14 +384,25 @@ public void onPlayerBedLeave(PlayerBedLeaveEvent evt) {
public void onPlayerChat(AsyncPlayerChatEvent evt) {
final Player p = evt.getPlayer();
final String msg = evt.getMessage();
getServer().getScheduler().scheduleSyncDelayedTask(DynmapPlugin.this, new Runnable() {
public void run() {
DynmapPlayer dp = null;
if(p != null)
dp = new BukkitPlayer(p);
core.listenerManager.processChatEvent(EventType.PLAYER_CHAT, dp, msg);
}
});
if (FoliaUtil.isFolia()) {
FoliaUtil.runGlobalSync(DynmapPlugin.this, new Runnable() {
public void run() {
DynmapPlayer dp = null;
if(p != null)
dp = new BukkitPlayer(p);
core.listenerManager.processChatEvent(EventType.PLAYER_CHAT, dp, msg);
}
});
} else {
getServer().getScheduler().scheduleSyncDelayedTask(DynmapPlugin.this, new Runnable() {
public void run() {
DynmapPlayer dp = null;
if(p != null)
dp = new BukkitPlayer(p);
core.listenerManager.processChatEvent(EventType.PLAYER_CHAT, dp, msg);
}
});
}
}
}, DynmapPlugin.this);
break;
Expand Down Expand Up @@ -1036,11 +1059,15 @@ public void onPluginEnabled(PluginEnableEvent evt) {
tps = 20.0;
perTickLimit = core.getMaxTickUseMS() * 1000000;

getServer().getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {
public void run() {
processTick();
}
}, 1, 1);
if (FoliaUtil.isFolia()) {
FoliaUtil.runGlobalTimer(this, t -> processTick(), 1, 1);
} else {
getServer().getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {
public void run() {
processTick();
}
}, 1, 1);
}
}

private boolean readyToEnable() {
Expand Down Expand Up @@ -1273,12 +1300,21 @@ private void registerPlayerLoginListener() {
public void onPlayerJoin(PlayerJoinEvent evt) {
final DynmapPlayer dp = new BukkitPlayer(evt.getPlayer());
// Give other handlers a change to prep player (nicknames and such from Essentials)
getServer().getScheduler().scheduleSyncDelayedTask(DynmapPlugin.this, new Runnable() {
@Override
public void run() {
core.listenerManager.processPlayerEvent(EventType.PLAYER_JOIN, dp);
}
}, 2);
if (FoliaUtil.isFolia()) {
FoliaUtil.runGlobalDelayed(DynmapPlugin.this, new Runnable() {
@Override
public void run() {
core.listenerManager.processPlayerEvent(EventType.PLAYER_JOIN, dp);
}
}, 2);
} else {
getServer().getScheduler().scheduleSyncDelayedTask(DynmapPlugin.this, new Runnable() {
@Override
public void run() {
core.listenerManager.processPlayerEvent(EventType.PLAYER_JOIN, dp);
}
}, 2);
}
}
@EventHandler(priority=EventPriority.MONITOR, ignoreCancelled=true)
public void onPlayerQuit(PlayerQuitEvent evt) {
Expand Down Expand Up @@ -1316,7 +1352,11 @@ public void startIfNeeded() {
if((blocks_to_check == null) && (blocks_to_check_accum.isEmpty() == false)) { /* More pending? */
blocks_to_check = blocks_to_check_accum;
blocks_to_check_accum = new LinkedList<BlockToCheck>();
getServer().getScheduler().scheduleSyncDelayedTask(DynmapPlugin.this, this, 10);
if (FoliaUtil.isFolia()) {
FoliaUtil.runGlobalDelayed(DynmapPlugin.this, this, 10);
} else {
getServer().getScheduler().scheduleSyncDelayedTask(DynmapPlugin.this, this, 10);
}
}
}
}
Expand Down
114 changes: 114 additions & 0 deletions spigot/src/main/java/org/dynmap/bukkit/FoliaUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package org.dynmap.bukkit;

import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

/**
* Folia compatibility layer — pure reflection, no Folia API JAR needed at compile time.
* Dynmap compiles against old Spigot API; Folia scheduler methods are called at runtime only.
*/
public final class FoliaUtil {

private static final boolean FOLIA;

static {
boolean folia;
try {
Class.forName("io.papermc.paper.threadedregions.RegionizedServer");
folia = true;
} catch (ClassNotFoundException ignored) {
folia = false;
}
FOLIA = folia;
}

private FoliaUtil() {}

public static boolean isFolia() {
return FOLIA;
}

/** Runs {@code task} on the global region scheduler immediately. */
public static void runGlobalSync(Plugin plugin, Runnable task) {
try {
Object s = globalScheduler();
s.getClass().getMethod("run", Plugin.class, Consumer.class)
.invoke(s, plugin, (Consumer<Object>) t -> task.run());
} catch (Exception e) {
e.printStackTrace();
}
}

/** Runs {@code task} on the global region scheduler after {@code delayTicks} ticks. */
public static void runGlobalDelayed(Plugin plugin, Runnable task, long delayTicks) {
try {
Object s = globalScheduler();
s.getClass().getMethod("runDelayed", Plugin.class, Consumer.class, long.class)
.invoke(s, plugin, (Consumer<Object>) t -> task.run(), delayTicks);
} catch (Exception e) {
e.printStackTrace();
}
}

/** Runs a repeating task on the global region scheduler; returns the opaque task handle. */
public static Object runGlobalTimer(Plugin plugin, Consumer<Object> consumer, long initialDelay, long period) {
try {
Object s = globalScheduler();
return s.getClass()
.getMethod("runAtFixedRate", Plugin.class, Consumer.class, long.class, long.class)
.invoke(s, plugin, consumer, initialDelay, period);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

/**
* Submits {@code task} to the global region scheduler and returns a Future for the result.
* Replaces {@code BukkitScheduler.callSyncMethod()} on Folia servers.
*/
public static <T> Future<T> callGlobalSync(Plugin plugin, java.util.concurrent.Callable<T> task) {
CompletableFuture<T> future = new CompletableFuture<>();
runGlobalSync(plugin, () -> {
try {
future.complete(task.call());
} catch (Exception e) {
future.completeExceptionally(e);
}
});
return future;
}

/** Cancels all tasks on both global region and async schedulers for the given plugin. */
public static void cancelAllTasks(Plugin plugin) {
try {
Object gs = globalScheduler();
gs.getClass().getMethod("cancelTasks", Plugin.class).invoke(gs, plugin);
} catch (Exception ignored) {}
try {
Object as = asyncScheduler();
as.getClass().getMethod("cancelTasks", Plugin.class).invoke(as, plugin);
} catch (Exception ignored) {}
}

/** Cancels a single opaque task handle returned by {@link #runGlobalTimer}. */
public static void cancelTask(Object task) {
if (task == null) return;
try {
task.getClass().getMethod("cancel").invoke(task);
} catch (Exception ignored) {}
}

private static Object globalScheduler() throws Exception {
return Bukkit.getServer().getClass().getMethod("getGlobalRegionScheduler").invoke(Bukkit.getServer());
}

private static Object asyncScheduler() throws Exception {
return Bukkit.getServer().getClass().getMethod("getAsyncScheduler").invoke(Bukkit.getServer());
}
}
1 change: 1 addition & 0 deletions spigot/src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: dynmap
main: org.dynmap.bukkit.DynmapPlugin
version: "${version}-${buildnumber}"
api-version: 1.13
folia-supported: true
authors: [mikeprimm]
website: "https://www.reddit.com/r/Dynmap/"
softdepend: [ Permissions, PermissionEx, bPermissions, PermissionsBukkit, GroupManager, LuckPerms, Vault, SkinsRestorer ]
Expand Down