diff --git a/Compatibility/src/main/java/com/songoda/core/compatibility/ServerVersion.java b/Compatibility/src/main/java/com/songoda/core/compatibility/ServerVersion.java
index 763eeef3..37316473 100644
--- a/Compatibility/src/main/java/com/songoda/core/compatibility/ServerVersion.java
+++ b/Compatibility/src/main/java/com/songoda/core/compatibility/ServerVersion.java
@@ -11,7 +11,10 @@ public enum ServerVersion {
private final static ServerVersion serverVersion;
private final static boolean isMocked;
+ private final static boolean isFolia;
+
static {
+ boolean isFolia1;
if (Bukkit.getServer() != null) {
String srvPackage = Bukkit.getServer().getClass().getPackage().getName();
isMocked = srvPackage.equals("be.seeseemelk.mockbukkit");
@@ -29,9 +32,21 @@ public enum ServerVersion {
isMocked = false;
}
+ try {
+ Class.forName("io.papermc.paper.threadedregions.RegionizedServer");
+ isFolia1 = true;
+ } catch (ClassNotFoundException e) {
+ isFolia1 = false;
+ }
+ isFolia = isFolia1;
+
serverVersion = getVersion();
}
+ public static boolean isFolia() {
+ return isFolia;
+ }
+
private static ServerVersion getVersion() {
for (ServerVersion version : values()) {
if (serverPackageVersion.toUpperCase().startsWith(version.name())) {
diff --git a/Core/pom.xml b/Core/pom.xml
index b56f1db4..855967af 100644
--- a/Core/pom.xml
+++ b/Core/pom.xml
@@ -84,6 +84,7 @@
org.apache.commons:commons-lang3
org.apache.commons:commons-text
org.yaml:snakeyaml
+ io.papermc:paperlib
@@ -109,8 +110,8 @@
- org.yaml.snakeyaml
- com.songoda.core.third_party.org.yaml.snakeyaml
+ io.papermc.lib
+ com.songoda.core.third_party.io.papermc.lib
@@ -142,6 +143,13 @@
+
+ dev.folia
+ folia-api
+ 1.19.4-R0.1-SNAPSHOT
+ provided
+
+
org.spigotmc
spigot
@@ -149,6 +157,13 @@
provided
+
+ io.papermc
+ paperlib
+ 1.0.7
+ compile
+
+
${project.groupId}
SongodaCore-Compatibility
@@ -156,6 +171,13 @@
compile
+
+ ${project.groupId}
+ Folia
+ ${project.version}
+ compile
+
+
${project.groupId}
SongodaCore-NMS
diff --git a/Core/src/main/java/com/songoda/core/SongodaCore.java b/Core/src/main/java/com/songoda/core/SongodaCore.java
index 81025e23..10636c2b 100644
--- a/Core/src/main/java/com/songoda/core/SongodaCore.java
+++ b/Core/src/main/java/com/songoda/core/SongodaCore.java
@@ -1,5 +1,7 @@
package com.songoda.core;
+import com.songoda.SchedulerTask;
+import com.songoda.SchedulerUtils;
import com.songoda.core.commands.CommandManager;
import com.songoda.core.compatibility.ClientVersion;
import com.songoda.core.compatibility.CompatibleMaterial;
@@ -198,15 +200,14 @@ public class SongodaCore {
Bukkit.getPluginManager().registerEvents(shadingListener, piggybackedPlugin);
// we aggressively want to own this command
- tasks.add(Bukkit.getScheduler().runTaskLaterAsynchronously(piggybackedPlugin, () ->
- CommandManager.registerCommandDynamically(piggybackedPlugin, "songoda", commandManager, commandManager),
- 10 * 60));
- tasks.add(Bukkit.getScheduler().runTaskLaterAsynchronously(piggybackedPlugin, () ->
- CommandManager.registerCommandDynamically(piggybackedPlugin, "songoda", commandManager, commandManager),
- 20 * 60));
- tasks.add(Bukkit.getScheduler().runTaskLaterAsynchronously(piggybackedPlugin, () ->
- CommandManager.registerCommandDynamically(piggybackedPlugin, "songoda", commandManager, commandManager),
- 20 * 60 * 2));
+ tasks.add(SchedulerUtils.runTaskLater(piggybackedPlugin, () ->
+ CommandManager.registerCommandDynamically(piggybackedPlugin, "songoda", commandManager, commandManager), 10 * 60));
+
+ tasks.add(SchedulerUtils.runTaskLater(piggybackedPlugin, () ->
+ CommandManager.registerCommandDynamically(piggybackedPlugin, "songoda", commandManager, commandManager), 20 * 60));
+
+ tasks.add(SchedulerUtils.runTaskLater(piggybackedPlugin, () ->
+ CommandManager.registerCommandDynamically(piggybackedPlugin, "songoda", commandManager, commandManager), 20 * 60 * 2));
}
/**
@@ -216,7 +217,7 @@ public class SongodaCore {
Bukkit.getServicesManager().unregister(SongodaCore.class, INSTANCE);
tasks.stream().filter(Objects::nonNull)
- .forEach(task -> Bukkit.getScheduler().cancelTask(task.getTaskId()));
+ .forEach(SchedulerUtils::cancelTask);
HandlerList.unregisterAll(loginListener);
if (!hasShading()) {
@@ -228,7 +229,7 @@ public class SongodaCore {
loginListener = null;
}
- private ArrayList tasks = new ArrayList<>();
+ private ArrayList tasks = new ArrayList<>();
private void register(JavaPlugin plugin, int pluginID, String icon, String libraryVersion) {
logger.info(getPrefix() + "Hooked " + plugin.getName() + ".");
@@ -237,7 +238,7 @@ public class SongodaCore {
// don't forget to check for language pack updates ;)
info.addModule(new LocaleModule());
registeredPlugins.add(info);
- tasks.add(Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> update(info), 60L));
+ tasks.add(SchedulerUtils.runTaskLaterAsynchronously(plugin, () -> update(info), 60L));
}
/**
@@ -416,9 +417,10 @@ public class SongodaCore {
// check for updates! ;)
for (PluginInfo plugin : getPlugins()) {
- if (plugin.getNotification() != null && plugin.getJavaPlugin().isEnabled())
- Bukkit.getScheduler().runTaskLaterAsynchronously(plugin.getJavaPlugin(), () ->
+ if (plugin.getNotification() != null && plugin.getJavaPlugin().isEnabled()) {
+ SchedulerUtils.runTaskLaterAsynchronously(plugin.getJavaPlugin(), () ->
player.sendMessage("[" + plugin.getJavaPlugin().getName() + "] " + plugin.getNotification()), 10L);
+ }
}
}
diff --git a/Core/src/main/java/com/songoda/core/SongodaPlugin.java b/Core/src/main/java/com/songoda/core/SongodaPlugin.java
index 41937b30..90ce9b6d 100644
--- a/Core/src/main/java/com/songoda/core/SongodaPlugin.java
+++ b/Core/src/main/java/com/songoda/core/SongodaPlugin.java
@@ -1,5 +1,6 @@
package com.songoda.core;
+import com.songoda.SchedulerUtils;
import com.songoda.core.configuration.Config;
import com.songoda.core.database.DataManagerAbstract;
import com.songoda.core.locale.Locale;
@@ -136,7 +137,7 @@ public abstract class SongodaPlugin extends JavaPlugin {
}
// Load Data.
- Bukkit.getScheduler().runTaskLater(this, this::onDataLoad, this.dataLoadDelay);
+ SchedulerUtils.runTaskLater(this, this::onDataLoad, this.dataLoadDelay);
if (this.emergencyStop) {
console.sendMessage(ChatColor.RED + "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
diff --git a/Core/src/main/java/com/songoda/core/database/DataManagerAbstract.java b/Core/src/main/java/com/songoda/core/database/DataManagerAbstract.java
index 78435c7d..ac28d912 100644
--- a/Core/src/main/java/com/songoda/core/database/DataManagerAbstract.java
+++ b/Core/src/main/java/com/songoda/core/database/DataManagerAbstract.java
@@ -1,5 +1,6 @@
package com.songoda.core.database;
+import com.songoda.SchedulerUtils;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
@@ -81,7 +82,7 @@ public class DataManagerAbstract {
*/
@Deprecated
public void async(Runnable runnable) {
- Bukkit.getScheduler().runTaskAsynchronously(this.plugin, runnable);
+ SchedulerUtils.runTaskAsynchronously(plugin, runnable);
}
/**
@@ -100,7 +101,7 @@ public class DataManagerAbstract {
* @param runnable task to run on the next server tick
*/
public void sync(Runnable runnable) {
- Bukkit.getScheduler().runTask(this.plugin, runnable);
+ SchedulerUtils.runTask(plugin, runnable);
}
public void runAsync(Runnable runnable) {
diff --git a/Core/src/main/java/com/songoda/core/gui/GuiManager.java b/Core/src/main/java/com/songoda/core/gui/GuiManager.java
index 66256a50..8d5fcdb2 100644
--- a/Core/src/main/java/com/songoda/core/gui/GuiManager.java
+++ b/Core/src/main/java/com/songoda/core/gui/GuiManager.java
@@ -1,5 +1,6 @@
package com.songoda.core.gui;
+import com.songoda.SchedulerUtils;
import com.songoda.core.compatibility.ClientVersion;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.ServerVersion;
@@ -102,7 +103,7 @@ public class GuiManager {
return;
}
- Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
+ SchedulerUtils.runTaskAsynchronously(plugin, () -> {
Gui openInv = openInventories.get(player);
if (openInv != null) {
@@ -111,7 +112,7 @@ public class GuiManager {
Inventory inv = gui.getOrCreateInventory(this);
- Bukkit.getScheduler().runTask(plugin, () -> {
+ SchedulerUtils.runTask(plugin, () -> {
player.openInventory(inv);
gui.onOpen(this, player);
@@ -136,7 +137,7 @@ public class GuiManager {
popup.add();
popup.grant(player);
- Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> {
+ SchedulerUtils.runTaskLaterAsynchronously(plugin, () -> {
popup.revoke(player);
popup.remove();
}, 70);
@@ -280,7 +281,7 @@ public class GuiManager {
if (manager.shutdown) {
gui.onClose(manager, player);
} else {
- Bukkit.getScheduler().runTaskLater(manager.plugin, () -> gui.onClose(manager, player), 1);
+ SchedulerUtils.runEntityTask(manager.plugin, player, () -> gui.onClose(manager, player), 1);
}
manager.openInventories.remove(player);
diff --git a/Core/src/main/java/com/songoda/core/input/ChatPrompt.java b/Core/src/main/java/com/songoda/core/input/ChatPrompt.java
index ca9add4b..a58dfb25 100644
--- a/Core/src/main/java/com/songoda/core/input/ChatPrompt.java
+++ b/Core/src/main/java/com/songoda/core/input/ChatPrompt.java
@@ -1,5 +1,7 @@
package com.songoda.core.input;
+import com.songoda.SchedulerTask;
+import com.songoda.SchedulerUtils;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -20,7 +22,7 @@ public class ChatPrompt implements Listener {
private final Plugin plugin;
private final ChatConfirmHandler handler;
- private int taskId;
+ private SchedulerTask taskId;
private OnClose onClose = null;
private OnCancel onCancel = null;
private Listener listener;
@@ -67,7 +69,7 @@ public class ChatPrompt implements Listener {
}
public ChatPrompt setTimeOut(Player player, long ticks) {
- taskId = Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> {
+ taskId = SchedulerUtils.scheduleSyncDelayedTask(plugin, () -> {
if (onClose != null) {
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () ->
onClose.onClose(), 0L);
@@ -108,7 +110,7 @@ public class ChatPrompt implements Listener {
}
HandlerList.unregisterAll(listener);
- Bukkit.getScheduler().cancelTask(taskId);
+ SchedulerUtils.cancelTask(taskId);
}
@EventHandler(priority = EventPriority.LOWEST)
@@ -132,7 +134,7 @@ public class ChatPrompt implements Listener {
}
HandlerList.unregisterAll(listener);
- Bukkit.getScheduler().cancelTask(taskId);
+ SchedulerUtils.cancelTask(taskId);
}
};
diff --git a/Core/src/main/java/com/songoda/core/lootables/loot/DropUtils.java b/Core/src/main/java/com/songoda/core/lootables/loot/DropUtils.java
index 4d57b8fe..19b38b8e 100644
--- a/Core/src/main/java/com/songoda/core/lootables/loot/DropUtils.java
+++ b/Core/src/main/java/com/songoda/core/lootables/loot/DropUtils.java
@@ -1,6 +1,7 @@
package com.songoda.core.lootables.loot;
import com.bgsoftware.wildstacker.api.objects.StackedItem;
+import com.songoda.SchedulerUtils;
import com.songoda.core.SongodaCore;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.settings.Settings;
@@ -87,7 +88,7 @@ public class DropUtils {
}
stack.setamount(newAmount);
}
- Bukkit.getScheduler().runTask(UltimateStacker.getInstance(), () -> {
+ SchedulerUtils.runLocationTask(UltimateStacker.getInstance(), event.getEntity().getLocation(), () -> {
for (StackedItem stack : stacks) {
UltimateStacker.spawnStackedItem(stack.getItem(), stack.getAmount(), event.getEntity().getLocation());
}
@@ -98,7 +99,7 @@ public class DropUtils {
}
private static void runCommands(LivingEntity entity, List commands) {
- Bukkit.getScheduler().runTask(SongodaCore.getHijackedPlugin(), () -> {
+ SchedulerUtils.runTask(SongodaCore.getHijackedPlugin(), () -> {
for (String command : commands) {
if (entity.getKiller() != null) {
command = command.replace("%player%", entity.getKiller().getName()
diff --git a/Core/src/main/java/com/songoda/core/nms/Nms.java b/Core/src/main/java/com/songoda/core/nms/Nms.java
index 7b01821e..60824e05 100644
--- a/Core/src/main/java/com/songoda/core/nms/Nms.java
+++ b/Core/src/main/java/com/songoda/core/nms/Nms.java
@@ -1,6 +1,7 @@
package com.songoda.core.nms;
import com.songoda.core.compatibility.ServerVersion;
+import com.songoda.core.nms.v1_19_R3.NmsImplementationsImpl;
public class Nms {
protected static NmsImplementations impl;
@@ -11,8 +12,17 @@ public class Nms {
public static NmsImplementations getImplementations() throws UnsupportedServerVersionException {
if (impl == null) {
try {
+ if (ServerVersion.isFolia()) {
+ impl = new NmsImplementationsImpl();
+ return impl;
+ }
+ switch (ServerVersion.getServerVersionString()) {
+ case "v1_19_R2":
+ impl = new com.songoda.core.nms.v1_19_R2.NmsImplementationsImpl();
+ break;
+ }
impl = (NmsImplementations) Class.forName("com.songoda.core.nms." + ServerVersion.getServerVersionString() + ".NmsImplementationsImpl").getConstructors()[0].newInstance();
- } catch (ReflectiveOperationException ex) {
+ } catch (Exception ex) {
throw new UnsupportedServerVersionException(ex);
}
}
diff --git a/Core/src/main/java/com/songoda/core/utils/Metrics.java b/Core/src/main/java/com/songoda/core/utils/Metrics.java
index 36aa7dca..32098d3b 100644
--- a/Core/src/main/java/com/songoda/core/utils/Metrics.java
+++ b/Core/src/main/java/com/songoda/core/utils/Metrics.java
@@ -1,5 +1,6 @@
package com.songoda.core.utils;
+import com.songoda.SchedulerUtils;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
@@ -188,7 +189,7 @@ public class Metrics {
}
// Nevertheless we want our code to run in the Bukkit main thread, so we have to use the Bukkit scheduler
// Don't be afraid! The connection to the bStats server is still async, only the stats collection is sync ;)
- Bukkit.getScheduler().runTask(plugin, () -> submitData());
+ SchedulerUtils.runTask(plugin, () -> submitData());
}
}, 1000 * 60 * 5, 1000 * 60 * 30);
// Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start
diff --git a/Core/src/main/java/com/songoda/core/world/SWorld.java b/Core/src/main/java/com/songoda/core/world/SWorld.java
index ac70ccff..125863ba 100644
--- a/Core/src/main/java/com/songoda/core/world/SWorld.java
+++ b/Core/src/main/java/com/songoda/core/world/SWorld.java
@@ -2,12 +2,14 @@ package com.songoda.core.world;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.core.nms.Nms;
+import io.papermc.paper.threadedregions.scheduler.EntityScheduler;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import java.util.List;
+import java.util.Map;
public class SWorld {
protected final com.songoda.core.nms.world.SWorld sWorld;
@@ -35,6 +37,14 @@ public class SWorld {
return sWorld.getLivingEntities();
}
+ /**
+ * For folia servers
+ * @return EntityScheduler and a list of entities belongs to it
+ */
+ public Map> getRegionizedEntities() {
+ return sWorld.getRegionizedEntities();
+ }
+
public World getWorld() {
return world;
}
diff --git a/Folia/pom.xml b/Folia/pom.xml
new file mode 100644
index 00000000..f6d8f446
--- /dev/null
+++ b/Folia/pom.xml
@@ -0,0 +1,49 @@
+
+
+ 4.0.0
+
+ com.songoda
+ SongodaCore-Modules
+ 2.6.22
+
+
+ Folia
+
+
+ 17
+ 17
+ UTF-8
+
+
+
+
+ papermc
+ https://repo.papermc.io/repository/maven-public/
+
+
+
+
+
+ ${project.groupId}
+ SongodaCore-Compatibility
+ ${project.version}
+ compile
+
+
+
+ dev.folia
+ folia-api
+ 1.19.4-R0.1-SNAPSHOT
+ provided
+
+
+
+ io.papermc.paper
+ paper-api
+ 1.19.4-R0.1-SNAPSHOT
+ provided
+
+
+
diff --git a/Folia/src/main/java/com/songoda/SchedulerTask.java b/Folia/src/main/java/com/songoda/SchedulerTask.java
new file mode 100644
index 00000000..c2bc40c5
--- /dev/null
+++ b/Folia/src/main/java/com/songoda/SchedulerTask.java
@@ -0,0 +1,24 @@
+package com.songoda;
+
+import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
+
+public class SchedulerTask {
+
+ private final Object task;
+
+ public SchedulerTask(Object task) {
+ this.task = task;
+ }
+
+ public Object getTask() {
+ return task;
+ }
+
+ public ScheduledTask getAsFoliaTask() {
+ return (ScheduledTask) task;
+ }
+
+ public int getAsBukkitTaskId() {
+ return (int) task;
+ }
+}
diff --git a/Folia/src/main/java/com/songoda/SchedulerUtils.java b/Folia/src/main/java/com/songoda/SchedulerUtils.java
new file mode 100644
index 00000000..f5e27253
--- /dev/null
+++ b/Folia/src/main/java/com/songoda/SchedulerUtils.java
@@ -0,0 +1,155 @@
+package com.songoda;
+
+import com.songoda.core.compatibility.ServerVersion;
+import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.entity.Entity;
+import org.bukkit.plugin.Plugin;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.concurrent.TimeUnit;
+
+public class SchedulerUtils {
+
+
+ /**
+ * Run a task on an entity or fallback for Bukkit#runTask
+ */
+ public static SchedulerTask runEntityTask(@NotNull Plugin plugin, @NotNull Entity entity, @NotNull Runnable runnable) {
+ if (ServerVersion.isFolia()) {
+ return new SchedulerTask(runEntityTask(plugin, entity, runnable, 1));
+ }
+ return new SchedulerTask(Bukkit.getScheduler().runTask(plugin, runnable));
+ }
+
+ public static SchedulerTask runEntityTask(@NotNull Plugin plugin, @NotNull Entity entity, @NotNull Runnable runnable, long delay) {
+ if (ServerVersion.isFolia()) {
+ return new SchedulerTask(entity.getScheduler().runDelayed(plugin, scheduledTask -> runnable.run(), null, delay));
+ }
+ return new SchedulerTask(Bukkit.getScheduler().runTask(plugin, runnable));
+ }
+
+ //location task
+
+ public static SchedulerTask runLocationTask(@NotNull Plugin plugin, @NotNull Location location, @NotNull Runnable runnable) {
+ if (ServerVersion.isFolia()) {
+ return new SchedulerTask(runLocationTask(plugin, location, runnable, 1));
+ }
+ return new SchedulerTask(Bukkit.getScheduler().runTask(plugin, runnable));
+ }
+
+ public static SchedulerTask runEntityTask(@NotNull Plugin plugin, @NotNull Entity entity, @NotNull Runnable runnable, long delay, long period) {
+ if (ServerVersion.isFolia()) {
+ return new SchedulerTask(entity.getScheduler().runAtFixedRate(plugin, scheduledTask -> runnable.run(), null, delay, period));
+ }
+ return new SchedulerTask(Bukkit.getScheduler().runTask(plugin, runnable));
+ }
+
+ /**
+ * Run a task on a location or fallback for Bukkit#runTask
+ * Delay is in ticks
+ */
+ public static SchedulerTask runLocationTask(@NotNull Plugin plugin, @NotNull Location location, @NotNull Runnable runnable, long delay) {
+ if (ServerVersion.isFolia()) {
+ return new SchedulerTask(plugin.getServer().getRegionScheduler().runDelayed(plugin, location, scheduledTask -> runnable.run(), delay));
+ }
+ return new SchedulerTask(Bukkit.getScheduler().runTask(plugin, runnable));
+ }
+
+ public static SchedulerTask runLocationTask(@NotNull Plugin plugin, @NotNull Location location, @NotNull Runnable runnable, long delay, long period) {
+ if (ServerVersion.isFolia()) {
+ return new SchedulerTask(plugin.getServer().getRegionScheduler().runAtFixedRate(plugin, location, scheduledTask -> runnable.run(), delay, period));
+ }
+ return new SchedulerTask(Bukkit.getScheduler().runTask(plugin, runnable));
+ }
+
+ public static SchedulerTask runTask(@NotNull Plugin plugin, @NotNull Runnable runnable) {
+ if (ServerVersion.isFolia()) {
+ return new SchedulerTask(plugin.getServer().getGlobalRegionScheduler().run(plugin, scheduledTask -> runnable.run()));
+ }
+ return new SchedulerTask(Bukkit.getScheduler().runTask(plugin, runnable));
+ }
+
+ public static SchedulerTask runTaskAsynchronously(@NotNull Plugin plugin, @NotNull Runnable runnable) {
+ if (ServerVersion.isFolia()) {
+ return new SchedulerTask(plugin.getServer().getAsyncScheduler().runNow(plugin, scheduledTask -> runnable.run()));
+ }
+ return new SchedulerTask(Bukkit.getScheduler().runTaskAsynchronously(plugin, runnable));
+ }
+
+ public static SchedulerTask runTaskLater(@NotNull Plugin plugin, @NotNull Runnable runnable, long delay) {
+ if (ServerVersion.isFolia()) {
+ return new SchedulerTask(plugin.getServer().getGlobalRegionScheduler().runDelayed(plugin, scheduledTask -> runnable.run(), delay));
+ }
+ return new SchedulerTask(Bukkit.getScheduler().runTaskLater(plugin, runnable, delay));
+ }
+
+ public static SchedulerTask runTaskLaterAsynchronously(@NotNull Plugin plugin, @NotNull Runnable runnable, long delay) {
+ if (ServerVersion.isFolia()) {
+ return new SchedulerTask(plugin.getServer().getAsyncScheduler().runDelayed(plugin, scheduledTask -> runnable.run(), delay, TimeUnit.MILLISECONDS));
+ }
+ return new SchedulerTask(Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, runnable, delay));
+ }
+
+ public static SchedulerTask scheduleSyncDelayedTask(@NotNull Plugin plugin, @NotNull Runnable runnable, long delay) {
+ if (ServerVersion.isFolia()) {
+ return new SchedulerTask(plugin.getServer().getGlobalRegionScheduler().runDelayed(plugin, scheduledTask -> runnable.run(), delay));
+ }
+ return new SchedulerTask(Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, runnable, delay));
+ }
+
+ public static SchedulerTask scheduleSyncRepeatingTask(@NotNull Plugin plugin, @NotNull Runnable runnable, long delay, long period) {
+ if (ServerVersion.isFolia()) {
+ return new SchedulerTask(plugin.getServer().getGlobalRegionScheduler().runAtFixedRate(plugin, scheduledTask -> runnable.run(), delay, period));
+ }
+ return new SchedulerTask(Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, runnable, delay, period));
+ }
+
+ public static SchedulerTask runTaskTimer(@NotNull Plugin plugin, @NotNull Runnable runnable, long delay, long period) {
+ if (ServerVersion.isFolia()) {
+ return new SchedulerTask(plugin.getServer().getGlobalRegionScheduler().runAtFixedRate(plugin, scheduledTask -> runnable.run(), delay, period));
+ }
+ return new SchedulerTask(Bukkit.getScheduler().runTaskTimer(plugin, runnable, delay, period));
+ }
+
+ public static SchedulerTask runTaskTimerAsynchronously(@NotNull Plugin plugin, @NotNull Runnable runnable, long delay, long period) {
+ if (ServerVersion.isFolia()) {
+ return new SchedulerTask(plugin.getServer().getAsyncScheduler().runAtFixedRate(plugin, scheduledTask -> runnable.run(), delay, period, TimeUnit.MILLISECONDS));
+ }
+ return new SchedulerTask(Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, runnable, delay, period));
+ }
+
+ public static void cancelTask(SchedulerTask task) {
+ if (ServerVersion.isFolia()) {
+ task.getAsFoliaTask().cancel();
+ } else {
+ Bukkit.getScheduler().cancelTask(task.getAsBukkitTaskId());
+ }
+ }
+
+ public static void cancelAllTasks(Plugin plugin) {
+ if (ServerVersion.isFolia()) {
+ Bukkit.getAsyncScheduler().cancelTasks(plugin);
+ Bukkit.getGlobalRegionScheduler().cancelTasks(plugin);
+ } else {
+ Bukkit.getScheduler().cancelTasks(plugin);
+ }
+ }
+
+ public static boolean isCurrentlyRunning(SchedulerTask task) {
+ if (ServerVersion.isFolia()) {
+ return task.getAsFoliaTask().getExecutionState() == ScheduledTask.ExecutionState.RUNNING;
+ } else {
+ return Bukkit.getScheduler().isCurrentlyRunning(task.getAsBukkitTaskId());
+ }
+ }
+
+ public static boolean isQueued(SchedulerTask task) {
+ if (ServerVersion.isFolia()) {
+ return task.getAsFoliaTask().getExecutionState() == ScheduledTask.ExecutionState.RUNNING;
+ } else {
+ return Bukkit.getScheduler().isQueued(task.getAsBukkitTaskId());
+ }
+ }
+}
diff --git a/NMS/NMS-API/pom.xml b/NMS/NMS-API/pom.xml
index b1be3987..dca76d92 100644
--- a/NMS/NMS-API/pom.xml
+++ b/NMS/NMS-API/pom.xml
@@ -13,6 +13,13 @@
SongodaCore-NMS-API
+
+ dev.folia
+ folia-api
+ 1.19.4-R0.1-SNAPSHOT
+ provided
+
+
org.spigotmc
diff --git a/NMS/NMS-API/src/main/java/com/songoda/core/nms/world/SWorld.java b/NMS/NMS-API/src/main/java/com/songoda/core/nms/world/SWorld.java
index 6f2dd16b..71bacf39 100644
--- a/NMS/NMS-API/src/main/java/com/songoda/core/nms/world/SWorld.java
+++ b/NMS/NMS-API/src/main/java/com/songoda/core/nms/world/SWorld.java
@@ -1,9 +1,13 @@
package com.songoda.core.nms.world;
+import io.papermc.paper.threadedregions.scheduler.EntityScheduler;
+import org.bukkit.Location;
import org.bukkit.Material;
+import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import java.util.List;
+import java.util.Map;
public interface SWorld {
List getLivingEntities();
@@ -17,4 +21,8 @@ public interface SWorld {
// TODO: Check if FabledSkyBlock *really* needs this method and if it can be removed.
// Would make thinks less complicated and I kinda cannot imagine it being *that* much faster to be worth it?
void setBlockFast(int x, int y, int z, Material material);
+
+ default Map> getRegionizedEntities() {
+ throw new UnsupportedOperationException("This server version does not support threaded regions. Not a Folia server.");
+ }
}
diff --git a/NMS/NMS-v1_19_R2/src/main/java/com/songoda/core/nms/v1_19_R2/NmsImplementationsImpl.java b/NMS/NMS-v1_19_R2/src/main/java/com/songoda/core/nms/v1_19_R2/NmsImplementationsImpl.java
new file mode 100644
index 00000000..147f32ef
--- /dev/null
+++ b/NMS/NMS-v1_19_R2/src/main/java/com/songoda/core/nms/v1_19_R2/NmsImplementationsImpl.java
@@ -0,0 +1,56 @@
+package com.songoda.core.nms.v1_19_R2;
+
+import com.songoda.core.nms.NmsImplementations;
+import com.songoda.core.nms.anvil.AnvilCore;
+import com.songoda.core.nms.entity.NMSPlayer;
+import com.songoda.core.nms.nbt.NBTCore;
+import com.songoda.core.nms.v1_19_R2.entity.NMSPlayerImpl;
+import com.songoda.core.nms.v1_19_R2.nbt.NBTCoreImpl;
+import com.songoda.core.nms.v1_19_R2.world.NmsWorldBorderImpl;
+import com.songoda.core.nms.v1_19_R2.world.WorldCoreImpl;
+import com.songoda.core.nms.world.NmsWorldBorder;
+import com.songoda.core.nms.world.WorldCore;
+import org.bukkit.craftbukkit.v1_19_R2.util.CraftMagicNumbers;
+import org.jetbrains.annotations.NotNull;
+
+@SuppressWarnings("unused")
+public class NmsImplementationsImpl implements NmsImplementations {
+ private final NMSPlayer player;
+ private final WorldCore world;
+ private final NmsWorldBorder worldBorder;
+ private final AnvilCore anvil;
+ private final NBTCore nbt;
+
+ public NmsImplementationsImpl() {
+ this.player = new NMSPlayerImpl();
+ this.world = new WorldCoreImpl();
+ this.worldBorder = new NmsWorldBorderImpl();
+ this.anvil = new com.songoda.core.nms.v1_19_R2.anvil.AnvilCore();
+ this.nbt = new NBTCoreImpl();
+ }
+
+ @Override
+ public @NotNull NMSPlayer getPlayer() {
+ return this.player;
+ }
+
+ @Override
+ public @NotNull WorldCore getWorld() {
+ return this.world;
+ }
+
+ @Override
+ public @NotNull NmsWorldBorder getWorldBorder() {
+ return this.worldBorder;
+ }
+
+ @Override
+ public @NotNull AnvilCore getAnvil() {
+ return this.anvil;
+ }
+
+ @Override
+ public @NotNull NBTCore getNbt() {
+ return this.nbt;
+ }
+}
diff --git a/NMS/NMS-v1_19_R2/src/main/java/com/songoda/core/nms/v1_19_R2/world/NmsWorldBorderImpl.java b/NMS/NMS-v1_19_R2/src/main/java/com/songoda/core/nms/v1_19_R2/world/NmsWorldBorderImpl.java
new file mode 100644
index 00000000..3dd9ee44
--- /dev/null
+++ b/NMS/NMS-v1_19_R2/src/main/java/com/songoda/core/nms/v1_19_R2/world/NmsWorldBorderImpl.java
@@ -0,0 +1,35 @@
+package com.songoda.core.nms.v1_19_R2.world;
+
+import com.songoda.core.nms.world.NmsWorldBorder;
+import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket;
+import net.minecraft.world.level.border.WorldBorder;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
+import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Objects;
+
+public class NmsWorldBorderImpl implements NmsWorldBorder {
+ @Override
+ public void send(Player player, BorderColor color, double size, @NotNull Location center) {
+ Objects.requireNonNull(center.getWorld());
+
+ WorldBorder worldBorder = new WorldBorder();
+ worldBorder.world = ((CraftWorld) center.getWorld()).getHandle();
+
+ worldBorder.setCenter(center.getX(), center.getZ());
+ worldBorder.setSize(size);
+ worldBorder.setWarningTime(0);
+ worldBorder.setWarningBlocks(0);
+
+ if (color == BorderColor.GREEN) {
+ worldBorder.lerpSizeBetween(size - 0.1D, size, Long.MAX_VALUE);
+ } else if (color == BorderColor.RED) {
+ worldBorder.lerpSizeBetween(size, size - 1.0D, Long.MAX_VALUE);
+ }
+
+ ((CraftPlayer) player).getHandle().connection.send(new ClientboundInitializeBorderPacket(worldBorder));
+ }
+}
diff --git a/NMS/NMS-v1_19_R3/pom.xml b/NMS/NMS-v1_19_R3/pom.xml
index 09883d3e..7a157eeb 100644
--- a/NMS/NMS-v1_19_R3/pom.xml
+++ b/NMS/NMS-v1_19_R3/pom.xml
@@ -62,6 +62,13 @@
+
+ dev.folia
+ folia-api
+ 1.19.4-R0.1-SNAPSHOT
+ provided
+
+
org.spigotmc
@@ -84,5 +91,12 @@
${project.version}
provided
+
+
+ io.papermc
+ paperlib
+ 1.0.7
+ provided
+
diff --git a/NMS/NMS-v1_19_R3/src/main/java/com/songoda/core/nms/v1_19_R3/NmsImplementationsImpl.java b/NMS/NMS-v1_19_R3/src/main/java/com/songoda/core/nms/v1_19_R3/NmsImplementationsImpl.java
new file mode 100644
index 00000000..efab9107
--- /dev/null
+++ b/NMS/NMS-v1_19_R3/src/main/java/com/songoda/core/nms/v1_19_R3/NmsImplementationsImpl.java
@@ -0,0 +1,56 @@
+package com.songoda.core.nms.v1_19_R3;
+
+import com.songoda.core.nms.NmsImplementations;
+import com.songoda.core.nms.anvil.AnvilCore;
+import com.songoda.core.nms.entity.NMSPlayer;
+import com.songoda.core.nms.nbt.NBTCore;
+import com.songoda.core.nms.v1_19_R3.entity.NMSPlayerImpl;
+import com.songoda.core.nms.v1_19_R3.nbt.NBTCoreImpl;
+import com.songoda.core.nms.v1_19_R3.world.NmsWorldBorderImpl;
+import com.songoda.core.nms.v1_19_R3.world.WorldCoreImpl;
+import com.songoda.core.nms.world.NmsWorldBorder;
+import com.songoda.core.nms.world.WorldCore;
+import org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers;
+import org.jetbrains.annotations.NotNull;
+
+@SuppressWarnings("unused")
+public class NmsImplementationsImpl implements NmsImplementations {
+ private final NMSPlayer player;
+ private final WorldCore world;
+ private final NmsWorldBorder worldBorder;
+ private final AnvilCore anvil;
+ private final NBTCore nbt;
+
+ public NmsImplementationsImpl() {
+ this.player = new NMSPlayerImpl();
+ this.world = new WorldCoreImpl();
+ this.worldBorder = new NmsWorldBorderImpl();
+ this.anvil = new com.songoda.core.nms.v1_19_R3.anvil.AnvilCore();
+ this.nbt = new NBTCoreImpl();
+ }
+
+ @Override
+ public @NotNull NMSPlayer getPlayer() {
+ return this.player;
+ }
+
+ @Override
+ public @NotNull WorldCore getWorld() {
+ return this.world;
+ }
+
+ @Override
+ public @NotNull NmsWorldBorder getWorldBorder() {
+ return this.worldBorder;
+ }
+
+ @Override
+ public @NotNull AnvilCore getAnvil() {
+ return this.anvil;
+ }
+
+ @Override
+ public @NotNull NBTCore getNbt() {
+ return this.nbt;
+ }
+}
diff --git a/NMS/NMS-v1_19_R3/src/main/java/com/songoda/core/nms/v1_19_R3/world/NmsWorldBorderImpl.java b/NMS/NMS-v1_19_R3/src/main/java/com/songoda/core/nms/v1_19_R3/world/NmsWorldBorderImpl.java
new file mode 100644
index 00000000..bb53f96c
--- /dev/null
+++ b/NMS/NMS-v1_19_R3/src/main/java/com/songoda/core/nms/v1_19_R3/world/NmsWorldBorderImpl.java
@@ -0,0 +1,35 @@
+package com.songoda.core.nms.v1_19_R3.world;
+
+import com.songoda.core.nms.world.NmsWorldBorder;
+import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket;
+import net.minecraft.world.level.border.WorldBorder;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_19_R3.CraftWorld;
+import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Objects;
+
+public class NmsWorldBorderImpl implements NmsWorldBorder {
+ @Override
+ public void send(Player player, BorderColor color, double size, @NotNull Location center) {
+ Objects.requireNonNull(center.getWorld());
+
+ WorldBorder worldBorder = new WorldBorder();
+ worldBorder.world = ((CraftWorld) center.getWorld()).getHandle();
+
+ worldBorder.setCenter(center.getX(), center.getZ());
+ worldBorder.setSize(size);
+ worldBorder.setWarningTime(0);
+ worldBorder.setWarningBlocks(0);
+
+ if (color == BorderColor.GREEN) {
+ worldBorder.lerpSizeBetween(size - 0.1D, size, Long.MAX_VALUE);
+ } else if (color == BorderColor.RED) {
+ worldBorder.lerpSizeBetween(size, size - 1.0D, Long.MAX_VALUE);
+ }
+
+ ((CraftPlayer) player).getHandle().connection.send(new ClientboundInitializeBorderPacket(worldBorder));
+ }
+}
diff --git a/NMS/NMS-v1_19_R3/src/main/java/com/songoda/core/nms/v1_19_R3/world/SSpawnerImpl.java b/NMS/NMS-v1_19_R3/src/main/java/com/songoda/core/nms/v1_19_R3/world/SSpawnerImpl.java
index b4722d8e..16ba1c5d 100644
--- a/NMS/NMS-v1_19_R3/src/main/java/com/songoda/core/nms/v1_19_R3/world/SSpawnerImpl.java
+++ b/NMS/NMS-v1_19_R3/src/main/java/com/songoda/core/nms/v1_19_R3/world/SSpawnerImpl.java
@@ -4,6 +4,7 @@ import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.CompatibleParticleHandler;
import com.songoda.core.nms.world.SSpawner;
import com.songoda.core.nms.world.SpawnedEntity;
+import io.papermc.lib.PaperLib;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
@@ -92,7 +93,7 @@ public class SSpawnerImpl implements SSpawner {
world.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.SPAWNER);
spot.setYaw(random.nextFloat() * 360.0F);
- craftEntity.teleport(spot);
+ PaperLib.teleportAsync(craftEntity, spot);
return craftEntity;
}
diff --git a/NMS/NMS-v1_19_R3/src/main/java/com/songoda/core/nms/v1_19_R3/world/SWorldImpl.java b/NMS/NMS-v1_19_R3/src/main/java/com/songoda/core/nms/v1_19_R3/world/SWorldImpl.java
index fa941282..c5a5727a 100644
--- a/NMS/NMS-v1_19_R3/src/main/java/com/songoda/core/nms/v1_19_R3/world/SWorldImpl.java
+++ b/NMS/NMS-v1_19_R3/src/main/java/com/songoda/core/nms/v1_19_R3/world/SWorldImpl.java
@@ -1,20 +1,28 @@
package com.songoda.core.nms.v1_19_R3.world;
+import com.songoda.core.compatibility.ServerVersion;
import com.songoda.core.nms.world.SWorld;
+import io.papermc.paper.threadedregions.scheduler.EntityScheduler;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.entity.LevelEntityGetter;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_19_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData;
import org.bukkit.entity.LivingEntity;
+import java.lang.reflect.Field;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
public class SWorldImpl implements SWorld {
private final World world;
@@ -49,4 +57,24 @@ public class SWorldImpl implements SWorld {
levelChunk.setBlockState(new BlockPos(x & 0xF, y, z & 0xF), blockState, true);
}
+
+ @Override
+ public Map> getRegionizedEntities() {
+ if (!ServerVersion.isFolia()) {
+ SWorld.super.getRegionizedEntities();
+ }
+ Map> result = new HashMap<>();
+
+ for (LivingEntity entity : getLivingEntities()) {
+ EntityScheduler scheduler = entity.getScheduler();
+
+ if (!result.containsKey(scheduler)) {
+ result.computeIfAbsent(scheduler, k -> new ArrayList<>(List.of(entity)));
+ }
+
+ result.get(scheduler).add(entity);
+ }
+
+ return result;
+ }
}
diff --git a/NMS/NMS/pom.xml b/NMS/NMS/pom.xml
index 38514e89..eff98e7f 100644
--- a/NMS/NMS/pom.xml
+++ b/NMS/NMS/pom.xml
@@ -141,5 +141,11 @@
${project.groupId}
compile
+
+ ${project.version}
+ SongodaCore-NMS-v1_19_R3
+ ${project.groupId}
+ compile
+
diff --git a/pom.xml b/pom.xml
index de44f20f..172ab59c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -48,6 +48,7 @@
NMS/NMS-v1_19_R1
NMS/NMS-v1_19_R2
NMS/NMS-v1_19_R3
+ Folia