diff --git a/divinemc-server/minecraft-patches/features/0036-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch b/divinemc-server/minecraft-patches/features/0004-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0036-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch rename to divinemc-server/minecraft-patches/features/0004-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch diff --git a/divinemc-server/minecraft-patches/features/0039-Paper-PR-Throttle-failed-spawn-attempts.patch b/divinemc-server/minecraft-patches/features/0005-Paper-PR-Throttle-failed-spawn-attempts.patch similarity index 99% rename from divinemc-server/minecraft-patches/features/0039-Paper-PR-Throttle-failed-spawn-attempts.patch rename to divinemc-server/minecraft-patches/features/0005-Paper-PR-Throttle-failed-spawn-attempts.patch index 6c35e64..3ee3718 100644 --- a/divinemc-server/minecraft-patches/features/0039-Paper-PR-Throttle-failed-spawn-attempts.patch +++ b/divinemc-server/minecraft-patches/features/0005-Paper-PR-Throttle-failed-spawn-attempts.patch @@ -175,10 +175,10 @@ index 345d4b80bd4383e0fb66d744d87bc8ef4100fd32..68a074a1eb11b158af773a2c44aa49d5 private static boolean isRightDistanceToPlayerAndSpawnPoint(ServerLevel level, ChunkAccess chunk, BlockPos.MutableBlockPos pos, double distance) { diff --git a/net/minecraft/world/level/chunk/ChunkAccess.java b/net/minecraft/world/level/chunk/ChunkAccess.java -index 5e9f3856c384dbb2bd462121b903cd2b326e4376..19f74518923783d8d5560b526a1f267dabd23156 100644 +index 182c14b660f8860bed627eed4e01fd4002153e9a..81511de113c292549fe5fe720a15bf3e0497ca84 100644 --- a/net/minecraft/world/level/chunk/ChunkAccess.java +++ b/net/minecraft/world/level/chunk/ChunkAccess.java -@@ -92,6 +92,7 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh +@@ -88,6 +88,7 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh public org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer(ChunkAccess.DATA_TYPE_REGISTRY); // CraftBukkit end public final Registry biomeRegistry; // CraftBukkit diff --git a/divinemc-server/minecraft-patches/features/0042-Raytrace-AntiXray-SDK-integration.patch b/divinemc-server/minecraft-patches/features/0006-Raytrace-AntiXray-SDK-integration.patch similarity index 96% rename from divinemc-server/minecraft-patches/features/0042-Raytrace-AntiXray-SDK-integration.patch rename to divinemc-server/minecraft-patches/features/0006-Raytrace-AntiXray-SDK-integration.patch index 8eb5ecb..0b7d832 100644 --- a/divinemc-server/minecraft-patches/features/0042-Raytrace-AntiXray-SDK-integration.patch +++ b/divinemc-server/minecraft-patches/features/0006-Raytrace-AntiXray-SDK-integration.patch @@ -25,7 +25,7 @@ index c4a4f08272b34f72dea4feaaeb66d153b2aab8c8..be5da5a81246b4f4abe19f7c0cf68990 } diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 6e8075618baf98fcc396f0b5e241a806805b3d94..37f5bd2a63e2ec074fbc55d366e0d128f1918089 100644 +index 4c1ce7e85f9c3315635472047ffaf15a711aeffd..9625213b7c1295b813071dbedea5366510c7072f 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java @@ -1171,6 +1171,12 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl diff --git a/divinemc-server/minecraft-patches/features/0049-Paper-PR-Add-ticket-on-player-join-to-avoid-chunk-lo.patch b/divinemc-server/minecraft-patches/features/0007-Paper-PR-Add-ticket-on-player-join-to-avoid-chunk-lo.patch similarity index 93% rename from divinemc-server/minecraft-patches/features/0049-Paper-PR-Add-ticket-on-player-join-to-avoid-chunk-lo.patch rename to divinemc-server/minecraft-patches/features/0007-Paper-PR-Add-ticket-on-player-join-to-avoid-chunk-lo.patch index ccb4be8..24cf19a 100644 --- a/divinemc-server/minecraft-patches/features/0049-Paper-PR-Add-ticket-on-player-join-to-avoid-chunk-lo.patch +++ b/divinemc-server/minecraft-patches/features/0007-Paper-PR-Add-ticket-on-player-join-to-avoid-chunk-lo.patch @@ -15,7 +15,7 @@ The delay is currently set to 2 seconds, however, we may want to adjust this bef This patch fixes PaperMC/Paper#9581 diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java -index e93a006cde4dd85a9976e0d6a64643755ba99fb7..62e89385fcdc3fa0202863f3199c98a2df4be2a6 100644 +index bdc1200ef5317fdaf58973bf580b0a672aee800f..1ed2ae41e47b2446bf1835efc8bad369408d52da 100644 --- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java @@ -48,6 +48,7 @@ public final class RegionizedPlayerChunkLoader { @@ -27,10 +27,10 @@ index e93a006cde4dd85a9976e0d6a64643755ba99fb7..62e89385fcdc3fa0202863f3199c98a2 public static final int GENERATED_TICKET_LEVEL = ChunkHolderManager.FULL_LOADED_TICKET_LEVEL; public static final int LOADED_TICKET_LEVEL = ChunkTaskScheduler.getTicketLevel(ChunkStatus.EMPTY); diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java -index e1ca822d41311e3be44c52badb907619ca681cf9..bd6cff4916fdf379ee887259d18ee274ff2f8bc6 100644 +index 8a67672f1175769ac213099331453fbae59442fa..c70b5ce2dc8cbcdea8715339a63e038f94849bfb 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java -@@ -316,6 +316,13 @@ public abstract class PlayerList { +@@ -315,6 +315,13 @@ public abstract class PlayerList { // this.broadcastAll(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(player))); // CraftBukkit - replaced with loop below // Paper start - Fire PlayerJoinEvent when Player is actually ready; correctly register player BEFORE PlayerJoinEvent, so the entity is valid and doesn't require tick delay hacks player.supressTrackerForLogin = true; diff --git a/divinemc-server/minecraft-patches/features/0054-Smooth-teleport-API.patch b/divinemc-server/minecraft-patches/features/0008-Smooth-teleport-API.patch similarity index 87% rename from divinemc-server/minecraft-patches/features/0054-Smooth-teleport-API.patch rename to divinemc-server/minecraft-patches/features/0008-Smooth-teleport-API.patch index 6878d12..bb87d52 100644 --- a/divinemc-server/minecraft-patches/features/0054-Smooth-teleport-API.patch +++ b/divinemc-server/minecraft-patches/features/0008-Smooth-teleport-API.patch @@ -5,22 +5,22 @@ Subject: [PATCH] Smooth teleport API diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index cf4ab76f463836a8ed9aeedd09ae95e75b9e8dbc..f5a0c5a2f56376bf89b16a809d465bc45a80eb38 100644 +index a1b4720ef128ba5cbe1466a7a584d4fe501a71f8..b75d2d2746c3e7b12f65b0bcb559cd7e0ce7ebf8 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java -@@ -431,6 +431,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc +@@ -430,6 +430,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc + private boolean tpsBar = false; // Purpur - Implement TPSBar private boolean compassBar = false; // Purpur - Add compass command private boolean ramBar = false; // Purpur - Implement rambar commands - public boolean hasTickedAtLeastOnceInNewWorld = false; // DivineMC - Parallel world ticking + public boolean smoothWorldTeleport; // DivineMC - Smooth teleport API // Paper start - rewrite chunk system private ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.PlayerChunkLoaderData chunkLoader; diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java -index 04f82f77e1ad2b7105cbace2a4ef99590965ae4f..147535646319018ec5dfe42d12fdb19d9e1f7543 100644 +index c70b5ce2dc8cbcdea8715339a63e038f94849bfb..9362bfdf8f5495d237b1e74be4dd925db2452dc0 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java -@@ -758,11 +758,11 @@ public abstract class PlayerList { +@@ -748,11 +748,11 @@ public abstract class PlayerList { byte b = (byte)(keepInventory ? 1 : 0); ServerLevel serverLevel = serverPlayer.level(); LevelData levelData = serverLevel.getLevelData(); @@ -34,7 +34,7 @@ index 04f82f77e1ad2b7105cbace2a4ef99590965ae4f..147535646319018ec5dfe42d12fdb19d serverPlayer.connection.send(new ClientboundSetDefaultSpawnPositionPacket(level.getSharedSpawnPos(), level.getSharedSpawnAngle())); serverPlayer.connection.send(new ClientboundChangeDifficultyPacket(levelData.getDifficulty(), levelData.isDifficultyLocked())); serverPlayer.connection -@@ -849,6 +849,12 @@ public abstract class PlayerList { +@@ -839,6 +839,12 @@ public abstract class PlayerList { return serverPlayer; } diff --git a/divinemc-server/paper-patches/features/0011-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch b/divinemc-server/paper-patches/features/0005-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch similarity index 92% rename from divinemc-server/paper-patches/features/0011-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch rename to divinemc-server/paper-patches/features/0005-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch index ac9198a..461c24f 100644 --- a/divinemc-server/paper-patches/features/0011-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch +++ b/divinemc-server/paper-patches/features/0005-Paper-PR-Add-FillBottleEvents-for-player-and-dispens.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Paper PR: Add FillBottleEvents for player and dispenser diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index 214bc24aa301f99c911a129676bc7d7d50df7236..83c6cf3cb062c8a6508728822e37d52a543415a3 100644 +index a162440a583801671787163d998d6b9546ef7e61..d10ee84ed2f6b1c81667b968984f3ebf5c39e445 100644 --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -2148,4 +2148,18 @@ public class CraftEventFactory { +@@ -2128,4 +2128,18 @@ public class CraftEventFactory { return disconnectReason; } diff --git a/divinemc-server/paper-patches/features/0012-Paper-PR-Player-standing-on-position-API.patch b/divinemc-server/paper-patches/features/0006-Paper-PR-Player-standing-on-position-API.patch similarity index 100% rename from divinemc-server/paper-patches/features/0012-Paper-PR-Player-standing-on-position-API.patch rename to divinemc-server/paper-patches/features/0006-Paper-PR-Player-standing-on-position-API.patch diff --git a/divinemc-server/paper-patches/features/0013-Paper-PR-Throttle-failed-spawn-attempts.patch b/divinemc-server/paper-patches/features/0007-Paper-PR-Throttle-failed-spawn-attempts.patch similarity index 100% rename from divinemc-server/paper-patches/features/0013-Paper-PR-Throttle-failed-spawn-attempts.patch rename to divinemc-server/paper-patches/features/0007-Paper-PR-Throttle-failed-spawn-attempts.patch diff --git a/divinemc-server/paper-patches/features/0015-Optimize-default-values-for-configs.patch b/divinemc-server/paper-patches/features/0008-Optimize-default-values-for-configs.patch similarity index 98% rename from divinemc-server/paper-patches/features/0015-Optimize-default-values-for-configs.patch rename to divinemc-server/paper-patches/features/0008-Optimize-default-values-for-configs.patch index 918b060..8c164d6 100644 --- a/divinemc-server/paper-patches/features/0015-Optimize-default-values-for-configs.patch +++ b/divinemc-server/paper-patches/features/0008-Optimize-default-values-for-configs.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Optimize default values for configs diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -index d13c749cfb49ce3c70b4c24ece780a4fc9482d78..a25a2bb0008901a249cf2cc320944bd69cf8ae72 100644 +index c5a491acfe4b93bfa8fd21861edbaf464a178bf3..f572613f3b2aeacfbfcd0a5f96048f55ec2384b9 100644 --- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java +++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -@@ -347,8 +347,8 @@ public class GlobalConfiguration extends ConfigurationPart { +@@ -348,8 +348,8 @@ public class GlobalConfiguration extends ConfigurationPart { @Constraints.Min(4) public int regionFileCacheSize = 256; @Comment("See https://luckformula.emc.gs") diff --git a/divinemc-server/paper-patches/features/0016-Implement-loading-plugins-from-external-folder.patch b/divinemc-server/paper-patches/features/0009-Implement-loading-plugins-from-external-folder.patch similarity index 100% rename from divinemc-server/paper-patches/features/0016-Implement-loading-plugins-from-external-folder.patch rename to divinemc-server/paper-patches/features/0009-Implement-loading-plugins-from-external-folder.patch diff --git a/divinemc-server/paper-patches/features/0017-Smooth-teleport-API.patch b/divinemc-server/paper-patches/features/0010-Smooth-teleport-API.patch similarity index 92% rename from divinemc-server/paper-patches/features/0017-Smooth-teleport-API.patch rename to divinemc-server/paper-patches/features/0010-Smooth-teleport-API.patch index cd260bc..6fbddaa 100644 --- a/divinemc-server/paper-patches/features/0017-Smooth-teleport-API.patch +++ b/divinemc-server/paper-patches/features/0010-Smooth-teleport-API.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Smooth teleport API diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index f2a7c688597d9a07e7ef07476cedbd423c8b3b0d..60669bf18850811546b46d85c6650b02cda963ab 100644 +index 218556fdaf4ea4993864e22530b4bad3335a535d..6a1ac6cdd0cf4f6a62216c264f6fd3cd25476254 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -1329,6 +1329,17 @@ public class CraftPlayer extends CraftHumanEntity implements Player, PluginMessa diff --git a/divinemc-server/purpur-patches/features/0004-Configurable-movement-speed-for-entities.patch b/divinemc-server/purpur-patches/features/0003-Configurable-movement-speed-for-entities.patch similarity index 100% rename from divinemc-server/purpur-patches/features/0004-Configurable-movement-speed-for-entities.patch rename to divinemc-server/purpur-patches/features/0003-Configurable-movement-speed-for-entities.patch diff --git a/divinemc-server/src/main/java/com/ishland/flowsched/executor/ExecutorManager.java b/divinemc-server/src/main/java/com/ishland/flowsched/executor/ExecutorManager.java deleted file mode 100644 index b1f2d69..0000000 --- a/divinemc-server/src/main/java/com/ishland/flowsched/executor/ExecutorManager.java +++ /dev/null @@ -1,191 +0,0 @@ -package com.ishland.flowsched.executor; - -import com.ishland.flowsched.structs.DynamicPriorityQueue; -import com.ishland.flowsched.util.Assertions; -import it.unimi.dsi.fastutil.objects.ReferenceArrayList; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.Executor; -import java.util.function.Consumer; - -public class ExecutorManager { - public final DynamicPriorityQueue globalWorkQueue; - protected final ConcurrentMap lockListeners = new ConcurrentHashMap<>(); - protected final WorkerThread[] workerThreads; - final Object workerMonitor = new Object(); - - /** - * Creates a new executor manager. - * - * @param workerThreadCount the number of worker threads. - */ - public ExecutorManager(int workerThreadCount) { - this(workerThreadCount, thread -> { }); - } - - /** - * Creates a new executor manager. - * - * @param workerThreadCount the number of worker threads. - * @param threadInitializer the thread initializer. - */ - public ExecutorManager(int workerThreadCount, Consumer threadInitializer) { - globalWorkQueue = new DynamicPriorityQueue<>(); - workerThreads = new WorkerThread[workerThreadCount]; - for (int i = 0; i < workerThreadCount; i++) { - final WorkerThread thread = new WorkerThread(this); - threadInitializer.accept(thread); - thread.start(); - workerThreads[i] = thread; - } - } - - /** - * Attempt to lock the given tokens. - * The caller should discard the task if this method returns false, as it reschedules the task. - * - * @return {@code true} if the lock is acquired, {@code false} otherwise. - */ - boolean tryLock(Task task) { - retry: - while (true) { - final FreeableTaskList listenerSet = new FreeableTaskList(); - LockToken[] lockTokens = task.lockTokens(); - for (int i = 0; i < lockTokens.length; i++) { - LockToken token = lockTokens[i]; - final FreeableTaskList present = this.lockListeners.putIfAbsent(token, listenerSet); - if (present != null) { - for (int j = 0; j < i; j++) { - this.lockListeners.remove(lockTokens[j], listenerSet); - } - callListeners(listenerSet); - synchronized (present) { - if (present.freed) { - continue retry; - } else { - present.add(task); - } - } - return false; - } - } - return true; - } - } - - /** - * Release the locks held by the given task. - * - * @param task the task. - */ - void releaseLocks(Task task) { - FreeableTaskList expectedListeners = null; - for (LockToken token : task.lockTokens()) { - final FreeableTaskList listeners = this.lockListeners.remove(token); - if (listeners != null) { - if (expectedListeners == null) { - expectedListeners = listeners; - } else { - Assertions.assertTrue(expectedListeners == listeners, "Inconsistent lock listeners"); - } - } else { - throw new IllegalStateException("Lock token " + token + " is not locked"); - } - } - if (expectedListeners != null) { - callListeners(expectedListeners); // synchronizes - } - } - - private void callListeners(FreeableTaskList listeners) { - synchronized (listeners) { - listeners.freed = true; - if (listeners.isEmpty()) return; - for (Task listener : listeners) { - this.schedule0(listener); - } - } - this.wakeup(); - } - - /** - * Polls an executable task from the global work queue. - * - * @return the task, or {@code null} if no task is executable. - */ - Task pollExecutableTask() { - Task task; - while ((task = this.globalWorkQueue.dequeue()) != null) { - if (this.tryLock(task)) { - return task; - } - } - return null; - } - - /** - * Shuts down the executor manager. - */ - public void shutdown() { - for (WorkerThread workerThread : workerThreads) { - workerThread.shutdown(); - } - } - - /** - * Schedules a task. - * - * @param task the task. - */ - public void schedule(Task task) { - schedule0(task); - wakeup(); - } - - private void schedule0(Task task) { - this.globalWorkQueue.enqueue(task, task.priority()); - } - - public void wakeup() { // Canvas - private -> public - synchronized (this.workerMonitor) { - this.workerMonitor.notify(); - } - } - - public boolean hasPendingTasks() { - return this.globalWorkQueue.size() != 0; - } - - /** - * Schedules a runnable for execution with the given priority. - * - * @param runnable the runnable. - * @param priority the priority. - */ - public void schedule(Runnable runnable, int priority) { - this.schedule(new SimpleTask(runnable, priority)); - } - - /** - * Creates an executor that schedules runnables with the given priority. - * - * @param priority the priority. - * @return the executor. - */ - public Executor executor(int priority) { - return runnable -> this.schedule(runnable, priority); - } - - /** - * Notifies the executor manager that the priority of the given task has changed. - * - * @param task the task. - */ - public void notifyPriorityChange(Task task) { - this.globalWorkQueue.changePriority(task, task.priority()); - } - - protected static class FreeableTaskList extends ReferenceArrayList { // Canvas - private -> protected - private boolean freed = false; - } -} diff --git a/divinemc-server/src/main/java/com/ishland/flowsched/executor/LockToken.java b/divinemc-server/src/main/java/com/ishland/flowsched/executor/LockToken.java deleted file mode 100644 index 96b9eb7..0000000 --- a/divinemc-server/src/main/java/com/ishland/flowsched/executor/LockToken.java +++ /dev/null @@ -1,3 +0,0 @@ -package com.ishland.flowsched.executor; - -public interface LockToken { } diff --git a/divinemc-server/src/main/java/com/ishland/flowsched/executor/SimpleTask.java b/divinemc-server/src/main/java/com/ishland/flowsched/executor/SimpleTask.java deleted file mode 100644 index 93a32fa..0000000 --- a/divinemc-server/src/main/java/com/ishland/flowsched/executor/SimpleTask.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.ishland.flowsched.executor; - -import java.util.Objects; - -public class SimpleTask implements Task { - private final Runnable wrapped; - private final int priority; - - public SimpleTask(Runnable wrapped, int priority) { - this.wrapped = Objects.requireNonNull(wrapped); - this.priority = priority; - } - - @Override - public void run(Runnable releaseLocks) { - try { - wrapped.run(); - } finally { - releaseLocks.run(); - } - } - - @Override - public void propagateException(Throwable t) { - t.printStackTrace(); - } - - @Override - public LockToken[] lockTokens() { - return new LockToken[0]; - } - - @Override - public int priority() { - return this.priority; - } -} diff --git a/divinemc-server/src/main/java/com/ishland/flowsched/executor/Task.java b/divinemc-server/src/main/java/com/ishland/flowsched/executor/Task.java deleted file mode 100644 index 86aa983..0000000 --- a/divinemc-server/src/main/java/com/ishland/flowsched/executor/Task.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.ishland.flowsched.executor; - -public interface Task { - void run(Runnable releaseLocks); - - void propagateException(Throwable t); - - LockToken[] lockTokens(); - - int priority(); -} diff --git a/divinemc-server/src/main/java/com/ishland/flowsched/executor/WorkerThread.java b/divinemc-server/src/main/java/com/ishland/flowsched/executor/WorkerThread.java deleted file mode 100644 index 6f93999..0000000 --- a/divinemc-server/src/main/java/com/ishland/flowsched/executor/WorkerThread.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.ishland.flowsched.executor; - -import ca.spottedleaf.moonrise.common.util.TickThread; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.LockSupport; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class WorkerThread extends TickThread { - private static final Logger LOGGER = LoggerFactory.getLogger("FlowSched Executor Worker Thread"); - - private final ExecutorManager executorManager; - private final AtomicBoolean shutdown = new AtomicBoolean(false); - public volatile boolean active = false; - - public WorkerThread(ExecutorManager executorManager) { - super("null_worker"); - this.executorManager = executorManager; - } - - @Override - public void run() { - main_loop: - while (true) { - if (this.shutdown.get()) { - return; - } - active = true; - if (pollTasks()) { - continue; - } - - synchronized (this.executorManager.workerMonitor) { - if (this.executorManager.hasPendingTasks()) continue main_loop; - try { - active = false; - this.executorManager.workerMonitor.wait(); - } catch (InterruptedException ignored) { - } - } - } - } - - private boolean pollTasks() { - final Task task = executorManager.pollExecutableTask(); - try { - if (task != null) { - AtomicBoolean released = new AtomicBoolean(false); - try { - task.run(() -> { - if (released.compareAndSet(false, true)) { - executorManager.releaseLocks(task); - } - }); - } catch (Throwable t) { - try { - if (released.compareAndSet(false, true)) { - executorManager.releaseLocks(task); - } - } catch (Throwable t1) { - t.addSuppressed(t1); - LOGGER.error("Exception thrown while releasing locks", t); - } - try { - task.propagateException(t); - } catch (Throwable t1) { - t.addSuppressed(t1); - LOGGER.error("Exception thrown while propagating exception", t); - } - } - return true; - } - return false; - } catch (Throwable t) { - LOGGER.error("Exception thrown while executing task", t); - return true; - } - } - - public void shutdown() { - shutdown.set(true); - LockSupport.unpark(this); - } -} diff --git a/divinemc-server/src/main/java/com/ishland/flowsched/structs/DynamicPriorityQueue.java b/divinemc-server/src/main/java/com/ishland/flowsched/structs/DynamicPriorityQueue.java deleted file mode 100644 index b17a49d..0000000 --- a/divinemc-server/src/main/java/com/ishland/flowsched/structs/DynamicPriorityQueue.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.ishland.flowsched.structs; - -import ca.spottedleaf.moonrise.common.util.MoonriseConstants; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicIntegerArray; - -@SuppressWarnings("unchecked") -public class DynamicPriorityQueue { - public static final int MAX_PRIORITY = MoonriseConstants.MAX_VIEW_DISTANCE + 3; - private final AtomicIntegerArray taskCount; - public final ConcurrentLinkedQueue[] priorities; - private final ConcurrentHashMap priorityMap = new ConcurrentHashMap<>(); - - public DynamicPriorityQueue() { - this.taskCount = new AtomicIntegerArray(MAX_PRIORITY); - this.priorities = new ConcurrentLinkedQueue[MAX_PRIORITY]; - for (int i = 0; i < (MAX_PRIORITY); i++) { - this.priorities[i] = new ConcurrentLinkedQueue<>(); - } - } - - public void enqueue(E element, int priority) { - if (this.priorityMap.putIfAbsent(element, priority) != null) - throw new IllegalArgumentException("Element already in queue"); - - this.priorities[priority].add(element); - this.taskCount.incrementAndGet(priority); - } - - public boolean changePriority(E element, int newPriority) { - Integer currentPriority = this.priorityMap.get(element); - if (currentPriority == null || currentPriority == newPriority) { - return false; - } - - int currentIndex = currentPriority; - boolean removedFromQueue = this.priorities[currentIndex].remove(element); - if (!removedFromQueue) { - return false; - } - - this.taskCount.decrementAndGet(currentIndex); - final boolean changeSuccess = this.priorityMap.replace(element, currentPriority, newPriority); - if (!changeSuccess) { - return false; - } - - this.priorities[newPriority].add(element); - this.taskCount.incrementAndGet(newPriority); - return true; - } - - public E dequeue() { - for (int i = 0; i < this.priorities.length; i++) { - if (this.taskCount.get(i) == 0) continue; - E element = priorities[i].poll(); - if (element != null) { - this.taskCount.decrementAndGet(i); - this.priorityMap.remove(element); - return element; - } - } - return null; - } - - public boolean contains(E element) { - return priorityMap.containsKey(element); - } - - public void remove(E element) { - Integer priority = this.priorityMap.remove(element); - if (priority == null) return; - - boolean removed = this.priorities[priority].remove(element); - if (removed) this.taskCount.decrementAndGet(priority); - } - - public int size() { - return priorityMap.size(); - } - - public boolean isEmpty() { - return size() == 0; - } -} diff --git a/divinemc-server/src/main/java/com/ishland/flowsched/util/Assertions.java b/divinemc-server/src/main/java/com/ishland/flowsched/util/Assertions.java deleted file mode 100644 index c3ee6c4..0000000 --- a/divinemc-server/src/main/java/com/ishland/flowsched/util/Assertions.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.ishland.flowsched.util; - -public final class Assertions { - public static void assertTrue(boolean value, String message) { - if (!value) { - final AssertionError error = new AssertionError(message); - error.printStackTrace(); - throw error; - } - } - - public static void assertTrue(boolean state, String format, Object... args) { - if (!state) { - final AssertionError error = new AssertionError(String.format(format, args)); - error.printStackTrace(); - throw error; - } - } - - public static void assertTrue(boolean value) { - if (!value) { - final AssertionError error = new AssertionError(); - error.printStackTrace(); - throw error; - } - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/IRegionFile.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/IRegionFile.java deleted file mode 100644 index cf4104a..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/IRegionFile.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.bxteam.divinemc.region; - -import ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.ChunkPos; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.file.Path; - -public interface IRegionFile extends AutoCloseable, ChunkSystemRegionFile { - Path getPath(); - - void flush() throws IOException; - - void clear(ChunkPos pos) throws IOException; - - @Override - void close() throws IOException; - - void setOversized(int x, int z, boolean b) throws IOException; - - void write(ChunkPos pos, ByteBuffer buffer) throws IOException; - - boolean hasChunk(ChunkPos pos); - - boolean doesChunkExist(ChunkPos pos) throws Exception; - - boolean isOversized(int x, int z); - - boolean recalculateHeader() throws IOException; - - int getRecalculateCount(); - - DataOutputStream getChunkDataOutputStream(ChunkPos pos) throws IOException; - - DataInputStream getChunkDataInputStream(ChunkPos pos) throws IOException; - - CompoundTag getOversizedData(int x, int z) throws IOException; -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/LinearImplementation.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/LinearImplementation.java deleted file mode 100644 index e521593..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/LinearImplementation.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.bxteam.divinemc.region; - -public enum LinearImplementation { - V1, - V2 -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/LinearRegionFile.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/LinearRegionFile.java deleted file mode 100644 index 3e25b24..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/LinearRegionFile.java +++ /dev/null @@ -1,664 +0,0 @@ -package org.bxteam.divinemc.region; - -import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; -import com.github.luben.zstd.ZstdInputStream; -import com.github.luben.zstd.ZstdOutputStream; -import com.mojang.logging.LogUtils; -import net.jpountz.lz4.LZ4Compressor; -import net.jpountz.lz4.LZ4Factory; -import net.jpountz.lz4.LZ4FastDecompressor; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.ChunkPos; -import net.openhft.hashing.LongHashFunction; -import org.bxteam.divinemc.config.DivineConfig; -import org.bxteam.divinemc.spark.ThreadDumperRegistry; -import org.jspecify.annotations.Nullable; -import org.slf4j.Logger; - -import java.io.BufferedOutputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.util.ArrayList; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.LockSupport; - -public class LinearRegionFile implements IRegionFile { - public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024; - private static final Object SAVE_LOCK = new Object(); - private static final long SUPERBLOCK = 0xc3ff13183cca9d9aL; - private static final Logger LOGGER = LogUtils.getLogger(); - - private static final byte V1_VERSION = 2; - private static final byte V2_VERSION = 3; - - private byte[][] bucketBuffers; - private final byte[][] chunkCompressedBuffers = new byte[1024][]; - private final int[] chunkUncompressedSizes = new int[1024]; - private final long[] chunkTimestamps = new long[1024]; - - private final Object markedToSaveLock = new Object(); - private boolean markedToSave = false; - - private final LZ4Compressor compressor; - private final LZ4FastDecompressor decompressor; - - private volatile boolean regionFileOpen = false; - private volatile boolean close = false; - - private final Path regionFilePath; - private final int gridSizeDefault = 8; - private int gridSize = gridSizeDefault; - private int bucketSize = 4; - private final int compressionLevel; - private final LinearImplementation linearImpl; - private final Thread schedulingThread; - - private static int activeSaveThreads = 0; - - public LinearRegionFile(Path path, LinearImplementation linearImplementation, int compressionLevel) { - this.regionFilePath = path; - this.linearImpl = linearImplementation; - this.compressionLevel = compressionLevel; - this.compressor = LZ4Factory.fastestInstance().fastCompressor(); - this.decompressor = LZ4Factory.fastestInstance().fastDecompressor(); - - Runnable flushCheck = () -> { - while (!close) { - synchronized (SAVE_LOCK) { - if (markedToSave && activeSaveThreads < DivineConfig.MiscCategory.linearFlushMaxThreads) { - activeSaveThreads++; - Runnable flushOperation = () -> { - try { - flush(); - } catch (IOException ex) { - LOGGER.error("Region file {} flush failed", regionFilePath.toAbsolutePath(), ex); - } finally { - synchronized (SAVE_LOCK) { - activeSaveThreads--; - } - } - }; - Thread saveThread = DivineConfig.MiscCategory.linearUseVirtualThread - ? Thread.ofVirtual().name("Linear IO - " + this.hashCode()).unstarted(flushOperation) - : Thread.ofPlatform().name("Linear IO - " + this.hashCode()).unstarted(flushOperation); - saveThread.setPriority(Thread.NORM_PRIORITY - 3); - saveThread.start(); - ThreadDumperRegistry.REGISTRY.add(saveThread.getName()); - } - } - LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(DivineConfig.MiscCategory.linearFlushDelay)); - } - }; - this.schedulingThread = DivineConfig.MiscCategory.linearUseVirtualThread - ? Thread.ofVirtual().unstarted(flushCheck) - : Thread.ofPlatform().unstarted(flushCheck); - this.schedulingThread.setName("Linear IO Schedule - " + this.hashCode()); - ThreadDumperRegistry.REGISTRY.add(this.schedulingThread.getName()); - } - - private synchronized void openRegionFile() { - if (regionFileOpen) return; - regionFileOpen = true; - - File file = regionFilePath.toFile(); - if (!file.canRead()) { - schedulingThread.start(); - return; - } - - try { - byte[] fileContent = Files.readAllBytes(regionFilePath); - ByteBuffer byteBuffer = ByteBuffer.wrap(fileContent); - - long superBlock = byteBuffer.getLong(); - if (superBlock != SUPERBLOCK) { - throw new RuntimeException("Invalid superblock: " + superBlock + " file " + regionFilePath); - } - - byte version = byteBuffer.get(); - if (version == V1_VERSION) { - parseLinearV1(byteBuffer); - } else if (version == V2_VERSION) { - parseLinearV2(byteBuffer); - } else { - throw new RuntimeException("Invalid version: " + version + " file " + regionFilePath); - } - - schedulingThread.start(); - } catch (IOException e) { - throw new RuntimeException("Failed to open region file " + regionFilePath, e); - } - } - - private void parseLinearV1(ByteBuffer buffer) throws IOException { - final int HEADER_SIZE = 32; - final int FOOTER_SIZE = 8; - buffer.position(buffer.position() + 11); - - int dataCount = buffer.getInt(); - long fileLength = regionFilePath.toFile().length(); - if (fileLength != HEADER_SIZE + dataCount + FOOTER_SIZE) { - throw new IOException("Invalid file length: " + regionFilePath + " " + fileLength + " expected " + (HEADER_SIZE + dataCount + FOOTER_SIZE)); - } - - buffer.position(buffer.position() + 8); - - byte[] rawCompressed = new byte[dataCount]; - buffer.get(rawCompressed); - - try (ByteArrayInputStream bais = new ByteArrayInputStream(rawCompressed); - ZstdInputStream zstdIn = new ZstdInputStream(bais)) { - ByteBuffer decompressedBuffer = ByteBuffer.wrap(zstdIn.readAllBytes()); - int[] starts = new int[1024]; - for (int i = 0; i < 1024; i++) { - starts[i] = decompressedBuffer.getInt(); - decompressedBuffer.getInt(); - } - - for (int i = 0; i < 1024; i++) { - if (starts[i] > 0) { - int size = starts[i]; - byte[] chunkData = new byte[size]; - decompressedBuffer.get(chunkData); - - int maxCompressedLength = compressor.maxCompressedLength(size); - byte[] compressed = new byte[maxCompressedLength]; - int compressedLength = compressor.compress(chunkData, 0, size, compressed, 0, maxCompressedLength); - byte[] finalCompressed = new byte[compressedLength]; - System.arraycopy(compressed, 0, finalCompressed, 0, compressedLength); - - chunkCompressedBuffers[i] = finalCompressed; - chunkUncompressedSizes[i] = size; - chunkTimestamps[i] = currentTimestamp(); - } - } - } - } - - private void parseLinearV2(ByteBuffer buffer) throws IOException { - buffer.getLong(); - gridSize = buffer.get(); - if (!(gridSize == 1 || gridSize == 2 || gridSize == 4 || gridSize == 8 || gridSize == 16 || gridSize == 32)) { - throw new RuntimeException("Invalid grid size: " + gridSize + " file " + regionFilePath); - } - bucketSize = 32 / gridSize; - - buffer.getInt(); - buffer.getInt(); - - boolean[] chunkExistenceBitmap = deserializeExistenceBitmap(buffer); - - while (true) { - byte featureNameLength = buffer.get(); - if (featureNameLength == 0) break; - byte[] featureNameBytes = new byte[featureNameLength]; - buffer.get(featureNameBytes); - String featureName = new String(featureNameBytes); - int featureValue = buffer.getInt(); - } - - int bucketCount = gridSize * gridSize; - int[] bucketSizes = new int[bucketCount]; - byte[] bucketCompressionLevels = new byte[bucketCount]; - long[] bucketHashes = new long[bucketCount]; - - for (int i = 0; i < bucketCount; i++) { - bucketSizes[i] = buffer.getInt(); - bucketCompressionLevels[i] = buffer.get(); - bucketHashes[i] = buffer.getLong(); - } - - bucketBuffers = new byte[bucketCount][]; - for (int i = 0; i < bucketCount; i++) { - if (bucketSizes[i] > 0) { - bucketBuffers[i] = new byte[bucketSizes[i]]; - buffer.get(bucketBuffers[i]); - long rawHash = LongHashFunction.xx().hashBytes(bucketBuffers[i]); - if (rawHash != bucketHashes[i]) { - throw new IOException("Region file hash incorrect " + regionFilePath); - } - } - } - - long footerSuperBlock = buffer.getLong(); - if (footerSuperBlock != SUPERBLOCK) { - throw new IOException("Footer superblock invalid " + regionFilePath); - } - } - - private synchronized void markToSave() { - synchronized (markedToSaveLock) { - markedToSave = true; - } - } - - private synchronized boolean isMarkedToSave() { - synchronized (markedToSaveLock) { - if (markedToSave) { - markedToSave = false; - return true; - } - return false; - } - } - - @Override - public synchronized boolean doesChunkExist(ChunkPos pos) { - openRegionFile(); - return hasChunk(pos); - } - - @Override - public synchronized boolean hasChunk(ChunkPos pos) { - openRegionFile(); - openBucketForChunk(pos.x, pos.z); - int index = getChunkIndex(pos.x, pos.z); - return chunkUncompressedSizes[index] > 0; - } - - @Override - public synchronized void flush() throws IOException { - if (!isMarkedToSave()) return; - openRegionFile(); - if (linearImpl == LinearImplementation.V1) { - flushLinearV1(); - } else if (linearImpl == LinearImplementation.V2) { - flushLinearV2(); - } - } - - private void flushLinearV1() throws IOException { - long timestamp = currentTimestamp(); - short chunkCount = 0; - File tempFile = new File(regionFilePath.toString() + ".tmp"); - - try (FileOutputStream fos = new FileOutputStream(tempFile); - ByteArrayOutputStream zstdBAOS = new ByteArrayOutputStream(); - ZstdOutputStream zstdOut = new ZstdOutputStream(zstdBAOS, compressionLevel); - DataOutputStream zstdDataOut = new DataOutputStream(zstdOut); - DataOutputStream fileDataOut = new DataOutputStream(fos)) { - - fileDataOut.writeLong(SUPERBLOCK); - fileDataOut.writeByte(V1_VERSION); - fileDataOut.writeLong(timestamp); - fileDataOut.writeByte(compressionLevel); - - ArrayList decompressedChunks = new ArrayList<>(1024); - for (int i = 0; i < 1024; i++) { - if (chunkUncompressedSizes[i] != 0) { - chunkCount++; - byte[] decompressed = new byte[chunkUncompressedSizes[i]]; - decompressor.decompress(chunkCompressedBuffers[i], 0, decompressed, 0, chunkUncompressedSizes[i]); - decompressedChunks.add(decompressed); - } else { - decompressedChunks.add(null); - } - } - - for (int i = 0; i < 1024; i++) { - zstdDataOut.writeInt(chunkUncompressedSizes[i]); - zstdDataOut.writeInt((int) chunkTimestamps[i]); - } - - for (int i = 0; i < 1024; i++) { - if (decompressedChunks.get(i) != null) { - zstdDataOut.write(decompressedChunks.get(i)); - } - } - zstdDataOut.close(); - - fileDataOut.writeShort(chunkCount); - byte[] compressedZstdData = zstdBAOS.toByteArray(); - fileDataOut.writeInt(compressedZstdData.length); - fileDataOut.writeLong(0); - fileDataOut.write(compressedZstdData); - fileDataOut.writeLong(SUPERBLOCK); - - fileDataOut.flush(); - fos.getFD().sync(); - fos.getChannel().force(true); - } - Files.move(tempFile.toPath(), regionFilePath, StandardCopyOption.REPLACE_EXISTING); - } - - private void flushLinearV2() throws IOException { - long timestamp = currentTimestamp(); - File tempFile = new File(regionFilePath.toString() + ".tmp"); - - try (FileOutputStream fos = new FileOutputStream(tempFile); - DataOutputStream dataOut = new DataOutputStream(fos)) { - - dataOut.writeLong(SUPERBLOCK); - dataOut.writeByte(V2_VERSION); - dataOut.writeLong(timestamp); - dataOut.writeByte(gridSize); - - int[] regionCoords = parseRegionCoordinates(regionFilePath.getFileName().toString()); - dataOut.writeInt(regionCoords[0]); - dataOut.writeInt(regionCoords[1]); - - boolean[] chunkExistence = new boolean[1024]; - for (int i = 0; i < 1024; i++) { - chunkExistence[i] = (chunkUncompressedSizes[i] > 0); - } - writeExistenceBitmap(dataOut, chunkExistence); - - writeNBTFeatures(dataOut); - - byte[][] buckets = buildBuckets(); - - int bucketCount = gridSize * gridSize; - for (int i = 0; i < bucketCount; i++) { - dataOut.writeInt(buckets[i] != null ? buckets[i].length : 0); - dataOut.writeByte(compressionLevel); - long bucketHash = buckets[i] != null ? LongHashFunction.xx().hashBytes(buckets[i]) : 0; - dataOut.writeLong(bucketHash); - } - for (int i = 0; i < bucketCount; i++) { - if (buckets[i] != null) { - dataOut.write(buckets[i]); - } - } - dataOut.writeLong(SUPERBLOCK); - - dataOut.flush(); - fos.getFD().sync(); - fos.getChannel().force(true); - } - Files.move(tempFile.toPath(), regionFilePath, StandardCopyOption.REPLACE_EXISTING); - } - - private void writeNBTFeatures(DataOutputStream dataOut) throws IOException { - dataOut.writeByte(0); - } - - private byte[][] buildBuckets() throws IOException { - int bucketCount = gridSize * gridSize; - byte[][] buckets = new byte[bucketCount][]; - - for (int bx = 0; bx < gridSize; bx++) { - for (int bz = 0; bz < gridSize; bz++) { - int bucketIdx = bx * gridSize + bz; - if (bucketBuffers != null && bucketBuffers[bucketIdx] != null) { - buckets[bucketIdx] = bucketBuffers[bucketIdx]; - continue; - } - - try (ByteArrayOutputStream bucketBAOS = new ByteArrayOutputStream(); - ZstdOutputStream bucketZstdOut = new ZstdOutputStream(bucketBAOS, compressionLevel); - DataOutputStream bucketDataOut = new DataOutputStream(bucketZstdOut)) { - - boolean hasData = false; - int cellCount = 32 / gridSize; - for (int cx = 0; cx < cellCount; cx++) { - for (int cz = 0; cz < cellCount; cz++) { - int chunkIndex = (bx * cellCount + cx) + (bz * cellCount + cz) * 32; - if (chunkUncompressedSizes[chunkIndex] > 0) { - hasData = true; - byte[] chunkData = new byte[chunkUncompressedSizes[chunkIndex]]; - decompressor.decompress(chunkCompressedBuffers[chunkIndex], 0, chunkData, 0, chunkUncompressedSizes[chunkIndex]); - bucketDataOut.writeInt(chunkData.length + 8); - bucketDataOut.writeLong(chunkTimestamps[chunkIndex]); - bucketDataOut.write(chunkData); - } else { - bucketDataOut.writeInt(0); - bucketDataOut.writeLong(chunkTimestamps[chunkIndex]); - } - } - } - bucketDataOut.close(); - if (hasData) { - buckets[bucketIdx] = bucketBAOS.toByteArray(); - } - } - } - } - return buckets; - } - - private void openBucketForChunk(int chunkX, int chunkZ) { - int modX = Math.floorMod(chunkX, 32); - int modZ = Math.floorMod(chunkZ, 32); - int bucketIdx = chunkToBucketIndex(modX, modZ); - if (bucketBuffers == null || bucketBuffers[bucketIdx] == null) { - return; - } - - try (ByteArrayInputStream bucketBAIS = new ByteArrayInputStream(bucketBuffers[bucketIdx]); - ZstdInputStream bucketZstdIn = new ZstdInputStream(bucketBAIS)) { - - ByteBuffer bucketBuffer = ByteBuffer.wrap(bucketZstdIn.readAllBytes()); - int cellsPerBucket = 32 / gridSize; - int bx = modX / bucketSize, bz = modZ / bucketSize; - for (int cx = 0; cx < cellsPerBucket; cx++) { - for (int cz = 0; cz < cellsPerBucket; cz++) { - int chunkIndex = (bx * cellsPerBucket + cx) + (bz * cellsPerBucket + cz) * 32; - int chunkSize = bucketBuffer.getInt(); - long timestamp = bucketBuffer.getLong(); - chunkTimestamps[chunkIndex] = timestamp; - - if (chunkSize > 0) { - byte[] chunkData = new byte[chunkSize - 8]; - bucketBuffer.get(chunkData); - - int maxCompressedLength = compressor.maxCompressedLength(chunkData.length); - byte[] compressed = new byte[maxCompressedLength]; - int compressedLength = compressor.compress(chunkData, 0, chunkData.length, compressed, 0, maxCompressedLength); - byte[] finalCompressed = new byte[compressedLength]; - System.arraycopy(compressed, 0, finalCompressed, 0, compressedLength); - - chunkCompressedBuffers[chunkIndex] = finalCompressed; - chunkUncompressedSizes[chunkIndex] = chunkData.length; - } - } - } - } catch (IOException ex) { - throw new RuntimeException("Region file corrupted: " + regionFilePath + " bucket: " + bucketIdx, ex); - } - bucketBuffers[bucketIdx] = null; - } - - @Override - public synchronized void write(ChunkPos pos, ByteBuffer buffer) { - openRegionFile(); - openBucketForChunk(pos.x, pos.z); - try { - byte[] rawData = toByteArray(new ByteArrayInputStream(buffer.array())); - int uncompressedSize = rawData.length; - if (uncompressedSize > MAX_CHUNK_SIZE) { - LOGGER.error("Chunk dupe attempt {}", regionFilePath); - clear(pos); - } else { - int maxCompressedLength = compressor.maxCompressedLength(uncompressedSize); - byte[] compressed = new byte[maxCompressedLength]; - int compressedLength = compressor.compress(rawData, 0, uncompressedSize, compressed, 0, maxCompressedLength); - byte[] finalCompressed = new byte[compressedLength]; - System.arraycopy(compressed, 0, finalCompressed, 0, compressedLength); - - int index = getChunkIndex(pos.x, pos.z); - chunkCompressedBuffers[index] = finalCompressed; - chunkTimestamps[index] = currentTimestamp(); - chunkUncompressedSizes[index] = uncompressedSize; - } - } catch (IOException e) { - LOGGER.error("Chunk write IOException {} {}", e, regionFilePath); - } - markToSave(); - } - - @Override - public DataOutputStream getChunkDataOutputStream(ChunkPos pos) { - openRegionFile(); - openBucketForChunk(pos.x, pos.z); - return new DataOutputStream(new BufferedOutputStream(new ChunkBuffer(pos))); - } - - @Override - public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(CompoundTag data, ChunkPos pos) { - DataOutputStream out = getChunkDataOutputStream(pos); - return new ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData( - data, - ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.WRITE, - out, - regionFile -> { - try { - out.close(); - } catch (IOException e) { - LOGGER.error("Failed to close region file stream", e); - } - } - ); - } - - private class ChunkBuffer extends ByteArrayOutputStream { - private final ChunkPos pos; - public ChunkBuffer(ChunkPos pos) { - super(); - this.pos = pos; - } - @Override - public void close() { - ByteBuffer byteBuffer = ByteBuffer.wrap(this.buf, 0, this.count); - LinearRegionFile.this.write(this.pos, byteBuffer); - } - } - - private byte[] toByteArray(InputStream in) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - byte[] tempBuffer = new byte[4096]; - int length; - while ((length = in.read(tempBuffer)) >= 0) { - out.write(tempBuffer, 0, length); - } - return out.toByteArray(); - } - - @Nullable - @Override - public synchronized DataInputStream getChunkDataInputStream(ChunkPos pos) { - openRegionFile(); - openBucketForChunk(pos.x, pos.z); - int index = getChunkIndex(pos.x, pos.z); - if (chunkUncompressedSizes[index] != 0) { - byte[] decompressed = new byte[chunkUncompressedSizes[index]]; - decompressor.decompress(chunkCompressedBuffers[index], 0, decompressed, 0, chunkUncompressedSizes[index]); - return new DataInputStream(new ByteArrayInputStream(decompressed)); - } - return null; - } - - @Override - public synchronized void clear(ChunkPos pos) { - openRegionFile(); - openBucketForChunk(pos.x, pos.z); - int index = getChunkIndex(pos.x, pos.z); - chunkCompressedBuffers[index] = null; - chunkUncompressedSizes[index] = 0; - chunkTimestamps[index] = 0; - markToSave(); - } - - @Override - public synchronized void close() throws IOException { - openRegionFile(); - close = true; - try { - flush(); - } catch (IOException e) { - throw new IOException("Region flush IOException " + e + " " + regionFilePath, e); - } - } - - private static int getChunkIndex(int x, int z) { - return (x & 31) + ((z & 31) << 5); - } - - private static int currentTimestamp() { - return (int) (System.currentTimeMillis() / 1000L); - } - - @Override - public boolean recalculateHeader() { - return false; - } - - @Override - public int getRecalculateCount() { - return 0; - } - - @Override - public void setOversized(int x, int z, boolean something) { - // stub - } - - @Override - public CompoundTag getOversizedData(int x, int z) throws IOException { - throw new IOException("getOversizedData is a stub " + regionFilePath); - } - - @Override - public boolean isOversized(int x, int z) { - return false; - } - - @Override - public Path getPath() { - return regionFilePath; - } - - private boolean[] deserializeExistenceBitmap(ByteBuffer buffer) { - boolean[] result = new boolean[1024]; - for (int i = 0; i < 128; i++) { - byte b = buffer.get(); - for (int j = 0; j < 8; j++) { - result[i * 8 + j] = ((b >> (7 - j)) & 1) == 1; - } - } - return result; - } - - private void writeExistenceBitmap(DataOutputStream out, boolean[] bitmap) throws IOException { - for (int i = 0; i < 128; i++) { - byte b = 0; - for (int j = 0; j < 8; j++) { - if (bitmap[i * 8 + j]) { - b |= (1 << (7 - j)); - } - } - out.writeByte(b); - } - } - - private int chunkToBucketIndex(int chunkX, int chunkZ) { - int bx = chunkX / bucketSize, bz = chunkZ / bucketSize; - return bx * gridSize + bz; - } - - private int[] parseRegionCoordinates(String fileName) { - int regionX = 0; - int regionZ = 0; - String[] parts = fileName.split("\\."); - if (parts.length >= 4) { - try { - regionX = Integer.parseInt(parts[1]); - regionZ = Integer.parseInt(parts[2]); - } catch (NumberFormatException e) { - LOGGER.error("Failed to parse region coordinates from file name: {}", fileName, e); - } - } else { - LOGGER.warn("Unexpected file name format: {}", fileName); - } - return new int[]{regionX, regionZ}; - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileFactory.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileFactory.java deleted file mode 100644 index 6d9584b..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileFactory.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.bxteam.divinemc.region; - -import net.minecraft.world.level.chunk.storage.RegionFile; -import net.minecraft.world.level.chunk.storage.RegionFileVersion; -import net.minecraft.world.level.chunk.storage.RegionStorageInfo; -import org.bxteam.divinemc.config.DivineConfig; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; - -import java.io.IOException; -import java.nio.file.Path; - -public class RegionFileFactory { - @Contract("_, _, _, _ -> new") - public static @NotNull IRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync) throws IOException { - return getAbstractRegionFile(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync); - } - - @Contract("_, _, _, _, _ -> new") - public static @NotNull IRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, @NotNull Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync) throws IOException { - final String fullFileName = path.getFileName().toString(); - final String[] fullNameSplit = fullFileName.split("\\."); - final String extensionName = fullNameSplit[fullNameSplit.length - 1]; - switch (RegionFileFormat.fromExtension(extensionName)) { - case LINEAR -> { - return new LinearRegionFile(path, DivineConfig.MiscCategory.linearImplementation, DivineConfig.MiscCategory.linearCompressionLevel); - } - - default -> { - return new RegionFile(storageKey, path, directory, compressionFormat, dsync); - } - } - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileFormat.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileFormat.java deleted file mode 100644 index 30a54e5..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileFormat.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.bxteam.divinemc.region; - -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import java.util.Locale; - -public enum RegionFileFormat { - LINEAR(".linear"), - ANVIL(".mca"), - UNKNOWN(null); - - private final String extension; - - RegionFileFormat(String extension) { - this.extension = extension; - } - - public String getExtensionName() { - return this.extension; - } - - @Contract(pure = true) - public static RegionFileFormat fromName(@NotNull String name) { - switch (name.toUpperCase(Locale.ROOT)) { - case "MCA", "ANVIL" -> { - return ANVIL; - } - - case "LINEAR" -> { - return LINEAR; - } - - default -> { - throw new IllegalArgumentException("Unknown region file format: " + name); - } - } - } - - @Contract(pure = true) - public static RegionFileFormat fromExtension(@NotNull String name) { - switch (name.toLowerCase()) { - case "mca", "anvil" -> { - return ANVIL; - } - - case "linear" -> { - return LINEAR; - } - - default -> { - return UNKNOWN; - } - } - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/server/chunk/ChunkSystemTaskQueue.java b/divinemc-server/src/main/java/org/bxteam/divinemc/server/chunk/ChunkSystemTaskQueue.java deleted file mode 100644 index 9842ea2..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/server/chunk/ChunkSystemTaskQueue.java +++ /dev/null @@ -1,404 +0,0 @@ -package org.bxteam.divinemc.server.chunk; - -import ca.spottedleaf.concurrentutil.executor.PrioritisedExecutor; -import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; -import ca.spottedleaf.concurrentutil.util.Priority; - -import java.lang.invoke.VarHandle; -import java.util.Comparator; -import java.util.Map; -import java.util.concurrent.ConcurrentSkipListMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; - -public final class ChunkSystemTaskQueue implements PrioritisedExecutor { - private final AtomicLong taskIdGenerator = new AtomicLong(); - private final AtomicLong scheduledTasks = new AtomicLong(); - private final AtomicLong executedTasks = new AtomicLong(); - private final AtomicLong subOrderGenerator = new AtomicLong(); - private final AtomicBoolean shutdown = new AtomicBoolean(); - private final ConcurrentSkipListMap tasks = new ConcurrentSkipListMap<>(ChunkSystemTaskQueue.PrioritisedQueuedTask.COMPARATOR); - private final TheChunkSystem chunkSystem; - - public ChunkSystemTaskQueue(TheChunkSystem chunkSystem) { - this.chunkSystem = chunkSystem; - } - - @Override - public long getTotalTasksScheduled() { - return this.scheduledTasks.get(); - } - - @Override - public long getTotalTasksExecuted() { - return this.executedTasks.get(); - } - - @Override - public long generateNextSubOrder() { - return this.subOrderGenerator.getAndIncrement(); - } - - @Override - public boolean shutdown() { - return !this.shutdown.getAndSet(true); - } - - @Override - public boolean isShutdown() { - return this.shutdown.get(); - } - - @Override - public boolean executeTask() { - for (; ; ) { - final Map.Entry firstEntry = this.tasks.pollFirstEntry(); - if (firstEntry != null) { - final ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder task = firstEntry.getKey(); - task.markRemoved(); - if (!task.task.execute()) { - continue; - } - return true; - } - - return false; - } - } - - @Override - public PrioritisedTask createTask(final Runnable task) { - return this.createTask(task, Priority.NORMAL, this.generateNextSubOrder()); - } - - @Override - public PrioritisedTask createTask(final Runnable task, final Priority priority) { - return this.createTask(task, priority, this.generateNextSubOrder()); - } - - @Override - public PrioritisedTask createTask(final Runnable task, final Priority priority, final long subOrder) { - return new ChunkSystemTaskQueue.PrioritisedQueuedTask(task, priority, subOrder); - } - - @Override - public PrioritisedTask queueTask(final Runnable task) { - return this.queueTask(task, Priority.NORMAL, this.generateNextSubOrder()); - } - - @Override - public PrioritisedTask queueTask(final Runnable task, final Priority priority) { - return this.queueTask(task, priority, this.generateNextSubOrder()); - } - - @Override - public PrioritisedTask queueTask(final Runnable task, final Priority priority, final long subOrder) { - final ChunkSystemTaskQueue.PrioritisedQueuedTask ret = new ChunkSystemTaskQueue.PrioritisedQueuedTask(task, priority, subOrder); - - ret.queue(); - - return ret; - } - - private final class PrioritisedQueuedTask implements PrioritisedExecutor.PrioritisedTask { - public static final Comparator COMPARATOR = (final ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder t1, final ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder t2) -> { - final int priorityCompare = t1.priority - t2.priority; - if (priorityCompare != 0) { - return priorityCompare; - } - - final int subOrderCompare = Long.compare(t1.subOrder, t2.subOrder); - if (subOrderCompare != 0) { - return subOrderCompare; - } - - return Long.compare(t1.id, t2.id); - }; - private final long id; - private final Runnable execute; - private Priority priority; - private long subOrder; - private ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder holder; - - public PrioritisedQueuedTask(final Runnable execute, final Priority priority, final long subOrder) { - if (!Priority.isValidPriority(priority)) { - throw new IllegalArgumentException("Invalid priority " + priority); - } - - this.execute = execute; - this.priority = priority; - this.subOrder = subOrder; - this.id = ChunkSystemTaskQueue.this.taskIdGenerator.getAndIncrement(); - } - - @Override - public PrioritisedExecutor getExecutor() { - return ChunkSystemTaskQueue.this; - } - - @Override - public boolean queue() { - synchronized (this) { - if (this.holder != null || this.priority == Priority.COMPLETING) { - return false; - } - - if (ChunkSystemTaskQueue.this.isShutdown()) { - throw new IllegalStateException("Queue is shutdown"); - } - - this.holder = new Holder(this, this.priority.priority, this.subOrder, this.id); - - ChunkSystemTaskQueue.this.scheduledTasks.getAndIncrement(); - ChunkSystemTaskQueue.this.chunkSystem.schedule(this.holder.task.execute, this.holder.task.priority.priority); - } - - if (ChunkSystemTaskQueue.this.isShutdown()) { - this.cancel(); - throw new IllegalStateException("Queue is shutdown"); - } - - return true; - } - - @Override - public boolean isQueued() { - synchronized (this) { - return this.holder != null && this.priority != Priority.COMPLETING; - } - } - - @Override - public boolean cancel() { - synchronized (this) { - if (this.priority == Priority.COMPLETING) { - return false; - } - - this.priority = Priority.COMPLETING; - - if (this.holder != null) { - if (this.holder.markRemoved()) { - ChunkSystemTaskQueue.this.tasks.remove(this.holder); - } - ChunkSystemTaskQueue.this.executedTasks.getAndIncrement(); - } - - return true; - } - } - - @Override - public boolean execute() { - final boolean increaseExecuted; - - synchronized (this) { - if (this.priority == Priority.COMPLETING) { - return false; - } - - this.priority = Priority.COMPLETING; - - if (increaseExecuted = (this.holder != null)) { - if (this.holder.markRemoved()) { - ChunkSystemTaskQueue.this.tasks.remove(this.holder); - } - } - } - - try { - this.execute.run(); - return true; - } finally { - if (increaseExecuted) { - ChunkSystemTaskQueue.this.executedTasks.getAndIncrement(); - } - } - } - - @Override - public Priority getPriority() { - synchronized (this) { - return this.priority; - } - } - - @Override - public boolean setPriority(final Priority priority) { - synchronized (this) { - if (this.priority == Priority.COMPLETING || this.priority == priority) { - return false; - } - - this.priority = priority; - - if (this.holder != null) { - if (this.holder.markRemoved()) { - ChunkSystemTaskQueue.this.tasks.remove(this.holder); - } - this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id); - ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE); - } - - return true; - } - } - - @Override - public boolean raisePriority(final Priority priority) { - synchronized (this) { - if (this.priority == Priority.COMPLETING || this.priority.isHigherOrEqualPriority(priority)) { - return false; - } - - this.priority = priority; - - if (this.holder != null) { - if (this.holder.markRemoved()) { - ChunkSystemTaskQueue.this.tasks.remove(this.holder); - } - this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id); - ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE); - } - - return true; - } - } - - @Override - public boolean lowerPriority(Priority priority) { - synchronized (this) { - if (this.priority == Priority.COMPLETING || this.priority.isLowerOrEqualPriority(priority)) { - return false; - } - - this.priority = priority; - - if (this.holder != null) { - if (this.holder.markRemoved()) { - ChunkSystemTaskQueue.this.tasks.remove(this.holder); - } - this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id); - ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE); - } - - return true; - } - } - - @Override - public long getSubOrder() { - synchronized (this) { - return this.subOrder; - } - } - - @Override - public boolean setSubOrder(final long subOrder) { - synchronized (this) { - if (this.priority == Priority.COMPLETING || this.subOrder == subOrder) { - return false; - } - - this.subOrder = subOrder; - - if (this.holder != null) { - if (this.holder.markRemoved()) { - ChunkSystemTaskQueue.this.tasks.remove(this.holder); - } - this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id); - ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE); - } - - return true; - } - } - - @Override - public boolean raiseSubOrder(long subOrder) { - synchronized (this) { - if (this.priority == Priority.COMPLETING || this.subOrder >= subOrder) { - return false; - } - - this.subOrder = subOrder; - - if (this.holder != null) { - if (this.holder.markRemoved()) { - ChunkSystemTaskQueue.this.tasks.remove(this.holder); - } - this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id); - ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE); - } - - return true; - } - } - - @Override - public boolean lowerSubOrder(final long subOrder) { - synchronized (this) { - if (this.priority == Priority.COMPLETING || this.subOrder <= subOrder) { - return false; - } - - this.subOrder = subOrder; - - if (this.holder != null) { - if (this.holder.markRemoved()) { - ChunkSystemTaskQueue.this.tasks.remove(this.holder); - } - this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id); - ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE); - } - - return true; - } - } - - @Override - public boolean setPriorityAndSubOrder(final Priority priority, final long subOrder) { - synchronized (this) { - if (this.priority == Priority.COMPLETING || (this.priority == priority && this.subOrder == subOrder)) { - return false; - } - - this.priority = priority; - this.subOrder = subOrder; - - if (this.holder != null) { - if (this.holder.markRemoved()) { - ChunkSystemTaskQueue.this.tasks.remove(this.holder); - } - this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id); - ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE); - } - - return true; - } - } - - private static final class Holder { - private static final VarHandle REMOVED_HANDLE = ConcurrentUtil.getVarHandle(ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder.class, "removed", boolean.class); - private final ChunkSystemTaskQueue.PrioritisedQueuedTask task; - private final int priority; - private final long subOrder; - private final long id; - private volatile boolean removed; - - private Holder( - final ChunkSystemTaskQueue.PrioritisedQueuedTask task, final int priority, final long subOrder, - final long id - ) { - this.task = task; - this.priority = priority; - this.subOrder = subOrder; - this.id = id; - } - - public boolean markRemoved() { - return !(boolean) REMOVED_HANDLE.getAndSet((ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder) this, (boolean) true); - } - } - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/server/chunk/TheChunkSystem.java b/divinemc-server/src/main/java/org/bxteam/divinemc/server/chunk/TheChunkSystem.java deleted file mode 100644 index 2a51c6f..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/server/chunk/TheChunkSystem.java +++ /dev/null @@ -1,355 +0,0 @@ -package org.bxteam.divinemc.server.chunk; - -import ca.spottedleaf.concurrentutil.executor.PrioritisedExecutor; -import ca.spottedleaf.concurrentutil.util.Priority; -import com.ishland.flowsched.executor.ExecutorManager; -import org.bxteam.divinemc.util.ThreadBuilder; -import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.lang.reflect.Array; -import java.util.Arrays; -import java.util.concurrent.atomic.AtomicLong; - -public class TheChunkSystem extends ExecutorManager { - protected final Logger LOGGER = LoggerFactory.getLogger("TheChunkSystem"); - - private final TheChunkSystem.COWArrayList executors = new TheChunkSystem.COWArrayList<>(TheChunkSystem.ExecutorGroup.class); - private boolean shutdown; - - public TheChunkSystem(final int workerThreadCount, final ThreadBuilder threadInitializer) { - super(workerThreadCount, threadInitializer); - LOGGER.info("Initialized new ChunkSystem with {} allocated threads", workerThreadCount); - } - - @Override - public void shutdown() { - synchronized (this) { - this.shutdown = true; - } - - super.shutdown(); - this.wakeup(); - - for (final TheChunkSystem.ExecutorGroup group : this.executors.getArray()) { - for (final TheChunkSystem.ExecutorGroup.ThreadPoolExecutor executor : group.executors.getArray()) { - executor.shutdown(); - } - } - - LOGGER.info("ChunkSystem shutdown complete"); - } - - private void notifyAllThreads() { - this.wakeup(); - } - - public TheChunkSystem.ExecutorGroup createExecutorGroup() { - synchronized (this) { - if (this.shutdown) { - throw new IllegalStateException("Queue is shutdown: " + this); - } - - final TheChunkSystem.ExecutorGroup ret = new TheChunkSystem.ExecutorGroup(); - - this.executors.add(ret); - - return ret; - } - } - - private static final class COWArrayList { - private volatile E[] array; - - public COWArrayList(final Class clazz) { - this.array = (E[]) Array.newInstance(clazz, 0); - } - - public E[] getArray() { - return this.array; - } - - public void add(final E element) { - synchronized (this) { - final E[] array = this.array; - - final E[] copy = Arrays.copyOf(array, array.length + 1); - copy[array.length] = element; - - this.array = copy; - } - } - - public boolean remove(final E element) { - synchronized (this) { - final E[] array = this.array; - int index = -1; - for (int i = 0, len = array.length; i < len; ++i) { - if (array[i] == element) { - index = i; - break; - } - } - - if (index == -1) { - return false; - } - - final E[] copy = (E[]) Array.newInstance(array.getClass().getComponentType(), array.length - 1); - - System.arraycopy(array, 0, copy, 0, index); - System.arraycopy(array, index + 1, copy, index, (array.length - 1) - index); - - this.array = copy; - } - - return true; - } - } - - public final class ExecutorGroup { - private final AtomicLong subOrderGenerator = new AtomicLong(); - private final TheChunkSystem.COWArrayList executors = new TheChunkSystem.COWArrayList<>(TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.class); - - private ExecutorGroup() { } - - public TheChunkSystem.ExecutorGroup.ThreadPoolExecutor[] getAllExecutors() { - return this.executors.getArray().clone(); - } - - private TheChunkSystem getThreadPool() { - return TheChunkSystem.this; - } - - public TheChunkSystem.ExecutorGroup.@NotNull ThreadPoolExecutor createExecutor() { - synchronized (TheChunkSystem.this) { - if (TheChunkSystem.this.shutdown) { - throw new IllegalStateException("Queue is shutdown: " + TheChunkSystem.this); - } - - final TheChunkSystem.ExecutorGroup.ThreadPoolExecutor ret = new TheChunkSystem.ExecutorGroup.ThreadPoolExecutor(); - - this.executors.add(ret); - - return ret; - } - } - - public final class ThreadPoolExecutor implements PrioritisedExecutor { - private final ChunkSystemTaskQueue taskBuilder = new ChunkSystemTaskQueue(TheChunkSystem.this); - private volatile boolean halt; - - private ThreadPoolExecutor() { } - - private TheChunkSystem.ExecutorGroup getGroup() { - return TheChunkSystem.ExecutorGroup.this; - } - - private void notifyPriorityShift() { - TheChunkSystem.this.notifyAllThreads(); - } - - private void notifyScheduled() { - TheChunkSystem.this.notifyAllThreads(); - } - - /** - * Removes this queue from the thread pool without shutting the queue down or waiting for queued tasks to be executed - */ - public void halt() { - this.halt = true; - - TheChunkSystem.ExecutorGroup.this.executors.remove(this); - } - - public boolean isActive() { - if (this.halt) { - return false; - } else { - if (!this.isShutdown()) { - return true; - } - - return !TheChunkSystem.this.globalWorkQueue.isEmpty(); - } - } - - @Override - public boolean shutdown() { - if (TheChunkSystem.this.globalWorkQueue.isEmpty()) { - TheChunkSystem.ExecutorGroup.this.executors.remove(this); - } - - return true; - } - - @Override - public boolean isShutdown() { - return TheChunkSystem.this.shutdown; - } - - @Override - public long getTotalTasksScheduled() { - return 0; // TODO: implement - } - - @Override - public long getTotalTasksExecuted() { - return 0; // TODO: implement - } - - @Override - public long generateNextSubOrder() { - return TheChunkSystem.ExecutorGroup.this.subOrderGenerator.getAndIncrement(); - } - - @Override - public boolean executeTask() { - throw new UnsupportedOperationException("Unable to execute task from ThreadPoolExecutor as interface into FlowSched"); - } - - @Override - public PrioritisedTask queueTask(final Runnable task) { - final PrioritisedTask ret = this.createTask(task); - - ret.queue(); - - return ret; - } - - @Override - public PrioritisedTask queueTask(final Runnable task, final Priority priority) { - final PrioritisedTask ret = this.createTask(task, priority); - - ret.queue(); - - return ret; - } - - @Override - public PrioritisedTask queueTask(final Runnable task, final Priority priority, final long subOrder) { - final PrioritisedTask ret = this.createTask(task, priority, subOrder); - - ret.queue(); - - return ret; - } - - @Override - public PrioritisedTask createTask(final Runnable task) { - return this.createTask(task, Priority.NORMAL); - } - - @Override - public PrioritisedTask createTask(final Runnable task, final Priority priority) { - return this.createTask(task, priority, this.generateNextSubOrder()); - } - - @Override - public PrioritisedTask createTask(final Runnable task, final Priority priority, final long subOrder) { - return new TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.WrappedTask(this.taskBuilder.createTask(task, priority, subOrder)); - } - - private final class WrappedTask implements PrioritisedTask { - private final PrioritisedTask wrapped; - - private WrappedTask(final PrioritisedTask wrapped) { - this.wrapped = wrapped; - } - - @Override - public PrioritisedExecutor getExecutor() { - return TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.this; - } - - @Override - public boolean queue() { - if (this.wrapped.queue()) { - final Priority priority = this.getPriority(); - if (priority != Priority.COMPLETING) { - TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.this.notifyScheduled(); - } - return true; - } - - return false; - } - - @Override - public boolean isQueued() { - return this.wrapped.isQueued(); - } - - @Override - public boolean cancel() { - return this.wrapped.cancel(); - } - - @Override - public boolean execute() { - return this.wrapped.execute(); - } - - @Override - public Priority getPriority() { - return this.wrapped.getPriority(); - } - - @Override - public boolean setPriority(final Priority priority) { - if (this.wrapped.setPriority(priority)) { - TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.this.notifyPriorityShift(); - return true; - } - - return false; - } - - @Override - public boolean raisePriority(final Priority priority) { - if (this.wrapped.raisePriority(priority)) { - TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.this.notifyPriorityShift(); - return true; - } - - return false; - } - - @Override - public boolean lowerPriority(final Priority priority) { - return this.wrapped.lowerPriority(priority); - } - - @Override - public long getSubOrder() { - return this.wrapped.getSubOrder(); - } - - @Override - public boolean setSubOrder(final long subOrder) { - return this.wrapped.setSubOrder(subOrder); - } - - @Override - public boolean raiseSubOrder(final long subOrder) { - return this.wrapped.raiseSubOrder(subOrder); - } - - @Override - public boolean lowerSubOrder(final long subOrder) { - return this.wrapped.lowerSubOrder(subOrder); - } - - @Override - public boolean setPriorityAndSubOrder(final Priority priority, final long subOrder) { - if (this.wrapped.setPriorityAndSubOrder(priority, subOrder)) { - TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.this.notifyPriorityShift(); - return true; - } - - return false; - } - } - } - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/ConcurrentFlagMatrix.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/ConcurrentFlagMatrix.java deleted file mode 100644 index ed26ad6..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/ConcurrentFlagMatrix.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.bxteam.divinemc.util; - -import java.util.concurrent.locks.ReentrantReadWriteLock; -import net.minecraft.world.level.levelgen.structure.structures.WoodlandMansionPieces; - -public class ConcurrentFlagMatrix extends WoodlandMansionPieces.SimpleGrid { - private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); - - public ConcurrentFlagMatrix(int rows, int columns, int fallbackValue) { - super(rows, columns, fallbackValue); - } - - public void set(int row, int column, int value) { - this.readWriteLock.writeLock().lock(); - - try { - super.set(row, column, value); - } finally { - this.readWriteLock.writeLock().unlock(); - } - } - - public void set(int startRow, int startColumn, int endRow, int endColumn, int value) { - this.readWriteLock.writeLock().lock(); - - try { - super.set(startRow, startColumn, endRow, endColumn, value); - } finally { - this.readWriteLock.writeLock().unlock(); - } - } - - public int get(int row, int column) { - this.readWriteLock.readLock().lock(); - - int result; - try { - result = super.get(row, column); - } finally { - this.readWriteLock.readLock().unlock(); - } - - return result; - } - - public void setIf(int row, int column, int expectedValue, int newValue) { - if (this.get(row, column) == expectedValue) { - this.set(row, column, newValue); - } - } - - public boolean edgesTo(int row, int column, int value) { - this.readWriteLock.readLock().lock(); - - boolean result; - try { - result = super.edgesTo(row, column, value); - } finally { - this.readWriteLock.readLock().unlock(); - } - - return result; - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/RandomUtil.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/RandomUtil.java deleted file mode 100644 index 5f47188..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/RandomUtil.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.bxteam.divinemc.util; - -import net.minecraft.util.Mth; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.levelgen.LegacyRandomSource; -import net.minecraft.world.level.levelgen.PositionalRandomFactory; -import net.minecraft.world.level.levelgen.SingleThreadedRandomSource; -import net.minecraft.world.level.levelgen.Xoroshiro128PlusPlus; -import net.minecraft.world.level.levelgen.XoroshiroRandomSource; -import org.jetbrains.annotations.NotNull; - -public final class RandomUtil { - public static @NotNull RandomSource getRandom(PositionalRandomFactory deriver) { - if (deriver instanceof XoroshiroRandomSource.XoroshiroPositionalRandomFactory) { - return new XoroshiroRandomSource(0L, 0L); - } - if (deriver instanceof LegacyRandomSource.LegacyPositionalRandomFactory) { - return new SingleThreadedRandomSource(0L); - } - throw new IllegalArgumentException(); - } - - private static final ThreadLocal xoroshiro = ThreadLocal.withInitial(() -> new XoroshiroRandomSource(0L, 0L)); - private static final ThreadLocal simple = ThreadLocal.withInitial(() -> new SingleThreadedRandomSource(0L)); - - public static void derive(PositionalRandomFactory deriver, RandomSource random, int x, int y, int z) { - if (deriver instanceof final XoroshiroRandomSource.XoroshiroPositionalRandomFactory deriver1) { - final Xoroshiro128PlusPlus implementation = ((XoroshiroRandomSource) random).randomNumberGenerator; - implementation.seedLo = (Mth.getSeed(x, y, z) ^ deriver1.seedLo()); - implementation.seedHi = (deriver1.seedHi()); - return; - } - if (deriver instanceof LegacyRandomSource.LegacyPositionalRandomFactory(long seed)) { - final SingleThreadedRandomSource random1 = (SingleThreadedRandomSource) random; - random1.setSeed(Mth.getSeed(x, y, z) ^ seed); - return; - } - throw new IllegalArgumentException(); - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/SynchronizedCodec.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/SynchronizedCodec.java deleted file mode 100644 index 3fca958..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/SynchronizedCodec.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.bxteam.divinemc.util; - -import com.mojang.datafixers.util.Pair; -import com.mojang.serialization.Codec; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.DynamicOps; -import java.util.concurrent.locks.ReentrantLock; - -public class SynchronizedCodec implements Codec { - private final ReentrantLock lock = new ReentrantLock(false); - private final Codec delegate; - - public SynchronizedCodec(Codec delegate) { - this.delegate = delegate; - } - - @Override - public DataResult> decode(DynamicOps ops, T input) { - try { - lock.lockInterruptibly(); - return this.delegate.decode(ops, input); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } finally { - if (lock.isHeldByCurrentThread()) lock.unlock(); - } - } - - @Override - public DataResult encode(A input, DynamicOps ops, T prefix) { - try { - lock.lockInterruptibly(); - return this.delegate.encode(input, ops, prefix); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } finally { - if (lock.isHeldByCurrentThread()) lock.unlock(); - } - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/ThreadBuilder.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/ThreadBuilder.java deleted file mode 100644 index 3922885..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/ThreadBuilder.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.bxteam.divinemc.util; - -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; - -public interface ThreadBuilder extends Consumer { - AtomicInteger id = new AtomicInteger(); - - default int getAndIncrementId() { - return id.getAndIncrement(); - } -} diff --git a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/map/MapPalette.java.patch b/patches/work/api/MapPalette.java.patch similarity index 100% rename from divinemc-api/paper-patches/files/src/main/java/org/bukkit/map/MapPalette.java.patch rename to patches/work/api/MapPalette.java.patch diff --git a/divinemc-server/minecraft-patches/features/0004-Implement-Secure-Seed.patch b/patches/work/server/minecraft/0004-Implement-Secure-Seed.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0004-Implement-Secure-Seed.patch rename to patches/work/server/minecraft/0004-Implement-Secure-Seed.patch diff --git a/divinemc-server/minecraft-patches/features/0005-Async-Pathfinding.patch b/patches/work/server/minecraft/0005-Async-Pathfinding.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0005-Async-Pathfinding.patch rename to patches/work/server/minecraft/0005-Async-Pathfinding.patch diff --git a/divinemc-server/minecraft-patches/features/0006-Async-locate-command.patch b/patches/work/server/minecraft/0006-Async-locate-command.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0006-Async-locate-command.patch rename to patches/work/server/minecraft/0006-Async-locate-command.patch diff --git a/divinemc-server/minecraft-patches/features/0007-Multithreaded-Tracker.patch b/patches/work/server/minecraft/0007-Multithreaded-Tracker.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0007-Multithreaded-Tracker.patch rename to patches/work/server/minecraft/0007-Multithreaded-Tracker.patch diff --git a/divinemc-server/minecraft-patches/features/0008-Misc-Optimizations.patch b/patches/work/server/minecraft/0008-Misc-Optimizations.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0008-Misc-Optimizations.patch rename to patches/work/server/minecraft/0008-Misc-Optimizations.patch diff --git a/divinemc-server/minecraft-patches/features/0009-Optimize-Fluids.patch b/patches/work/server/minecraft/0009-Optimize-Fluids.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0009-Optimize-Fluids.patch rename to patches/work/server/minecraft/0009-Optimize-Fluids.patch diff --git a/divinemc-server/minecraft-patches/features/0010-Chunk-System-Optimizations.patch b/patches/work/server/minecraft/0010-Chunk-System-Optimizations.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0010-Chunk-System-Optimizations.patch rename to patches/work/server/minecraft/0010-Chunk-System-Optimizations.patch diff --git a/divinemc-server/minecraft-patches/features/0011-Optimize-entity-stupid-brain.patch b/patches/work/server/minecraft/0011-Optimize-entity-stupid-brain.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0011-Optimize-entity-stupid-brain.patch rename to patches/work/server/minecraft/0011-Optimize-entity-stupid-brain.patch diff --git a/divinemc-server/minecraft-patches/features/0012-Lag-compensation.patch b/patches/work/server/minecraft/0012-Lag-compensation.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0012-Lag-compensation.patch rename to patches/work/server/minecraft/0012-Lag-compensation.patch diff --git a/divinemc-server/minecraft-patches/features/0013-Implement-NoChatReports.patch b/patches/work/server/minecraft/0013-Implement-NoChatReports.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0013-Implement-NoChatReports.patch rename to patches/work/server/minecraft/0013-Implement-NoChatReports.patch diff --git a/divinemc-server/minecraft-patches/features/0014-Carpet-Fixes-RecipeManager-Optimize.patch b/patches/work/server/minecraft/0014-Carpet-Fixes-RecipeManager-Optimize.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0014-Carpet-Fixes-RecipeManager-Optimize.patch rename to patches/work/server/minecraft/0014-Carpet-Fixes-RecipeManager-Optimize.patch diff --git a/divinemc-server/minecraft-patches/features/0015-Optimize-explosions.patch b/patches/work/server/minecraft/0015-Optimize-explosions.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0015-Optimize-explosions.patch rename to patches/work/server/minecraft/0015-Optimize-explosions.patch diff --git a/divinemc-server/minecraft-patches/features/0016-Option-to-allow-weird-movement-and-disable-teleporti.patch b/patches/work/server/minecraft/0016-Option-to-allow-weird-movement-and-disable-teleporti.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0016-Option-to-allow-weird-movement-and-disable-teleporti.patch rename to patches/work/server/minecraft/0016-Option-to-allow-weird-movement-and-disable-teleporti.patch diff --git a/divinemc-server/minecraft-patches/features/0017-Snowball-and-Egg-knockback.patch b/patches/work/server/minecraft/0017-Snowball-and-Egg-knockback.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0017-Snowball-and-Egg-knockback.patch rename to patches/work/server/minecraft/0017-Snowball-and-Egg-knockback.patch diff --git a/divinemc-server/minecraft-patches/features/0018-Block-Log4Shell-exploit.patch b/patches/work/server/minecraft/0018-Block-Log4Shell-exploit.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0018-Block-Log4Shell-exploit.patch rename to patches/work/server/minecraft/0018-Block-Log4Shell-exploit.patch diff --git a/divinemc-server/minecraft-patches/features/0019-Skip-distanceToSqr-call-in-ServerEntity-sendChanges-.patch b/patches/work/server/minecraft/0019-Skip-distanceToSqr-call-in-ServerEntity-sendChanges-.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0019-Skip-distanceToSqr-call-in-ServerEntity-sendChanges-.patch rename to patches/work/server/minecraft/0019-Skip-distanceToSqr-call-in-ServerEntity-sendChanges-.patch diff --git a/divinemc-server/minecraft-patches/features/0020-Optimize-canSee-checks.patch b/patches/work/server/minecraft/0020-Optimize-canSee-checks.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0020-Optimize-canSee-checks.patch rename to patches/work/server/minecraft/0020-Optimize-canSee-checks.patch diff --git a/divinemc-server/minecraft-patches/features/0021-Verify-Minecraft-EULA-earlier.patch b/patches/work/server/minecraft/0021-Verify-Minecraft-EULA-earlier.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0021-Verify-Minecraft-EULA-earlier.patch rename to patches/work/server/minecraft/0021-Verify-Minecraft-EULA-earlier.patch diff --git a/divinemc-server/minecraft-patches/features/0022-Option-to-disable-saving-of-snowball-and-firework.patch b/patches/work/server/minecraft/0022-Option-to-disable-saving-of-snowball-and-firework.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0022-Option-to-disable-saving-of-snowball-and-firework.patch rename to patches/work/server/minecraft/0022-Option-to-disable-saving-of-snowball-and-firework.patch diff --git a/divinemc-server/minecraft-patches/features/0023-Re-Fix-MC-117075.patch b/patches/work/server/minecraft/0023-Re-Fix-MC-117075.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0023-Re-Fix-MC-117075.patch rename to patches/work/server/minecraft/0023-Re-Fix-MC-117075.patch diff --git a/divinemc-server/minecraft-patches/features/0024-Virtual-Threads.patch b/patches/work/server/minecraft/0024-Virtual-Threads.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0024-Virtual-Threads.patch rename to patches/work/server/minecraft/0024-Virtual-Threads.patch diff --git a/divinemc-server/minecraft-patches/features/0025-Optimize-Structure-Generation.patch b/patches/work/server/minecraft/0025-Optimize-Structure-Generation.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0025-Optimize-Structure-Generation.patch rename to patches/work/server/minecraft/0025-Optimize-Structure-Generation.patch diff --git a/divinemc-server/minecraft-patches/features/0026-Option-to-disable-disconnect.spam.patch b/patches/work/server/minecraft/0026-Option-to-disable-disconnect.spam.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0026-Option-to-disable-disconnect.spam.patch rename to patches/work/server/minecraft/0026-Option-to-disable-disconnect.spam.patch diff --git a/divinemc-server/minecraft-patches/features/0027-Async-Chunk-Sending.patch b/patches/work/server/minecraft/0027-Async-Chunk-Sending.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0027-Async-Chunk-Sending.patch rename to patches/work/server/minecraft/0027-Async-Chunk-Sending.patch diff --git a/divinemc-server/minecraft-patches/features/0028-Configurable-MC-67.patch b/patches/work/server/minecraft/0028-Configurable-MC-67.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0028-Configurable-MC-67.patch rename to patches/work/server/minecraft/0028-Configurable-MC-67.patch diff --git a/divinemc-server/minecraft-patches/features/0029-Configurable-MC-59471.patch b/patches/work/server/minecraft/0029-Configurable-MC-59471.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0029-Configurable-MC-59471.patch rename to patches/work/server/minecraft/0029-Configurable-MC-59471.patch diff --git a/divinemc-server/minecraft-patches/features/0030-ModernFix-compact_bit_storage.patch b/patches/work/server/minecraft/0030-ModernFix-compact_bit_storage.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0030-ModernFix-compact_bit_storage.patch rename to patches/work/server/minecraft/0030-ModernFix-compact_bit_storage.patch diff --git a/divinemc-server/minecraft-patches/features/0031-lithium-fast_util.patch b/patches/work/server/minecraft/0031-lithium-fast_util.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0031-lithium-fast_util.patch rename to patches/work/server/minecraft/0031-lithium-fast_util.patch diff --git a/divinemc-server/minecraft-patches/features/0032-Command-block-parse-results-caching.patch b/patches/work/server/minecraft/0032-Command-block-parse-results-caching.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0032-Command-block-parse-results-caching.patch rename to patches/work/server/minecraft/0032-Command-block-parse-results-caching.patch diff --git a/divinemc-server/minecraft-patches/features/0033-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch b/patches/work/server/minecraft/0033-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0033-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch rename to patches/work/server/minecraft/0033-Leaf-Improve-BlockEntity-ticking-isRemoved-check.patch diff --git a/divinemc-server/minecraft-patches/features/0034-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch b/patches/work/server/minecraft/0034-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0034-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch rename to patches/work/server/minecraft/0034-SparklyPaper-Allow-throttling-hopper-checks-if-the-t.patch diff --git a/divinemc-server/minecraft-patches/features/0035-Configurable-movement-speed-for-entities.patch b/patches/work/server/minecraft/0035-Configurable-movement-speed-for-entities.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0035-Configurable-movement-speed-for-entities.patch rename to patches/work/server/minecraft/0035-Configurable-movement-speed-for-entities.patch diff --git a/divinemc-server/minecraft-patches/features/0037-Dynamic-Activation-of-Brain.patch b/patches/work/server/minecraft/0037-Dynamic-Activation-of-Brain.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0037-Dynamic-Activation-of-Brain.patch rename to patches/work/server/minecraft/0037-Dynamic-Activation-of-Brain.patch diff --git a/divinemc-server/minecraft-patches/features/0038-Linear-region-file-format.patch b/patches/work/server/minecraft/0038-Linear-region-file-format.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0038-Linear-region-file-format.patch rename to patches/work/server/minecraft/0038-Linear-region-file-format.patch diff --git a/divinemc-server/minecraft-patches/features/0040-Player-ProfileResult-caching.patch b/patches/work/server/minecraft/0040-Player-ProfileResult-caching.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0040-Player-ProfileResult-caching.patch rename to patches/work/server/minecraft/0040-Player-ProfileResult-caching.patch diff --git a/divinemc-server/minecraft-patches/features/0041-Async-mob-spawning.patch b/patches/work/server/minecraft/0041-Async-mob-spawning.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0041-Async-mob-spawning.patch rename to patches/work/server/minecraft/0041-Async-mob-spawning.patch diff --git a/divinemc-server/minecraft-patches/features/0043-Carpet-Fixes-Sheep-Optimization.patch b/patches/work/server/minecraft/0043-Carpet-Fixes-Sheep-Optimization.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0043-Carpet-Fixes-Sheep-Optimization.patch rename to patches/work/server/minecraft/0043-Carpet-Fixes-Sheep-Optimization.patch diff --git a/divinemc-server/minecraft-patches/features/0044-Density-Function-Compiler.patch b/patches/work/server/minecraft/0044-Density-Function-Compiler.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0044-Density-Function-Compiler.patch rename to patches/work/server/minecraft/0044-Density-Function-Compiler.patch diff --git a/divinemc-server/minecraft-patches/features/0045-Parallel-world-ticking.patch b/patches/work/server/minecraft/0045-Parallel-world-ticking.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0045-Parallel-world-ticking.patch rename to patches/work/server/minecraft/0045-Parallel-world-ticking.patch diff --git a/divinemc-server/minecraft-patches/features/0046-MSPT-Tracking-for-each-world.patch b/patches/work/server/minecraft/0046-MSPT-Tracking-for-each-world.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0046-MSPT-Tracking-for-each-world.patch rename to patches/work/server/minecraft/0046-MSPT-Tracking-for-each-world.patch diff --git a/divinemc-server/minecraft-patches/features/0047-Optimize-Raids.patch b/patches/work/server/minecraft/0047-Optimize-Raids.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0047-Optimize-Raids.patch rename to patches/work/server/minecraft/0047-Optimize-Raids.patch diff --git a/divinemc-server/minecraft-patches/features/0048-Catch-update-suppressors.patch b/patches/work/server/minecraft/0048-Catch-update-suppressors.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0048-Catch-update-suppressors.patch rename to patches/work/server/minecraft/0048-Catch-update-suppressors.patch diff --git a/divinemc-server/minecraft-patches/features/0050-Optimize-suffocation.patch b/patches/work/server/minecraft/0050-Optimize-suffocation.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0050-Optimize-suffocation.patch rename to patches/work/server/minecraft/0050-Optimize-suffocation.patch diff --git a/divinemc-server/minecraft-patches/features/0051-Reduce-chunk-loading-lookups.patch b/patches/work/server/minecraft/0051-Reduce-chunk-loading-lookups.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0051-Reduce-chunk-loading-lookups.patch rename to patches/work/server/minecraft/0051-Reduce-chunk-loading-lookups.patch diff --git a/divinemc-server/minecraft-patches/features/0052-Carpet-AMS-Addition-Optimized-dragon-respawn.patch b/patches/work/server/minecraft/0052-Carpet-AMS-Addition-Optimized-dragon-respawn.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0052-Carpet-AMS-Addition-Optimized-dragon-respawn.patch rename to patches/work/server/minecraft/0052-Carpet-AMS-Addition-Optimized-dragon-respawn.patch diff --git a/divinemc-server/minecraft-patches/features/0053-Regionized-Chunk-Ticking.patch b/patches/work/server/minecraft/0053-Regionized-Chunk-Ticking.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0053-Regionized-Chunk-Ticking.patch rename to patches/work/server/minecraft/0053-Regionized-Chunk-Ticking.patch diff --git a/divinemc-server/minecraft-patches/features/0055-Clump-experience-orbs.patch b/patches/work/server/minecraft/0055-Clump-experience-orbs.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0055-Clump-experience-orbs.patch rename to patches/work/server/minecraft/0055-Clump-experience-orbs.patch diff --git a/divinemc-server/paper-patches/features/0005-Implement-Secure-Seed.patch b/patches/work/server/paper/0005-Implement-Secure-Seed.patch similarity index 100% rename from divinemc-server/paper-patches/features/0005-Implement-Secure-Seed.patch rename to patches/work/server/paper/0005-Implement-Secure-Seed.patch diff --git a/divinemc-server/paper-patches/features/0006-Chunk-System-Optimizations.patch b/patches/work/server/paper/0006-Chunk-System-Optimizations.patch similarity index 100% rename from divinemc-server/paper-patches/features/0006-Chunk-System-Optimizations.patch rename to patches/work/server/paper/0006-Chunk-System-Optimizations.patch diff --git a/divinemc-server/paper-patches/features/0007-Optimize-canSee-checks.patch b/patches/work/server/paper/0007-Optimize-canSee-checks.patch similarity index 100% rename from divinemc-server/paper-patches/features/0007-Optimize-canSee-checks.patch rename to patches/work/server/paper/0007-Optimize-canSee-checks.patch diff --git a/divinemc-server/paper-patches/features/0008-Configurable-thread-pool-priority.patch b/patches/work/server/paper/0008-Configurable-thread-pool-priority.patch similarity index 100% rename from divinemc-server/paper-patches/features/0008-Configurable-thread-pool-priority.patch rename to patches/work/server/paper/0008-Configurable-thread-pool-priority.patch diff --git a/divinemc-server/paper-patches/features/0009-Virtual-Threads.patch b/patches/work/server/paper/0009-Virtual-Threads.patch similarity index 100% rename from divinemc-server/paper-patches/features/0009-Virtual-Threads.patch rename to patches/work/server/paper/0009-Virtual-Threads.patch diff --git a/divinemc-server/paper-patches/features/0010-Multithreaded-Tracker.patch b/patches/work/server/paper/0010-Multithreaded-Tracker.patch similarity index 100% rename from divinemc-server/paper-patches/features/0010-Multithreaded-Tracker.patch rename to patches/work/server/paper/0010-Multithreaded-Tracker.patch diff --git a/divinemc-server/paper-patches/features/0014-Parallel-world-ticking.patch b/patches/work/server/paper/0014-Parallel-world-ticking.patch similarity index 100% rename from divinemc-server/paper-patches/features/0014-Parallel-world-ticking.patch rename to patches/work/server/paper/0014-Parallel-world-ticking.patch diff --git a/divinemc-server/purpur-patches/features/0003-MSPT-Tracking-for-each-world.patch b/patches/work/server/purpur/0003-MSPT-Tracking-for-each-world.patch similarity index 100% rename from divinemc-server/purpur-patches/features/0003-MSPT-Tracking-for-each-world.patch rename to patches/work/server/purpur/0003-MSPT-Tracking-for-each-world.patch