From 48f34f8c903823cd39ad8bc8a5714485b84e21de Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Fri, 20 Dec 2024 10:52:51 -0800 Subject: [PATCH] Port CB changes from Moonrise patch --- .../0021-Moonrise-optimisation-patches.patch | 155 +++++++++++++++++- .../io/papermc/paper/FeatureHooks.java.patch | 153 ++++++++++++++++- .../org/bukkit/craftbukkit/CraftChunk.java | 58 +------ .../org/bukkit/craftbukkit/CraftServer.java | 4 +- .../org/bukkit/craftbukkit/CraftWorld.java | 67 ++------ .../craftbukkit/entity/CraftPlayer.java | 6 +- .../generator/CustomChunkGenerator.java | 2 +- .../main/java/org/spigotmc/AsyncCatcher.java | 2 +- .../java/org/spigotmc/WatchdogThread.java | 2 +- 9 files changed, 337 insertions(+), 112 deletions(-) diff --git a/paper-server/patches/features/0021-Moonrise-optimisation-patches.patch b/paper-server/patches/features/0021-Moonrise-optimisation-patches.patch index 70f66817f7..fdbf5905fa 100644 --- a/paper-server/patches/features/0021-Moonrise-optimisation-patches.patch +++ b/paper-server/patches/features/0021-Moonrise-optimisation-patches.patch @@ -22768,7 +22768,7 @@ index 0000000000000000000000000000000000000000..689ce367164e79e0426eeecb81dbbc52 + private SaveUtil() {} +} diff --git a/io/papermc/paper/FeatureHooks.java b/io/papermc/paper/FeatureHooks.java -index d3aebc7f833764351c8e5fe1fad1aa2f8718ca37..046a6304ea7e9dd66cb9d4cb004a582f13018295 100644 +index e40b83502c74d7dcae05d9d0c865affeee186893..c4ddf4b6fee8086481581fab88a807f63e211b5c 100644 --- a/io/papermc/paper/FeatureHooks.java +++ b/io/papermc/paper/FeatureHooks.java @@ -1,6 +1,8 @@ @@ -22793,6 +22793,159 @@ index d3aebc7f833764351c8e5fe1fad1aa2f8718ca37..046a6304ea7e9dd66cb9d4cb004a582f } public static LevelChunkSection createSection(final Registry biomeRegistry, final Level level, final ChunkPos chunkPos, final int chunkSection) { +@@ -79,89 +84,30 @@ public final class FeatureHooks { + } + + public static boolean isSpiderCollidingWithWorldBorder(final Spider spider) { +- return true; // ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isCollidingWithBorder(spider.level().getWorldBorder(), spider.getBoundingBox().inflate(ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON)) ++ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isCollidingWithBorder(spider.level().getWorldBorder(), spider.getBoundingBox().inflate(ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON)); // Paper - rewrite collision system + } + + public static void dumpAllChunkLoadInfo(net.minecraft.server.MinecraftServer server, boolean isLongTimeout) { ++ ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler.dumpAllChunkLoadInfo(server, isLongTimeout); // Paper - rewrite chunk system + } + + private static void dumpEntity(final Entity entity) { + } + + public static org.bukkit.entity.Entity[] getChunkEntities(net.minecraft.server.level.ServerLevel world, int chunkX, int chunkZ) { +- world.getChunk(chunkX, chunkZ); // ensure full loaded +- +- net.minecraft.world.level.entity.PersistentEntitySectionManager entityManager = world.entityManager; +- long pair = ChunkPos.asLong(chunkX, chunkZ); +- +- if (entityManager.areEntitiesLoaded(pair)) { +- return entityManager.getEntities(new ChunkPos(chunkX, chunkZ)).stream() +- .map(net.minecraft.world.entity.Entity::getBukkitEntity) +- .filter(java.util.Objects::nonNull).toArray(org.bukkit.entity.Entity[]::new); +- } +- +- entityManager.ensureChunkQueuedForLoad(pair); // Start entity loading +- +- // SPIGOT-6772: Use entity mailbox and re-schedule entities if they get unloaded +- net.minecraft.util.thread.ConsecutiveExecutor mailbox = ((net.minecraft.world.level.chunk.storage.EntityStorage) entityManager.permanentStorage).entityDeserializerQueue; +- java.util.function.BooleanSupplier supplier = () -> { +- // only execute inbox if our entities are not present +- if (entityManager.areEntitiesLoaded(pair)) { +- return true; +- } +- +- if (!entityManager.isPending(pair)) { +- // Our entities got unloaded, this should normally not happen. +- entityManager.ensureChunkQueuedForLoad(pair); // Re-start entity loading +- } +- +- // tick loading inbox, which loads the created entities to the world +- // (if present) +- entityManager.tick(); +- // check if our entities are loaded +- return entityManager.areEntitiesLoaded(pair); +- }; +- +- // now we wait until the entities are loaded, +- // the converting from NBT to entity object is done on the main Thread which is why we wait +- while (!supplier.getAsBoolean()) { +- if (mailbox.size() != 0) { +- mailbox.run(); +- } else { +- Thread.yield(); +- java.util.concurrent.locks.LockSupport.parkNanos("waiting for entity loading", 100000L); +- } +- } +- +- return entityManager.getEntities(new ChunkPos(chunkX, chunkZ)).stream() +- .map(net.minecraft.world.entity.Entity::getBukkitEntity) +- .filter(java.util.Objects::nonNull).toArray(org.bukkit.entity.Entity[]::new); ++ return world.getChunkEntities(chunkX, chunkZ); // Paper - rewrite chunk system + } + + public static java.util.Collection getPluginChunkTickets(net.minecraft.server.level.ServerLevel world, + int x, int z) { +- net.minecraft.server.level.DistanceManager chunkDistanceManager = world.getChunkSource().chunkMap.distanceManager; +- net.minecraft.util.SortedArraySet> tickets = chunkDistanceManager.tickets.get(ChunkPos.asLong(x, z)); +- +- if (tickets == null) { +- return java.util.Collections.emptyList(); +- } +- +- com.google.common.collect.ImmutableList.Builder ret = com.google.common.collect.ImmutableList.builder(); +- for (net.minecraft.server.level.Ticket ticket : tickets) { +- if (ticket.getType() == net.minecraft.server.level.TicketType.PLUGIN_TICKET) { +- ret.add((org.bukkit.plugin.Plugin) ticket.key); +- } +- } +- +- return ret.build(); ++ return world.moonrise$getChunkTaskScheduler().chunkHolderManager.getPluginChunkTickets(x, z); // Paper - rewrite chunk system + } + + public static Map> getPluginChunkTickets(net.minecraft.server.level.ServerLevel world) { + Map> ret = new HashMap<>(); + net.minecraft.server.level.DistanceManager chunkDistanceManager = world.getChunkSource().chunkMap.distanceManager; + +- for (it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry>> chunkTickets : chunkDistanceManager.tickets.long2ObjectEntrySet()) { ++ for (it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry>> chunkTickets : chunkDistanceManager.moonrise$getChunkHolderManager().getTicketsCopy().long2ObjectEntrySet()) { // Paper - rewrite chunk system + long chunkKey = chunkTickets.getLongKey(); + net.minecraft.util.SortedArraySet> tickets = chunkTickets.getValue(); + +@@ -183,15 +129,15 @@ public final class FeatureHooks { + } + + public static int getViewDistance(net.minecraft.server.level.ServerLevel world) { +- return world.getChunkSource().chunkMap.serverViewDistance; ++ return world.moonrise$getPlayerChunkLoader().getAPIViewDistance(); // Paper - rewrite chunk system + } + + public static int getSimulationDistance(net.minecraft.server.level.ServerLevel world) { +- return world.getChunkSource().chunkMap.getDistanceManager().simulationDistance; ++ return world.moonrise$getPlayerChunkLoader().getAPITickDistance(); // Paper - rewrite chunk system + } + + public static int getSendViewDistance(net.minecraft.server.level.ServerLevel world) { +- return getViewDistance(world); ++ return world.moonrise$getPlayerChunkLoader().getAPISendViewDistance(); // Paper - rewrite chunk system + } + + public static void setViewDistance(net.minecraft.server.level.ServerLevel world, int distance) { +@@ -209,31 +155,31 @@ public final class FeatureHooks { + } + + public static void setSendViewDistance(net.minecraft.server.level.ServerLevel world, int distance) { +- throw new UnsupportedOperationException("Not implemented yet"); ++ world.chunkSource.setSendViewDistance(distance); // Paper - rewrite chunk system + } + + public static void tickEntityManager(net.minecraft.server.level.ServerLevel world) { +- world.entityManager.tick(); ++ // Paper - rewrite chunk system + } + + public static void closeEntityManager(net.minecraft.server.level.ServerLevel world, boolean save) { +- world.entityManager.close(save); ++ // Paper - rewrite chunk system + } + + public static java.util.concurrent.Executor getWorldgenExecutor() { +- return net.minecraft.Util.backgroundExecutor(); ++ return Runnable::run; // Paper - rewrite chunk system + } + + public static void setViewDistance(ServerPlayer player, int distance) { +- throw new UnsupportedOperationException("Not implemented yet"); ++ ((ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer)player).moonrise$getViewDistanceHolder().setLoadViewDistance(distance == -1 ? distance : distance + 1); // Paper - rewrite chunk system + } + + public static void setSimulationDistance(ServerPlayer player, int distance) { +- throw new UnsupportedOperationException("Not implemented yet"); ++ ((ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer)player).moonrise$getViewDistanceHolder().setTickViewDistance(distance); // Paper - rewrite chunk system + } + + public static void setSendViewDistance(ServerPlayer player, int distance) { +- throw new UnsupportedOperationException("Not implemented yet"); ++ ((ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer)player).moonrise$getViewDistanceHolder().setSendViewDistance(distance); // Paper - rewrite chunk system + } + + } diff --git a/io/papermc/paper/command/subcommands/ChunkDebugCommand.java b/io/papermc/paper/command/subcommands/ChunkDebugCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..2dca7afbd93cfbb8686f336fcd3b45dd01fba0fc diff --git a/paper-server/patches/sources/io/papermc/paper/FeatureHooks.java.patch b/paper-server/patches/sources/io/papermc/paper/FeatureHooks.java.patch index 5c3b4d6856..f9337524bb 100644 --- a/paper-server/patches/sources/io/papermc/paper/FeatureHooks.java.patch +++ b/paper-server/patches/sources/io/papermc/paper/FeatureHooks.java.patch @@ -1,6 +1,6 @@ --- /dev/null +++ b/io/papermc/paper/FeatureHooks.java -@@ -1,0 +_,84 @@ +@@ -1,0 +_,233 @@ +package io.papermc.paper; + +import io.papermc.paper.command.PaperSubcommand; @@ -79,9 +79,158 @@ + return true; // ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isCollidingWithBorder(spider.level().getWorldBorder(), spider.getBoundingBox().inflate(ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON)) + } + -+ public static void dumpTickingInfo() { ++ public static void dumpAllChunkLoadInfo(net.minecraft.server.MinecraftServer server, boolean isLongTimeout) { + } + + private static void dumpEntity(final Entity entity) { + } ++ ++ public static org.bukkit.entity.Entity[] getChunkEntities(net.minecraft.server.level.ServerLevel world, int chunkX, int chunkZ) { ++ world.getChunk(chunkX, chunkZ); // ensure full loaded ++ ++ net.minecraft.world.level.entity.PersistentEntitySectionManager entityManager = world.entityManager; ++ long pair = ChunkPos.asLong(chunkX, chunkZ); ++ ++ if (entityManager.areEntitiesLoaded(pair)) { ++ return entityManager.getEntities(new ChunkPos(chunkX, chunkZ)).stream() ++ .map(net.minecraft.world.entity.Entity::getBukkitEntity) ++ .filter(java.util.Objects::nonNull).toArray(org.bukkit.entity.Entity[]::new); ++ } ++ ++ entityManager.ensureChunkQueuedForLoad(pair); // Start entity loading ++ ++ // SPIGOT-6772: Use entity mailbox and re-schedule entities if they get unloaded ++ net.minecraft.util.thread.ConsecutiveExecutor mailbox = ((net.minecraft.world.level.chunk.storage.EntityStorage) entityManager.permanentStorage).entityDeserializerQueue; ++ java.util.function.BooleanSupplier supplier = () -> { ++ // only execute inbox if our entities are not present ++ if (entityManager.areEntitiesLoaded(pair)) { ++ return true; ++ } ++ ++ if (!entityManager.isPending(pair)) { ++ // Our entities got unloaded, this should normally not happen. ++ entityManager.ensureChunkQueuedForLoad(pair); // Re-start entity loading ++ } ++ ++ // tick loading inbox, which loads the created entities to the world ++ // (if present) ++ entityManager.tick(); ++ // check if our entities are loaded ++ return entityManager.areEntitiesLoaded(pair); ++ }; ++ ++ // now we wait until the entities are loaded, ++ // the converting from NBT to entity object is done on the main Thread which is why we wait ++ while (!supplier.getAsBoolean()) { ++ if (mailbox.size() != 0) { ++ mailbox.run(); ++ } else { ++ Thread.yield(); ++ java.util.concurrent.locks.LockSupport.parkNanos("waiting for entity loading", 100000L); ++ } ++ } ++ ++ return entityManager.getEntities(new ChunkPos(chunkX, chunkZ)).stream() ++ .map(net.minecraft.world.entity.Entity::getBukkitEntity) ++ .filter(java.util.Objects::nonNull).toArray(org.bukkit.entity.Entity[]::new); ++ } ++ ++ public static java.util.Collection getPluginChunkTickets(net.minecraft.server.level.ServerLevel world, ++ int x, int z) { ++ net.minecraft.server.level.DistanceManager chunkDistanceManager = world.getChunkSource().chunkMap.distanceManager; ++ net.minecraft.util.SortedArraySet> tickets = chunkDistanceManager.tickets.get(ChunkPos.asLong(x, z)); ++ ++ if (tickets == null) { ++ return java.util.Collections.emptyList(); ++ } ++ ++ com.google.common.collect.ImmutableList.Builder ret = com.google.common.collect.ImmutableList.builder(); ++ for (net.minecraft.server.level.Ticket ticket : tickets) { ++ if (ticket.getType() == net.minecraft.server.level.TicketType.PLUGIN_TICKET) { ++ ret.add((org.bukkit.plugin.Plugin) ticket.key); ++ } ++ } ++ ++ return ret.build(); ++ } ++ ++ public static Map> getPluginChunkTickets(net.minecraft.server.level.ServerLevel world) { ++ Map> ret = new HashMap<>(); ++ net.minecraft.server.level.DistanceManager chunkDistanceManager = world.getChunkSource().chunkMap.distanceManager; ++ ++ for (it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry>> chunkTickets : chunkDistanceManager.tickets.long2ObjectEntrySet()) { ++ long chunkKey = chunkTickets.getLongKey(); ++ net.minecraft.util.SortedArraySet> tickets = chunkTickets.getValue(); ++ ++ org.bukkit.Chunk chunk = null; ++ for (net.minecraft.server.level.Ticket ticket : tickets) { ++ if (ticket.getType() != net.minecraft.server.level.TicketType.PLUGIN_TICKET) { ++ continue; ++ } ++ ++ if (chunk == null) { ++ chunk = world.getWorld().getChunkAt(ChunkPos.getX(chunkKey), ChunkPos.getZ(chunkKey)); ++ } ++ ++ ret.computeIfAbsent((org.bukkit.plugin.Plugin) ticket.key, (key) -> com.google.common.collect.ImmutableList.builder()).add(chunk); ++ } ++ } ++ ++ return ret.entrySet().stream().collect(com.google.common.collect.ImmutableMap.toImmutableMap(Map.Entry::getKey, (entry) -> entry.getValue().build())); ++ } ++ ++ public static int getViewDistance(net.minecraft.server.level.ServerLevel world) { ++ return world.getChunkSource().chunkMap.serverViewDistance; ++ } ++ ++ public static int getSimulationDistance(net.minecraft.server.level.ServerLevel world) { ++ return world.getChunkSource().chunkMap.getDistanceManager().simulationDistance; ++ } ++ ++ public static int getSendViewDistance(net.minecraft.server.level.ServerLevel world) { ++ return getViewDistance(world); ++ } ++ ++ public static void setViewDistance(net.minecraft.server.level.ServerLevel world, int distance) { ++ if (distance < 2 || distance > 32) { ++ throw new IllegalArgumentException("View distance " + distance + " is out of range of [2, 32]"); ++ } ++ world.chunkSource.chunkMap.setServerViewDistance(distance); ++ } ++ ++ public static void setSimulationDistance(net.minecraft.server.level.ServerLevel world, int distance) { ++ if (distance < 2 || distance > 32) { ++ throw new IllegalArgumentException("Simulation distance " + distance + " is out of range of [2, 32]"); ++ } ++ world.chunkSource.chunkMap.distanceManager.updateSimulationDistance(distance); ++ } ++ ++ public static void setSendViewDistance(net.minecraft.server.level.ServerLevel world, int distance) { ++ throw new UnsupportedOperationException("Not implemented yet"); ++ } ++ ++ public static void tickEntityManager(net.minecraft.server.level.ServerLevel world) { ++ world.entityManager.tick(); ++ } ++ ++ public static void closeEntityManager(net.minecraft.server.level.ServerLevel world, boolean save) { ++ world.entityManager.close(save); ++ } ++ ++ public static java.util.concurrent.Executor getWorldgenExecutor() { ++ return net.minecraft.Util.backgroundExecutor(); ++ } ++ ++ public static void setViewDistance(ServerPlayer player, int distance) { ++ throw new UnsupportedOperationException("Not implemented yet"); ++ } ++ ++ public static void setSimulationDistance(ServerPlayer player, int distance) { ++ throw new UnsupportedOperationException("Not implemented yet"); ++ } ++ ++ public static void setSendViewDistance(ServerPlayer player, int distance) { ++ throw new UnsupportedOperationException("Not implemented yet"); ++ } ++ +} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunk.java index f3ab07e44e..de8b9048c8 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunk.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftChunk.java @@ -83,6 +83,12 @@ public class CraftChunk implements Chunk { } public ChunkAccess getHandle(ChunkStatus chunkStatus) { + // Paper start - chunk system + net.minecraft.world.level.chunk.LevelChunk full = this.worldServer.getChunkIfLoaded(this.x, this.z); + if (full != null) { + return full; + } + // Paper end - chunk system ChunkAccess chunkAccess = this.worldServer.getChunk(this.x, this.z, chunkStatus); // SPIGOT-7332: Get unwrapped extension @@ -117,60 +123,12 @@ public class CraftChunk implements Chunk { @Override public boolean isEntitiesLoaded() { - return this.getCraftWorld().getHandle().entityManager.areEntitiesLoaded(ChunkPos.asLong(this.x, this.z)); + return this.getCraftWorld().getHandle().areEntitiesLoaded(ChunkPos.asLong(this.x, this.z)); // Paper - chunk system } @Override public Entity[] getEntities() { - if (!this.isLoaded()) { - this.getWorld().getChunkAt(this.x, this.z); // Transient load for this tick - } - - PersistentEntitySectionManager entityManager = this.getCraftWorld().getHandle().entityManager; - long pair = ChunkPos.asLong(this.x, this.z); - - if (entityManager.areEntitiesLoaded(pair)) { - return entityManager.getEntities(new ChunkPos(this.x, this.z)).stream() - .map(net.minecraft.world.entity.Entity::getBukkitEntity) - .filter(Objects::nonNull).toArray(Entity[]::new); - } - - entityManager.ensureChunkQueuedForLoad(pair); // Start entity loading - - // SPIGOT-6772: Use entity mailbox and re-schedule entities if they get unloaded - ConsecutiveExecutor mailbox = ((EntityStorage) entityManager.permanentStorage).entityDeserializerQueue; - BooleanSupplier supplier = () -> { - // only execute inbox if our entities are not present - if (entityManager.areEntitiesLoaded(pair)) { - return true; - } - - if (!entityManager.isPending(pair)) { - // Our entities got unloaded, this should normally not happen. - entityManager.ensureChunkQueuedForLoad(pair); // Re-start entity loading - } - - // tick loading inbox, which loads the created entities to the world - // (if present) - entityManager.tick(); - // check if our entities are loaded - return entityManager.areEntitiesLoaded(pair); - }; - - // now we wait until the entities are loaded, - // the converting from NBT to entity object is done on the main Thread which is why we wait - while (!supplier.getAsBoolean()) { - if (mailbox.size() != 0) { - mailbox.run(); - } else { - Thread.yield(); - LockSupport.parkNanos("waiting for entity loading", 100000L); - } - } - - return entityManager.getEntities(new ChunkPos(this.x, this.z)).stream() - .map(net.minecraft.world.entity.Entity::getBukkitEntity) - .filter(Objects::nonNull).toArray(Entity[]::new); + return FeatureHooks.getChunkEntities(this.worldServer, this.x, this.z); // Paper - chunk system } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java index d3ad9f5097..104caaf260 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -1448,7 +1448,7 @@ public final class CraftServer implements Server { // Paper - Put world into worldlist before initing the world; move up this.getServer().prepareLevels(internal.getChunkSource().chunkMap.progressListener, internal); - internal.entityManager.tick(); // SPIGOT-6526: Load pending entities so they are available to the API + io.papermc.paper.FeatureHooks.tickEntityManager(internal); // SPIGOT-6526: Load pending entities so they are available to the API // Paper - chunk system this.pluginManager.callEvent(new WorldLoadEvent(internal.getWorld())); return internal.getWorld(); @@ -1493,7 +1493,7 @@ public final class CraftServer implements Server { } handle.getChunkSource().close(save); - handle.entityManager.close(save); // SPIGOT-6722: close entityManager + io.papermc.paper.FeatureHooks.closeEntityManager(handle, save); // SPIGOT-6722: close entityManager // Paper - chunk system handle.levelStorageAccess.close(); } catch (Exception ex) { this.getLogger().log(Level.SEVERE, null, ex); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 9649f41a95..7ebe1d8090 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -502,14 +502,17 @@ public class CraftWorld extends CraftRegionAccessor implements World { ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.getVisibleChunkIfPresent(ChunkPos.asLong(x, z)); if (playerChunk == null) return false; - playerChunk.getTickingChunkFuture().thenAccept(either -> { - either.ifSuccess(chunk -> { + // Paper start - chunk system + net.minecraft.world.level.chunk.LevelChunk chunk = playerChunk.getChunkToSend(); + if (chunk == null) { + return false; + } + // Paper end - chunk system List playersInRange = playerChunk.playerProvider.getPlayers(playerChunk.getPos(), false); - if (playersInRange.isEmpty()) return; + if (playersInRange.isEmpty()) return true; // Paper - chunk system FeatureHooks.sendChunkRefreshPackets(playersInRange, chunk); - }); - }); + // Paper - chunk system return true; } @@ -611,47 +614,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public Collection getPluginChunkTickets(int x, int z) { - DistanceManager chunkDistanceManager = this.world.getChunkSource().chunkMap.distanceManager; - SortedArraySet> tickets = chunkDistanceManager.tickets.get(ChunkPos.asLong(x, z)); - - if (tickets == null) { - return Collections.emptyList(); - } - - ImmutableList.Builder ret = ImmutableList.builder(); - for (Ticket ticket : tickets) { - if (ticket.getType() == TicketType.PLUGIN_TICKET) { - ret.add((Plugin) ticket.key); - } - } - - return ret.build(); + return FeatureHooks.getPluginChunkTickets(this.world, x, z); // Paper - chunk system } @Override public Map> getPluginChunkTickets() { - Map> ret = new HashMap<>(); - DistanceManager chunkDistanceManager = this.world.getChunkSource().chunkMap.distanceManager; - - for (Long2ObjectMap.Entry>> chunkTickets : chunkDistanceManager.tickets.long2ObjectEntrySet()) { - long chunkKey = chunkTickets.getLongKey(); - SortedArraySet> tickets = chunkTickets.getValue(); - - Chunk chunk = null; - for (Ticket ticket : tickets) { - if (ticket.getType() != TicketType.PLUGIN_TICKET) { - continue; - } - - if (chunk == null) { - chunk = this.getChunkAt(ChunkPos.getX(chunkKey), ChunkPos.getZ(chunkKey)); - } - - ret.computeIfAbsent((Plugin) ticket.key, (key) -> ImmutableList.builder()).add(chunk); - } - } - - return ret.entrySet().stream().collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, (entry) -> entry.getValue().build())); + return FeatureHooks.getPluginChunkTickets(this.world); // Paper - chunk system } @NotNull @@ -1336,12 +1304,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public int getViewDistance() { - return this.world.getChunkSource().chunkMap.serverViewDistance; + return FeatureHooks.getViewDistance(this.world); // Paper - chunk system } @Override public int getSimulationDistance() { - return this.world.getChunkSource().chunkMap.getDistanceManager().simulationDistance; + return FeatureHooks.getSimulationDistance(this.world); // Paper - chunk system } public BlockMetadataStore getBlockMetadata() { @@ -2472,25 +2440,22 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setViewDistance(final int viewDistance) { - if (viewDistance < 2 || viewDistance > 32) { - throw new IllegalArgumentException("View distance " + viewDistance + " is out of range of [2, 32]"); - } - this.getHandle().chunkSource.chunkMap.setServerViewDistance(viewDistance); + FeatureHooks.setViewDistance(this.world, viewDistance); // Paper - chunk system } @Override public void setSimulationDistance(final int simulationDistance) { - throw new UnsupportedOperationException("Not implemented yet"); + FeatureHooks.setSimulationDistance(this.world, simulationDistance); // Paper - chunk system } @Override public int getSendViewDistance() { - return this.getViewDistance(); + return FeatureHooks.getSendViewDistance(this.world); // Paper - chunk system } @Override public void setSendViewDistance(final int viewDistance) { - throw new UnsupportedOperationException("Not implemented yet"); + FeatureHooks.setSendViewDistance(this.world, viewDistance); // Paper - chunk system } // Paper start - implement pointers diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index 039e17ad5d..18100c2c7c 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -3527,7 +3527,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @Override public void setViewDistance(final int viewDistance) { - throw new UnsupportedOperationException("Not implemented yet"); + FeatureHooks.setViewDistance(this.getHandle(), viewDistance); // Paper - chunk system } @Override @@ -3537,7 +3537,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @Override public void setSimulationDistance(final int simulationDistance) { - throw new UnsupportedOperationException("Not implemented yet"); + FeatureHooks.setSimulationDistance(this.getHandle(), simulationDistance); // Paper - chunk system } @Override @@ -3547,7 +3547,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @Override public void setSendViewDistance(final int viewDistance) { - throw new UnsupportedOperationException("Not implemented yet"); + FeatureHooks.setSendViewDistance(this.getHandle(), viewDistance); // Paper - chunk system } // Paper start - entity effect API diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java b/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java index 39377ba073..6bf553bd44 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java @@ -264,7 +264,7 @@ public class CustomChunkGenerator extends InternalChunkGenerator { return ichunkaccess1; }; - return future == null ? CompletableFuture.supplyAsync(() -> function.apply(chunk), net.minecraft.Util.backgroundExecutor()) : future.thenApply(function); + return future == null ? CompletableFuture.supplyAsync(() -> function.apply(chunk), io.papermc.paper.FeatureHooks.getWorldgenExecutor()) : future.thenApply(function); // Paper - chunk system } @Override diff --git a/paper-server/src/main/java/org/spigotmc/AsyncCatcher.java b/paper-server/src/main/java/org/spigotmc/AsyncCatcher.java index 86fba4d18a..50f01faa88 100644 --- a/paper-server/src/main/java/org/spigotmc/AsyncCatcher.java +++ b/paper-server/src/main/java/org/spigotmc/AsyncCatcher.java @@ -7,7 +7,7 @@ public class AsyncCatcher { public static boolean enabled = true; public static void catchOp(String reason) { - if (AsyncCatcher.enabled && Thread.currentThread() != MinecraftServer.getServer().serverThread) { + if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThread()) { // Paper - chunk system MinecraftServer.LOGGER.error("Thread {} failed main thread check: {}", Thread.currentThread().getName(), reason, new Throwable()); // Paper throw new IllegalStateException("Asynchronous " + reason + "!"); } diff --git a/paper-server/src/main/java/org/spigotmc/WatchdogThread.java b/paper-server/src/main/java/org/spigotmc/WatchdogThread.java index 0c67e3297e..a9339f59f8 100644 --- a/paper-server/src/main/java/org/spigotmc/WatchdogThread.java +++ b/paper-server/src/main/java/org/spigotmc/WatchdogThread.java @@ -110,7 +110,7 @@ public class WatchdogThread extends Thread { // Paper end - Different message for short timeout logger.log(Level.SEVERE, "------------------------------"); logger.log(Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):"); // Paper - FeatureHooks.dumpTickingInfo(); // Paper - log detailed tick information + FeatureHooks.dumpAllChunkLoadInfo(MinecraftServer.getServer(), isLongTimeout); // Paper - log detailed tick information WatchdogThread.dumpThread(ManagementFactory.getThreadMXBean().getThreadInfo(MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE), logger); logger.log(Level.SEVERE, "------------------------------");