diff --git a/gradle.properties b/gradle.properties index c3150b7..ff7fb01 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ group = me.earthme.lightingluminol version = 1.20.6-R0.1-SNAPSHOT -luminolCommit = 15bb0f42d07c96c9357bdc793158613a42618e50 +luminolCommit = e6027bdfbf5fb4fb52d38064fc5b626757a6557f org.gradle.caching = true org.gradle.parallel = true diff --git a/patches/server/0003-Base-Dirty-Patches.patch b/patches/server/0003-Base-Dirty-Patches.patch index 6948604..bea37f7 100644 --- a/patches/server/0003-Base-Dirty-Patches.patch +++ b/patches/server/0003-Base-Dirty-Patches.patch @@ -1,6 +1,6 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Sun, 26 May 2024 11:26:08 +0000 +From: MrHua269 +Date: Wed, 17 Jul 2024 17:30:34 +0800 Subject: [PATCH] Base Dirty Patches @@ -87,50 +87,6 @@ index 190c5f0b02a3d99054704ae1afbffb3498ddffe1..8106114c49e4589a70bf00430a83a132 final E lastRet = this.lastRet; if (lastRet == null) { -diff --git a/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java b/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java -index 239475187fdf0d05823b31e2068651559d3497e5..260c29732fec8faecb20c274073952c5e8f3da76 100644 ---- a/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java -+++ b/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java -@@ -221,7 +221,7 @@ public class RegionizedPlayerChunkLoader { - public void updatePlayer(final ServerPlayer player) { - final PlayerChunkLoaderData loader = player.chunkLoader; - if (loader != null) { -- player.serverLevel().chunkSource.chunkMap.getNearbyPlayers().tickPlayer(player); // Folia - region threading -+ player.serverLevel().chunkSource.chunkMap.level.regionizedWorldDataAccessor.getAny(player).getNearbyPlayers().tickPlayer(player); // Folia - region threading - loader.update(); - } - } -diff --git a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java -index 5bef4f50082e56b89239cfd62dd7429926b71c09..9e81cfcdfd6c4ed13130cbef28cd9a07cd8bb3ca 100644 ---- a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java -+++ b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java -@@ -443,7 +443,7 @@ public final class EntityLookup implements LevelEntityGetter { - - entity.setLevelCallback(new EntityCallback(entity)); - -- this.world.getCurrentWorldData().addEntity(entity); // Folia - region threading -+ this.world.regionizedWorldDataAccessor.getAny(entity).addEntity(entity); // Folia - region threading - - this.entityStatusChange(entity, slices, Visibility.HIDDEN, getEntityStatus(entity), false, !fromDisk, false); - -@@ -888,7 +888,7 @@ public final class EntityLookup implements LevelEntityGetter { - @Override - public void onMove() { - final Entity entity = this.entity; -- final io.papermc.paper.threadedregions.RegionizedWorldData regionData = entity.level().getCurrentWorldData(); // Folia - region threading -+ final io.papermc.paper.threadedregions.RegionizedWorldData regionData = entity.level().regionizedWorldDataAccessor.getAny(entity); // Folia - region threading - final Visibility oldVisibility = getEntityStatus(entity); - final ChunkEntitySlices newSlices = EntityLookup.this.moveEntity(this.entity); - if (newSlices == null) { -@@ -918,7 +918,7 @@ public final class EntityLookup implements LevelEntityGetter { - this.entity.setLevelCallback(NoOpCallback.INSTANCE); - - // only AFTER full removal callbacks, so that thread checking will work. // Folia - region threading -- EntityLookup.this.world.getCurrentWorldData().removeEntity(entity); // Folia - region threading -+ EntityLookup.this.world.regionizedWorldDataAccessor.getAny(entity).removeEntity(entity); // Folia - region threading - } - } - diff --git a/src/main/java/io/papermc/paper/plugin/provider/type/paper/PaperPluginProviderFactory.java b/src/main/java/io/papermc/paper/plugin/provider/type/paper/PaperPluginProviderFactory.java index 6369b13e1fcdbdb25dd9d6e4d3bffdedbee4f739..740d7994a76e73332fb8b4accf388a550e0cf6ce 100644 --- a/src/main/java/io/papermc/paper/plugin/provider/type/paper/PaperPluginProviderFactory.java @@ -145,10 +101,10 @@ index 6369b13e1fcdbdb25dd9d6e4d3bffdedbee4f739..740d7994a76e73332fb8b4accf388a55 // Folia end - block plugins not marked as supported Logger jul = PaperPluginLogger.getLogger(configuration); diff --git a/src/main/java/io/papermc/paper/plugin/provider/type/spigot/SpigotPluginProviderFactory.java b/src/main/java/io/papermc/paper/plugin/provider/type/spigot/SpigotPluginProviderFactory.java -index 1b2964d5a3d839950e6831b7542e9587187bd375..e1b9659e9884bd1912c34b17337647859406f653 100644 +index a45235493bfed0e271a3fee1bbf27e62606bf0d3..f1be99100f9c4f78254fae38ecec382e3658a620 100644 --- a/src/main/java/io/papermc/paper/plugin/provider/type/spigot/SpigotPluginProviderFactory.java +++ b/src/main/java/io/papermc/paper/plugin/provider/type/spigot/SpigotPluginProviderFactory.java -@@ -28,7 +28,7 @@ class SpigotPluginProviderFactory implements PluginTypeFactory> chunkToRegionShift, pos.z >> chunkToRegionShift)) ++ from.world.worldDataSwitcher.randomIfNull(regionToData, regionToData.get(CoordinateUtils.getChunkKey(pos.x >> chunkToRegionShift, pos.z >> chunkToRegionShift))) + .connections.add(conn); + } ++ from.world.worldDataSwitcher.resetRandomIdx(); + // entities + for (final ServerPlayer player : from.localPlayers) { + final ChunkPos pos = player.chunkPosition(); + // Note: It is impossible for an entity in the world to _not_ be in an entity chunk, which means + // the chunk holder must _exist_, and so the region section exists. +- final RegionizedWorldData into = regionToData.get(CoordinateUtils.getChunkKey(pos.x >> chunkToRegionShift, pos.z >> chunkToRegionShift)); ++ final RegionizedWorldData into = from.world.worldDataSwitcher.randomIfNull(regionToData, regionToData.get(CoordinateUtils.getChunkKey(pos.x >> chunkToRegionShift, pos.z >> chunkToRegionShift))); + into.localPlayers.add(player); + into.nearbyPlayers.addPlayer(player); + } ++ from.world.worldDataSwitcher.resetRandomIdx(); + for (final Entity entity : from.allEntities) { + final ChunkPos pos = entity.chunkPosition(); + // Note: It is impossible for an entity in the world to _not_ be in an entity chunk, which means + // the chunk holder must _exist_, and so the region section exists. +- final RegionizedWorldData into = regionToData.get(CoordinateUtils.getChunkKey(pos.x >> chunkToRegionShift, pos.z >> chunkToRegionShift)); ++ final RegionizedWorldData into = from.world.worldDataSwitcher.randomIfNull(regionToData, regionToData.get(CoordinateUtils.getChunkKey(pos.x >> chunkToRegionShift, pos.z >> chunkToRegionShift))); + into.allEntities.add(entity); + // Note: entityTickList is a subset of allEntities + if (from.entityTickList.contains(entity)) { +@@ -196,20 +203,21 @@ public final class RegionizedWorldData { + into.navigatingMobs.add(mob); + } + } ++ from.world.worldDataSwitcher.resetRandomIdx(); + // block ticking + for (final BlockEventData blockEventData : from.blockEvents) { + final BlockPos pos = blockEventData.pos(); + final int chunkX = pos.getX() >> 4; + final int chunkZ = pos.getZ() >> 4; + +- final RegionizedWorldData into = regionToData.get(CoordinateUtils.getChunkKey(chunkX >> chunkToRegionShift, chunkZ >> chunkToRegionShift)); ++ final RegionizedWorldData into = from.world.worldDataSwitcher.randomIfNull(regionToData, regionToData.get(CoordinateUtils.getChunkKey(chunkX >> chunkToRegionShift, chunkZ >> chunkToRegionShift))); + // Unlike entities, the chunk holder is not guaranteed to exist for block events, because the block events + // is just some list. So if it unloads, I guess it's just lost. + if (into != null) { + into.blockEvents.add(blockEventData); + } + } +- ++ from.world.worldDataSwitcher.resetRandomIdx(); + final Long2ReferenceOpenHashMap> levelTicksBlockRegionData = new Long2ReferenceOpenHashMap<>(regionToData.size(), 0.75f); + final Long2ReferenceOpenHashMap> levelTicksFluidRegionData = new Long2ReferenceOpenHashMap<>(regionToData.size(), 0.75f); + +@@ -232,23 +240,25 @@ public final class RegionizedWorldData { + final int chunkX = pos.getX() >> 4; + final int chunkZ = pos.getZ() >> 4; + +- final RegionizedWorldData into = regionToData.get(CoordinateUtils.getChunkKey(chunkX >> chunkToRegionShift, chunkZ >> chunkToRegionShift)); ++ final RegionizedWorldData into = from.world.worldDataSwitcher.randomIfNull(regionToData, regionToData.get(CoordinateUtils.getChunkKey(chunkX >> chunkToRegionShift, chunkZ >> chunkToRegionShift))); + if (into != null) { + into.pendingBlockEntityTickers.add(tileEntity); + } // else: when a chunk unloads, it does not actually _remove_ the tile entity from the list, it just gets + // marked as removed. So if there is no section, it's probably removed! + } ++ from.world.worldDataSwitcher.resetRandomIdx(); + for (final TickingBlockEntity tileEntity : from.blockEntityTickers) { + final BlockPos pos = tileEntity.getPos(); + final int chunkX = pos.getX() >> 4; + final int chunkZ = pos.getZ() >> 4; + +- final RegionizedWorldData into = regionToData.get(CoordinateUtils.getChunkKey(chunkX >> chunkToRegionShift, chunkZ >> chunkToRegionShift)); ++ final RegionizedWorldData into = from.world.worldDataSwitcher.randomIfNull(regionToData, regionToData.get(CoordinateUtils.getChunkKey(chunkX >> chunkToRegionShift, chunkZ >> chunkToRegionShift))); + if (into != null) { + into.blockEntityTickers.add(tileEntity); + } // else: when a chunk unloads, it does not actually _remove_ the tile entity from the list, it just gets + // marked as removed. So if there is no section, it's probably removed! + } ++ from.world.worldDataSwitcher.resetRandomIdx(); + // time + for (final RegionizedWorldData regionizedWorldData : dataSet) { + regionizedWorldData.redstoneTime = from.redstoneTime; +@@ -259,23 +269,25 @@ public final class RegionizedWorldData { + final ChunkPos pos = levelChunk.getPos(); + + // Impossible for get() to return null, as the chunk is entity ticking - thus the chunk holder is loaded +- regionToData.get(CoordinateUtils.getChunkKey(pos.x >> chunkToRegionShift, pos.z >> chunkToRegionShift)) ++ from.world.worldDataSwitcher.randomIfNull(regionToData, regionToData.get(CoordinateUtils.getChunkKey(pos.x >> chunkToRegionShift, pos.z >> chunkToRegionShift))) + .entityTickingChunks.add(levelChunk); + } ++ from.world.worldDataSwitcher.resetRandomIdx(); + for (final Iterator iterator = from.tickingChunks.unsafeIterator(); iterator.hasNext();) { + final LevelChunk levelChunk = iterator.next(); + final ChunkPos pos = levelChunk.getPos(); + + // Impossible for get() to return null, as the chunk is entity ticking - thus the chunk holder is loaded +- regionToData.get(CoordinateUtils.getChunkKey(pos.x >> chunkToRegionShift, pos.z >> chunkToRegionShift)) ++ from.world.worldDataSwitcher.randomIfNull(regionToData, regionToData.get(CoordinateUtils.getChunkKey(pos.x >> chunkToRegionShift, pos.z >> chunkToRegionShift))) + .tickingChunks.add(levelChunk); + } ++ from.world.worldDataSwitcher.resetRandomIdx(); + // redstone torches + if (from.redstoneUpdateInfos != null && !from.redstoneUpdateInfos.isEmpty()) { + for (final net.minecraft.world.level.block.RedstoneTorchBlock.Toggle info : from.redstoneUpdateInfos) { + final BlockPos pos = info.pos; + +- final RegionizedWorldData worldData = regionToData.get(CoordinateUtils.getChunkKey((pos.getX() >> 4) >> chunkToRegionShift, (pos.getZ() >> 4) >> chunkToRegionShift)); ++ final RegionizedWorldData worldData = from.world.worldDataSwitcher.randomIfNull(regionToData, regionToData.get(CoordinateUtils.getChunkKey((pos.getX() >> 4) >> chunkToRegionShift, (pos.getZ() >> 4) >> chunkToRegionShift))); + if (worldData != null) { + if (worldData.redstoneUpdateInfos == null) { + worldData.redstoneUpdateInfos = new ArrayDeque<>(); +@@ -284,6 +296,7 @@ public final class RegionizedWorldData { + } // else: chunk unloaded + } + } ++ from.world.worldDataSwitcher.resetRandomIdx(); + // light chunks being worked on + for (final Iterator iterator = from.chunksBeingWorkedOn.long2IntEntrySet().fastIterator(); iterator.hasNext();) { + final Long2IntOpenHashMap.Entry entry = iterator.next(); +@@ -293,8 +306,9 @@ public final class RegionizedWorldData { + final int value = entry.getIntValue(); + + // should never be null, as it is a reference counter for ticket +- regionToData.get(CoordinateUtils.getChunkKey(chunkX >> chunkToRegionShift, chunkZ >> chunkToRegionShift)).chunksBeingWorkedOn.put(pos, value); ++ from.world.worldDataSwitcher.randomIfNull(regionToData, regionToData.get(CoordinateUtils.getChunkKey(chunkX >> chunkToRegionShift, chunkZ >> chunkToRegionShift))).chunksBeingWorkedOn.put(pos, value); + } ++ from.world.worldDataSwitcher.resetRandomIdx(); + // mob spawning + for (final RegionizedWorldData regionizedWorldData : dataSet) { + regionizedWorldData.catSpawnerNextTick = from.catSpawnerNextTick; +@@ -313,7 +327,7 @@ public final class RegionizedWorldData { private RegionizedServer.WorldLevelData tickData; // connections @@ -234,7 +319,7 @@ index 245efed41de40dc506301af942a7f3c3a2b60d65..6bdc2e6f527ecc6c4e4b6b4461e9f080 // misc. fields private boolean isHandlingTick; -@@ -327,12 +332,12 @@ public final class RegionizedWorldData { +@@ -327,12 +341,12 @@ public final class RegionizedWorldData { } // entities @@ -249,7 +334,7 @@ index 245efed41de40dc506301af942a7f3c3a2b60d65..6bdc2e6f527ecc6c4e4b6b4461e9f080 private final IteratorSafeOrderedReferenceSet navigatingMobs = new IteratorSafeOrderedReferenceSet<>(); // block ticking -@@ -341,8 +346,8 @@ public final class RegionizedWorldData { +@@ -341,8 +355,8 @@ public final class RegionizedWorldData { private final LevelTicks fluidLevelTicks; // tile entity ticking @@ -260,10 +345,10 @@ index 245efed41de40dc506301af942a7f3c3a2b60d65..6bdc2e6f527ecc6c4e4b6b4461e9f080 private boolean tickingBlockEntities; // time -@@ -379,8 +384,8 @@ public final class RegionizedWorldData { - public boolean preventPoiUpdated = false; // CraftBukkit - SPIGOT-5710 +@@ -380,8 +394,8 @@ public final class RegionizedWorldData { public boolean captureBlockStates = false; public boolean captureTreeGeneration = false; + public boolean isBlockPlaceCancelled = false; // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent - public final Map capturedBlockStates = new java.util.LinkedHashMap<>(); // Paper - public final Map capturedTileEntities = new java.util.LinkedHashMap<>(); // Paper + public final Map capturedBlockStates = Maps.newConcurrentMap(); // Paper @@ -271,7 +356,7 @@ index 245efed41de40dc506301af942a7f3c3a2b60d65..6bdc2e6f527ecc6c4e4b6b4461e9f080 public List captureDrops; // Paper start public int wakeupInactiveRemainingAnimals; -@@ -596,11 +601,8 @@ public final class RegionizedWorldData { +@@ -597,11 +611,8 @@ public final class RegionizedWorldData { } public void addEntityTickingEntity(final Entity entity) { @@ -284,7 +369,7 @@ index 245efed41de40dc506301af942a7f3c3a2b60d65..6bdc2e6f527ecc6c4e4b6b4461e9f080 } public boolean hasEntityTickingEntity(final Entity entity) { -@@ -608,11 +610,8 @@ public final class RegionizedWorldData { +@@ -609,11 +620,8 @@ public final class RegionizedWorldData { } public void removeEntityTickingEntity(final Entity entity) { @@ -297,7 +382,7 @@ index 245efed41de40dc506301af942a7f3c3a2b60d65..6bdc2e6f527ecc6c4e4b6b4461e9f080 } public void forEachTickingEntity(final Consumer action) { -@@ -627,15 +626,12 @@ public final class RegionizedWorldData { +@@ -628,15 +636,12 @@ public final class RegionizedWorldData { } public void addEntity(final Entity entity) { @@ -314,7 +399,7 @@ index 245efed41de40dc506301af942a7f3c3a2b60d65..6bdc2e6f527ecc6c4e4b6b4461e9f080 } } -@@ -644,34 +640,25 @@ public final class RegionizedWorldData { +@@ -645,34 +650,25 @@ public final class RegionizedWorldData { } public void removeEntity(final Entity entity) { @@ -352,7 +437,7 @@ index 245efed41de40dc506301af942a7f3c3a2b60d65..6bdc2e6f527ecc6c4e4b6b4461e9f080 } // block ticking hooks -@@ -744,12 +731,12 @@ public final class RegionizedWorldData { +@@ -745,12 +741,12 @@ public final class RegionizedWorldData { // ticking chunks public void addEntityTickingChunk(final LevelChunk levelChunk) { this.entityTickingChunks.add(levelChunk); @@ -367,7 +452,7 @@ index 245efed41de40dc506301af942a7f3c3a2b60d65..6bdc2e6f527ecc6c4e4b6b4461e9f080 } public IteratorSafeOrderedReferenceSet getEntityTickingChunks() { -@@ -772,12 +759,12 @@ public final class RegionizedWorldData { +@@ -773,12 +769,12 @@ public final class RegionizedWorldData { public void addChunk(final LevelChunk levelChunk) { this.chunks.add(levelChunk); @@ -382,20 +467,8 @@ index 245efed41de40dc506301af942a7f3c3a2b60d65..6bdc2e6f527ecc6c4e4b6b4461e9f080 } public IteratorSafeOrderedReferenceSet getChunks() { -diff --git a/src/main/java/io/papermc/paper/threadedregions/ThreadedRegionizer.java b/src/main/java/io/papermc/paper/threadedregions/ThreadedRegionizer.java -index fd0053369eb68f0fd596d8acfba4a5247ef8105a..69b2f6182e135ba86ac878956aabfd472f103f11 100644 ---- a/src/main/java/io/papermc/paper/threadedregions/ThreadedRegionizer.java -+++ b/src/main/java/io/papermc/paper/threadedregions/ThreadedRegionizer.java -@@ -640,6 +640,7 @@ public final class ThreadedRegionizer) region); - - // create new regions - final Long2ReferenceOpenHashMap> newRegionsMap = new Long2ReferenceOpenHashMap<>(); diff --git a/src/main/java/io/papermc/paper/threadedregions/TickRegionScheduler.java b/src/main/java/io/papermc/paper/threadedregions/TickRegionScheduler.java -index ab5f832aafc479eca1c5da012e180d6374e32325..d4871db7c15e569ea6427e78b5e1e9e706e88f1f 100644 +index ab5f832aafc479eca1c5da012e180d6374e32325..2b892dcccdc8810d732f44af0e82049e85ed9dec 100644 --- a/src/main/java/io/papermc/paper/threadedregions/TickRegionScheduler.java +++ b/src/main/java/io/papermc/paper/threadedregions/TickRegionScheduler.java @@ -210,9 +210,9 @@ public final class TickRegionScheduler { @@ -410,8 +483,16 @@ index ab5f832aafc479eca1c5da012e180d6374e32325..d4871db7c15e569ea6427e78b5e1e9e7 private RegionizedWorldData currentTickingWorldRegionizedData; private SchedulerThreadPool.SchedulableTick currentTickingTask; // Folia start - profiler +@@ -410,6 +410,7 @@ public final class TickRegionScheduler { + // regionFailed will schedule a shutdown, so we should avoid letting this region tick further + return false; + } finally { ++ if (this.region != null) { this.region.region.regioniser.world.worldDataSwitcher.onTickFinished(); } + final long tickEnd = System.nanoTime(); + final long cpuEnd = MEASURE_CPU_TIME ? THREAD_MX_BEAN.getCurrentThreadCpuTime() : 0L; + diff --git a/src/main/java/io/papermc/paper/threadedregions/TickRegions.java b/src/main/java/io/papermc/paper/threadedregions/TickRegions.java -index 78c50292fb25e8703e9c91db892f05456f07d72f..dfd565ff01bf6c396d7c6025206eb6e9b75e43a7 100644 +index 183fede965c3d227bbcc7e54781869e09796081f..5f9587f136e157f469675194137d23bfacbfafd1 100644 --- a/src/main/java/io/papermc/paper/threadedregions/TickRegions.java +++ b/src/main/java/io/papermc/paper/threadedregions/TickRegions.java @@ -12,6 +12,8 @@ import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; @@ -470,8 +551,8 @@ index 78c50292fb25e8703e9c91db892f05456f07d72f..dfd565ff01bf6c396d7c6025206eb6e9 ret = regionizedData.createNewValue(); this.regionizedData.put(regionizedData, ret); -+ if (ret instanceof RegionizedWorldData regionizedWorldData){ -+ regionizedWorldData.world.regionizedWorldDataAccessor.updateWorldData(this.region,regionizedWorldData); ++ if (ret instanceof RegionizedWorldData worldData){ ++ worldData.world.worldDataSwitcher.updateCurrent(worldData); + } + return ret; @@ -566,13 +647,15 @@ index 906f1c9e619a924c622acc76652a4569305edc8d..98fc618612feb1f119d00be1370b3ef6 diff --git a/src/main/java/me/earthme/lightingluminol/RegonizedWorldDataSwitcher.java b/src/main/java/me/earthme/lightingluminol/RegonizedWorldDataSwitcher.java new file mode 100644 -index 0000000000000000000000000000000000000000..a714c1a1443901913fb39634e97d49bc6319a24e +index 0000000000000000000000000000000000000000..40b904249eeab6e2691020e5c4145ba18bd8d6db --- /dev/null +++ b/src/main/java/me/earthme/lightingluminol/RegonizedWorldDataSwitcher.java -@@ -0,0 +1,15 @@ +@@ -0,0 +1,61 @@ +package me.earthme.lightingluminol; + +import io.papermc.paper.threadedregions.RegionizedWorldData; ++import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap; ++ + +public class RegonizedWorldDataSwitcher { + private volatile RegionizedWorldData lastMatch = null; @@ -584,6 +667,50 @@ index 0000000000000000000000000000000000000000..a714c1a1443901913fb39634e97d49bc + public void updateCurrent(RegionizedWorldData data){ + this.lastMatch = data; + } ++ ++ private final ThreadLocal randomIndex = ThreadLocal.withInitial(() -> 0); ++ private final ThreadLocal calledTimes = ThreadLocal.withInitial(() -> 0); ++ ++ public void onTickFinished(){ ++ this.randomIndex.remove(); ++ this.calledTimes.remove(); ++ } ++ ++ public void resetRandomIdx(){ ++ this.randomIndex.set(0); ++ this.calledTimes.set(0); ++ } ++ ++ public RegionizedWorldData randomIfNull(Long2ReferenceOpenHashMap regionToData, RegionizedWorldData data){ ++ if (data != null){ ++ return data; ++ } ++ ++ int idx = this.randomIndex.get(); ++ ++ if (this.calledTimes.get() / regionToData.size() >= 400){ //TODO Is that a truly exact value? ++ this.calledTimes.set(0); ++ this.randomIndex.set(idx+1); ++ } ++ ++ if (idx > regionToData.size()){ ++ this.randomIndex.set(0); ++ idx = 0; ++ } ++ ++ int curr = 0; ++ RegionizedWorldData result = this.getLastMatch(); ++ ++ for (RegionizedWorldData target : regionToData.values()){ ++ if (curr == idx){ ++ result = target; ++ } ++ ++ curr++; ++ } ++ ++ return result; ++ } +} diff --git a/src/main/java/me/earthme/lightingluminol/SchedulerUtil.java b/src/main/java/me/earthme/lightingluminol/SchedulerUtil.java new file mode 100644 @@ -622,233 +749,25 @@ index 0000000000000000000000000000000000000000..e022464207f271e0f2047ec60ff593bc + return CompletableFuture.supplyAsync(act,regionSchedulerAsExecutor(world,x,z)).join(); + } +} -diff --git a/src/main/java/me/earthme/lightingluminol/WorldDataAccessor.java b/src/main/java/me/earthme/lightingluminol/WorldDataAccessor.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e308cf5af5dc9211b0ac1f5ad379817c5265656c ---- /dev/null -+++ b/src/main/java/me/earthme/lightingluminol/WorldDataAccessor.java -@@ -0,0 +1,129 @@ -+package me.earthme.lightingluminol; -+ -+import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; -+import io.papermc.paper.threadedregions.RegionizedWorldData; -+import io.papermc.paper.threadedregions.ThreadedRegionizer; -+import io.papermc.paper.threadedregions.TickRegionScheduler; -+import io.papermc.paper.threadedregions.TickRegions; -+import io.papermc.paper.util.TickThread; -+import it.unimi.dsi.fastutil.objects.Reference2ObjectLinkedOpenHashMap; -+import net.minecraft.core.BlockPos; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.level.ChunkPos; -+import net.minecraft.world.level.Level; -+ -+import java.util.Map; -+import java.util.concurrent.ConcurrentHashMap; -+import java.util.concurrent.atomic.AtomicReference; -+import java.util.concurrent.locks.Lock; -+import java.util.concurrent.locks.ReadWriteLock; -+import java.util.concurrent.locks.ReentrantReadWriteLock; -+ -+public class WorldDataAccessor { -+ private final Level owner; -+ private final boolean ensureLoaded; -+ private final Map,RegionizedWorldData> region2Data = new Reference2ObjectLinkedOpenHashMap<>(); -+ private final ReadWriteLock accessLock = new ReentrantReadWriteLock(); -+ -+ public void removeRegion(ThreadedRegionizer.ThreadedRegion region){ -+ this.accessLock.writeLock().lock(); -+ try { -+ this.region2Data.remove(region); -+ }finally { -+ this.accessLock.writeLock().unlock(); -+ } -+ } -+ -+ public void updateWorldData(ThreadedRegionizer.ThreadedRegion region,RegionizedWorldData data) { -+ this.accessLock.writeLock().lock(); -+ try { -+ if (!this.region2Data.containsKey(region)){ -+ this.region2Data.put(region,data); -+ return; -+ } -+ -+ this.region2Data.replace(region,data); -+ }finally { -+ this.accessLock.writeLock().unlock(); -+ } -+ } -+ -+ public RegionizedWorldData getDataOf(ThreadedRegionizer.ThreadedRegion key){ -+ this.accessLock.readLock().lock(); -+ try { -+ return this.region2Data.get(key); -+ }finally { -+ this.accessLock.readLock().unlock(); -+ } -+ } -+ -+ public WorldDataAccessor(Level owner, boolean ensureLoaded) { -+ this.owner = owner; -+ this.ensureLoaded = ensureLoaded; -+ } -+ -+ public RegionizedWorldData getDirectly(int cposX,int cposZ){ -+ final ServerLevel serverLevel = ((ServerLevel) this.owner); -+ ThreadedRegionizer.ThreadedRegion targetRegion = serverLevel.regioniser.getRegionAtUnsynchronised(cposX,cposZ); -+ -+ if (targetRegion != null){ -+ return this.getDataOf(targetRegion); -+ } -+ -+ if (ensureLoaded && !TickThread.isTickThreadFor(serverLevel,cposX,cposZ)){ -+ AtomicReference result = new AtomicReference<>(); -+ -+ serverLevel.loadChunksAsync(cposX,cposX + 1,cposZ,cposZ + 1, PrioritisedExecutor.Priority.HIGHEST,callback -> { -+ result.set(serverLevel.getCurrentWorldData()); -+ }); -+ -+ while (true){ -+ if (result.get() != null){ -+ return result.get(); -+ } -+ } -+ }else if (TickThread.isTickThreadFor(serverLevel,cposX,cposZ)){ -+ return serverLevel.getCurrentWorldData(); -+ } -+ -+ return null; -+ } -+ -+ public RegionizedWorldData getAnyCPos(int cposX,int cposZ){ -+ final RegionizedWorldData current = this.owner.getCurrentWorldDataUnsafe(); -+ final RegionizedWorldData got = getDirectly(cposX,cposZ); -+ -+ if (current == null || current != got){ -+ return got; -+ } -+ -+ return current; -+ } -+ -+ public RegionizedWorldData getAny(int x,int z){ -+ return getAnyCPos(x >> 4,z >> 4); -+ } -+ -+ public RegionizedWorldData getAny(ChunkPos cpos){ -+ return getAnyCPos(cpos.x,cpos.z); -+ } -+ -+ public RegionizedWorldData getAny(BlockPos pos){ -+ return getAny(pos.getX(),pos.getZ()); -+ } -+ -+ public RegionizedWorldData getAny(Entity ent){ -+ return getAny(ent.blockPosition.getX(),ent.blockPosition.getZ()); -+ } -+ -+ private ThreadedRegionizer.ThreadedRegion getRegion(int cposX, int cposZ){ -+ ThreadedRegionizer.ThreadedRegion result = ((ServerLevel) this.owner).regioniser.getRegionAtSynchronised(cposX,cposZ); -+ -+ if (result != null){ -+ return result; -+ } -+ -+ return ((ServerLevel) this.owner).regioniser.getRegionAtUnsynchronised(cposX,cposZ); -+ } -+} -diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -index 2e701ff7dc2c04f77e2f003cae0416483b290217..e5e2e8e550d4be89d9bd653135bcc762fe9d1bc4 100644 ---- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -@@ -634,7 +634,7 @@ public interface DispenseItemBehavior { - } - } - -- io.papermc.paper.threadedregions.RegionizedWorldData worldData = worldserver.getCurrentWorldData(); // Folia - region threading -+ io.papermc.paper.threadedregions.RegionizedWorldData worldData = worldserver.regionizedWorldDataAccessor.getAny(pointer.pos()); // Folia - region threading - worldData.captureTreeGeneration = true; // Folia - region threading - // CraftBukkit end - diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index e169a9d4c2e633fdba3fe425e2f3f766d2200af5..15d780a12209e4378d4e28efbf6754f8fedae52b 100644 +index 87664187c073685573cb93bf51ba84ef26e6bd8c..35c0b9b0bcf82db03eefa65a772974d7b41efcf8 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -189,7 +189,7 @@ import org.bukkit.Bukkit; - import org.bukkit.craftbukkit.CraftRegistry; - import org.bukkit.event.server.ServerLoadEvent; - // CraftBukkit end -- -+import io.papermc.paper.threadedregions.RegionizedServer; - import co.aikar.timings.MinecraftTimings; // Paper - - public abstract class MinecraftServer extends ReentrantBlockableEventLoop implements ServerInfo, CommandSource, AutoCloseable { -@@ -2290,7 +2290,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop inRange = -- this.getNearbyPlayers().getPlayers(entity.chunkPosition(), io.papermc.paper.util.player.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE); -+ this.level.regionizedWorldDataAccessor.getAny(entity).getNearbyPlayers().getPlayers(entity.chunkPosition(), io.papermc.paper.util.player.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE); - if (inRange == null) { - return; - } -@@ -326,7 +326,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - int idx = mobCategory.ordinal(); - final com.destroystokyo.paper.util.maplist.ReferenceList inRange = -- this.getNearbyPlayers().getPlayersByChunk(chunkX, chunkZ, io.papermc.paper.util.player.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE); -+ this.level.regionizedWorldDataAccessor.getAny(chunkX,chunkZ).getNearbyPlayers().getPlayersByChunk(chunkX, chunkZ, io.papermc.paper.util.player.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE); - if (inRange == null) { - return; - } -@@ -1063,7 +1063,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - - this.updatePlayerStatus(entityplayer, true); - // Folia start - region threading -- for (Entity possible : this.level.getCurrentWorldData().getLoadedEntities()) { -+ for (Entity possible : this.level.regionizedWorldDataAccessor.getAny(entity).getLoadedEntities()) { - if (possible.tracker != null) { - possible.tracker.updatePlayer(entityplayer); - } -@@ -1081,7 +1081,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - if (entity instanceof ServerPlayer entityplayer) { - this.updatePlayerStatus(entityplayer, false); - // Folia start - region threading -- for (Entity possible : this.level.getCurrentWorldData().getLocalEntities()) { -+ for (Entity possible : this.level.regionizedWorldDataAccessor.getAny(entity).getLocalEntities()) { - if (possible.tracker != null) { - possible.tracker.removePlayer(entityplayer); - } diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 1cb09933aa4fa9f766c92ce000aed103fb2a5f54..6edd7209eacc1d6f0b27c96c59a85e9da88564f7 100644 +index 69feb8ee4dd959554a6fb9ccae78e32870b0e7b3..2f019a748ca5181cd97de20007effadb7f6d7886 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -44,6 +44,10 @@ import net.minecraft.world.level.levelgen.RandomState; - import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; - import net.minecraft.world.level.storage.DimensionDataStorage; - import net.minecraft.world.level.storage.LevelStorageSource; -+import io.papermc.paper.threadedregions.RegionizedServer; -+import io.papermc.paper.util.TickThread; -+import me.earthme.lightingluminol.SchedulerUtil; -+ - - public class ServerChunkCache extends ChunkSource { - -@@ -198,9 +202,9 @@ public class ServerChunkCache extends ChunkSource { +@@ -198,9 +198,9 @@ public class ServerChunkCache extends ChunkSource { public ChunkAccess getChunk(int x, int z, ChunkStatus leastStatus, boolean create) { final int x1 = x; final int z1 = z; // Paper - conflict on variable change if (!io.papermc.paper.util.TickThread.isTickThread()) { // Paper - rewrite chunk system @@ -856,16 +775,16 @@ index 1cb09933aa4fa9f766c92ce000aed103fb2a5f54..6edd7209eacc1d6f0b27c96c59a85e9d + return CompletableFuture.supplyAsync(() -> { return this.getChunk(x, z, leastStatus, create); - }, this.mainThreadProcessor).join(); -+ }, SchedulerUtil.regionSchedulerAsExecutor(this.level.getWorld(),x,z)).join(); ++ }, me.earthme.lightingluminol.SchedulerUtil.regionSchedulerAsExecutor(this.level.getWorld(),x,z)).join(); } else { // Paper start - Perf: Optimise getChunkAt calls for loaded chunks LevelChunk ifLoaded = this.getChunkAtIfLoadedMainThread(x, z); -@@ -224,7 +228,11 @@ public class ServerChunkCache extends ChunkSource { +@@ -224,7 +224,11 @@ public class ServerChunkCache extends ChunkSource { io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.pushChunkWait(this.level, x1, z1); // Paper - rewrite chunk system com.destroystokyo.paper.io.SyncLoadFinder.logSyncLoad(this.level, x, z); // Paper - Add debug for sync chunk loads this.level.timings.syncChunkLoad.startTiming(); // Paper - chunkproviderserver_b.managedBlock(completablefuture::isDone); -+ if (!RegionizedServer.isGlobalTickThread() || !TickThread.isTickThreadFor(this.level,x,z)){ ++ if (!io.papermc.paper.threadedregions.RegionizedServer.isGlobalTickThread() || !io.papermc.paper.util.TickThread.isTickThreadFor(this.level,x,z)){ + chunkproviderserver_b.managedBlock(completablefuture::isDone); + }else{ + completablefuture.join(); @@ -873,13 +792,13 @@ index 1cb09933aa4fa9f766c92ce000aed103fb2a5f54..6edd7209eacc1d6f0b27c96c59a85e9d io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.popChunkWait(); // Paper - rewrite chunk system this.level.timings.syncChunkLoad.stopTiming(); // Paper } // Paper -@@ -874,8 +882,10 @@ public class ServerChunkCache extends ChunkSource { +@@ -874,8 +878,10 @@ public class ServerChunkCache extends ChunkSource { // CraftBukkit start - process pending Chunk loadCallback() and unloadCallback() after each run task public boolean pollTask() { // Folia start - region threading - if (ServerChunkCache.this.level != io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegionizedWorldData().world) { - throw new IllegalStateException("Polling tasks from non-owned region"); -+ if (!RegionizedServer.isGlobalTickThread()){ ++ if (!io.papermc.paper.threadedregions.RegionizedServer.isGlobalTickThread()){ + if (ServerChunkCache.this.level != io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegionizedWorldData().world) { + throw new IllegalStateException("Polling tasks from non-owned region"); + } @@ -887,60 +806,10 @@ index 1cb09933aa4fa9f766c92ce000aed103fb2a5f54..6edd7209eacc1d6f0b27c96c59a85e9d // Folia end - region threading if (ServerChunkCache.this.runDistanceManagerUpdates()) { diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 573cca66b905c5decb0e59c58cfa861d1788d5d3..e9678cf456a8ab5c75d56b5fe854fc356aa1eaaa 100644 +index 573cca66b905c5decb0e59c58cfa861d1788d5d3..88e8ee69620795cf7603e7e462fa2dff6611cc00 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -181,6 +181,7 @@ import org.bukkit.event.server.MapInitializeEvent; - import org.bukkit.event.weather.LightningStrikeEvent; - import org.bukkit.event.world.TimeSkipEvent; - // CraftBukkit end -+import io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet; - - public class ServerLevel extends Level implements WorldGenLevel { - -@@ -620,7 +621,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - @Override - public Player getNearestPlayer(double x, double y, double z, double maxDistance, @Nullable Predicate targetPredicate) { - if (maxDistance > 0.0D) { -- io.papermc.paper.util.player.NearbyPlayers players = this.chunkSource.chunkMap.getNearbyPlayers(); -+ io.papermc.paper.util.player.NearbyPlayers players = this.regionizedWorldDataAccessor.getAny((int) x, (int) z).getNearbyPlayers(); - - com.destroystokyo.paper.util.maplist.ReferenceList nearby = players.getPlayersByBlock( - io.papermc.paper.util.CoordinateUtils.getBlockCoordinate(x), -@@ -679,7 +680,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - double x, double y, double z) { - double range = targetPredicate.range; - if (range > 0.0D) { -- io.papermc.paper.util.player.NearbyPlayers players = this.chunkSource.chunkMap.getNearbyPlayers(); -+ io.papermc.paper.util.player.NearbyPlayers players = this.regionizedWorldDataAccessor.getAny(entity).getNearbyPlayers(); - - com.destroystokyo.paper.util.maplist.ReferenceList nearby = players.getPlayersByBlock( - io.papermc.paper.util.CoordinateUtils.getBlockCoordinate(x), -@@ -1888,10 +1889,12 @@ public class ServerLevel extends Level implements WorldGenLevel { - // WorldServer.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityTypes.getKey(entity.getType())); // CraftBukkit - return false; - } else { -+ var got = ServerLevel.this.regionizedWorldDataAccessor.getAny(entity); -+ - if (entity instanceof net.minecraft.world.entity.item.ItemEntity itemEntity && itemEntity.getItem().isEmpty()) return false; // Paper - Prevent empty items from being added - // Paper start - capture all item additions to the world -- if (this.getCurrentWorldData().captureDrops != null && entity instanceof net.minecraft.world.entity.item.ItemEntity) { // Folia - region threading -- this.getCurrentWorldData().captureDrops.add((net.minecraft.world.entity.item.ItemEntity) entity); // Folia - region threading -+ if (got.captureDrops != null && entity instanceof net.minecraft.world.entity.item.ItemEntity) { // Folia - region threading -+ got.captureDrops.add((net.minecraft.world.entity.item.ItemEntity) entity); // Folia - region threading - return true; - } - // Paper end - capture all item additions to the world -@@ -2053,7 +2056,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - } - - this.getChunkSource().blockChanged(pos); -- final io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.getCurrentWorldData(); // Folia - region threading -+ final io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.regionizedWorldDataAccessor.getAny(pos); // Folia - region threading - regionizedWorldData.pathTypesByPosCache.invalidate(pos); // Folia - region threading - if (this.paperConfig().misc.updatePathfindingOnBlockUpdate) { // Paper - option to disable pathfinding updates - VoxelShape voxelshape = oldState.getCollisionShape(this, pos); -@@ -2061,7 +2064,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2061,7 +2061,7 @@ public class ServerLevel extends Level implements WorldGenLevel { if (Shapes.joinIsNotEmpty(voxelshape, voxelshape1, BooleanOp.NOT_SAME)) { List list = new ObjectArrayList(); @@ -949,179 +818,11 @@ index 573cca66b905c5decb0e59c58cfa861d1788d5d3..e9678cf456a8ab5c75d56b5fe854fc35 while (iterator.hasNext()) { // CraftBukkit start - fix SPIGOT-6362 -@@ -2102,23 +2105,31 @@ public class ServerLevel extends Level implements WorldGenLevel { - - @Override - public void updateNeighborsAt(BlockPos pos, Block sourceBlock) { -- if (this.getCurrentWorldData().captureBlockStates) { return; } // Paper - Cancel all physics during placement // Folia - region threading -- this.getCurrentWorldData().neighborUpdater.updateNeighborsAtExceptFromFacing(pos, sourceBlock, (Direction) null); // Folia - region threading -+ var got = this.regionizedWorldDataAccessor.getAny(pos); -+ -+ if (got.captureBlockStates) { return; } // Paper - Cancel all physics during placement // Folia - region threading -+ got.neighborUpdater.updateNeighborsAtExceptFromFacing(pos, sourceBlock, (Direction) null); // Folia - region threading - } - - @Override - public void updateNeighborsAtExceptFromFacing(BlockPos pos, Block sourceBlock, Direction direction) { -- this.getCurrentWorldData().neighborUpdater.updateNeighborsAtExceptFromFacing(pos, sourceBlock, direction); // Folia - region threading -+ var got = this.regionizedWorldDataAccessor.getAny(pos); -+ -+ got.neighborUpdater.updateNeighborsAtExceptFromFacing(pos, sourceBlock, direction); // Folia - region threading - } - - @Override - public void neighborChanged(BlockPos pos, Block sourceBlock, BlockPos sourcePos) { -- this.getCurrentWorldData().neighborUpdater.neighborChanged(pos, sourceBlock, sourcePos); // Folia - region threading -+ var got = this.regionizedWorldDataAccessor.getAny(pos); -+ -+ got.neighborUpdater.neighborChanged(pos, sourceBlock, sourcePos); // Folia - region threading - } - - @Override - public void neighborChanged(BlockState state, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) { -- this.getCurrentWorldData().neighborUpdater.neighborChanged(state, pos, sourceBlock, sourcePos, notify); // Folia - region threading -+ var got = this.regionizedWorldDataAccessor.getAny(pos); -+ -+ got.neighborUpdater.neighborChanged(state, pos, sourceBlock, sourcePos, notify); // Folia - region threading - } - - @Override -@@ -2164,7 +2175,9 @@ public class ServerLevel extends Level implements WorldGenLevel { - - @Override - public void blockEvent(BlockPos pos, Block block, int type, int data) { -- this.getCurrentWorldData().pushBlockEvent(new BlockEventData(pos, block, type, data)); // Folia - regionised ticking -+ var got = this.regionizedWorldDataAccessor.getAny(pos); -+ -+ got.pushBlockEvent(new BlockEventData(pos, block, type, data)); // Folia - regionised ticking - } - - private void runBlockEvents() { -@@ -2693,9 +2706,11 @@ public class ServerLevel extends Level implements WorldGenLevel { - - @Override - public void blockUpdated(BlockPos pos, Block block) { -+ var got = this.regionizedWorldDataAccessor.getAny(pos); -+ - if (!this.isDebug()) { - // CraftBukkit start -- if (this.getCurrentWorldData().populating) { // Folia - region threading -+ if (got.populating) { // Folia - region threading - return; - } - // CraftBukkit end -@@ -2918,12 +2933,16 @@ public class ServerLevel extends Level implements WorldGenLevel { - } - - public void onTickingStart(Entity entity) { -+ var got = ServerLevel.this.regionizedWorldDataAccessor.getAny(entity); -+ - if (entity instanceof net.minecraft.world.entity.Marker && !paperConfig().entities.markers.tick) return; // Paper - Configurable marker ticking -- ServerLevel.this.getCurrentWorldData().addEntityTickingEntity(entity); // Folia - region threading -+ got.addEntityTickingEntity(entity); // Folia - region threading - } - - public void onTickingEnd(Entity entity) { -- ServerLevel.this.getCurrentWorldData().removeEntityTickingEntity(entity); // Folia - region threading -+ var got = ServerLevel.this.regionizedWorldDataAccessor.getAny(entity); -+ -+ got.removeEntityTickingEntity(entity); // Folia - region threading - // Paper start - Reset pearls when they stop being ticked - if (paperConfig().fixes.disableUnloadedChunkEnderpearlExploit && entity instanceof net.minecraft.world.entity.projectile.ThrownEnderpearl pearl) { - pearl.cachedOwner = null; -@@ -2934,7 +2953,9 @@ public class ServerLevel extends Level implements WorldGenLevel { - - public void onTrackingStart(Entity entity) { - org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot -- ServerLevel.this.getCurrentWorldData().addLoadedEntity(entity); // Folia - region threading -+ var got = ServerLevel.this.regionizedWorldDataAccessor.getAny(entity); -+ -+ got.addLoadedEntity(entity); // Folia - region threading - // ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server; moved down below valid=true - if (entity instanceof ServerPlayer entityplayer) { - ServerLevel.this.players.add(entityplayer); -@@ -2948,7 +2969,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - Util.logAndPauseIfInIde("onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration")); - } - -- ServerLevel.this.getCurrentWorldData().addNavigatingMob(entityinsentient); // Folia - region threading -+ got.addNavigatingMob(entityinsentient); // Folia - region threading - } - - if (entity instanceof EnderDragon entityenderdragon) { -@@ -2982,7 +3003,9 @@ public class ServerLevel extends Level implements WorldGenLevel { - - public void onTrackingEnd(Entity entity) { - org.spigotmc.AsyncCatcher.catchOp("entity unregister"); // Spigot -- ServerLevel.this.getCurrentWorldData().removeLoadedEntity(entity); -+ var got = ServerLevel.this.regionizedWorldDataAccessor.getAny(entity); -+ -+ got.removeLoadedEntity(entity); - // Spigot start - if ( entity instanceof Player ) - { -@@ -3040,7 +3063,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - Util.logAndPauseIfInIde("onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration")); - } - -- ServerLevel.this.getCurrentWorldData().removeNavigatingMob(entityinsentient); // Folia - region threading -+ got.removeNavigatingMob(entityinsentient); // Folia - region threading - } - - if (entity instanceof EnderDragon entityenderdragon) { -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index 990879f69e4ee37d6633c77ea31433736dd154f8..b7a5805e20a8fb1fbb65acd987b19fd73c12951c 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -419,7 +419,9 @@ public class ServerPlayerGameMode { - } else { - // CraftBukkit start - org.bukkit.block.BlockState state = bblock.getState(); -- this.level.getCurrentWorldData().captureDrops = new ArrayList<>(); // Folia - region threading -+ var got = this.level.regionizedWorldDataAccessor.getAny(bblock.getX(),bblock.getZ()); -+ -+ got.captureDrops = new ArrayList<>(); // Folia - region threading - // CraftBukkit end - BlockState iblockdata1 = block.playerWillDestroy(this.level, pos, iblockdata, this.player); - boolean flag = this.level.removeBlock(pos, false); -@@ -447,8 +449,8 @@ public class ServerPlayerGameMode { - // return true; // CraftBukkit - } - // CraftBukkit start -- java.util.List itemsToDrop = this.level.getCurrentWorldData().captureDrops; // Paper - capture all item additions to the world // Folia - region threading -- this.level.getCurrentWorldData().captureDrops = null; // Paper - capture all item additions to the world; Remove this earlier so that we can actually drop stuff // Folia - region threading -+ java.util.List itemsToDrop = got.captureDrops; // Paper - capture all item additions to the world // Folia - region threading -+ got.captureDrops = null; // Paper - capture all item additions to the world; Remove this earlier so that we can actually drop stuff // Folia - region threading - if (event.isDropItems()) { - org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDropItemEvent(bblock, state, this.player, itemsToDrop); // Paper - capture all item additions to the world - } -diff --git a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java -index cc274fee6cd0a8b532ea2cf7be2876d9f5a708ee..83697752f69200f64ada063e3901c9520bf05537 100644 ---- a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java -+++ b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java -@@ -167,7 +167,7 @@ public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCl - } - updateFuture.isTicketAdded = true; - -- final int references = this.chunkMap.level.getCurrentWorldData().chunksBeingWorkedOn.addTo(key, 1); // Folia - region threading -+ final int references = this.chunkMap.level.regionizedWorldDataAccessor.getAnyCPos(chunkX,chunkZ).chunksBeingWorkedOn.addTo(key, 1); // Folia - region threading - if (references == 0) { - final ChunkPos pos = new ChunkPos(chunkX, chunkZ); - world.getChunkSource().addRegionTicket(ca.spottedleaf.starlight.common.light.StarLightInterface.CHUNK_WORK_TICKET, pos, 0, pos); diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 00d801aa1ffce0ccd8e7176f614d831ae09259d3..c32a75d3114be4100eed659c5e83b5552a0b0f65 100644 +index 56216f11320c1c12aa3f850d3764dbfd89d333e1..a385cf9d540dc1317e5c314393c64d7dd9298532 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -161,6 +161,8 @@ import org.bukkit.event.entity.EntityRemoveEvent; - import org.bukkit.event.player.PlayerTeleportEvent; - import org.bukkit.plugin.PluginManager; - // CraftBukkit end -+import org.bukkit.event.player.PlayerPortalEvent; -+import io.papermc.paper.util.MCUtil; - - public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, CommandSource, ScoreHolder { - -@@ -4094,7 +4096,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4099,7 +4099,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess if (!this.canTeleportAsync()) { return false; } @@ -1138,7 +839,7 @@ index 00d801aa1ffce0ccd8e7176f614d831ae09259d3..c32a75d3114be4100eed659c5e83b555 if ((teleportFlags & TELEPORT_FLAG_UNMOUNT) == 0L) { for (Entity entity : this.getIndirectPassengers()) { if (!entity.canTeleportAsync()) { -@@ -4528,6 +4538,21 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4533,6 +4541,21 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess // we just have to abandon this teleport to prevent duplication return; } @@ -1152,7 +853,7 @@ index 00d801aa1ffce0ccd8e7176f614d831ae09259d3..c32a75d3114be4100eed659c5e83b555 + case NETHER -> cause = PlayerTeleportEvent.TeleportCause.NETHER_PORTAL; + } + -+ final PlayerPortalEvent eventWrapped = new PlayerPortalEvent(bukkitPlayer,MCUtil.toLocation(originWorld,initialPosition),MCUtil.toLocation(destination,info.pos),cause,0,true, 0); ++ final org.bukkit.event.player.PlayerPortalEvent eventWrapped = new org.bukkit.event.player.PlayerPortalEvent(bukkitPlayer,MCUtil.toLocation(originWorld,initialPosition),MCUtil.toLocation(destination,info.pos),cause,0,true, 0); + eventWrapped.callEvent(); + info.pos = MCUtil.toVec3(eventWrapped.getTo()); + } @@ -1215,208 +916,40 @@ index cd133931de618e5d8ed5062f8ebfde9d8a9e799c..a03cf8f8be5afcc3e9f251e868e52406 } super.setPos(x, y, z); diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 8c124cb3d1238c9f3297f9f2d2345399055147fe..6ee2616cbe6362a3ae950133a7dfaf810d07f874 100644 +index 75ecbdb5bdacb4d4b27d60fe1c1a35c3a9c16207..a2dbedba33eca92a02d988937f09e04db2c9312a 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -10,6 +10,9 @@ import java.util.function.Consumer; +@@ -10,6 +10,8 @@ import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.Supplier; import javax.annotation.Nullable; + -+import io.papermc.paper.threadedregions.RegionizedWorldData; -+import me.earthme.lightingluminol.WorldDataAccessor; ++import me.earthme.lightingluminol.RegonizedWorldDataSwitcher; import net.minecraft.CrashReport; import net.minecraft.CrashReportCategory; import net.minecraft.ReportedException; -@@ -211,11 +214,25 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -202,16 +204,19 @@ public abstract class Level implements LevelAccessor, AutoCloseable { ); public volatile io.papermc.paper.threadedregions.RegionizedServer.WorldLevelData tickData; public final java.util.concurrent.ConcurrentHashMap.KeySetView needsChangeBroadcasting = java.util.concurrent.ConcurrentHashMap.newKeySet(); -+ public WorldDataAccessor regionizedWorldDataAccessor = new WorldDataAccessor(this,false); -+ -+ public io.papermc.paper.threadedregions.RegionizedWorldData getCurrentWorldDataUnsafe() { -+ final io.papermc.paper.threadedregions.RegionizedWorldData ret = io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegionizedWorldData(); -+ if (ret == null) { -+ return null; -+ } -+ Level world = ret.world; -+ if (world != this) { -+ return null; -+ } -+ return ret; -+ } -+ ++ public final RegonizedWorldDataSwitcher worldDataSwitcher = new RegonizedWorldDataSwitcher(); public io.papermc.paper.threadedregions.RegionizedWorldData getCurrentWorldData() { final io.papermc.paper.threadedregions.RegionizedWorldData ret = io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegionizedWorldData(); if (ret == null) { - return ret; -+ return null; ++ return this.worldDataSwitcher.getLastMatch(); } Level world = ret.world; if (world != this) { -@@ -864,8 +881,9 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - @Nullable - public final BlockState getBlockStateIfLoaded(BlockPos pos) { - // CraftBukkit start - tree generation -- if (this.getCurrentWorldData().captureTreeGeneration) { // Folia - region threading -- CraftBlockState previous = this.getCurrentWorldData().capturedBlockStates.get(pos); // Folia - region threading -+ var got = this.regionizedWorldDataAccessor.getAny(pos); -+ if (got.captureTreeGeneration) { // Folia - region threading -+ CraftBlockState previous = got.capturedBlockStates.get(pos); // Folia - region threading - if (previous != null) { - return previous.getHandle(); - } -@@ -928,7 +946,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - @Override - public boolean setBlock(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) { - io.papermc.paper.util.TickThread.ensureTickThread((ServerLevel)this, pos, "Updating block asynchronously"); // Folia - region threading -- io.papermc.paper.threadedregions.RegionizedWorldData worldData = this.getCurrentWorldData(); // Folia - region threading -+ io.papermc.paper.threadedregions.RegionizedWorldData worldData = this.regionizedWorldDataAccessor.getAny(pos); // Folia - region threading - // CraftBukkit start - tree generation - if (worldData.captureTreeGeneration) { // Folia - region threading - // Paper start - Protect Bedrock and End Portal/Frames from being destroyed -@@ -1049,6 +1067,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - } - } - -+ var worlddata = this.regionizedWorldDataAccessor.getAny(blockposition); -+ - if ((i & 16) == 0 && j > 0) { - int k = i & -34; - -@@ -1056,7 +1076,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - iblockdata1.updateIndirectNeighbourShapes(this, blockposition, k, j - 1); // Don't call an event for the old block to limit event spam - CraftWorld world = ((ServerLevel) this).getWorld(); - boolean cancelledUpdates = false; // Paper - Fix block place logic -- if (world != null && ((ServerLevel)this).getCurrentWorldData().hasPhysicsEvent) { // Paper - BlockPhysicsEvent // Folia - region threading -+ if (world != null && worlddata.hasPhysicsEvent) { // Paper - BlockPhysicsEvent // Folia - region threading - BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), CraftBlockData.fromData(iblockdata)); - this.getCraftServer().getPluginManager().callEvent(event); - -@@ -1070,7 +1090,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - } - - // CraftBukkit start - SPIGOT-5710 -- if (!this.getCurrentWorldData().preventPoiUpdated) { // Folia - region threading -+ if (!worlddata.preventPoiUpdated) { // Folia - region threading - this.onBlockStateChange(blockposition, iblockdata1, iblockdata2); - } - // CraftBukkit end -@@ -1154,7 +1174,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - - @Override - public void neighborShapeChanged(Direction direction, BlockState neighborState, BlockPos pos, BlockPos neighborPos, int flags, int maxUpdateDepth) { -- this.getCurrentWorldData().neighborUpdater.shapeUpdate(direction, neighborState, pos, neighborPos, flags, maxUpdateDepth); // Folia - region threading -+ this.regionizedWorldDataAccessor.getAny(pos).neighborUpdater.shapeUpdate(direction, neighborState, pos, neighborPos, flags, maxUpdateDepth); // Folia - region threading - } - - @Override -@@ -1205,8 +1225,9 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - @Override - public BlockState getBlockState(BlockPos pos) { - // CraftBukkit start - tree generation -- if (this.getCurrentWorldData().captureTreeGeneration) { // Folia - region threading -- CraftBlockState previous = this.getCurrentWorldData().capturedBlockStates.get(pos); // Paper // Folia - region threading -+ var got = this.regionizedWorldDataAccessor.getAny(pos); -+ if (got.captureTreeGeneration) { // Folia - region threading -+ CraftBlockState previous = got.capturedBlockStates.get(pos); // Paper // Folia - region threading - if (previous != null) { - return previous.getHandle(); - } -@@ -1301,7 +1322,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - } - - public void addBlockEntityTicker(TickingBlockEntity ticker) { -- ((ServerLevel)this).getCurrentWorldData().addBlockEntityTicker(ticker); // Folia - regionised ticking -+ this.regionizedWorldDataAccessor.getAny(ticker.getPos()).addBlockEntityTicker(ticker); // Folia - regionised ticking - } - - protected void tickBlockEntities() { -@@ -1478,7 +1499,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - // Folia end - region threading - // Paper start - Perf: Optimize capturedTileEntities lookup - net.minecraft.world.level.block.entity.BlockEntity blockEntity; -- if (!this.getCurrentWorldData().capturedTileEntities.isEmpty() && (blockEntity = this.getCurrentWorldData().capturedTileEntities.get(blockposition)) != null) { // Folia - region threading -+ var got = this.regionizedWorldDataAccessor.getAny(blockposition); -+ if (!got.capturedTileEntities.isEmpty() && (blockEntity = got.capturedTileEntities.get(blockposition)) != null) { // Folia - region threading - return blockEntity; - } - // Paper end - Perf: Optimize capturedTileEntities lookup -@@ -1489,10 +1511,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - public void setBlockEntity(BlockEntity blockEntity) { - BlockPos blockposition = blockEntity.getBlockPos(); - -+ var got = this.regionizedWorldDataAccessor.getAny(blockposition); - if (!this.isOutsideBuildHeight(blockposition)) { - // CraftBukkit start -- if (this.getCurrentWorldData().captureBlockStates) { // Folia - region threading -- this.getCurrentWorldData().capturedTileEntities.put(blockposition.immutable(), blockEntity); // Folia - region threading -+ if (got.captureBlockStates) { // Folia - region threading -+ got.capturedTileEntities.put(blockposition.immutable(), blockEntity); // Folia - region threading - return; - } - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java -index b266cc2319177366471ee0bbf570a931974b642a..721103971dfa5260f63b7b4b733e3933707f75eb 100644 ---- a/src/main/java/net/minecraft/world/level/block/Block.java -+++ b/src/main/java/net/minecraft/world/level/block/Block.java -@@ -390,8 +390,9 @@ public class Block extends BlockBehaviour implements ItemLike { - - entityitem.setDefaultPickUpDelay(); - // CraftBukkit start -- if (world.getCurrentWorldData().captureDrops != null) { // Folia - region threading -- world.getCurrentWorldData().captureDrops.add(entityitem); // Folia - region threading -+ var got = world.regionizedWorldDataAccessor.getAny(entityitem); -+ if (got.captureDrops != null) { // Folia - region threading -+ got.captureDrops.add(entityitem); // Folia - region threading - } else { - world.addFreshEntity(entityitem); - } -diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index c15be74b855a7c62f23499143634057e2ac27b7a..b1a85a6f1b3b0b39d2bca73d6105fde777d6a6b0 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -470,8 +470,10 @@ public class LevelChunk extends ChunkAccess { - if (!chunksection.getBlockState(j, k, l).is(block)) { - return null; - } else { -+ var got = this.level.regionizedWorldDataAccessor.getAny(blockposition); -+ - // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled. -- if (!this.level.isClientSide && doPlace && (!this.level.getCurrentWorldData().captureBlockStates || block instanceof net.minecraft.world.level.block.BaseEntityBlock)) { // Folia - region threading -+ if (!this.level.isClientSide && doPlace && (!got.captureBlockStates || block instanceof net.minecraft.world.level.block.BaseEntityBlock)) { // Folia - region threading - iblockdata.onPlace(this.level, blockposition, iblockdata1, flag); - } - -@@ -517,7 +519,8 @@ public class LevelChunk extends ChunkAccess { - @Nullable - public BlockEntity getBlockEntity(BlockPos pos, LevelChunk.EntityCreationType creationType) { - // CraftBukkit start -- BlockEntity tileentity = this.level.getCurrentWorldData().capturedTileEntities.get(pos); // Folia - region threading -+ var got = this.level.regionizedWorldDataAccessor.getAny(pos); -+ BlockEntity tileentity = got.capturedTileEntities.get(pos); // Folia - region threading - if (tileentity == null) { - tileentity = (BlockEntity) this.blockEntities.get(pos); +- throw new IllegalStateException("World mismatch: expected " + this.getWorld().getName() + " but got " + world.getWorld().getName()); ++ //throw new IllegalStateException("World mismatch: expected " + this.getWorld().getName() + " but got " + world.getWorld().getName()); ++ return this.worldDataSwitcher.getLastMatch(); } -@@ -805,13 +808,15 @@ public class LevelChunk extends ChunkAccess { ++ this.worldDataSwitcher.updateCurrent(ret); + return ret; + } - org.bukkit.World world = this.level.getWorld(); - if (world != null) { -- this.level.getCurrentWorldData().populating = true; // Folia - region threading -+ var got = this.level.regionizedWorldDataAccessor.getAnyCPos(this.chunkPos.x,this.chunkPos.z); -+ -+ got.populating = true; // Folia - region threading - try { - for (org.bukkit.generator.BlockPopulator populator : world.getPopulators()) { - populator.populate(world, random, bukkitChunk); - } - } finally { -- this.level.getCurrentWorldData().populating = false; // Folia - region threading -+ got.populating = false; // Folia - region threading - } - } - server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkPopulateEvent(bukkitChunk)); diff --git a/src/main/java/net/minecraft/world/level/portal/PortalInfo.java b/src/main/java/net/minecraft/world/level/portal/PortalInfo.java index 34c0d9fe03cc834e949889f9c4f8269206c18040..4953371d205a1c3982a29252a51dcc99b1f5e99a 100644 --- a/src/main/java/net/minecraft/world/level/portal/PortalInfo.java @@ -1431,21 +964,10 @@ index 34c0d9fe03cc834e949889f9c4f8269206c18040..4953371d205a1c3982a29252a51dcc99 public final float yRot; public final float xRot; diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 273c37b63df3f14488586f9217c7b19a8f3d8ad5..cacae3b7c54b62e9cc54cb72f813db327f4ea334 100644 +index af077ce30c01c5d1870b99617b339393f8907d36..b0b9015b8ccdefcfe323a7b9e83547dbeb4cb2d1 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -262,6 +262,10 @@ import net.md_5.bungee.api.chat.BaseComponent; // Spigot - - import javax.annotation.Nullable; // Paper - import javax.annotation.Nonnull; // Paper -+import io.papermc.paper.threadedregions.RegionizedServer; -+import java.util.concurrent.atomic.AtomicBoolean; -+import java.util.concurrent.locks.LockSupport; -+import static org.bukkit.craftbukkit.scheduler.CraftScheduler.MINECRAFT; - - public final class CraftServer implements Server { - private final String serverName = io.papermc.paper.ServerBuildInfo.buildInfo().brandName(); // Paper -@@ -1270,7 +1274,6 @@ public final class CraftServer implements Server { +@@ -1294,7 +1294,6 @@ public final class CraftServer implements Server { @Override public World createWorld(WorldCreator creator) { @@ -1453,11 +975,13 @@ index 273c37b63df3f14488586f9217c7b19a8f3d8ad5..cacae3b7c54b62e9cc54cb72f813db32 Preconditions.checkState(this.console.getAllLevels().iterator().hasNext(), "Cannot create additional worlds on STARTUP"); //Preconditions.checkState(!this.console.isIteratingOverLevels, "Cannot create a world while worlds are being ticked"); // Paper - Cat - Temp disable. We'll see how this goes. Preconditions.checkArgument(creator != null, "WorldCreator cannot be null"); -@@ -1435,7 +1438,17 @@ public final class CraftServer implements Server { +@@ -1454,7 +1453,19 @@ public final class CraftServer implements Server { } this.console.addLevel(internal); // Paper - Put world into worldlist before initing the world; move up - this.console.initWorld(internal, worlddata, worlddata, worlddata.worldGenOptions()); ++ //this.console.initWorld(internal, worlddata, worlddata, worlddata.worldGenOptions()); ++ + io.papermc.paper.threadedregions.RegionizedServer.getInstance().addWorld(internal); + int loadRegionRadius = ((32) >> 4); + internal.randomSpawnSelection = new net.minecraft.world.level.ChunkPos(internal.getChunkSource().randomState().sampler().findSpawnPosition()); @@ -1472,7 +996,7 @@ index 273c37b63df3f14488586f9217c7b19a8f3d8ad5..cacae3b7c54b62e9cc54cb72f813db32 internal.setSpawnSettings(true, true); // Paper - Put world into worldlist before initing the world; move up -@@ -1453,7 +1466,7 @@ public final class CraftServer implements Server { +@@ -1472,7 +1483,7 @@ public final class CraftServer implements Server { @Override public boolean unloadWorld(World world, boolean save) { @@ -1481,22 +1005,19 @@ index 273c37b63df3f14488586f9217c7b19a8f3d8ad5..cacae3b7c54b62e9cc54cb72f813db32 //Preconditions.checkState(!this.console.isIteratingOverLevels, "Cannot unload a world while worlds are being ticked"); // Paper - Cat - Temp disable. We'll see how this goes. if (world == null) { return false; -@@ -1481,13 +1494,40 @@ public final class CraftServer implements Server { +@@ -1500,13 +1511,41 @@ public final class CraftServer implements Server { } try { - if (save) { - handle.save(null, true, false); // Paper - Fix saving in unloadWorld - } -+ if (RegionizedServer.isGlobalTickThread()) { ++ if (io.papermc.paper.threadedregions.RegionizedServer.isGlobalTickThread()) { + try { + if (save) { + handle.save(null, true, false); // Paper - don't disable saving + } - -- handle.getChunkSource().close(save); -- // handle.entityManager.close(save); // SPIGOT-6722: close entityManager // Paper - rewrite chunk system -- handle.convertable.close(); ++ + handle.getChunkSource().close(save); + // handle.entityManager.close(save); // SPIGOT-6722: close entityManager // Paper - rewrite chunk system + handle.convertable.close(); @@ -1504,13 +1025,16 @@ index 273c37b63df3f14488586f9217c7b19a8f3d8ad5..cacae3b7c54b62e9cc54cb72f813db32 + this.getLogger().log(Level.SEVERE, null, ex); + } + } else { -+ final AtomicBoolean finished = new AtomicBoolean(false); -+ Bukkit.getGlobalRegionScheduler().run(MINECRAFT, t -> { ++ final java.util.concurrent.atomic.AtomicBoolean finished = new java.util.concurrent.atomic.AtomicBoolean(false); ++ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { + try { + if (save) { + handle.save(null, true, false); // Paper - don't disable saving + } -+ + +- handle.getChunkSource().close(save); +- // handle.entityManager.close(save); // SPIGOT-6722: close entityManager // Paper - rewrite chunk system +- handle.convertable.close(); + handle.getChunkSource().close(save); + // handle.entityManager.close(save); // SPIGOT-6722: close entityManager // Paper - rewrite chunk system + handle.convertable.close(); @@ -1522,14 +1046,15 @@ index 273c37b63df3f14488586f9217c7b19a8f3d8ad5..cacae3b7c54b62e9cc54cb72f813db32 + }); + + while (!finished.get()) { -+ LockSupport.parkNanos(1_000_000L); ++ Thread.yield(); ++ java.util.concurrent.locks.LockSupport.parkNanos(1_000L); + } + } } catch (Exception ex) { this.getLogger().log(Level.SEVERE, null, ex); } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6a990d4a0 100644 +index 53d0481d349b4c9c0ddbe8242532f7195866421b..f118cac5e338a4c7c2c1588b5d837cd78cc256ab 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -147,6 +147,7 @@ import org.bukkit.util.StructureSearchResult; @@ -1562,16 +1087,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 if (chunkStatus == ChunkStatus.NOISE) { net.minecraft.world.level.levelgen.Heightmap.primeHeightmaps(future.join(), ChunkStatus.POST_FEATURES); } -@@ -846,7 +851,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - @Override - public boolean generateTree(Location loc, TreeType type, BlockChangeDelegate delegate) { - io.papermc.paper.util.TickThread.ensureTickThread(this.world, loc.getX(), loc.getZ(), "Cannot generate tree asynchronously"); // Folia - region threading -- io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.getCurrentWorldData(); // Folia - region threading -+ io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.regionizedWorldDataAccessor.getAny(loc.getBlockX(),loc.getBlockZ()); // Folia - region threading - worldData.captureTreeGeneration = true; // Folia - region threading - worldData.captureBlockStates = true; // Folia - region threading - boolean grownTree = this.generateTree(loc, type); -@@ -898,7 +903,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -923,7 +928,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setTime(long time) { @@ -1580,7 +1096,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 long margin = (time - this.getFullTime()) % 24000; if (margin < 0) margin += 24000; this.setFullTime(this.getFullTime() + margin); -@@ -911,7 +916,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -936,7 +941,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setFullTime(long time) { @@ -1589,7 +1105,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 // Notify anyone who's listening TimeSkipEvent event = new TimeSkipEvent(this, TimeSkipEvent.SkipReason.CUSTOM, time - this.world.getDayTime()); this.server.getPluginManager().callEvent(event); -@@ -1393,7 +1398,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1418,7 +1423,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setStorm(boolean hasStorm) { @@ -1598,7 +1114,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 this.world.serverLevelData.setRaining(hasStorm, org.bukkit.event.weather.WeatherChangeEvent.Cause.PLUGIN); // Paper - Add cause to Weather/ThunderChangeEvents this.setWeatherDuration(0); // Reset weather duration (legacy behaviour) this.setClearWeatherDuration(0); // Reset clear weather duration (reset "/weather clear" commands) -@@ -1406,7 +1411,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1431,7 +1436,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setWeatherDuration(int duration) { @@ -1607,7 +1123,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 this.world.serverLevelData.setRainTime(duration); } -@@ -1417,7 +1422,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1442,7 +1447,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setThundering(boolean thundering) { @@ -1616,7 +1132,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 this.world.serverLevelData.setThundering(thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause.PLUGIN); // Paper - Add cause to Weather/ThunderChangeEvents this.setThunderDuration(0); // Reset weather duration (legacy behaviour) this.setClearWeatherDuration(0); // Reset clear weather duration (reset "/weather clear" commands) -@@ -1430,7 +1435,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1455,7 +1460,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setThunderDuration(int duration) { @@ -1625,7 +1141,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 this.world.serverLevelData.setThunderTime(duration); } -@@ -1441,7 +1446,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1466,7 +1471,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setClearWeatherDuration(int duration) { @@ -1634,7 +1150,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 this.world.serverLevelData.setClearWeatherTime(duration); } -@@ -1636,7 +1641,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1661,7 +1666,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setKeepSpawnInMemory(boolean keepLoaded) { @@ -1643,7 +1159,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 if (keepLoaded) { this.setGameRule(GameRule.SPAWN_CHUNK_RADIUS, this.getGameRuleDefault(GameRule.SPAWN_CHUNK_RADIUS)); } else { -@@ -1705,7 +1710,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1730,7 +1735,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setHardcore(boolean hardcore) { @@ -1652,7 +1168,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 this.world.serverLevelData.settings.hardcore = hardcore; } -@@ -1718,7 +1723,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1743,7 +1748,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setTicksPerAnimalSpawns(int ticksPerAnimalSpawns) { @@ -1661,7 +1177,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 this.setTicksPerSpawns(SpawnCategory.ANIMAL, ticksPerAnimalSpawns); } -@@ -1731,7 +1736,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1756,7 +1761,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setTicksPerMonsterSpawns(int ticksPerMonsterSpawns) { @@ -1670,7 +1186,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 this.setTicksPerSpawns(SpawnCategory.MONSTER, ticksPerMonsterSpawns); } -@@ -1744,7 +1749,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1769,7 +1774,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setTicksPerWaterSpawns(int ticksPerWaterSpawns) { @@ -1679,7 +1195,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 this.setTicksPerSpawns(SpawnCategory.WATER_ANIMAL, ticksPerWaterSpawns); } -@@ -1757,7 +1762,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1782,7 +1787,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setTicksPerWaterAmbientSpawns(int ticksPerWaterAmbientSpawns) { @@ -1688,7 +1204,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 this.setTicksPerSpawns(SpawnCategory.WATER_AMBIENT, ticksPerWaterAmbientSpawns); } -@@ -1770,7 +1775,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1795,7 +1800,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setTicksPerWaterUndergroundCreatureSpawns(int ticksPerWaterUndergroundCreatureSpawns) { @@ -1697,7 +1213,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 this.setTicksPerSpawns(SpawnCategory.WATER_UNDERGROUND_CREATURE, ticksPerWaterUndergroundCreatureSpawns); } -@@ -1783,13 +1788,13 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1808,13 +1813,13 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setTicksPerAmbientSpawns(int ticksPerAmbientSpawns) { @@ -1713,7 +1229,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 Preconditions.checkArgument(spawnCategory != null, "SpawnCategory cannot be null"); Preconditions.checkArgument(CraftSpawnCategory.isValidForLimits(spawnCategory), "SpawnCategory.%s are not supported", spawnCategory); -@@ -1806,25 +1811,25 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1831,25 +1836,25 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setMetadata(String metadataKey, MetadataValue newMetadataValue) { @@ -1743,7 +1259,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 this.server.getWorldMetadata().removeMetadata(this, metadataKey, owningPlugin); } -@@ -1837,7 +1842,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1862,7 +1867,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setMonsterSpawnLimit(int limit) { @@ -1752,7 +1268,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 this.setSpawnLimit(SpawnCategory.MONSTER, limit); } -@@ -1850,7 +1855,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1875,7 +1880,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setAnimalSpawnLimit(int limit) { @@ -1761,7 +1277,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 this.setSpawnLimit(SpawnCategory.ANIMAL, limit); } -@@ -1863,7 +1868,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1888,7 +1893,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setWaterAnimalSpawnLimit(int limit) { @@ -1770,7 +1286,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 this.setSpawnLimit(SpawnCategory.WATER_ANIMAL, limit); } -@@ -1876,7 +1881,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1901,7 +1906,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setWaterAmbientSpawnLimit(int limit) { @@ -1779,7 +1295,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 this.setSpawnLimit(SpawnCategory.WATER_AMBIENT, limit); } -@@ -1889,7 +1894,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1914,7 +1919,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setWaterUndergroundCreatureSpawnLimit(int limit) { @@ -1788,7 +1304,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 this.setSpawnLimit(SpawnCategory.WATER_UNDERGROUND_CREATURE, limit); } -@@ -1902,7 +1907,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1927,7 +1932,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override @Deprecated public void setAmbientSpawnLimit(int limit) { @@ -1797,7 +1313,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 this.setSpawnLimit(SpawnCategory.AMBIENT, limit); } -@@ -1925,7 +1930,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1950,7 +1955,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setSpawnLimit(SpawnCategory spawnCategory, int limit) { @@ -1806,7 +1322,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 Preconditions.checkArgument(spawnCategory != null, "SpawnCategory cannot be null"); Preconditions.checkArgument(CraftSpawnCategory.isValidForLimits(spawnCategory), "SpawnCategory.%s are not supported", spawnCategory); -@@ -2109,7 +2114,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -2134,7 +2139,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean setGameRuleValue(String rule, String value) { @@ -1815,7 +1331,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 // No null values allowed if (rule == null || value == null) return false; -@@ -2152,7 +2157,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -2177,7 +2182,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean setGameRule(GameRule rule, T newValue) { @@ -1825,7 +1341,7 @@ index 0e549bfbecc15befc129a0382e189ba8cdd74c87..8a09e2a1f31c14a0c0d4b7e0446006d6 Preconditions.checkArgument(newValue != null, "GameRule value cannot be null"); diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -index 9efe9fce59a0b4fe7315dc41d1e21615b97e5cf6..3a2f3320dfdfdaf8a18470eadd64707b586f4665 100644 +index 9efe9fce59a0b4fe7315dc41d1e21615b97e5cf6..772d79494bdfe81ef017b15524c150a5ed24a51e 100644 --- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java @@ -15,6 +15,7 @@ import net.minecraft.world.item.BoneMealItem; @@ -1836,20 +1352,11 @@ index 9efe9fce59a0b4fe7315dc41d1e21615b97e5cf6..3a2f3320dfdfdaf8a18470eadd64707b import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.Blocks; -@@ -598,7 +599,7 @@ public class CraftBlock implements Block { - ServerLevel world = this.getCraftWorld().getHandle(); - UseOnContext context = new UseOnContext(world, null, InteractionHand.MAIN_HAND, Items.BONE_MEAL.getDefaultInstance(), new BlockHitResult(Vec3.ZERO, direction, this.getPosition(), false)); - -- io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.getCurrentWorldData(); // Folia - region threading -+ io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.regionizedWorldDataAccessor.getAny(this.position); // Folia - region threading - // SPIGOT-6895: Call StructureGrowEvent and BlockFertilizeEvent - worldData.captureTreeGeneration = true; // Folia - region threading - InteractionResult result = BoneMealItem.applyBonemeal(context); diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index ae53333f8ebffea8874259495026484b003d1ad9..a40de83c307949a48bd0c001c0b9dfc2b5c64f44 100644 +index a3aca277422d623c6998bbbe5d9574cd1e10f544..f99f5c6a36e3bce0822830cb0bd8151c62b20ee8 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -1396,7 +1396,8 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -1397,7 +1397,8 @@ public class CraftPlayer extends CraftHumanEntity implements Player { public boolean teleport(Location location, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause, io.papermc.paper.entity.TeleportFlag... flags) { // Folia start - region threading if (true) { @@ -2059,10 +1566,10 @@ index ce8b91f00f925960ad17f381162a11294e8b511d..506a8edda4fbf710b36919806ceb39b7 return this.getEntryTeam(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName()); } diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 8248cd6c908c82b6b7a18df7410a9a4a46a91959..f09b522a3a28ee86b3988897f66a8b5491482a37 100644 +index 5a349c554000417cebb5c74fd719fad569b15b05..88d2d17dbdd43dda79b308f89432ed3dfc221e24 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -389,7 +389,7 @@ public final class CraftMagicNumbers implements UnsafeValues { +@@ -391,7 +391,7 @@ public final class CraftMagicNumbers implements UnsafeValues { // Folia start - block plugins not marked as supported if (!pdf.isFoliaSupported()) {