diff --git a/patches/server/0008-MC-Utils.patch b/patches/server/0008-MC-Utils.patch index de1b60d84..3f7ecbecd 100644 --- a/patches/server/0008-MC-Utils.patch +++ b/patches/server/0008-MC-Utils.patch @@ -989,7 +989,7 @@ index 0000000000000000000000000000000000000000..190c5f0b02a3d99054704ae1afbffb34 +} diff --git a/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java b/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java new file mode 100644 -index 0000000000000000000000000000000000000000..c89f6986eda5a132a948732ea1b6923370685317 +index 0000000000000000000000000000000000000000..41b9405d6759d865e0d14dd4f95163e9690e967d --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java @@ -0,0 +1,453 @@ @@ -1000,7 +1000,7 @@ index 0000000000000000000000000000000000000000..c89f6986eda5a132a948732ea1b69233 +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.ChunkPos; +import javax.annotation.Nullable; @@ -1448,7 +1448,7 @@ index 0000000000000000000000000000000000000000..c89f6986eda5a132a948732ea1b69233 +} diff --git a/src/main/java/com/destroystokyo/paper/util/misc/DistanceTrackingAreaMap.java b/src/main/java/com/destroystokyo/paper/util/misc/DistanceTrackingAreaMap.java new file mode 100644 -index 0000000000000000000000000000000000000000..eacec5074ab1237986635c6cb19a4d34a89d4d3f +index 0000000000000000000000000000000000000000..896c3ff7ddb07f1f6f05f90e1e3fe7fb615071d4 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/util/misc/DistanceTrackingAreaMap.java @@ -0,0 +1,175 @@ @@ -1456,7 +1456,7 @@ index 0000000000000000000000000000000000000000..eacec5074ab1237986635c6cb19a4d34 + +import io.papermc.paper.util.IntegerUtil; +import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; +import net.minecraft.world.level.ChunkPos; + +/** @author Spottedleaf */ @@ -1990,13 +1990,13 @@ index 0000000000000000000000000000000000000000..e51104e65a07b6ea7bbbcbb6afb066ef +} diff --git a/src/main/java/com/destroystokyo/paper/util/pooled/PooledObjects.java b/src/main/java/com/destroystokyo/paper/util/pooled/PooledObjects.java new file mode 100644 -index 0000000000000000000000000000000000000000..d0c77068e9a53d1b8bbad0f3f6b420d6bc85f8c8 +index 0000000000000000000000000000000000000000..a743703502cea333bd4231b6557de50e8eaf81eb --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/util/pooled/PooledObjects.java @@ -0,0 +1,85 @@ +package com.destroystokyo.paper.util.pooled; + -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; +import org.apache.commons.lang3.mutable.MutableInt; + +import java.util.ArrayDeque; @@ -2172,7 +2172,7 @@ index 46cab7a8c7b87ab01b26074b04f5a02b3907cfc4..49019b4a9bc4e634d54a9b0acaf9229a } diff --git a/src/main/java/io/papermc/paper/chunk/SingleThreadChunkRegionManager.java b/src/main/java/io/papermc/paper/chunk/SingleThreadChunkRegionManager.java new file mode 100644 -index 0000000000000000000000000000000000000000..0b71cf7a462d25c3e4f910e09a37270ce9bc7776 +index 0000000000000000000000000000000000000000..a5f706d6f716b2a463ae58adcde69d9e665c7733 --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/SingleThreadChunkRegionManager.java @@ -0,0 +1,477 @@ @@ -2182,7 +2182,7 @@ index 0000000000000000000000000000000000000000..0b71cf7a462d25c3e4f910e09a37270c +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet; +import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import java.util.ArrayList; @@ -2653,6 +2653,306 @@ index 0000000000000000000000000000000000000000..0b71cf7a462d25c3e4f910e09a37270c + + } +} +diff --git a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8a5e93961dac4d87c81c0e70b6f4124a1f1d2556 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java +@@ -0,0 +1,294 @@ ++package io.papermc.paper.chunk.system; ++ ++import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; ++import com.destroystokyo.paper.util.SneakyThrow; ++import com.mojang.datafixers.util.Either; ++import com.mojang.logging.LogUtils; ++import io.papermc.paper.util.CoordinateUtils; ++import net.minecraft.server.level.ChunkHolder; ++import net.minecraft.server.level.ChunkMap; ++import net.minecraft.server.level.ServerLevel; ++import net.minecraft.server.level.ServerPlayer; ++import net.minecraft.server.level.TicketType; ++import net.minecraft.world.entity.Entity; ++import net.minecraft.world.level.ChunkPos; ++import net.minecraft.world.level.chunk.ChunkAccess; ++import net.minecraft.world.level.chunk.ChunkStatus; ++import net.minecraft.world.level.chunk.LevelChunk; ++import org.bukkit.Bukkit; ++import org.slf4j.Logger; ++import java.util.ArrayList; ++import java.util.List; ++import java.util.concurrent.CompletableFuture; ++import java.util.function.Consumer; ++ ++public final class ChunkSystem { ++ ++ private static final Logger LOGGER = LogUtils.getLogger(); ++ ++ public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run) { ++ scheduleChunkTask(level, chunkX, chunkZ, run, PrioritisedExecutor.Priority.NORMAL); ++ } ++ ++ public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final PrioritisedExecutor.Priority priority) { ++ level.chunkSource.mainThreadProcessor.execute(run); ++ } ++ ++ public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final boolean gen, ++ final ChunkStatus toStatus, final boolean addTicket, final PrioritisedExecutor.Priority priority, ++ final Consumer onComplete) { ++ if (gen) { ++ scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); ++ return; ++ } ++ scheduleChunkLoad(level, chunkX, chunkZ, ChunkStatus.EMPTY, addTicket, priority, (final ChunkAccess chunk) -> { ++ if (chunk == null) { ++ onComplete.accept(null); ++ } else { ++ if (chunk.getStatus().isOrAfter(toStatus)) { ++ scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); ++ } else { ++ onComplete.accept(null); ++ } ++ } ++ }); ++ } ++ ++ static final TicketType CHUNK_LOAD = TicketType.create("chunk_load", Long::compareTo); ++ ++ private static long chunkLoadCounter = 0L; ++ public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus, ++ final boolean addTicket, final PrioritisedExecutor.Priority priority, final Consumer onComplete) { ++ if (!Bukkit.isPrimaryThread()) { ++ scheduleChunkTask(level, chunkX, chunkZ, () -> { ++ scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); ++ }, priority); ++ return; ++ } ++ ++ final int minLevel = 33 + ChunkStatus.getDistance(toStatus); ++ final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; ++ final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); ++ ++ if (addTicket) { ++ level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); ++ } ++ level.chunkSource.runDistanceManagerUpdates(); ++ ++ final Consumer loadCallback = (final ChunkAccess chunk) -> { ++ try { ++ if (onComplete != null) { ++ onComplete.accept(chunk); ++ } ++ } catch (final ThreadDeath death) { ++ throw death; ++ } catch (final Throwable thr) { ++ LOGGER.error("Exception handling chunk load callback", thr); ++ SneakyThrow.sneaky(thr); ++ } finally { ++ if (addTicket) { ++ level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); ++ level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); ++ } ++ } ++ }; ++ ++ final ChunkHolder holder = level.chunkSource.chunkMap.getUpdatingChunkIfPresent(CoordinateUtils.getChunkKey(chunkX, chunkZ)); ++ ++ if (holder == null || holder.getTicketLevel() > minLevel) { ++ loadCallback.accept(null); ++ return; ++ } ++ ++ final CompletableFuture> loadFuture = holder.getOrScheduleFuture(toStatus, level.chunkSource.chunkMap); ++ ++ if (loadFuture.isDone()) { ++ loadCallback.accept(loadFuture.join().left().orElse(null)); ++ return; ++ } ++ ++ loadFuture.whenCompleteAsync((final Either either, final Throwable thr) -> { ++ if (thr != null) { ++ loadCallback.accept(null); ++ return; ++ } ++ loadCallback.accept(either.left().orElse(null)); ++ }, (final Runnable r) -> { ++ scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); ++ }); ++ } ++ ++ public static void scheduleTickingState(final ServerLevel level, final int chunkX, final int chunkZ, ++ final ChunkHolder.FullChunkStatus toStatus, final boolean addTicket, ++ final PrioritisedExecutor.Priority priority, final Consumer onComplete) { ++ if (toStatus == ChunkHolder.FullChunkStatus.INACCESSIBLE) { ++ throw new IllegalArgumentException("Cannot wait for INACCESSIBLE status"); ++ } ++ ++ if (!Bukkit.isPrimaryThread()) { ++ scheduleChunkTask(level, chunkX, chunkZ, () -> { ++ scheduleTickingState(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); ++ }, priority); ++ return; ++ } ++ ++ final int minLevel = 33 - (toStatus.ordinal() - 1); ++ final int radius = toStatus.ordinal() - 1; ++ final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; ++ final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); ++ ++ if (addTicket) { ++ level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); ++ } ++ level.chunkSource.runDistanceManagerUpdates(); ++ ++ final Consumer loadCallback = (final LevelChunk chunk) -> { ++ try { ++ if (onComplete != null) { ++ onComplete.accept(chunk); ++ } ++ } catch (final ThreadDeath death) { ++ throw death; ++ } catch (final Throwable thr) { ++ LOGGER.error("Exception handling chunk load callback", thr); ++ SneakyThrow.sneaky(thr); ++ } finally { ++ if (addTicket) { ++ level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); ++ level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); ++ } ++ } ++ }; ++ ++ final ChunkHolder holder = level.chunkSource.chunkMap.getUpdatingChunkIfPresent(CoordinateUtils.getChunkKey(chunkX, chunkZ)); ++ ++ if (holder == null || holder.getTicketLevel() > minLevel) { ++ loadCallback.accept(null); ++ return; ++ } ++ ++ final CompletableFuture> tickingState; ++ switch (toStatus) { ++ case BORDER: { ++ tickingState = holder.getFullChunkFuture(); ++ break; ++ } ++ case TICKING: { ++ tickingState = holder.getTickingChunkFuture(); ++ break; ++ } ++ case ENTITY_TICKING: { ++ tickingState = holder.getEntityTickingChunkFuture(); ++ break; ++ } ++ default: { ++ throw new IllegalStateException("Cannot reach here"); ++ } ++ } ++ ++ if (tickingState.isDone()) { ++ loadCallback.accept(tickingState.join().left().orElse(null)); ++ return; ++ } ++ ++ tickingState.whenCompleteAsync((final Either either, final Throwable thr) -> { ++ if (thr != null) { ++ loadCallback.accept(null); ++ return; ++ } ++ loadCallback.accept(either.left().orElse(null)); ++ }, (final Runnable r) -> { ++ scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); ++ }); ++ } ++ ++ public static List getVisibleChunkHolders(final ServerLevel level) { ++ return new ArrayList<>(level.chunkSource.chunkMap.visibleChunkMap.values()); ++ } ++ ++ public static List getUpdatingChunkHolders(final ServerLevel level) { ++ return new ArrayList<>(level.chunkSource.chunkMap.updatingChunkMap.values()); ++ } ++ ++ public static int getVisibleChunkHolderCount(final ServerLevel level) { ++ return level.chunkSource.chunkMap.visibleChunkMap.size(); ++ } ++ ++ public static int getUpdatingChunkHolderCount(final ServerLevel level) { ++ return level.chunkSource.chunkMap.updatingChunkMap.size(); ++ } ++ ++ public static boolean hasAnyChunkHolders(final ServerLevel level) { ++ return getUpdatingChunkHolderCount(level) != 0; ++ } ++ ++ public static void onEntityPreAdd(final ServerLevel level, final Entity entity) { ++ ++ } ++ ++ public static void onChunkHolderCreate(final ServerLevel level, final ChunkHolder holder) { ++ final ChunkMap chunkMap = level.chunkSource.chunkMap; ++ for (int index = 0, len = chunkMap.regionManagers.size(); index < len; ++index) { ++ chunkMap.regionManagers.get(index).addChunk(holder.pos.x, holder.pos.z); ++ } ++ } ++ ++ public static void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder) { ++ final ChunkMap chunkMap = level.chunkSource.chunkMap; ++ for (int index = 0, len = chunkMap.regionManagers.size(); index < len; ++index) { ++ chunkMap.regionManagers.get(index).removeChunk(holder.pos.x, holder.pos.z); ++ } ++ } ++ ++ public static void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) { ++ chunk.playerChunk = holder; ++ } ++ ++ public static void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder) { ++ ++ } ++ ++ public static void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder) { ++ chunk.level.getChunkSource().tickingChunks.add(chunk); ++ } ++ ++ public static void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) { ++ chunk.level.getChunkSource().tickingChunks.remove(chunk); ++ } ++ ++ public static void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { ++ chunk.level.getChunkSource().entityTickingChunks.add(chunk); ++ } ++ ++ public static void onChunkNotEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { ++ chunk.level.getChunkSource().entityTickingChunks.remove(chunk); ++ } ++ ++ public static ChunkHolder getUnloadingChunkHolder(final ServerLevel level, final int chunkX, final int chunkZ) { ++ return level.chunkSource.chunkMap.getUnloadingChunkHolder(chunkX, chunkZ); ++ } ++ ++ public static int getSendViewDistance(final ServerPlayer player) { ++ return getLoadViewDistance(player); ++ } ++ ++ public static int getLoadViewDistance(final ServerPlayer player) { ++ final ServerLevel level = player.getLevel(); ++ if (level == null) { ++ return Bukkit.getViewDistance() + 1; ++ } ++ return level.chunkSource.chunkMap.getEffectiveViewDistance() + 1; ++ } ++ ++ public static int getTickViewDistance(final ServerPlayer player) { ++ final ServerLevel level = player.getLevel(); ++ if (level == null) { ++ return Bukkit.getSimulationDistance(); ++ } ++ return level.chunkSource.chunkMap.distanceManager.getSimulationDistance(); ++ } ++ ++ private ChunkSystem() { ++ throw new RuntimeException(); ++ } ++} diff --git a/src/main/java/io/papermc/paper/util/CachedLists.java b/src/main/java/io/papermc/paper/util/CachedLists.java new file mode 100644 index 0000000000000000000000000000000000000000..be668387f65a633c6ac497fca632a4767a1bf3a2 @@ -3154,6 +3454,524 @@ index 0000000000000000000000000000000000000000..cea9c098ade00ee87b8efc8164ab72f5 + return this.sum; + } +} +diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9798a1010120125039cbf226a0e3679cc92f92c7 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/util/MCUtil.java +@@ -0,0 +1,512 @@ ++package io.papermc.paper.util; ++ ++import com.google.common.util.concurrent.ThreadFactoryBuilder; ++import it.unimi.dsi.fastutil.objects.ObjectRBTreeSet; ++import java.lang.ref.Cleaner; ++import net.minecraft.core.BlockPos; ++import net.minecraft.core.Direction; ++import net.minecraft.server.MinecraftServer; ++import net.minecraft.server.level.ServerLevel; ++import net.minecraft.world.entity.Entity; ++import net.minecraft.world.level.ChunkPos; ++import net.minecraft.world.level.ClipContext; ++import net.minecraft.world.level.Level; ++import org.apache.commons.lang.exception.ExceptionUtils; ++import org.bukkit.Location; ++import org.bukkit.block.BlockFace; ++import org.bukkit.craftbukkit.CraftWorld; ++import org.bukkit.craftbukkit.util.Waitable; ++import org.spigotmc.AsyncCatcher; ++ ++import javax.annotation.Nonnull; ++import javax.annotation.Nullable; ++import java.util.List; ++import java.util.Queue; ++import java.util.concurrent.CompletableFuture; ++import java.util.concurrent.ExecutionException; ++import java.util.concurrent.LinkedBlockingQueue; ++import java.util.concurrent.ThreadPoolExecutor; ++import java.util.concurrent.TimeUnit; ++import java.util.concurrent.TimeoutException; ++import java.util.concurrent.atomic.AtomicBoolean; ++import java.util.function.BiConsumer; ++import java.util.function.Consumer; ++import java.util.function.Supplier; ++ ++public final class MCUtil { ++ public static final ThreadPoolExecutor asyncExecutor = new ThreadPoolExecutor( ++ 0, 2, 60L, TimeUnit.SECONDS, ++ new LinkedBlockingQueue<>(), ++ new ThreadFactoryBuilder() ++ .setNameFormat("Paper Async Task Handler Thread - %1$d") ++ .setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(MinecraftServer.LOGGER)) ++ .build() ++ ); ++ public static final ThreadPoolExecutor cleanerExecutor = new ThreadPoolExecutor( ++ 1, 1, 0L, TimeUnit.SECONDS, ++ new LinkedBlockingQueue<>(), ++ new ThreadFactoryBuilder() ++ .setNameFormat("Paper Object Cleaner") ++ .setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(MinecraftServer.LOGGER)) ++ .build() ++ ); ++ ++ public static final long INVALID_CHUNK_KEY = getCoordinateKey(Integer.MAX_VALUE, Integer.MAX_VALUE); ++ ++ ++ public static Runnable once(Runnable run) { ++ AtomicBoolean ran = new AtomicBoolean(false); ++ return () -> { ++ if (ran.compareAndSet(false, true)) { ++ run.run(); ++ } ++ }; ++ } ++ ++ public static Runnable once(List list, Consumer cb) { ++ return once(() -> { ++ list.forEach(cb); ++ }); ++ } ++ ++ private static Runnable makeCleanerCallback(Runnable run) { ++ return once(() -> cleanerExecutor.execute(run)); ++ } ++ ++ /** ++ * DANGER WILL ROBINSON: Be sure you do not use a lambda that lives in the object being monitored, or leaky leaky! ++ * @param obj ++ * @param run ++ * @return ++ */ ++ public static Runnable registerCleaner(Object obj, Runnable run) { ++ // Wrap callback in its own method above or the lambda will leak object ++ Runnable cleaner = makeCleanerCallback(run); ++ CleanerHolder.CLEANER.register(obj, cleaner); ++ return cleaner; ++ } ++ ++ private static final class CleanerHolder { ++ private static final Cleaner CLEANER = Cleaner.create(); ++ } ++ ++ /** ++ * DANGER WILL ROBINSON: Be sure you do not use a lambda that lives in the object being monitored, or leaky leaky! ++ * @param obj ++ * @param list ++ * @param cleaner ++ * @param ++ * @return ++ */ ++ public static Runnable registerListCleaner(Object obj, List list, Consumer cleaner) { ++ return registerCleaner(obj, () -> { ++ list.forEach(cleaner); ++ list.clear(); ++ }); ++ } ++ ++ /** ++ * DANGER WILL ROBINSON: Be sure you do not use a lambda that lives in the object being monitored, or leaky leaky! ++ * @param obj ++ * @param resource ++ * @param cleaner ++ * @param ++ * @return ++ */ ++ public static Runnable registerCleaner(Object obj, T resource, java.util.function.Consumer cleaner) { ++ return registerCleaner(obj, () -> cleaner.accept(resource)); ++ } ++ ++ public static List getSpiralOutChunks(BlockPos blockposition, int radius) { ++ List list = com.google.common.collect.Lists.newArrayList(); ++ ++ list.add(new ChunkPos(blockposition.getX() >> 4, blockposition.getZ() >> 4)); ++ for (int r = 1; r <= radius; r++) { ++ int x = -r; ++ int z = r; ++ ++ // Iterates the edge of half of the box; then negates for other half. ++ while (x <= r && z > -r) { ++ list.add(new ChunkPos((blockposition.getX() + (x << 4)) >> 4, (blockposition.getZ() + (z << 4)) >> 4)); ++ list.add(new ChunkPos((blockposition.getX() - (x << 4)) >> 4, (blockposition.getZ() - (z << 4)) >> 4)); ++ ++ if (x < r) { ++ x++; ++ } else { ++ z--; ++ } ++ } ++ } ++ return list; ++ } ++ ++ public static int fastFloor(double x) { ++ int truncated = (int)x; ++ return x < (double)truncated ? truncated - 1 : truncated; ++ } ++ ++ public static int fastFloor(float x) { ++ int truncated = (int)x; ++ return x < (double)truncated ? truncated - 1 : truncated; ++ } ++ ++ public static float normalizeYaw(float f) { ++ float f1 = f % 360.0F; ++ ++ if (f1 >= 180.0F) { ++ f1 -= 360.0F; ++ } ++ ++ if (f1 < -180.0F) { ++ f1 += 360.0F; ++ } ++ ++ return f1; ++ } ++ ++ /** ++ * Quickly generate a stack trace for current location ++ * ++ * @return Stacktrace ++ */ ++ public static String stack() { ++ return ExceptionUtils.getFullStackTrace(new Throwable()); ++ } ++ ++ /** ++ * Quickly generate a stack trace for current location with message ++ * ++ * @param str ++ * @return Stacktrace ++ */ ++ public static String stack(String str) { ++ return ExceptionUtils.getFullStackTrace(new Throwable(str)); ++ } ++ ++ public static long getCoordinateKey(final BlockPos blockPos) { ++ return ((long)(blockPos.getZ() >> 4) << 32) | ((blockPos.getX() >> 4) & 0xFFFFFFFFL); ++ } ++ ++ public static long getCoordinateKey(final Entity entity) { ++ return ((long)(MCUtil.fastFloor(entity.getZ()) >> 4) << 32) | ((MCUtil.fastFloor(entity.getX()) >> 4) & 0xFFFFFFFFL); ++ } ++ ++ public static long getCoordinateKey(final ChunkPos pair) { ++ return ((long)pair.z << 32) | (pair.x & 0xFFFFFFFFL); ++ } ++ ++ public static long getCoordinateKey(final int x, final int z) { ++ return ((long)z << 32) | (x & 0xFFFFFFFFL); ++ } ++ ++ public static int getCoordinateX(final long key) { ++ return (int)key; ++ } ++ ++ public static int getCoordinateZ(final long key) { ++ return (int)(key >>> 32); ++ } ++ ++ public static int getChunkCoordinate(final double coordinate) { ++ return MCUtil.fastFloor(coordinate) >> 4; ++ } ++ ++ public static int getBlockCoordinate(final double coordinate) { ++ return MCUtil.fastFloor(coordinate); ++ } ++ ++ public static long getBlockKey(final int x, final int y, final int z) { ++ return ((long)x & 0x7FFFFFF) | (((long)z & 0x7FFFFFF) << 27) | ((long)y << 54); ++ } ++ ++ public static long getBlockKey(final BlockPos pos) { ++ return ((long)pos.getX() & 0x7FFFFFF) | (((long)pos.getZ() & 0x7FFFFFF) << 27) | ((long)pos.getY() << 54); ++ } ++ ++ public static long getBlockKey(final Entity entity) { ++ return getBlockKey(getBlockCoordinate(entity.getX()), getBlockCoordinate(entity.getY()), getBlockCoordinate(entity.getZ())); ++ } ++ ++ // assumes the sets have the same comparator, and if this comparator is null then assume T is Comparable ++ public static void mergeSortedSets(final java.util.function.Consumer consumer, final java.util.Comparator comparator, final java.util.SortedSet...sets) { ++ final ObjectRBTreeSet all = new ObjectRBTreeSet<>(comparator); ++ // note: this is done in log(n!) ~ nlogn time. It could be improved if it were to mimic what mergesort does. ++ for (java.util.SortedSet set : sets) { ++ if (set != null) { ++ all.addAll(set); ++ } ++ } ++ all.forEach(consumer); ++ } ++ ++ private MCUtil() {} ++ ++ public static final java.util.concurrent.Executor MAIN_EXECUTOR = (run) -> { ++ if (!isMainThread()) { ++ MinecraftServer.getServer().execute(run); ++ } else { ++ run.run(); ++ } ++ }; ++ ++ public static CompletableFuture ensureMain(CompletableFuture future) { ++ return future.thenApplyAsync(r -> r, MAIN_EXECUTOR); ++ } ++ ++ public static void thenOnMain(CompletableFuture future, Consumer consumer) { ++ future.thenAcceptAsync(consumer, MAIN_EXECUTOR); ++ } ++ public static void thenOnMain(CompletableFuture future, BiConsumer consumer) { ++ future.whenCompleteAsync(consumer, MAIN_EXECUTOR); ++ } ++ ++ public static boolean isMainThread() { ++ return MinecraftServer.getServer().isSameThread(); ++ } ++ ++ public static org.bukkit.scheduler.BukkitTask scheduleTask(int ticks, Runnable runnable) { ++ return scheduleTask(ticks, runnable, null); ++ } ++ ++ public static org.bukkit.scheduler.BukkitTask scheduleTask(int ticks, Runnable runnable, String taskName) { ++ return MinecraftServer.getServer().server.getScheduler().scheduleInternalTask(runnable, ticks, taskName); ++ } ++ ++ public static void processQueue() { ++ Runnable runnable; ++ Queue processQueue = getProcessQueue(); ++ while ((runnable = processQueue.poll()) != null) { ++ try { ++ runnable.run(); ++ } catch (Exception e) { ++ MinecraftServer.LOGGER.error("Error executing task", e); ++ } ++ } ++ } ++ public static T processQueueWhileWaiting(CompletableFuture future) { ++ try { ++ if (isMainThread()) { ++ while (!future.isDone()) { ++ try { ++ return future.get(1, TimeUnit.MILLISECONDS); ++ } catch (TimeoutException ignored) { ++ processQueue(); ++ } ++ } ++ } ++ return future.get(); ++ } catch (Exception e) { ++ throw new RuntimeException(e); ++ } ++ } ++ ++ public static void ensureMain(Runnable run) { ++ ensureMain(null, run); ++ } ++ /** ++ * Ensures the target code is running on the main thread ++ * @param reason ++ * @param run ++ * @return ++ */ ++ public static void ensureMain(String reason, Runnable run) { ++ if (!isMainThread()) { ++ if (reason != null) { ++ MinecraftServer.LOGGER.warn("Asynchronous " + reason + "!", new IllegalStateException()); ++ } ++ getProcessQueue().add(run); ++ return; ++ } ++ run.run(); ++ } ++ ++ private static Queue getProcessQueue() { ++ return MinecraftServer.getServer().processQueue; ++ } ++ ++ public static T ensureMain(Supplier run) { ++ return ensureMain(null, run); ++ } ++ /** ++ * Ensures the target code is running on the main thread ++ * @param reason ++ * @param run ++ * @param ++ * @return ++ */ ++ public static T ensureMain(String reason, Supplier run) { ++ if (!isMainThread()) { ++ if (reason != null) { ++ MinecraftServer.LOGGER.warn("Asynchronous " + reason + "! Blocking thread until it returns ", new IllegalStateException()); ++ } ++ Waitable wait = new Waitable() { ++ @Override ++ protected T evaluate() { ++ return run.get(); ++ } ++ }; ++ getProcessQueue().add(wait); ++ try { ++ return wait.get(); ++ } catch (InterruptedException | ExecutionException e) { ++ MinecraftServer.LOGGER.warn("Encountered exception", e); ++ } ++ return null; ++ } ++ return run.get(); ++ } ++ ++ /** ++ * Calculates distance between 2 entities ++ * @param e1 ++ * @param e2 ++ * @return ++ */ ++ public static double distance(Entity e1, Entity e2) { ++ return Math.sqrt(distanceSq(e1, e2)); ++ } ++ ++ ++ /** ++ * Calculates distance between 2 block positions ++ * @param e1 ++ * @param e2 ++ * @return ++ */ ++ public static double distance(BlockPos e1, BlockPos e2) { ++ return Math.sqrt(distanceSq(e1, e2)); ++ } ++ ++ /** ++ * Gets the distance between 2 positions ++ * @param x1 ++ * @param y1 ++ * @param z1 ++ * @param x2 ++ * @param y2 ++ * @param z2 ++ * @return ++ */ ++ public static double distance(double x1, double y1, double z1, double x2, double y2, double z2) { ++ return Math.sqrt(distanceSq(x1, y1, z1, x2, y2, z2)); ++ } ++ ++ /** ++ * Get's the distance squared between 2 entities ++ * @param e1 ++ * @param e2 ++ * @return ++ */ ++ public static double distanceSq(Entity e1, Entity e2) { ++ return distanceSq(e1.getX(),e1.getY(),e1.getZ(), e2.getX(),e2.getY(),e2.getZ()); ++ } ++ ++ /** ++ * Gets the distance sqaured between 2 block positions ++ * @param pos1 ++ * @param pos2 ++ * @return ++ */ ++ public static double distanceSq(BlockPos pos1, BlockPos pos2) { ++ return distanceSq(pos1.getX(), pos1.getY(), pos1.getZ(), pos2.getX(), pos2.getY(), pos2.getZ()); ++ } ++ ++ /** ++ * Gets the distance squared between 2 positions ++ * @param x1 ++ * @param y1 ++ * @param z1 ++ * @param x2 ++ * @param y2 ++ * @param z2 ++ * @return ++ */ ++ public static double distanceSq(double x1, double y1, double z1, double x2, double y2, double z2) { ++ return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2); ++ } ++ ++ /** ++ * Converts a NMS World/BlockPosition to Bukkit Location ++ * @param world ++ * @param x ++ * @param y ++ * @param z ++ * @return ++ */ ++ public static Location toLocation(Level world, double x, double y, double z) { ++ return new Location(world.getWorld(), x, y, z); ++ } ++ ++ /** ++ * Converts a NMS World/BlockPosition to Bukkit Location ++ * @param world ++ * @param pos ++ * @return ++ */ ++ public static Location toLocation(Level world, BlockPos pos) { ++ return new Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ()); ++ } ++ ++ /** ++ * Converts an NMS entity's current location to a Bukkit Location ++ * @param entity ++ * @return ++ */ ++ public static Location toLocation(Entity entity) { ++ return new Location(entity.getCommandSenderWorld().getWorld(), entity.getX(), entity.getY(), entity.getZ()); ++ } ++ ++ public static org.bukkit.block.Block toBukkitBlock(Level world, BlockPos pos) { ++ return world.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ()); ++ } ++ ++ public static BlockPos toBlockPosition(Location loc) { ++ return new BlockPos(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); ++ } ++ ++ public static boolean isEdgeOfChunk(BlockPos pos) { ++ final int modX = pos.getX() & 15; ++ final int modZ = pos.getZ() & 15; ++ return (modX == 0 || modX == 15 || modZ == 0 || modZ == 15); ++ } ++ ++ /** ++ * Posts a task to be executed asynchronously ++ * @param run ++ */ ++ public static void scheduleAsyncTask(Runnable run) { ++ asyncExecutor.execute(run); ++ } ++ ++ @Nonnull ++ public static ServerLevel getNMSWorld(@Nonnull org.bukkit.World world) { ++ return ((CraftWorld) world).getHandle(); ++ } ++ ++ public static ServerLevel getNMSWorld(@Nonnull org.bukkit.entity.Entity entity) { ++ return getNMSWorld(entity.getWorld()); ++ } ++ ++ public static BlockFace toBukkitBlockFace(Direction enumDirection) { ++ switch (enumDirection) { ++ case DOWN: ++ return BlockFace.DOWN; ++ case UP: ++ return BlockFace.UP; ++ case NORTH: ++ return BlockFace.NORTH; ++ case SOUTH: ++ return BlockFace.SOUTH; ++ case WEST: ++ return BlockFace.WEST; ++ case EAST: ++ return BlockFace.EAST; ++ default: ++ return null; ++ } ++ } ++ ++ public static int getTicketLevelFor(net.minecraft.world.level.chunk.ChunkStatus status) { ++ return net.minecraft.server.level.ChunkMap.MAX_VIEW_DISTANCE + net.minecraft.world.level.chunk.ChunkStatus.getDistance(status); ++ } ++} diff --git a/src/main/java/io/papermc/paper/util/StackWalkerUtil.java b/src/main/java/io/papermc/paper/util/StackWalkerUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..f7114d5b8f2f93f62883e24da29afaf9f74ee1a6 @@ -3881,7 +4699,7 @@ index 0000000000000000000000000000000000000000..470402573bc31106d5a63e415b958fb7 +} diff --git a/src/main/java/io/papermc/paper/util/misc/Delayed8WayDistancePropagator2D.java b/src/main/java/io/papermc/paper/util/misc/Delayed8WayDistancePropagator2D.java new file mode 100644 -index 0000000000000000000000000000000000000000..4d3dc8fba51bf5c0dceb06744781d1df2bbf2df6 +index 0000000000000000000000000000000000000000..808d1449ac44ae86a650932365081fbaf178d141 --- /dev/null +++ b/src/main/java/io/papermc/paper/util/misc/Delayed8WayDistancePropagator2D.java @@ -0,0 +1,718 @@ @@ -3893,7 +4711,7 @@ index 0000000000000000000000000000000000000000..4d3dc8fba51bf5c0dceb06744781d1df +import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue; +import it.unimi.dsi.fastutil.longs.LongIterator; +import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; + +public final class Delayed8WayDistancePropagator2D { + @@ -4673,825 +5491,8 @@ index 207f1c1fc9d4451d27047bb8362bded8cd53e32f..021a26a6b1c258deffc26c035ab52a4e if (packet.isSkippable()) { throw new SkipPacketException(var10); } else { -diff --git a/src/main/java/net/minecraft/server/ChunkSystem.java b/src/main/java/net/minecraft/server/ChunkSystem.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c59fca05484c30b28e883f5b5dde0362f294b517 ---- /dev/null -+++ b/src/main/java/net/minecraft/server/ChunkSystem.java -@@ -0,0 +1,294 @@ -+package net.minecraft.server; -+ -+import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; -+import com.destroystokyo.paper.util.SneakyThrow; -+import com.mojang.datafixers.util.Either; -+import com.mojang.logging.LogUtils; -+import io.papermc.paper.util.CoordinateUtils; -+import net.minecraft.server.level.ChunkHolder; -+import net.minecraft.server.level.ChunkMap; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.server.level.TicketType; -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.level.ChunkPos; -+import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.ChunkStatus; -+import net.minecraft.world.level.chunk.LevelChunk; -+import org.bukkit.Bukkit; -+import org.slf4j.Logger; -+import java.util.ArrayList; -+import java.util.List; -+import java.util.concurrent.CompletableFuture; -+import java.util.function.Consumer; -+ -+public final class ChunkSystem { -+ -+ private static final Logger LOGGER = LogUtils.getLogger(); -+ -+ public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run) { -+ scheduleChunkTask(level, chunkX, chunkZ, run, PrioritisedExecutor.Priority.NORMAL); -+ } -+ -+ public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final PrioritisedExecutor.Priority priority) { -+ level.chunkSource.mainThreadProcessor.execute(run); -+ } -+ -+ public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final boolean gen, -+ final ChunkStatus toStatus, final boolean addTicket, final PrioritisedExecutor.Priority priority, -+ final Consumer onComplete) { -+ if (gen) { -+ scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); -+ return; -+ } -+ scheduleChunkLoad(level, chunkX, chunkZ, ChunkStatus.EMPTY, addTicket, priority, (final ChunkAccess chunk) -> { -+ if (chunk == null) { -+ onComplete.accept(null); -+ } else { -+ if (chunk.getStatus().isOrAfter(toStatus)) { -+ scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); -+ } else { -+ onComplete.accept(null); -+ } -+ } -+ }); -+ } -+ -+ static final TicketType CHUNK_LOAD = TicketType.create("chunk_load", Long::compareTo); -+ -+ private static long chunkLoadCounter = 0L; -+ public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus, -+ final boolean addTicket, final PrioritisedExecutor.Priority priority, final Consumer onComplete) { -+ if (!Bukkit.isPrimaryThread()) { -+ scheduleChunkTask(level, chunkX, chunkZ, () -> { -+ scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); -+ }, priority); -+ return; -+ } -+ -+ final int minLevel = 33 + ChunkStatus.getDistance(toStatus); -+ final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; -+ final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); -+ -+ if (addTicket) { -+ level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); -+ } -+ level.chunkSource.runDistanceManagerUpdates(); -+ -+ final Consumer loadCallback = (final ChunkAccess chunk) -> { -+ try { -+ if (onComplete != null) { -+ onComplete.accept(chunk); -+ } -+ } catch (final ThreadDeath death) { -+ throw death; -+ } catch (final Throwable thr) { -+ LOGGER.error("Exception handling chunk load callback", thr); -+ SneakyThrow.sneaky(thr); -+ } finally { -+ if (addTicket) { -+ level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); -+ level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); -+ } -+ } -+ }; -+ -+ final ChunkHolder holder = level.chunkSource.chunkMap.getUpdatingChunkIfPresent(CoordinateUtils.getChunkKey(chunkX, chunkZ)); -+ -+ if (holder == null || holder.getTicketLevel() > minLevel) { -+ loadCallback.accept(null); -+ return; -+ } -+ -+ final CompletableFuture> loadFuture = holder.getOrScheduleFuture(toStatus, level.chunkSource.chunkMap); -+ -+ if (loadFuture.isDone()) { -+ loadCallback.accept(loadFuture.join().left().orElse(null)); -+ return; -+ } -+ -+ loadFuture.whenCompleteAsync((final Either either, final Throwable thr) -> { -+ if (thr != null) { -+ loadCallback.accept(null); -+ return; -+ } -+ loadCallback.accept(either.left().orElse(null)); -+ }, (final Runnable r) -> { -+ scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); -+ }); -+ } -+ -+ public static void scheduleTickingState(final ServerLevel level, final int chunkX, final int chunkZ, -+ final ChunkHolder.FullChunkStatus toStatus, final boolean addTicket, -+ final PrioritisedExecutor.Priority priority, final Consumer onComplete) { -+ if (toStatus == ChunkHolder.FullChunkStatus.INACCESSIBLE) { -+ throw new IllegalArgumentException("Cannot wait for INACCESSIBLE status"); -+ } -+ -+ if (!Bukkit.isPrimaryThread()) { -+ scheduleChunkTask(level, chunkX, chunkZ, () -> { -+ scheduleTickingState(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); -+ }, priority); -+ return; -+ } -+ -+ final int minLevel = 33 - (toStatus.ordinal() - 1); -+ final int radius = toStatus.ordinal() - 1; -+ final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; -+ final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); -+ -+ if (addTicket) { -+ level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); -+ } -+ level.chunkSource.runDistanceManagerUpdates(); -+ -+ final Consumer loadCallback = (final LevelChunk chunk) -> { -+ try { -+ if (onComplete != null) { -+ onComplete.accept(chunk); -+ } -+ } catch (final ThreadDeath death) { -+ throw death; -+ } catch (final Throwable thr) { -+ LOGGER.error("Exception handling chunk load callback", thr); -+ SneakyThrow.sneaky(thr); -+ } finally { -+ if (addTicket) { -+ level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); -+ level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); -+ } -+ } -+ }; -+ -+ final ChunkHolder holder = level.chunkSource.chunkMap.getUpdatingChunkIfPresent(CoordinateUtils.getChunkKey(chunkX, chunkZ)); -+ -+ if (holder == null || holder.getTicketLevel() > minLevel) { -+ loadCallback.accept(null); -+ return; -+ } -+ -+ final CompletableFuture> tickingState; -+ switch (toStatus) { -+ case BORDER: { -+ tickingState = holder.getFullChunkFuture(); -+ break; -+ } -+ case TICKING: { -+ tickingState = holder.getTickingChunkFuture(); -+ break; -+ } -+ case ENTITY_TICKING: { -+ tickingState = holder.getEntityTickingChunkFuture(); -+ break; -+ } -+ default: { -+ throw new IllegalStateException("Cannot reach here"); -+ } -+ } -+ -+ if (tickingState.isDone()) { -+ loadCallback.accept(tickingState.join().left().orElse(null)); -+ return; -+ } -+ -+ tickingState.whenCompleteAsync((final Either either, final Throwable thr) -> { -+ if (thr != null) { -+ loadCallback.accept(null); -+ return; -+ } -+ loadCallback.accept(either.left().orElse(null)); -+ }, (final Runnable r) -> { -+ scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); -+ }); -+ } -+ -+ public static List getVisibleChunkHolders(final ServerLevel level) { -+ return new ArrayList<>(level.chunkSource.chunkMap.visibleChunkMap.values()); -+ } -+ -+ public static List getUpdatingChunkHolders(final ServerLevel level) { -+ return new ArrayList<>(level.chunkSource.chunkMap.updatingChunkMap.values()); -+ } -+ -+ public static int getVisibleChunkHolderCount(final ServerLevel level) { -+ return level.chunkSource.chunkMap.visibleChunkMap.size(); -+ } -+ -+ public static int getUpdatingChunkHolderCount(final ServerLevel level) { -+ return level.chunkSource.chunkMap.updatingChunkMap.size(); -+ } -+ -+ public static boolean hasAnyChunkHolders(final ServerLevel level) { -+ return getUpdatingChunkHolderCount(level) != 0; -+ } -+ -+ public static void onEntityPreAdd(final ServerLevel level, final Entity entity) { -+ -+ } -+ -+ public static void onChunkHolderCreate(final ServerLevel level, final ChunkHolder holder) { -+ final ChunkMap chunkMap = level.chunkSource.chunkMap; -+ for (int index = 0, len = chunkMap.regionManagers.size(); index < len; ++index) { -+ chunkMap.regionManagers.get(index).addChunk(holder.pos.x, holder.pos.z); -+ } -+ } -+ -+ public static void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder) { -+ final ChunkMap chunkMap = level.chunkSource.chunkMap; -+ for (int index = 0, len = chunkMap.regionManagers.size(); index < len; ++index) { -+ chunkMap.regionManagers.get(index).removeChunk(holder.pos.x, holder.pos.z); -+ } -+ } -+ -+ public static void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) { -+ chunk.playerChunk = holder; -+ } -+ -+ public static void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder) { -+ -+ } -+ -+ public static void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder) { -+ chunk.level.getChunkSource().tickingChunks.add(chunk); -+ } -+ -+ public static void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) { -+ chunk.level.getChunkSource().tickingChunks.remove(chunk); -+ } -+ -+ public static void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { -+ chunk.level.getChunkSource().entityTickingChunks.add(chunk); -+ } -+ -+ public static void onChunkNotEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { -+ chunk.level.getChunkSource().entityTickingChunks.remove(chunk); -+ } -+ -+ public static ChunkHolder getUnloadingChunkHolder(final ServerLevel level, final int chunkX, final int chunkZ) { -+ return level.chunkSource.chunkMap.getUnloadingChunkHolder(chunkX, chunkZ); -+ } -+ -+ public static int getSendViewDistance(final ServerPlayer player) { -+ return getLoadViewDistance(player); -+ } -+ -+ public static int getLoadViewDistance(final ServerPlayer player) { -+ final ServerLevel level = player.getLevel(); -+ if (level == null) { -+ return Bukkit.getViewDistance() + 1; -+ } -+ return level.chunkSource.chunkMap.getEffectiveViewDistance() + 1; -+ } -+ -+ public static int getTickViewDistance(final ServerPlayer player) { -+ final ServerLevel level = player.getLevel(); -+ if (level == null) { -+ return Bukkit.getSimulationDistance(); -+ } -+ return level.chunkSource.chunkMap.distanceManager.getSimulationDistance(); -+ } -+ -+ private ChunkSystem() { -+ throw new RuntimeException(); -+ } -+} -diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9db975e84609956b2206076e30f17a350adb77d6 ---- /dev/null -+++ b/src/main/java/net/minecraft/server/MCUtil.java -@@ -0,0 +1,511 @@ -+package net.minecraft.server; -+ -+import com.google.common.util.concurrent.ThreadFactoryBuilder; -+import it.unimi.dsi.fastutil.objects.ObjectRBTreeSet; -+import java.lang.ref.Cleaner; -+import net.minecraft.core.BlockPos; -+import net.minecraft.core.Direction; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.level.ChunkPos; -+import net.minecraft.world.level.ClipContext; -+import net.minecraft.world.level.Level; -+import org.apache.commons.lang.exception.ExceptionUtils; -+import org.bukkit.Location; -+import org.bukkit.block.BlockFace; -+import org.bukkit.craftbukkit.CraftWorld; -+import org.bukkit.craftbukkit.util.Waitable; -+import org.spigotmc.AsyncCatcher; -+ -+import javax.annotation.Nonnull; -+import javax.annotation.Nullable; -+import java.util.List; -+import java.util.Queue; -+import java.util.concurrent.CompletableFuture; -+import java.util.concurrent.ExecutionException; -+import java.util.concurrent.LinkedBlockingQueue; -+import java.util.concurrent.ThreadPoolExecutor; -+import java.util.concurrent.TimeUnit; -+import java.util.concurrent.TimeoutException; -+import java.util.concurrent.atomic.AtomicBoolean; -+import java.util.function.BiConsumer; -+import java.util.function.Consumer; -+import java.util.function.Supplier; -+ -+public final class MCUtil { -+ public static final ThreadPoolExecutor asyncExecutor = new ThreadPoolExecutor( -+ 0, 2, 60L, TimeUnit.SECONDS, -+ new LinkedBlockingQueue<>(), -+ new ThreadFactoryBuilder() -+ .setNameFormat("Paper Async Task Handler Thread - %1$d") -+ .setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(MinecraftServer.LOGGER)) -+ .build() -+ ); -+ public static final ThreadPoolExecutor cleanerExecutor = new ThreadPoolExecutor( -+ 1, 1, 0L, TimeUnit.SECONDS, -+ new LinkedBlockingQueue<>(), -+ new ThreadFactoryBuilder() -+ .setNameFormat("Paper Object Cleaner") -+ .setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(MinecraftServer.LOGGER)) -+ .build() -+ ); -+ -+ public static final long INVALID_CHUNK_KEY = getCoordinateKey(Integer.MAX_VALUE, Integer.MAX_VALUE); -+ -+ -+ public static Runnable once(Runnable run) { -+ AtomicBoolean ran = new AtomicBoolean(false); -+ return () -> { -+ if (ran.compareAndSet(false, true)) { -+ run.run(); -+ } -+ }; -+ } -+ -+ public static Runnable once(List list, Consumer cb) { -+ return once(() -> { -+ list.forEach(cb); -+ }); -+ } -+ -+ private static Runnable makeCleanerCallback(Runnable run) { -+ return once(() -> cleanerExecutor.execute(run)); -+ } -+ -+ /** -+ * DANGER WILL ROBINSON: Be sure you do not use a lambda that lives in the object being monitored, or leaky leaky! -+ * @param obj -+ * @param run -+ * @return -+ */ -+ public static Runnable registerCleaner(Object obj, Runnable run) { -+ // Wrap callback in its own method above or the lambda will leak object -+ Runnable cleaner = makeCleanerCallback(run); -+ CleanerHolder.CLEANER.register(obj, cleaner); -+ return cleaner; -+ } -+ -+ private static final class CleanerHolder { -+ private static final Cleaner CLEANER = Cleaner.create(); -+ } -+ -+ /** -+ * DANGER WILL ROBINSON: Be sure you do not use a lambda that lives in the object being monitored, or leaky leaky! -+ * @param obj -+ * @param list -+ * @param cleaner -+ * @param -+ * @return -+ */ -+ public static Runnable registerListCleaner(Object obj, List list, Consumer cleaner) { -+ return registerCleaner(obj, () -> { -+ list.forEach(cleaner); -+ list.clear(); -+ }); -+ } -+ -+ /** -+ * DANGER WILL ROBINSON: Be sure you do not use a lambda that lives in the object being monitored, or leaky leaky! -+ * @param obj -+ * @param resource -+ * @param cleaner -+ * @param -+ * @return -+ */ -+ public static Runnable registerCleaner(Object obj, T resource, java.util.function.Consumer cleaner) { -+ return registerCleaner(obj, () -> cleaner.accept(resource)); -+ } -+ -+ public static List getSpiralOutChunks(BlockPos blockposition, int radius) { -+ List list = com.google.common.collect.Lists.newArrayList(); -+ -+ list.add(new ChunkPos(blockposition.getX() >> 4, blockposition.getZ() >> 4)); -+ for (int r = 1; r <= radius; r++) { -+ int x = -r; -+ int z = r; -+ -+ // Iterates the edge of half of the box; then negates for other half. -+ while (x <= r && z > -r) { -+ list.add(new ChunkPos((blockposition.getX() + (x << 4)) >> 4, (blockposition.getZ() + (z << 4)) >> 4)); -+ list.add(new ChunkPos((blockposition.getX() - (x << 4)) >> 4, (blockposition.getZ() - (z << 4)) >> 4)); -+ -+ if (x < r) { -+ x++; -+ } else { -+ z--; -+ } -+ } -+ } -+ return list; -+ } -+ -+ public static int fastFloor(double x) { -+ int truncated = (int)x; -+ return x < (double)truncated ? truncated - 1 : truncated; -+ } -+ -+ public static int fastFloor(float x) { -+ int truncated = (int)x; -+ return x < (double)truncated ? truncated - 1 : truncated; -+ } -+ -+ public static float normalizeYaw(float f) { -+ float f1 = f % 360.0F; -+ -+ if (f1 >= 180.0F) { -+ f1 -= 360.0F; -+ } -+ -+ if (f1 < -180.0F) { -+ f1 += 360.0F; -+ } -+ -+ return f1; -+ } -+ -+ /** -+ * Quickly generate a stack trace for current location -+ * -+ * @return Stacktrace -+ */ -+ public static String stack() { -+ return ExceptionUtils.getFullStackTrace(new Throwable()); -+ } -+ -+ /** -+ * Quickly generate a stack trace for current location with message -+ * -+ * @param str -+ * @return Stacktrace -+ */ -+ public static String stack(String str) { -+ return ExceptionUtils.getFullStackTrace(new Throwable(str)); -+ } -+ -+ public static long getCoordinateKey(final BlockPos blockPos) { -+ return ((long)(blockPos.getZ() >> 4) << 32) | ((blockPos.getX() >> 4) & 0xFFFFFFFFL); -+ } -+ -+ public static long getCoordinateKey(final Entity entity) { -+ return ((long)(MCUtil.fastFloor(entity.getZ()) >> 4) << 32) | ((MCUtil.fastFloor(entity.getX()) >> 4) & 0xFFFFFFFFL); -+ } -+ -+ public static long getCoordinateKey(final ChunkPos pair) { -+ return ((long)pair.z << 32) | (pair.x & 0xFFFFFFFFL); -+ } -+ -+ public static long getCoordinateKey(final int x, final int z) { -+ return ((long)z << 32) | (x & 0xFFFFFFFFL); -+ } -+ -+ public static int getCoordinateX(final long key) { -+ return (int)key; -+ } -+ -+ public static int getCoordinateZ(final long key) { -+ return (int)(key >>> 32); -+ } -+ -+ public static int getChunkCoordinate(final double coordinate) { -+ return MCUtil.fastFloor(coordinate) >> 4; -+ } -+ -+ public static int getBlockCoordinate(final double coordinate) { -+ return MCUtil.fastFloor(coordinate); -+ } -+ -+ public static long getBlockKey(final int x, final int y, final int z) { -+ return ((long)x & 0x7FFFFFF) | (((long)z & 0x7FFFFFF) << 27) | ((long)y << 54); -+ } -+ -+ public static long getBlockKey(final BlockPos pos) { -+ return ((long)pos.getX() & 0x7FFFFFF) | (((long)pos.getZ() & 0x7FFFFFF) << 27) | ((long)pos.getY() << 54); -+ } -+ -+ public static long getBlockKey(final Entity entity) { -+ return getBlockKey(getBlockCoordinate(entity.getX()), getBlockCoordinate(entity.getY()), getBlockCoordinate(entity.getZ())); -+ } -+ -+ // assumes the sets have the same comparator, and if this comparator is null then assume T is Comparable -+ public static void mergeSortedSets(final java.util.function.Consumer consumer, final java.util.Comparator comparator, final java.util.SortedSet...sets) { -+ final ObjectRBTreeSet all = new ObjectRBTreeSet<>(comparator); -+ // note: this is done in log(n!) ~ nlogn time. It could be improved if it were to mimic what mergesort does. -+ for (java.util.SortedSet set : sets) { -+ if (set != null) { -+ all.addAll(set); -+ } -+ } -+ all.forEach(consumer); -+ } -+ -+ private MCUtil() {} -+ -+ public static final java.util.concurrent.Executor MAIN_EXECUTOR = (run) -> { -+ if (!isMainThread()) { -+ MinecraftServer.getServer().execute(run); -+ } else { -+ run.run(); -+ } -+ }; -+ -+ public static CompletableFuture ensureMain(CompletableFuture future) { -+ return future.thenApplyAsync(r -> r, MAIN_EXECUTOR); -+ } -+ -+ public static void thenOnMain(CompletableFuture future, Consumer consumer) { -+ future.thenAcceptAsync(consumer, MAIN_EXECUTOR); -+ } -+ public static void thenOnMain(CompletableFuture future, BiConsumer consumer) { -+ future.whenCompleteAsync(consumer, MAIN_EXECUTOR); -+ } -+ -+ public static boolean isMainThread() { -+ return MinecraftServer.getServer().isSameThread(); -+ } -+ -+ public static org.bukkit.scheduler.BukkitTask scheduleTask(int ticks, Runnable runnable) { -+ return scheduleTask(ticks, runnable, null); -+ } -+ -+ public static org.bukkit.scheduler.BukkitTask scheduleTask(int ticks, Runnable runnable, String taskName) { -+ return MinecraftServer.getServer().server.getScheduler().scheduleInternalTask(runnable, ticks, taskName); -+ } -+ -+ public static void processQueue() { -+ Runnable runnable; -+ Queue processQueue = getProcessQueue(); -+ while ((runnable = processQueue.poll()) != null) { -+ try { -+ runnable.run(); -+ } catch (Exception e) { -+ MinecraftServer.LOGGER.error("Error executing task", e); -+ } -+ } -+ } -+ public static T processQueueWhileWaiting(CompletableFuture future) { -+ try { -+ if (isMainThread()) { -+ while (!future.isDone()) { -+ try { -+ return future.get(1, TimeUnit.MILLISECONDS); -+ } catch (TimeoutException ignored) { -+ processQueue(); -+ } -+ } -+ } -+ return future.get(); -+ } catch (Exception e) { -+ throw new RuntimeException(e); -+ } -+ } -+ -+ public static void ensureMain(Runnable run) { -+ ensureMain(null, run); -+ } -+ /** -+ * Ensures the target code is running on the main thread -+ * @param reason -+ * @param run -+ * @return -+ */ -+ public static void ensureMain(String reason, Runnable run) { -+ if (!isMainThread()) { -+ if (reason != null) { -+ MinecraftServer.LOGGER.warn("Asynchronous " + reason + "!", new IllegalStateException()); -+ } -+ getProcessQueue().add(run); -+ return; -+ } -+ run.run(); -+ } -+ -+ private static Queue getProcessQueue() { -+ return MinecraftServer.getServer().processQueue; -+ } -+ -+ public static T ensureMain(Supplier run) { -+ return ensureMain(null, run); -+ } -+ /** -+ * Ensures the target code is running on the main thread -+ * @param reason -+ * @param run -+ * @param -+ * @return -+ */ -+ public static T ensureMain(String reason, Supplier run) { -+ if (!isMainThread()) { -+ if (reason != null) { -+ MinecraftServer.LOGGER.warn("Asynchronous " + reason + "! Blocking thread until it returns ", new IllegalStateException()); -+ } -+ Waitable wait = new Waitable() { -+ @Override -+ protected T evaluate() { -+ return run.get(); -+ } -+ }; -+ getProcessQueue().add(wait); -+ try { -+ return wait.get(); -+ } catch (InterruptedException | ExecutionException e) { -+ MinecraftServer.LOGGER.warn("Encountered exception", e); -+ } -+ return null; -+ } -+ return run.get(); -+ } -+ -+ /** -+ * Calculates distance between 2 entities -+ * @param e1 -+ * @param e2 -+ * @return -+ */ -+ public static double distance(Entity e1, Entity e2) { -+ return Math.sqrt(distanceSq(e1, e2)); -+ } -+ -+ -+ /** -+ * Calculates distance between 2 block positions -+ * @param e1 -+ * @param e2 -+ * @return -+ */ -+ public static double distance(BlockPos e1, BlockPos e2) { -+ return Math.sqrt(distanceSq(e1, e2)); -+ } -+ -+ /** -+ * Gets the distance between 2 positions -+ * @param x1 -+ * @param y1 -+ * @param z1 -+ * @param x2 -+ * @param y2 -+ * @param z2 -+ * @return -+ */ -+ public static double distance(double x1, double y1, double z1, double x2, double y2, double z2) { -+ return Math.sqrt(distanceSq(x1, y1, z1, x2, y2, z2)); -+ } -+ -+ /** -+ * Get's the distance squared between 2 entities -+ * @param e1 -+ * @param e2 -+ * @return -+ */ -+ public static double distanceSq(Entity e1, Entity e2) { -+ return distanceSq(e1.getX(),e1.getY(),e1.getZ(), e2.getX(),e2.getY(),e2.getZ()); -+ } -+ -+ /** -+ * Gets the distance sqaured between 2 block positions -+ * @param pos1 -+ * @param pos2 -+ * @return -+ */ -+ public static double distanceSq(BlockPos pos1, BlockPos pos2) { -+ return distanceSq(pos1.getX(), pos1.getY(), pos1.getZ(), pos2.getX(), pos2.getY(), pos2.getZ()); -+ } -+ -+ /** -+ * Gets the distance squared between 2 positions -+ * @param x1 -+ * @param y1 -+ * @param z1 -+ * @param x2 -+ * @param y2 -+ * @param z2 -+ * @return -+ */ -+ public static double distanceSq(double x1, double y1, double z1, double x2, double y2, double z2) { -+ return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2); -+ } -+ -+ /** -+ * Converts a NMS World/BlockPosition to Bukkit Location -+ * @param world -+ * @param x -+ * @param y -+ * @param z -+ * @return -+ */ -+ public static Location toLocation(Level world, double x, double y, double z) { -+ return new Location(world.getWorld(), x, y, z); -+ } -+ -+ /** -+ * Converts a NMS World/BlockPosition to Bukkit Location -+ * @param world -+ * @param pos -+ * @return -+ */ -+ public static Location toLocation(Level world, BlockPos pos) { -+ return new Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ()); -+ } -+ -+ /** -+ * Converts an NMS entity's current location to a Bukkit Location -+ * @param entity -+ * @return -+ */ -+ public static Location toLocation(Entity entity) { -+ return new Location(entity.getCommandSenderWorld().getWorld(), entity.getX(), entity.getY(), entity.getZ()); -+ } -+ -+ public static org.bukkit.block.Block toBukkitBlock(Level world, BlockPos pos) { -+ return world.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ()); -+ } -+ -+ public static BlockPos toBlockPosition(Location loc) { -+ return new BlockPos(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); -+ } -+ -+ public static boolean isEdgeOfChunk(BlockPos pos) { -+ final int modX = pos.getX() & 15; -+ final int modZ = pos.getZ() & 15; -+ return (modX == 0 || modX == 15 || modZ == 0 || modZ == 15); -+ } -+ -+ /** -+ * Posts a task to be executed asynchronously -+ * @param run -+ */ -+ public static void scheduleAsyncTask(Runnable run) { -+ asyncExecutor.execute(run); -+ } -+ -+ @Nonnull -+ public static ServerLevel getNMSWorld(@Nonnull org.bukkit.World world) { -+ return ((CraftWorld) world).getHandle(); -+ } -+ -+ public static ServerLevel getNMSWorld(@Nonnull org.bukkit.entity.Entity entity) { -+ return getNMSWorld(entity.getWorld()); -+ } -+ -+ public static BlockFace toBukkitBlockFace(Direction enumDirection) { -+ switch (enumDirection) { -+ case DOWN: -+ return BlockFace.DOWN; -+ case UP: -+ return BlockFace.UP; -+ case NORTH: -+ return BlockFace.NORTH; -+ case SOUTH: -+ return BlockFace.SOUTH; -+ case WEST: -+ return BlockFace.WEST; -+ case EAST: -+ return BlockFace.EAST; -+ default: -+ return null; -+ } -+ } -+ -+ public static int getTicketLevelFor(net.minecraft.world.level.chunk.ChunkStatus status) { -+ return net.minecraft.server.level.ChunkMap.MAX_VIEW_DISTANCE + net.minecraft.world.level.chunk.ChunkStatus.getDistance(status); -+ } -+} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 80a3c56fb5e73c09c542b17aac952fb63081a662..805a1773d55e2551911e5b8e69052e23f630359b 100644 +index 80a3c56fb5e73c09c542b17aac952fb63081a662..d7ece1ae4e9c97935de96eafd6d22cded1f8aa42 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -282,6 +282,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { + // note: Here is a very good place to add callbacks to logic waiting on this. + ChunkHolder.this.isTickingReady = true; -+ net.minecraft.server.ChunkSystem.onChunkTicking(chunk, this); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkTicking(chunk, this); + }); + }); + // Paper end @@ -5732,7 +5733,7 @@ index f902b1f7062fc2c81e0ce43e8b8599192469e57c..0873134f1f6de0c372ba28b89a20302c - this.tickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); + // Paper start + if (this.isTickingReady) { -+ net.minecraft.server.ChunkSystem.onChunkNotTicking(this.tickingChunkFuture.join().left().get(), this); // Paper ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkNotTicking(this.tickingChunkFuture.join().left().get(), this); // Paper + } + // Paper end + this.tickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); this.isTickingReady = false; // Paper - cache chunk ticking stage @@ -5747,7 +5748,7 @@ index f902b1f7062fc2c81e0ce43e8b8599192469e57c..0873134f1f6de0c372ba28b89a20302c + this.entityTickingChunkFuture.thenAccept(either -> { + either.ifLeft(chunk -> { + ChunkHolder.this.isEntityTickingReady = true; -+ net.minecraft.server.ChunkSystem.onChunkEntityTicking(chunk, this); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkEntityTicking(chunk, this); + }); + }); + // Paper end @@ -5758,7 +5759,7 @@ index f902b1f7062fc2c81e0ce43e8b8599192469e57c..0873134f1f6de0c372ba28b89a20302c - this.entityTickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); + // Paper start + if (this.isEntityTickingReady) { -+ net.minecraft.server.ChunkSystem.onChunkNotEntityTicking(this.entityTickingChunkFuture.join().left().get(), this); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkNotEntityTicking(this.entityTickingChunkFuture.join().left().get(), this); + } + // Paper end + this.entityTickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); this.isEntityTickingReady = false; // Paper - cache chunk ticking stage @@ -5785,14 +5786,14 @@ index f902b1f7062fc2c81e0ce43e8b8599192469e57c..0873134f1f6de0c372ba28b89a20302c + // Paper end } diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 91a9b9ff0d7821a2261e7137fb1b3989ba096b88..1fbe1b6de925f71763f79fe3d2371b70a8650f25 100644 +index 91a9b9ff0d7821a2261e7137fb1b3989ba096b88..5095519f9bd009a4d5af49d5b42c5795114411a2 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -63,6 +63,7 @@ import net.minecraft.network.protocol.game.ClientboundSetChunkCacheCenterPacket; import net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket; import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket; import net.minecraft.network.protocol.game.DebugPackets; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.server.network.ServerPlayerConnection; import net.minecraft.util.CsvOutput; @@ -5884,10 +5885,10 @@ index 91a9b9ff0d7821a2261e7137fb1b3989ba096b88..1fbe1b6de925f71763f79fe3d2371b70 stringbuilder.append("Updating:").append(System.lineSeparator()); - this.updatingChunkMap.values().forEach(consumer); -+ net.minecraft.server.ChunkSystem.getUpdatingChunkHolders(this.level).forEach(consumer); // Paper ++ io.papermc.paper.chunk.system.ChunkSystem.getUpdatingChunkHolders(this.level).forEach(consumer); // Paper stringbuilder.append("Visible:").append(System.lineSeparator()); - this.visibleChunkMap.values().forEach(consumer); -+ net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).forEach(consumer); // Paper ++ io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).forEach(consumer); // Paper CrashReport crashreport = CrashReport.forThrowable(exception, "Chunk loading"); CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Chunk loading"); @@ -5896,7 +5897,7 @@ index 91a9b9ff0d7821a2261e7137fb1b3989ba096b88..1fbe1b6de925f71763f79fe3d2371b70 } else { holder = new ChunkHolder(new ChunkPos(pos), level, this.level, this.lightEngine, this.queueSorter, this); + // Paper start -+ net.minecraft.server.ChunkSystem.onChunkHolderCreate(this.level, holder); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkHolderCreate(this.level, holder); + // Paper end } @@ -5911,7 +5912,7 @@ index 91a9b9ff0d7821a2261e7137fb1b3989ba096b88..1fbe1b6de925f71763f79fe3d2371b70 protected void saveAllChunks(boolean flush) { if (flush) { - List list = (List) this.visibleChunkMap.values().stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); -+ List list = (List) net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); // Paper ++ List list = (List) io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); // Paper MutableBoolean mutableboolean = new MutableBoolean(); do { @@ -5920,7 +5921,7 @@ index 91a9b9ff0d7821a2261e7137fb1b3989ba096b88..1fbe1b6de925f71763f79fe3d2371b70 this.flushWorker(); } else { - this.visibleChunkMap.values().forEach(this::saveChunkIfNeeded); -+ net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).forEach(this::saveChunkIfNeeded); ++ io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).forEach(this::saveChunkIfNeeded); } } @@ -5929,7 +5930,7 @@ index 91a9b9ff0d7821a2261e7137fb1b3989ba096b88..1fbe1b6de925f71763f79fe3d2371b70 public boolean hasWork() { - return this.lightEngine.hasLightWork() || !this.pendingUnloads.isEmpty() || !this.updatingChunkMap.isEmpty() || this.poiManager.hasWork() || !this.toDrop.isEmpty() || !this.unloadQueue.isEmpty() || this.queueSorter.hasWork() || this.distanceManager.hasTickets(); -+ return this.lightEngine.hasLightWork() || !this.pendingUnloads.isEmpty() || net.minecraft.server.ChunkSystem.hasAnyChunkHolders(this.level) || this.poiManager.hasWork() || !this.toDrop.isEmpty() || !this.unloadQueue.isEmpty() || this.queueSorter.hasWork() || this.distanceManager.hasTickets(); // Paper ++ return this.lightEngine.hasLightWork() || !this.pendingUnloads.isEmpty() || io.papermc.paper.chunk.system.ChunkSystem.hasAnyChunkHolders(this.level) || this.poiManager.hasWork() || !this.toDrop.isEmpty() || !this.unloadQueue.isEmpty() || this.queueSorter.hasWork() || this.distanceManager.hasTickets(); // Paper } private void processUnloads(BooleanSupplier shouldKeepTicking) { @@ -5946,7 +5947,7 @@ index 91a9b9ff0d7821a2261e7137fb1b3989ba096b88..1fbe1b6de925f71763f79fe3d2371b70 int l = 0; - ObjectIterator objectiterator = this.visibleChunkMap.values().iterator(); -+ Iterator objectiterator = net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper ++ Iterator objectiterator = io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper while (l < 20 && shouldKeepTicking.getAsBoolean() && objectiterator.hasNext()) { if (this.saveChunkIfNeeded((ChunkHolder) objectiterator.next())) { @@ -5958,7 +5959,7 @@ index 91a9b9ff0d7821a2261e7137fb1b3989ba096b88..1fbe1b6de925f71763f79fe3d2371b70 + // Paper start + boolean removed; + if ((removed = this.pendingUnloads.remove(pos, holder)) && ichunkaccess != null) { -+ net.minecraft.server.ChunkSystem.onChunkHolderDelete(this.level, holder); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkHolderDelete(this.level, holder); + // Paper end if (ichunkaccess instanceof LevelChunk) { ((LevelChunk) ichunkaccess).setLoaded(false); @@ -5969,7 +5970,7 @@ index 91a9b9ff0d7821a2261e7137fb1b3989ba096b88..1fbe1b6de925f71763f79fe3d2371b70 this.chunkSaveCooldowns.remove(ichunkaccess.getPos().toLong()); - } + } else if (removed) { // Paper start -+ net.minecraft.server.ChunkSystem.onChunkHolderDelete(this.level, holder); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkHolderDelete(this.level, holder); + } // Paper end } @@ -5979,7 +5980,7 @@ index 91a9b9ff0d7821a2261e7137fb1b3989ba096b88..1fbe1b6de925f71763f79fe3d2371b70 this.viewDistance = j; this.distanceManager.updatePlayerTickets(this.viewDistance + 1); - ObjectIterator objectiterator = this.updatingChunkMap.values().iterator(); -+ Iterator objectiterator = net.minecraft.server.ChunkSystem.getUpdatingChunkHolders(this.level).iterator(); // Paper ++ Iterator objectiterator = io.papermc.paper.chunk.system.ChunkSystem.getUpdatingChunkHolders(this.level).iterator(); // Paper while (objectiterator.hasNext()) { ChunkHolder playerchunk = (ChunkHolder) objectiterator.next(); @@ -5988,7 +5989,7 @@ index 91a9b9ff0d7821a2261e7137fb1b3989ba096b88..1fbe1b6de925f71763f79fe3d2371b70 public int size() { - return this.visibleChunkMap.size(); -+ return net.minecraft.server.ChunkSystem.getVisibleChunkHolderCount(this.level); // Paper ++ return io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolderCount(this.level); // Paper } public DistanceManager getDistanceManager() { @@ -5997,14 +5998,14 @@ index 91a9b9ff0d7821a2261e7137fb1b3989ba096b88..1fbe1b6de925f71763f79fe3d2371b70 protected Iterable getChunks() { - return Iterables.unmodifiableIterable(this.visibleChunkMap.values()); -+ return Iterables.unmodifiableIterable(net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level)); // Paper ++ return Iterables.unmodifiableIterable(io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level)); // Paper } void dumpChunks(Writer writer) throws IOException { CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("z").addColumn("level").addColumn("in_memory").addColumn("status").addColumn("full_status").addColumn("accessible_ready").addColumn("ticking_ready").addColumn("entity_ticking_ready").addColumn("ticket").addColumn("spawning").addColumn("block_entity_count").addColumn("ticking_ticket").addColumn("ticking_level").addColumn("block_ticks").addColumn("fluid_ticks").build(writer); TickingTracker tickingtracker = this.distanceManager.tickingTracker(); - ObjectBidirectionalIterator objectbidirectionaliterator = this.visibleChunkMap.long2ObjectEntrySet().iterator(); -+ Iterator objectbidirectionaliterator = net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper ++ Iterator objectbidirectionaliterator = io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper while (objectbidirectionaliterator.hasNext()) { - Entry entry = (Entry) objectbidirectionaliterator.next(); @@ -6097,7 +6098,7 @@ index 6c98676827ceb6999f340fa2b06a0b3e1cb4cae2..fbe62a31ab199d83a1db0a4e0b1a8138 while (objectiterator.hasNext()) { diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index ce88976db29b9e9524dbe45b16721ef90afb692b..1a8c5ce3ecce9cbbc8496ea3882b18c297964e33 100644 +index ce88976db29b9e9524dbe45b16721ef90afb692b..359de6697ec69f68fe79a691c7306d4c0e42fd58 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java @@ -50,6 +50,7 @@ import net.minecraft.world.level.storage.LevelStorageSource; @@ -6186,21 +6187,21 @@ index ce88976db29b9e9524dbe45b16721ef90afb692b..1a8c5ce3ecce9cbbc8496ea3882b18c2 + long chunkFutureAwaitCounter; // Paper - private -> package private + + public void getEntityTickingChunkAsync(int x, int z, java.util.function.Consumer onLoad) { -+ net.minecraft.server.ChunkSystem.scheduleTickingState( ++ io.papermc.paper.chunk.system.ChunkSystem.scheduleTickingState( + this.level, x, z, ChunkHolder.FullChunkStatus.ENTITY_TICKING, true, + ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.NORMAL, onLoad + ); + } + + public void getTickingChunkAsync(int x, int z, java.util.function.Consumer onLoad) { -+ net.minecraft.server.ChunkSystem.scheduleTickingState( ++ io.papermc.paper.chunk.system.ChunkSystem.scheduleTickingState( + this.level, x, z, ChunkHolder.FullChunkStatus.TICKING, true, + ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.NORMAL, onLoad + ); + } + + public void getFullChunkAsync(int x, int z, java.util.function.Consumer onLoad) { -+ net.minecraft.server.ChunkSystem.scheduleTickingState( ++ io.papermc.paper.chunk.system.ChunkSystem.scheduleTickingState( + this.level, x, z, ChunkHolder.FullChunkStatus.BORDER, true, + ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.NORMAL, onLoad + ); @@ -6224,7 +6225,7 @@ index ce88976db29b9e9524dbe45b16721ef90afb692b..1a8c5ce3ecce9cbbc8496ea3882b18c2 + return; + } + -+ net.minecraft.server.ChunkSystem.scheduleChunkLoad( ++ io.papermc.paper.chunk.system.ChunkSystem.scheduleChunkLoad( + this.level, chunkX, chunkZ, ChunkHolder.getStatus(ticketLevel), true, + ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.NORMAL, consumer + ); @@ -6261,7 +6262,7 @@ index ce88976db29b9e9524dbe45b16721ef90afb692b..1a8c5ce3ecce9cbbc8496ea3882b18c2 + return; + } + -+ this.getChunkAtAsynchronously(chunkX, chunkZ, net.minecraft.server.MCUtil.getTicketLevelFor(ChunkStatus.EMPTY), (ChunkAccess chunk) -> { ++ this.getChunkAtAsynchronously(chunkX, chunkZ, io.papermc.paper.util.MCUtil.getTicketLevelFor(ChunkStatus.EMPTY), (ChunkAccess chunk) -> { + if (chunk == null) { + throw new IllegalStateException("Chunk cannot be null"); + } @@ -6404,7 +6405,7 @@ index ce88976db29b9e9524dbe45b16721ef90afb692b..1a8c5ce3ecce9cbbc8496ea3882b18c2 ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos); diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index aa396df025115c7fd866cbc63a44c2c17abfde84..b2f79a0c9caa6783816afc36531c94378e832cb7 100644 +index aa396df025115c7fd866cbc63a44c2c17abfde84..6e2cd39d4ca7466bbb480d0d9331f644ccda62cd 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -168,6 +168,7 @@ import org.bukkit.event.weather.LightningStrikeEvent; @@ -6503,7 +6504,7 @@ index aa396df025115c7fd866cbc63a44c2c17abfde84..b2f79a0c9caa6783816afc36531c9437 + + for (int cx = minChunkX; cx <= maxChunkX; ++cx) { + for (int cz = minChunkZ; cz <= maxChunkZ; ++cz) { -+ net.minecraft.server.ChunkSystem.scheduleChunkLoad( ++ io.papermc.paper.chunk.system.ChunkSystem.scheduleChunkLoad( + this, cx, cz, net.minecraft.world.level.chunk.ChunkStatus.FULL, true, priority, consumer + ); + } @@ -7265,7 +7266,7 @@ index 9668a960dbd3b4ff3c0635df2fb7cc1af289d235..603111a52346f678aba0fd66b010d8f3 public BlockState getBlockState(BlockPos pos) { int i = pos.getY(); diff --git a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java -index dfd1afc57664dd18c11f8a2547616074ccc55690..ab7eadf2fc4c4598fa89068332eaaf9a8e0a100f 100644 +index dfd1afc57664dd18c11f8a2547616074ccc55690..21e1d86bd287c5e90db43c9c0247d6b7ee1425ae 100644 --- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java +++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java @@ -90,6 +90,18 @@ public class PersistentEntitySectionManager implements A @@ -7277,7 +7278,7 @@ index dfd1afc57664dd18c11f8a2547616074ccc55690..ab7eadf2fc4c4598fa89068332eaaf9a + // I don't want to know why this is a generic type. + Entity entityCasted = (Entity)entity; + boolean wasRemoved = entityCasted.isRemoved(); -+ net.minecraft.server.ChunkSystem.onEntityPreAdd((net.minecraft.server.level.ServerLevel)entityCasted.level, entityCasted); ++ io.papermc.paper.chunk.system.ChunkSystem.onEntityPreAdd((net.minecraft.server.level.ServerLevel)entityCasted.level, entityCasted); + if (!wasRemoved && entityCasted.isRemoved()) { + // removed by callback + return false; @@ -7288,7 +7289,7 @@ index dfd1afc57664dd18c11f8a2547616074ccc55690..ab7eadf2fc4c4598fa89068332eaaf9a return false; } else { diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 93308369f0bbd1e95569d9d573b8b6f42c8ae5a7..6d9469d577dcbb9d5b5b703cf47c8863e0b43b13 100644 +index 93308369f0bbd1e95569d9d573b8b6f42c8ae5a7..452bd97c699261623bf504ee3a177f8f4df97d11 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -234,8 +234,8 @@ public class CraftWorld extends CraftRegionAccessor implements World { @@ -7297,7 +7298,7 @@ index 93308369f0bbd1e95569d9d573b8b6f42c8ae5a7..6d9469d577dcbb9d5b5b703cf47c8863 public Chunk[] getLoadedChunks() { - Long2ObjectLinkedOpenHashMap chunks = this.world.getChunkSource().chunkMap.visibleChunkMap; - return chunks.values().stream().map(ChunkHolder::getFullChunkNow).filter(Objects::nonNull).map(net.minecraft.world.level.chunk.LevelChunk::getBukkitChunk).toArray(Chunk[]::new); -+ List chunks = net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.world); // Paper ++ List chunks = io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.world); // Paper + return chunks.stream().map(ChunkHolder::getFullChunkNow).filter(Objects::nonNull).map(net.minecraft.world.level.chunk.LevelChunk::getBukkitChunk).toArray(Chunk[]::new); } @@ -7333,7 +7334,7 @@ index 93308369f0bbd1e95569d9d573b8b6f42c8ae5a7..6d9469d577dcbb9d5b5b703cf47c8863 + + java.util.concurrent.CompletableFuture ret = new java.util.concurrent.CompletableFuture<>(); + -+ net.minecraft.server.ChunkSystem.scheduleChunkLoad(this.getHandle(), x, z, gen, ChunkStatus.FULL, true, priority, (c) -> { ++ io.papermc.paper.chunk.system.ChunkSystem.scheduleChunkLoad(this.getHandle(), x, z, gen, ChunkStatus.FULL, true, priority, (c) -> { + net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> { + net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk)c; + ret.complete(chunk == null ? null : chunk.getBukkitChunk()); diff --git a/patches/server/0014-Starlight.patch b/patches/server/0014-Starlight.patch index c9ef4a631..b0b2e367c 100644 --- a/patches/server/0014-Starlight.patch +++ b/patches/server/0014-Starlight.patch @@ -4348,7 +4348,7 @@ index b3a58bf4b654e336826dc04da9e2f80ff8b9a9a7..c9a2ac696f7cefc8b0715f53db3fc541 .flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue()))) diff --git a/src/main/java/io/papermc/paper/command/subcommands/FixLightCommand.java b/src/main/java/io/papermc/paper/command/subcommands/FixLightCommand.java new file mode 100644 -index 0000000000000000000000000000000000000000..450bd95218852174cfbc88d4517e17daee5ffd5f +index 0000000000000000000000000000000000000000..7784d72ddd6db00c674e22759c00c430222c4b85 --- /dev/null +++ b/src/main/java/io/papermc/paper/command/subcommands/FixLightCommand.java @@ -0,0 +1,115 @@ @@ -4357,7 +4357,7 @@ index 0000000000000000000000000000000000000000..450bd95218852174cfbc88d4517e17da +import io.papermc.paper.command.PaperSubcommand; +import java.util.ArrayDeque; +import java.util.Deque; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerLevel; @@ -4468,7 +4468,7 @@ index 0000000000000000000000000000000000000000..450bd95218852174cfbc88d4517e17da + } +} diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java -index 0873134f1f6de0c372ba28b89a20302c9a0115d8..86c33f029ae56fcace51b69763202be9f8bc5f44 100644 +index fa800bb4fbbd553ca2a70ba9717546f1415bfc0e..27e1880c4b74a36391f66b1126a92a8b7789c069 100644 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java @@ -55,7 +55,7 @@ public class ChunkHolder { @@ -4481,7 +4481,7 @@ index 0873134f1f6de0c372ba28b89a20302c9a0115d8..86c33f029ae56fcace51b69763202be9 private final DebugBuffer chunkToSaveHistory; public int oldTicketLevel; diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 2a9e5fb8164f79b0f9c1cb5497216e51f9df3454..cbd4e749574c55c6e52f42b62dd6da8cfcca97f9 100644 +index 47a07a372f1e160c0da2c3e8d59ec42166edaf8b..4850ca166a664e2f4b2f28188f72b18812c302f0 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -128,7 +128,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -4507,7 +4507,7 @@ index fbe62a31ab199d83a1db0a4e0b1a813824e6f2c2..d38ad1b1eee92a6dbd2b79b4fcdb8959 while (objectiterator.hasNext()) { diff --git a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java -index 5b238e41ffa3e374b52ee955cb39087571c6ffc2..3fb8d2626a1ef097c05fa5810bc1e051b4a6ad44 100644 +index 5b238e41ffa3e374b52ee955cb39087571c6ffc2..275b7f7dd36a2073a3eb9f89f4c832839e5aa9af 100644 --- a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java +++ b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java @@ -23,6 +23,17 @@ import net.minecraft.world.level.chunk.LightChunkGetter; @@ -4581,7 +4581,7 @@ index 5b238e41ffa3e374b52ee955cb39087571c6ffc2..3fb8d2626a1ef097c05fa5810bc1e051 + + final Long id = Long.valueOf(this.relightCounter++); + -+ ((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().addTicketAtLevel(TicketType.CHUNK_RELIGHT, chunkPos, net.minecraft.server.MCUtil.getTicketLevelFor(ChunkStatus.LIGHT), id); ++ ((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().addTicketAtLevel(TicketType.CHUNK_RELIGHT, chunkPos, io.papermc.paper.util.MCUtil.getTicketLevelFor(ChunkStatus.LIGHT), id); + ticketIds.put(chunkPos, id); + + ++totalChunks; @@ -4592,7 +4592,7 @@ index 5b238e41ffa3e374b52ee955cb39087571c6ffc2..3fb8d2626a1ef097c05fa5810bc1e051 + chunkLightCallback.accept(chunkPos); + ((java.util.concurrent.Executor)((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().mainThreadProcessor).execute(() -> { + ((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().chunkMap.getUpdatingChunkIfPresent(chunkPos.toLong()).broadcast(new net.minecraft.network.protocol.game.ClientboundLightUpdatePacket(chunkPos, ThreadedLevelLightEngine.this, null, null, true), false); -+ ((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().removeTicketAtLevel(TicketType.CHUNK_RELIGHT, chunkPos, net.minecraft.server.MCUtil.getTicketLevelFor(ChunkStatus.LIGHT), ticketIds.get(chunkPos)); ++ ((ServerLevel)this.theLightEngine.getWorld()).getChunkSource().removeTicketAtLevel(TicketType.CHUNK_RELIGHT, chunkPos, io.papermc.paper.util.MCUtil.getTicketLevelFor(ChunkStatus.LIGHT), ticketIds.get(chunkPos)); + }); + }, onComplete); + }); diff --git a/patches/server/0016-Rewrite-chunk-system.patch b/patches/server/0016-Rewrite-chunk-system.patch index 74a4470d3..7e3c8d8b1 100644 --- a/patches/server/0016-Rewrite-chunk-system.patch +++ b/patches/server/0016-Rewrite-chunk-system.patch @@ -1303,7 +1303,7 @@ index 0000000000000000000000000000000000000000..99f49b5625cf51d6c97640553cf5c420 +} diff --git a/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java b/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java new file mode 100644 -index 0000000000000000000000000000000000000000..dd501e83d991e45598509134fab05bafc1904953 +index 0000000000000000000000000000000000000000..0b060183429f4c72ec767075538477b4302bbf0d --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java @@ -0,0 +1,1128 @@ @@ -1322,7 +1322,7 @@ index 0000000000000000000000000000000000000000..dd501e83d991e45598509134fab05baf +import net.minecraft.network.protocol.game.ClientboundSetChunkCacheCenterPacket; +import net.minecraft.network.protocol.game.ClientboundSetChunkCacheRadiusPacket; +import net.minecraft.network.protocol.game.ClientboundSetSimulationDistancePacket; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.*; +import net.minecraft.util.Mth; @@ -2435,9 +2435,241 @@ index 0000000000000000000000000000000000000000..dd501e83d991e45598509134fab05baf + } + } +} +diff --git a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java +index 8a5e93961dac4d87c81c0e70b6f4124a1f1d2556..0dc94dec1317b3f86d38074c6cbe41ab828cab1d 100644 +--- a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java ++++ b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java +@@ -31,191 +31,41 @@ public final class ChunkSystem { + } + + public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final PrioritisedExecutor.Priority priority) { +- level.chunkSource.mainThreadProcessor.execute(run); ++ level.chunkTaskScheduler.scheduleChunkTask(chunkX, chunkZ, run, priority); // Paper - rewrite chunk system + } + + public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final boolean gen, + final ChunkStatus toStatus, final boolean addTicket, final PrioritisedExecutor.Priority priority, + final Consumer onComplete) { +- if (gen) { +- scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); +- return; +- } +- scheduleChunkLoad(level, chunkX, chunkZ, ChunkStatus.EMPTY, addTicket, priority, (final ChunkAccess chunk) -> { +- if (chunk == null) { +- onComplete.accept(null); +- } else { +- if (chunk.getStatus().isOrAfter(toStatus)) { +- scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); +- } else { +- onComplete.accept(null); +- } +- } +- }); ++ level.chunkTaskScheduler.scheduleChunkLoad(chunkX, chunkZ, gen, toStatus, addTicket, priority, onComplete); // Paper - rewrite chunk system + } + +- static final TicketType CHUNK_LOAD = TicketType.create("chunk_load", Long::compareTo); +- +- private static long chunkLoadCounter = 0L; ++ // Paper - rewrite chunk system + public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus, + final boolean addTicket, final PrioritisedExecutor.Priority priority, final Consumer onComplete) { +- if (!Bukkit.isPrimaryThread()) { +- scheduleChunkTask(level, chunkX, chunkZ, () -> { +- scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); +- }, priority); +- return; +- } +- +- final int minLevel = 33 + ChunkStatus.getDistance(toStatus); +- final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; +- final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); +- +- if (addTicket) { +- level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); +- } +- level.chunkSource.runDistanceManagerUpdates(); +- +- final Consumer loadCallback = (final ChunkAccess chunk) -> { +- try { +- if (onComplete != null) { +- onComplete.accept(chunk); +- } +- } catch (final ThreadDeath death) { +- throw death; +- } catch (final Throwable thr) { +- LOGGER.error("Exception handling chunk load callback", thr); +- SneakyThrow.sneaky(thr); +- } finally { +- if (addTicket) { +- level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); +- level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); +- } +- } +- }; +- +- final ChunkHolder holder = level.chunkSource.chunkMap.getUpdatingChunkIfPresent(CoordinateUtils.getChunkKey(chunkX, chunkZ)); +- +- if (holder == null || holder.getTicketLevel() > minLevel) { +- loadCallback.accept(null); +- return; +- } +- +- final CompletableFuture> loadFuture = holder.getOrScheduleFuture(toStatus, level.chunkSource.chunkMap); +- +- if (loadFuture.isDone()) { +- loadCallback.accept(loadFuture.join().left().orElse(null)); +- return; +- } +- +- loadFuture.whenCompleteAsync((final Either either, final Throwable thr) -> { +- if (thr != null) { +- loadCallback.accept(null); +- return; +- } +- loadCallback.accept(either.left().orElse(null)); +- }, (final Runnable r) -> { +- scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); +- }); ++ level.chunkTaskScheduler.scheduleChunkLoad(chunkX, chunkZ, toStatus, addTicket, priority, onComplete); // Paper - rewrite chunk system + } + + public static void scheduleTickingState(final ServerLevel level, final int chunkX, final int chunkZ, + final ChunkHolder.FullChunkStatus toStatus, final boolean addTicket, + final PrioritisedExecutor.Priority priority, final Consumer onComplete) { +- if (toStatus == ChunkHolder.FullChunkStatus.INACCESSIBLE) { +- throw new IllegalArgumentException("Cannot wait for INACCESSIBLE status"); +- } +- +- if (!Bukkit.isPrimaryThread()) { +- scheduleChunkTask(level, chunkX, chunkZ, () -> { +- scheduleTickingState(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); +- }, priority); +- return; +- } +- +- final int minLevel = 33 - (toStatus.ordinal() - 1); +- final int radius = toStatus.ordinal() - 1; +- final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; +- final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); +- +- if (addTicket) { +- level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); +- } +- level.chunkSource.runDistanceManagerUpdates(); +- +- final Consumer loadCallback = (final LevelChunk chunk) -> { +- try { +- if (onComplete != null) { +- onComplete.accept(chunk); +- } +- } catch (final ThreadDeath death) { +- throw death; +- } catch (final Throwable thr) { +- LOGGER.error("Exception handling chunk load callback", thr); +- SneakyThrow.sneaky(thr); +- } finally { +- if (addTicket) { +- level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); +- level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); +- } +- } +- }; +- +- final ChunkHolder holder = level.chunkSource.chunkMap.getUpdatingChunkIfPresent(CoordinateUtils.getChunkKey(chunkX, chunkZ)); +- +- if (holder == null || holder.getTicketLevel() > minLevel) { +- loadCallback.accept(null); +- return; +- } +- +- final CompletableFuture> tickingState; +- switch (toStatus) { +- case BORDER: { +- tickingState = holder.getFullChunkFuture(); +- break; +- } +- case TICKING: { +- tickingState = holder.getTickingChunkFuture(); +- break; +- } +- case ENTITY_TICKING: { +- tickingState = holder.getEntityTickingChunkFuture(); +- break; +- } +- default: { +- throw new IllegalStateException("Cannot reach here"); +- } +- } +- +- if (tickingState.isDone()) { +- loadCallback.accept(tickingState.join().left().orElse(null)); +- return; +- } +- +- tickingState.whenCompleteAsync((final Either either, final Throwable thr) -> { +- if (thr != null) { +- loadCallback.accept(null); +- return; +- } +- loadCallback.accept(either.left().orElse(null)); +- }, (final Runnable r) -> { +- scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); +- }); ++ level.chunkTaskScheduler.scheduleTickingState(chunkX, chunkZ, toStatus, addTicket, priority, onComplete); // Paper - rewrite chunk system + } + + public static List getVisibleChunkHolders(final ServerLevel level) { +- return new ArrayList<>(level.chunkSource.chunkMap.visibleChunkMap.values()); ++ return level.chunkTaskScheduler.chunkHolderManager.getOldChunkHolders(); // Paper - rewrite chunk system + } + + public static List getUpdatingChunkHolders(final ServerLevel level) { +- return new ArrayList<>(level.chunkSource.chunkMap.updatingChunkMap.values()); ++ return level.chunkTaskScheduler.chunkHolderManager.getOldChunkHolders(); // Paper - rewrite chunk system + } + + public static int getVisibleChunkHolderCount(final ServerLevel level) { +- return level.chunkSource.chunkMap.visibleChunkMap.size(); ++ return level.chunkTaskScheduler.chunkHolderManager.size(); // Paper - rewrite chunk system + } + + public static int getUpdatingChunkHolderCount(final ServerLevel level) { +- return level.chunkSource.chunkMap.updatingChunkMap.size(); ++ return level.chunkTaskScheduler.chunkHolderManager.size(); // Paper - rewrite chunk system + } + + public static boolean hasAnyChunkHolders(final ServerLevel level) { +@@ -269,23 +119,15 @@ public final class ChunkSystem { + } + + public static int getSendViewDistance(final ServerPlayer player) { +- return getLoadViewDistance(player); ++ return io.papermc.paper.chunk.PlayerChunkLoader.getSendViewDistance(player); + } + + public static int getLoadViewDistance(final ServerPlayer player) { +- final ServerLevel level = player.getLevel(); +- if (level == null) { +- return Bukkit.getViewDistance() + 1; +- } +- return level.chunkSource.chunkMap.getEffectiveViewDistance() + 1; ++ return io.papermc.paper.chunk.PlayerChunkLoader.getLoadViewDistance(player); + } + + public static int getTickViewDistance(final ServerPlayer player) { +- final ServerLevel level = player.getLevel(); +- if (level == null) { +- return Bukkit.getSimulationDistance(); +- } +- return level.chunkSource.chunkMap.distanceManager.getSimulationDistance(); ++ return io.papermc.paper.chunk.PlayerChunkLoader.getTickViewDistance(player); + } + + private ChunkSystem() { 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 new file mode 100644 -index 0000000000000000000000000000000000000000..7d37b2b02dd64acdac7e5981bebcf988e2f5a7c1 +index 0000000000000000000000000000000000000000..c37adf64ad6133a8d79bfad4a852a6a7e284b6d3 --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java @@ -0,0 +1,839 @@ @@ -2453,7 +2685,7 @@ index 0000000000000000000000000000000000000000..7d37b2b02dd64acdac7e5981bebcf988 +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; +import net.minecraft.core.BlockPos; -+import net.minecraft.server.ChunkSystem; ++import io.papermc.paper.chunk.system.ChunkSystem; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; @@ -5248,7 +5480,7 @@ index 0000000000000000000000000000000000000000..fb42d776f15f735fb59e972e00e2b512 +} diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java new file mode 100644 -index 0000000000000000000000000000000000000000..d220507e1a432883d3092720e3634e8d1d961dbe +index 0000000000000000000000000000000000000000..7a513a6fd8caa61e0444b38daa0ff20d9475220e --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkHolderManager.java @@ -0,0 +1,1190 @@ @@ -5277,7 +5509,7 @@ index 0000000000000000000000000000000000000000..d220507e1a432883d3092720e3634e8d +import it.unimi.dsi.fastutil.objects.ObjectRBTreeSet; +import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet; +import net.minecraft.nbt.CompoundTag; -+import net.minecraft.server.ChunkSystem; ++import io.papermc.paper.chunk.system.ChunkSystem; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ChunkMap; @@ -7247,7 +7479,7 @@ index 0000000000000000000000000000000000000000..322675a470eacbf0e5452f4009c643f2 +} diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkTaskScheduler.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkTaskScheduler.java new file mode 100644 -index 0000000000000000000000000000000000000000..c43c62fb22a26e4e3f5df4001f1b3e65d3833833 +index 0000000000000000000000000000000000000000..84cc9397237fa0c17aa1012dfb5683c90eb6d3b8 --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkTaskScheduler.java @@ -0,0 +1,780 @@ @@ -7264,7 +7496,7 @@ index 0000000000000000000000000000000000000000..c43c62fb22a26e4e3f5df4001f1b3e65 +import net.minecraft.CrashReport; +import net.minecraft.CrashReportCategory; +import net.minecraft.ReportedException; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ChunkMap; @@ -11321,7 +11553,7 @@ index c9a2ac696f7cefc8b0715f53db3fc541f26b62f6..1e9105cf5ab2ff0ee847fafd00b41e1b .flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue()))) diff --git a/src/main/java/io/papermc/paper/command/subcommands/ChunkDebugCommand.java b/src/main/java/io/papermc/paper/command/subcommands/ChunkDebugCommand.java new file mode 100644 -index 0000000000000000000000000000000000000000..628c549b1436c3de75071ecd6182a9beadd4840b +index 0000000000000000000000000000000000000000..a6fb7ae77d7cad2243e28a33718e4631f65697fa --- /dev/null +++ b/src/main/java/io/papermc/paper/command/subcommands/ChunkDebugCommand.java @@ -0,0 +1,264 @@ @@ -11336,7 +11568,7 @@ index 0000000000000000000000000000000000000000..628c549b1436c3de75071ecd6182a9be +import java.util.Collections; +import java.util.List; +import java.util.Locale; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerLevel; @@ -11432,7 +11664,7 @@ index 0000000000000000000000000000000000000000..628c549b1436c3de75071ecd6182a9be + int ticking = 0; + int entityTicking = 0; + -+ for (final ChunkHolder chunk : net.minecraft.server.ChunkSystem.getVisibleChunkHolders(world)) { ++ for (final ChunkHolder chunk : io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(world)) { + if (chunk.getFullChunkNowUnchecked() == null) { + continue; + } @@ -11589,6 +11821,153 @@ index 0000000000000000000000000000000000000000..628c549b1436c3de75071ecd6182a9be + } + +} +diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java +index 9798a1010120125039cbf226a0e3679cc92f92c7..3a0e4934af1f1c711e55ed6f439241364b7448f4 100644 +--- a/src/main/java/io/papermc/paper/util/MCUtil.java ++++ b/src/main/java/io/papermc/paper/util/MCUtil.java +@@ -1,16 +1,29 @@ + package io.papermc.paper.util; + + import com.google.common.util.concurrent.ThreadFactoryBuilder; ++import com.google.gson.JsonArray; ++import com.google.gson.JsonObject; ++import com.google.gson.internal.Streams; ++import com.google.gson.stream.JsonWriter; ++import com.mojang.datafixers.util.Either; + import it.unimi.dsi.fastutil.objects.ObjectRBTreeSet; + import java.lang.ref.Cleaner; ++import it.unimi.dsi.fastutil.objects.ReferenceArrayList; + import net.minecraft.core.BlockPos; + import net.minecraft.core.Direction; + import net.minecraft.server.MinecraftServer; ++import net.minecraft.server.level.ChunkHolder; ++import net.minecraft.server.level.ChunkMap; ++import net.minecraft.server.level.DistanceManager; + import net.minecraft.server.level.ServerLevel; ++import net.minecraft.server.level.ServerPlayer; ++import net.minecraft.server.level.Ticket; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.level.ChunkPos; + import net.minecraft.world.level.ClipContext; + import net.minecraft.world.level.Level; ++import net.minecraft.world.level.chunk.ChunkAccess; ++import net.minecraft.world.level.chunk.ChunkStatus; + import org.apache.commons.lang.exception.ExceptionUtils; + import org.bukkit.Location; + import org.bukkit.block.BlockFace; +@@ -20,8 +33,11 @@ import org.spigotmc.AsyncCatcher; + + import javax.annotation.Nonnull; + import javax.annotation.Nullable; ++import java.io.*; ++import java.nio.charset.StandardCharsets; + import java.util.List; + import java.util.Queue; ++import java.util.Set; + import java.util.concurrent.CompletableFuture; + import java.util.concurrent.ExecutionException; + import java.util.concurrent.LinkedBlockingQueue; +@@ -506,6 +522,100 @@ public final class MCUtil { + } + } + ++ public static ChunkStatus getChunkStatus(ChunkHolder chunk) { ++ return chunk.getChunkHolderStatus(); ++ } ++ ++ public static void dumpChunks(File file, boolean watchdog) throws IOException { ++ file.getParentFile().mkdirs(); ++ file.createNewFile(); ++ ReferenceArrayList worlds = new ReferenceArrayList<>(org.bukkit.Bukkit.getWorlds()); ++ ReferenceArrayList loadedWorlds = new ReferenceArrayList<>(worlds); ++ JsonObject data = new JsonObject(); ++ ++ data.addProperty("server-version", org.bukkit.Bukkit.getVersion()); ++ data.addProperty("data-version", 1); ++ ++ { ++ JsonArray players = new JsonArray(); ++ data.add("all-players", players); ++ List playerList = MinecraftServer.getServer().getPlayerList().players; ++ for (ServerPlayer player : playerList) { ++ JsonObject playerData = new JsonObject(); ++ players.add(playerData); ++ ++ Level playerWorld = player.getLevel(); ++ org.bukkit.World craftWorld = playerWorld.getWorld(); ++ Entity.RemovalReason removalReason = player.getRemovalReason(); ++ ++ playerData.addProperty("name", player.getScoreboardName()); ++ playerData.addProperty("x", player.getX()); ++ playerData.addProperty("y", player.getY()); ++ playerData.addProperty("z", player.getZ()); ++ playerData.addProperty("world", playerWorld == null ? "null world" : craftWorld.getName()); ++ playerData.addProperty("removalReason", removalReason == null ? "null" : removalReason.name()); ++ ++ if (!worlds.contains(craftWorld)) { ++ worlds.add(craftWorld); ++ } ++ } ++ } ++ ++ JsonArray chunkWaitInformation = new JsonArray(); ++ data.add("chunk-wait-infos", chunkWaitInformation); ++ ++ for (io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.ChunkInfo chunkInfo : io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.getChunkInfos()) { ++ chunkWaitInformation.add(chunkInfo.toString()); ++ } ++ ++ JsonArray worldsData = new JsonArray(); ++ ++ for (org.bukkit.World bukkitWorld : worlds) { ++ JsonObject worldData = new JsonObject(); ++ ++ ServerLevel world = ((org.bukkit.craftbukkit.CraftWorld)bukkitWorld).getHandle(); ++ List players = world.players; ++ ++ worldData.addProperty("is-loaded", loadedWorlds.contains(bukkitWorld)); ++ worldData.addProperty("name", world.getWorld().getName()); ++ worldData.addProperty("view-distance", world.getChunkSource().chunkMap.playerChunkManager.getTargetNoTickViewDistance()); // Paper - replace chunk loader system ++ worldData.addProperty("tick-view-distance", world.getChunkSource().chunkMap.playerChunkManager.getTargetTickViewDistance()); // Paper - replace chunk loader system ++ worldData.addProperty("keep-spawn-loaded", world.keepSpawnInMemory); ++ worldData.addProperty("keep-spawn-loaded-range", world.paperConfig().spawn.keepSpawnLoadedRange * 16); ++ ++ JsonArray playersData = new JsonArray(); ++ ++ for (ServerPlayer player : players) { ++ JsonObject playerData = new JsonObject(); ++ ++ playerData.addProperty("name", player.getScoreboardName()); ++ playerData.addProperty("x", player.getX()); ++ playerData.addProperty("y", player.getY()); ++ playerData.addProperty("z", player.getZ()); ++ ++ playersData.add(playerData); ++ } ++ ++ worldData.add("players", playersData); ++ worldData.add("chunk-data", watchdog ? world.chunkTaskScheduler.chunkHolderManager.getDebugJsonForWatchdog() : world.chunkTaskScheduler.chunkHolderManager.getDebugJson()); ++ worldsData.add(worldData); ++ } ++ ++ data.add("worlds", worldsData); ++ ++ StringWriter stringWriter = new StringWriter(); ++ JsonWriter jsonWriter = new JsonWriter(stringWriter); ++ jsonWriter.setIndent(" "); ++ jsonWriter.setLenient(false); ++ Streams.write(data, jsonWriter); ++ ++ String fileData = stringWriter.toString(); ++ ++ try (PrintStream out = new PrintStream(new FileOutputStream(file), false, StandardCharsets.UTF_8)) { ++ out.print(fileData); ++ } ++ } ++ + public static int getTicketLevelFor(net.minecraft.world.level.chunk.ChunkStatus status) { + return net.minecraft.server.level.ChunkMap.MAX_VIEW_DISTANCE + net.minecraft.world.level.chunk.ChunkStatus.getDistance(status); + } diff --git a/src/main/java/io/papermc/paper/util/TickThread.java b/src/main/java/io/papermc/paper/util/TickThread.java index d59885ee9c8b29d5bac34dce0597e345e5358c77..fc57850b80303fcade89ca95794f63910404a407 100644 --- a/src/main/java/io/papermc/paper/util/TickThread.java @@ -12316,384 +12695,6 @@ index a5e438a834826161c52ca9db57d234d9ff80a591..b8bc1b9b8e8a33df90a963f9f9769292 } @Override -diff --git a/src/main/java/net/minecraft/server/ChunkSystem.java b/src/main/java/net/minecraft/server/ChunkSystem.java -index c59fca05484c30b28e883f5b5dde0362f294b517..0c6534e64ef023cf613f2c5407c7598c6ed81bc6 100644 ---- a/src/main/java/net/minecraft/server/ChunkSystem.java -+++ b/src/main/java/net/minecraft/server/ChunkSystem.java -@@ -31,191 +31,41 @@ public final class ChunkSystem { - } - - public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final PrioritisedExecutor.Priority priority) { -- level.chunkSource.mainThreadProcessor.execute(run); -+ level.chunkTaskScheduler.scheduleChunkTask(chunkX, chunkZ, run, priority); // Paper - rewrite chunk system - } - - public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final boolean gen, - final ChunkStatus toStatus, final boolean addTicket, final PrioritisedExecutor.Priority priority, - final Consumer onComplete) { -- if (gen) { -- scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); -- return; -- } -- scheduleChunkLoad(level, chunkX, chunkZ, ChunkStatus.EMPTY, addTicket, priority, (final ChunkAccess chunk) -> { -- if (chunk == null) { -- onComplete.accept(null); -- } else { -- if (chunk.getStatus().isOrAfter(toStatus)) { -- scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); -- } else { -- onComplete.accept(null); -- } -- } -- }); -+ level.chunkTaskScheduler.scheduleChunkLoad(chunkX, chunkZ, gen, toStatus, addTicket, priority, onComplete); // Paper - rewrite chunk system - } - -- static final TicketType CHUNK_LOAD = TicketType.create("chunk_load", Long::compareTo); -- -- private static long chunkLoadCounter = 0L; -+ // Paper - rewrite chunk system - public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus, - final boolean addTicket, final PrioritisedExecutor.Priority priority, final Consumer onComplete) { -- if (!Bukkit.isPrimaryThread()) { -- scheduleChunkTask(level, chunkX, chunkZ, () -> { -- scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); -- }, priority); -- return; -- } -- -- final int minLevel = 33 + ChunkStatus.getDistance(toStatus); -- final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; -- final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); -- -- if (addTicket) { -- level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); -- } -- level.chunkSource.runDistanceManagerUpdates(); -- -- final Consumer loadCallback = (final ChunkAccess chunk) -> { -- try { -- if (onComplete != null) { -- onComplete.accept(chunk); -- } -- } catch (final ThreadDeath death) { -- throw death; -- } catch (final Throwable thr) { -- LOGGER.error("Exception handling chunk load callback", thr); -- SneakyThrow.sneaky(thr); -- } finally { -- if (addTicket) { -- level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); -- level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); -- } -- } -- }; -- -- final ChunkHolder holder = level.chunkSource.chunkMap.getUpdatingChunkIfPresent(CoordinateUtils.getChunkKey(chunkX, chunkZ)); -- -- if (holder == null || holder.getTicketLevel() > minLevel) { -- loadCallback.accept(null); -- return; -- } -- -- final CompletableFuture> loadFuture = holder.getOrScheduleFuture(toStatus, level.chunkSource.chunkMap); -- -- if (loadFuture.isDone()) { -- loadCallback.accept(loadFuture.join().left().orElse(null)); -- return; -- } -- -- loadFuture.whenCompleteAsync((final Either either, final Throwable thr) -> { -- if (thr != null) { -- loadCallback.accept(null); -- return; -- } -- loadCallback.accept(either.left().orElse(null)); -- }, (final Runnable r) -> { -- scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); -- }); -+ level.chunkTaskScheduler.scheduleChunkLoad(chunkX, chunkZ, toStatus, addTicket, priority, onComplete); // Paper - rewrite chunk system - } - - public static void scheduleTickingState(final ServerLevel level, final int chunkX, final int chunkZ, - final ChunkHolder.FullChunkStatus toStatus, final boolean addTicket, - final PrioritisedExecutor.Priority priority, final Consumer onComplete) { -- if (toStatus == ChunkHolder.FullChunkStatus.INACCESSIBLE) { -- throw new IllegalArgumentException("Cannot wait for INACCESSIBLE status"); -- } -- -- if (!Bukkit.isPrimaryThread()) { -- scheduleChunkTask(level, chunkX, chunkZ, () -> { -- scheduleTickingState(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); -- }, priority); -- return; -- } -- -- final int minLevel = 33 - (toStatus.ordinal() - 1); -- final int radius = toStatus.ordinal() - 1; -- final Long chunkReference = addTicket ? Long.valueOf(++chunkLoadCounter) : null; -- final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); -- -- if (addTicket) { -- level.chunkSource.addTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); -- } -- level.chunkSource.runDistanceManagerUpdates(); -- -- final Consumer loadCallback = (final LevelChunk chunk) -> { -- try { -- if (onComplete != null) { -- onComplete.accept(chunk); -- } -- } catch (final ThreadDeath death) { -- throw death; -- } catch (final Throwable thr) { -- LOGGER.error("Exception handling chunk load callback", thr); -- SneakyThrow.sneaky(thr); -- } finally { -- if (addTicket) { -- level.chunkSource.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, minLevel, chunkPos); -- level.chunkSource.removeTicketAtLevel(CHUNK_LOAD, chunkPos, minLevel, chunkReference); -- } -- } -- }; -- -- final ChunkHolder holder = level.chunkSource.chunkMap.getUpdatingChunkIfPresent(CoordinateUtils.getChunkKey(chunkX, chunkZ)); -- -- if (holder == null || holder.getTicketLevel() > minLevel) { -- loadCallback.accept(null); -- return; -- } -- -- final CompletableFuture> tickingState; -- switch (toStatus) { -- case BORDER: { -- tickingState = holder.getFullChunkFuture(); -- break; -- } -- case TICKING: { -- tickingState = holder.getTickingChunkFuture(); -- break; -- } -- case ENTITY_TICKING: { -- tickingState = holder.getEntityTickingChunkFuture(); -- break; -- } -- default: { -- throw new IllegalStateException("Cannot reach here"); -- } -- } -- -- if (tickingState.isDone()) { -- loadCallback.accept(tickingState.join().left().orElse(null)); -- return; -- } -- -- tickingState.whenCompleteAsync((final Either either, final Throwable thr) -> { -- if (thr != null) { -- loadCallback.accept(null); -- return; -- } -- loadCallback.accept(either.left().orElse(null)); -- }, (final Runnable r) -> { -- scheduleChunkTask(level, chunkX, chunkZ, r, PrioritisedExecutor.Priority.HIGHEST); -- }); -+ level.chunkTaskScheduler.scheduleTickingState(chunkX, chunkZ, toStatus, addTicket, priority, onComplete); // Paper - rewrite chunk system - } - - public static List getVisibleChunkHolders(final ServerLevel level) { -- return new ArrayList<>(level.chunkSource.chunkMap.visibleChunkMap.values()); -+ return level.chunkTaskScheduler.chunkHolderManager.getOldChunkHolders(); // Paper - rewrite chunk system - } - - public static List getUpdatingChunkHolders(final ServerLevel level) { -- return new ArrayList<>(level.chunkSource.chunkMap.updatingChunkMap.values()); -+ return level.chunkTaskScheduler.chunkHolderManager.getOldChunkHolders(); // Paper - rewrite chunk system - } - - public static int getVisibleChunkHolderCount(final ServerLevel level) { -- return level.chunkSource.chunkMap.visibleChunkMap.size(); -+ return level.chunkTaskScheduler.chunkHolderManager.size(); // Paper - rewrite chunk system - } - - public static int getUpdatingChunkHolderCount(final ServerLevel level) { -- return level.chunkSource.chunkMap.updatingChunkMap.size(); -+ return level.chunkTaskScheduler.chunkHolderManager.size(); // Paper - rewrite chunk system - } - - public static boolean hasAnyChunkHolders(final ServerLevel level) { -@@ -269,23 +119,15 @@ public final class ChunkSystem { - } - - public static int getSendViewDistance(final ServerPlayer player) { -- return getLoadViewDistance(player); -+ return io.papermc.paper.chunk.PlayerChunkLoader.getSendViewDistance(player); - } - - public static int getLoadViewDistance(final ServerPlayer player) { -- final ServerLevel level = player.getLevel(); -- if (level == null) { -- return Bukkit.getViewDistance() + 1; -- } -- return level.chunkSource.chunkMap.getEffectiveViewDistance() + 1; -+ return io.papermc.paper.chunk.PlayerChunkLoader.getLoadViewDistance(player); - } - - public static int getTickViewDistance(final ServerPlayer player) { -- final ServerLevel level = player.getLevel(); -- if (level == null) { -- return Bukkit.getSimulationDistance(); -- } -- return level.chunkSource.chunkMap.distanceManager.getSimulationDistance(); -+ return io.papermc.paper.chunk.PlayerChunkLoader.getTickViewDistance(player); - } - - private ChunkSystem() { -diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java -index 9db975e84609956b2206076e30f17a350adb77d6..f99929c0c5652dedf94b7e34ba599cedf5daf508 100644 ---- a/src/main/java/net/minecraft/server/MCUtil.java -+++ b/src/main/java/net/minecraft/server/MCUtil.java -@@ -1,15 +1,28 @@ - package net.minecraft.server; - - import com.google.common.util.concurrent.ThreadFactoryBuilder; -+import com.google.gson.JsonArray; -+import com.google.gson.JsonObject; -+import com.google.gson.internal.Streams; -+import com.google.gson.stream.JsonWriter; -+import com.mojang.datafixers.util.Either; - import it.unimi.dsi.fastutil.objects.ObjectRBTreeSet; - import java.lang.ref.Cleaner; -+import it.unimi.dsi.fastutil.objects.ReferenceArrayList; - import net.minecraft.core.BlockPos; - import net.minecraft.core.Direction; -+import net.minecraft.server.level.ChunkHolder; -+import net.minecraft.server.level.ChunkMap; -+import net.minecraft.server.level.DistanceManager; - import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.server.level.Ticket; - import net.minecraft.world.entity.Entity; - import net.minecraft.world.level.ChunkPos; - import net.minecraft.world.level.ClipContext; - import net.minecraft.world.level.Level; -+import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.ChunkStatus; - import org.apache.commons.lang.exception.ExceptionUtils; - import org.bukkit.Location; - import org.bukkit.block.BlockFace; -@@ -19,8 +32,11 @@ import org.spigotmc.AsyncCatcher; - - import javax.annotation.Nonnull; - import javax.annotation.Nullable; -+import java.io.*; -+import java.nio.charset.StandardCharsets; - import java.util.List; - import java.util.Queue; -+import java.util.Set; - import java.util.concurrent.CompletableFuture; - import java.util.concurrent.ExecutionException; - import java.util.concurrent.LinkedBlockingQueue; -@@ -505,6 +521,100 @@ public final class MCUtil { - } - } - -+ public static ChunkStatus getChunkStatus(ChunkHolder chunk) { -+ return chunk.getChunkHolderStatus(); -+ } -+ -+ public static void dumpChunks(File file, boolean watchdog) throws IOException { -+ file.getParentFile().mkdirs(); -+ file.createNewFile(); -+ ReferenceArrayList worlds = new ReferenceArrayList<>(org.bukkit.Bukkit.getWorlds()); -+ ReferenceArrayList loadedWorlds = new ReferenceArrayList<>(worlds); -+ JsonObject data = new JsonObject(); -+ -+ data.addProperty("server-version", org.bukkit.Bukkit.getVersion()); -+ data.addProperty("data-version", 1); -+ -+ { -+ JsonArray players = new JsonArray(); -+ data.add("all-players", players); -+ List playerList = MinecraftServer.getServer().getPlayerList().players; -+ for (ServerPlayer player : playerList) { -+ JsonObject playerData = new JsonObject(); -+ players.add(playerData); -+ -+ Level playerWorld = player.getLevel(); -+ org.bukkit.World craftWorld = playerWorld.getWorld(); -+ Entity.RemovalReason removalReason = player.getRemovalReason(); -+ -+ playerData.addProperty("name", player.getScoreboardName()); -+ playerData.addProperty("x", player.getX()); -+ playerData.addProperty("y", player.getY()); -+ playerData.addProperty("z", player.getZ()); -+ playerData.addProperty("world", playerWorld == null ? "null world" : craftWorld.getName()); -+ playerData.addProperty("removalReason", removalReason == null ? "null" : removalReason.name()); -+ -+ if (!worlds.contains(craftWorld)) { -+ worlds.add(craftWorld); -+ } -+ } -+ } -+ -+ JsonArray chunkWaitInformation = new JsonArray(); -+ data.add("chunk-wait-infos", chunkWaitInformation); -+ -+ for (io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.ChunkInfo chunkInfo : io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.getChunkInfos()) { -+ chunkWaitInformation.add(chunkInfo.toString()); -+ } -+ -+ JsonArray worldsData = new JsonArray(); -+ -+ for (org.bukkit.World bukkitWorld : worlds) { -+ JsonObject worldData = new JsonObject(); -+ -+ ServerLevel world = ((org.bukkit.craftbukkit.CraftWorld)bukkitWorld).getHandle(); -+ List players = world.players; -+ -+ worldData.addProperty("is-loaded", loadedWorlds.contains(bukkitWorld)); -+ worldData.addProperty("name", world.getWorld().getName()); -+ worldData.addProperty("view-distance", world.getChunkSource().chunkMap.playerChunkManager.getTargetNoTickViewDistance()); // Paper - replace chunk loader system -+ worldData.addProperty("tick-view-distance", world.getChunkSource().chunkMap.playerChunkManager.getTargetTickViewDistance()); // Paper - replace chunk loader system -+ worldData.addProperty("keep-spawn-loaded", world.keepSpawnInMemory); -+ worldData.addProperty("keep-spawn-loaded-range", world.paperConfig().spawn.keepSpawnLoadedRange * 16); -+ -+ JsonArray playersData = new JsonArray(); -+ -+ for (ServerPlayer player : players) { -+ JsonObject playerData = new JsonObject(); -+ -+ playerData.addProperty("name", player.getScoreboardName()); -+ playerData.addProperty("x", player.getX()); -+ playerData.addProperty("y", player.getY()); -+ playerData.addProperty("z", player.getZ()); -+ -+ playersData.add(playerData); -+ } -+ -+ worldData.add("players", playersData); -+ worldData.add("chunk-data", watchdog ? world.chunkTaskScheduler.chunkHolderManager.getDebugJsonForWatchdog() : world.chunkTaskScheduler.chunkHolderManager.getDebugJson()); -+ worldsData.add(worldData); -+ } -+ -+ data.add("worlds", worldsData); -+ -+ StringWriter stringWriter = new StringWriter(); -+ JsonWriter jsonWriter = new JsonWriter(stringWriter); -+ jsonWriter.setIndent(" "); -+ jsonWriter.setLenient(false); -+ Streams.write(data, jsonWriter); -+ -+ String fileData = stringWriter.toString(); -+ -+ try (PrintStream out = new PrintStream(new FileOutputStream(file), false, StandardCharsets.UTF_8)) { -+ out.print(fileData); -+ } -+ } -+ - public static int getTicketLevelFor(net.minecraft.world.level.chunk.ChunkStatus status) { - return net.minecraft.server.level.ChunkMap.MAX_VIEW_DISTANCE + net.minecraft.world.level.chunk.ChunkStatus.getDistance(status); - } diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java index 4dd3af1416cbdad330365a19ad664079f3598c15..45db9f1b1d19319e7f92bd4e61be9ea9b06dd5e5 100644 --- a/src/main/java/net/minecraft/server/Main.java @@ -12707,7 +12708,7 @@ index 4dd3af1416cbdad330365a19ad664079f3598c15..45db9f1b1d19319e7f92bd4e61be9ea9 DedicatedServer dedicatedserver1 = new DedicatedServer(optionset, config.get(), ops.get(), thread, convertable_conversionsession, resourcepackrepository, worldstem, dedicatedserversettings, DataFixers.getDataFixer(), services, LoggerChunkProgressListener::new); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 53be6189d3fa6a65a09996683913fbbf5133dcb7..317cd6f68c2368b2f70dfb809db3e418de040f05 100644 +index 2b2b71f3963e66fa0d2683b10581b1a38c774549..0d2114be30df99c5b50f82def97b0a44e797e573 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -287,7 +287,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { - // note: Here is a very good place to add callbacks to logic waiting on this. - ChunkHolder.this.isTickingReady = true; -- net.minecraft.server.ChunkSystem.onChunkTicking(chunk, this); +- io.papermc.paper.chunk.system.ChunkSystem.onChunkTicking(chunk, this); - }); - }); - // Paper end @@ -13378,7 +13379,7 @@ index 86c33f029ae56fcace51b69763202be9f8bc5f44..2ba3bb4e5670ece798a8882801a856d8 - if (flag4 && !flag5) { - // Paper start - if (this.isTickingReady) { -- net.minecraft.server.ChunkSystem.onChunkNotTicking(this.tickingChunkFuture.join().left().get(), this); // Paper +- io.papermc.paper.chunk.system.ChunkSystem.onChunkNotTicking(this.tickingChunkFuture.join().left().get(), this); // Paper - } - // Paper end - this.tickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); this.isTickingReady = false; // Paper - cache chunk ticking stage @@ -13399,7 +13400,7 @@ index 86c33f029ae56fcace51b69763202be9f8bc5f44..2ba3bb4e5670ece798a8882801a856d8 - this.entityTickingChunkFuture.thenAccept(either -> { - either.ifLeft(chunk -> { - ChunkHolder.this.isEntityTickingReady = true; -- net.minecraft.server.ChunkSystem.onChunkEntityTicking(chunk, this); +- io.papermc.paper.chunk.system.ChunkSystem.onChunkEntityTicking(chunk, this); - }); - }); - // Paper end @@ -13409,7 +13410,7 @@ index 86c33f029ae56fcace51b69763202be9f8bc5f44..2ba3bb4e5670ece798a8882801a856d8 - if (flag6 && !flag7) { - // Paper start - if (this.isEntityTickingReady) { -- net.minecraft.server.ChunkSystem.onChunkNotEntityTicking(this.entityTickingChunkFuture.join().left().get(), this); +- io.papermc.paper.chunk.system.ChunkSystem.onChunkNotEntityTicking(this.entityTickingChunkFuture.join().left().get(), this); - } - // Paper end - this.entityTickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); this.isEntityTickingReady = false; // Paper - cache chunk ticking stage @@ -13509,7 +13510,7 @@ index 86c33f029ae56fcace51b69763202be9f8bc5f44..2ba3bb4e5670ece798a8882801a856d8 // Paper end } diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index cbd4e749574c55c6e52f42b62dd6da8cfcca97f9..13814643e28e36c72173d0d62b9271a7f6113f6a 100644 +index 1fa6d7ba1c04f9f4773f9303cc220d75415a56fb..82f5316ee44edd64f23178edc9b47f3be8dc39ca 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -122,10 +122,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -13783,7 +13784,7 @@ index cbd4e749574c55c6e52f42b62dd6da8cfcca97f9..13814643e28e36c72173d0d62b9271a7 - } else { - holder = new ChunkHolder(new ChunkPos(pos), level, this.level, this.lightEngine, this.queueSorter, this); - // Paper start -- net.minecraft.server.ChunkSystem.onChunkHolderCreate(this.level, holder); +- io.papermc.paper.chunk.system.ChunkSystem.onChunkHolderCreate(this.level, holder); - // Paper end - } - @@ -13818,7 +13819,7 @@ index cbd4e749574c55c6e52f42b62dd6da8cfcca97f9..13814643e28e36c72173d0d62b9271a7 protected void saveAllChunks(boolean flush) { - if (flush) { -- List list = (List) net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); // Paper +- List list = (List) io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); // Paper - MutableBoolean mutableboolean = new MutableBoolean(); - - do { @@ -13847,7 +13848,7 @@ index cbd4e749574c55c6e52f42b62dd6da8cfcca97f9..13814643e28e36c72173d0d62b9271a7 - }); - this.flushWorker(); - } else { -- net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).forEach(this::saveChunkIfNeeded); +- io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).forEach(this::saveChunkIfNeeded); - } - + this.level.chunkTaskScheduler.chunkHolderManager.saveAllChunks(flush, false, false); // Paper - rewrite chunk system @@ -13871,7 +13872,7 @@ index cbd4e749574c55c6e52f42b62dd6da8cfcca97f9..13814643e28e36c72173d0d62b9271a7 } public boolean hasWork() { -- return this.lightEngine.hasLightWork() || !this.pendingUnloads.isEmpty() || net.minecraft.server.ChunkSystem.hasAnyChunkHolders(this.level) || this.poiManager.hasWork() || !this.toDrop.isEmpty() || !this.unloadQueue.isEmpty() || this.queueSorter.hasWork() || this.distanceManager.hasTickets(); // Paper +- return this.lightEngine.hasLightWork() || !this.pendingUnloads.isEmpty() || io.papermc.paper.chunk.system.ChunkSystem.hasAnyChunkHolders(this.level) || this.poiManager.hasWork() || !this.toDrop.isEmpty() || !this.unloadQueue.isEmpty() || this.queueSorter.hasWork() || this.distanceManager.hasTickets(); // Paper + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -13901,7 +13902,7 @@ index cbd4e749574c55c6e52f42b62dd6da8cfcca97f9..13814643e28e36c72173d0d62b9271a7 - } - - int l = 0; -- Iterator objectiterator = net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper +- Iterator objectiterator = io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper - - while (l < 20 && shouldKeepTicking.getAsBoolean() && objectiterator.hasNext()) { - if (this.saveChunkIfNeeded((ChunkHolder) objectiterator.next())) { @@ -13923,7 +13924,7 @@ index cbd4e749574c55c6e52f42b62dd6da8cfcca97f9..13814643e28e36c72173d0d62b9271a7 - // Paper start - boolean removed; - if ((removed = this.pendingUnloads.remove(pos, holder)) && ichunkaccess != null) { -- net.minecraft.server.ChunkSystem.onChunkHolderDelete(this.level, holder); +- io.papermc.paper.chunk.system.ChunkSystem.onChunkHolderDelete(this.level, holder); - // Paper end - if (ichunkaccess instanceof LevelChunk) { - ((LevelChunk) ichunkaccess).setLoaded(false); @@ -13941,7 +13942,7 @@ index cbd4e749574c55c6e52f42b62dd6da8cfcca97f9..13814643e28e36c72173d0d62b9271a7 - this.progressListener.onStatusChange(ichunkaccess.getPos(), (ChunkStatus) null); - this.chunkSaveCooldowns.remove(ichunkaccess.getPos().toLong()); - } else if (removed) { // Paper start -- net.minecraft.server.ChunkSystem.onChunkHolderDelete(this.level, holder); +- io.papermc.paper.chunk.system.ChunkSystem.onChunkHolderDelete(this.level, holder); - } // Paper end - - } @@ -14295,7 +14296,7 @@ index cbd4e749574c55c6e52f42b62dd6da8cfcca97f9..13814643e28e36c72173d0d62b9271a7 this.viewDistance = j; - this.distanceManager.updatePlayerTickets(this.viewDistance + 1); -- Iterator objectiterator = net.minecraft.server.ChunkSystem.getUpdatingChunkHolders(this.level).iterator(); // Paper +- Iterator objectiterator = io.papermc.paper.chunk.system.ChunkSystem.getUpdatingChunkHolders(this.level).iterator(); // Paper - - while (objectiterator.hasNext()) { - ChunkHolder playerchunk = (ChunkHolder) objectiterator.next(); @@ -14333,7 +14334,7 @@ index cbd4e749574c55c6e52f42b62dd6da8cfcca97f9..13814643e28e36c72173d0d62b9271a7 void dumpChunks(Writer writer) throws IOException { - CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("z").addColumn("level").addColumn("in_memory").addColumn("status").addColumn("full_status").addColumn("accessible_ready").addColumn("ticking_ready").addColumn("entity_ticking_ready").addColumn("ticket").addColumn("spawning").addColumn("block_entity_count").addColumn("ticking_ticket").addColumn("ticking_level").addColumn("block_ticks").addColumn("fluid_ticks").build(writer); - TickingTracker tickingtracker = this.distanceManager.tickingTracker(); -- Iterator objectbidirectionaliterator = net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper +- Iterator objectbidirectionaliterator = io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper - - while (objectbidirectionaliterator.hasNext()) { - ChunkHolder playerchunk = objectbidirectionaliterator.next(); // Paper @@ -14990,7 +14991,7 @@ index d38ad1b1eee92a6dbd2b79b4fcdb8959cdb4007d..ffa1e457decf8502c3283352bf5be94d + */ // Paper - rewrite chunk system } diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 8c99e9d1cc1abf5a425846eb4edd52bf38aa2f75..b3cff10fece84839fe85feb297fafbcd4a02d838 100644 +index 203bca8839a9c1c0fd8171d3a17d0a55086f20a1..39d96933e2d922e377df866367057f1991471c8d 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java @@ -366,7 +366,7 @@ public class ServerChunkCache extends ChunkSource { @@ -15017,7 +15018,7 @@ index 8c99e9d1cc1abf5a425846eb4edd52bf38aa2f75..b3cff10fece84839fe85feb297fafbcd + priority = ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.NORMAL; + } + -+ net.minecraft.server.ChunkSystem.scheduleChunkLoad(this.level, x, z, gen, ChunkStatus.FULL, true, priority, (chunk) -> { ++ io.papermc.paper.chunk.system.ChunkSystem.scheduleChunkLoad(this.level, x, z, gen, ChunkStatus.FULL, true, priority, (chunk) -> { + if (chunk == null) { + ret.complete(ChunkHolder.UNLOADED_CHUNK); + } else { @@ -15304,7 +15305,7 @@ index 8c99e9d1cc1abf5a425846eb4edd52bf38aa2f75..b3cff10fece84839fe85feb297fafbcd } diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 99d44faab5b5da244fdc170c73d73723c174c8fd..7c709be5d43bcd45064c79e84d5b2fff0b3d0cfe 100644 +index b24b68aad942401815548fa49b968a7bf1f7939d..c5cc5e2c235b46f15d120b6aa5f71410d535a486 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -190,7 +190,7 @@ public class ServerLevel extends Level implements WorldGenLevel { @@ -15666,7 +15667,7 @@ index 99d44faab5b5da244fdc170c73d73723c174c8fd..7c709be5d43bcd45064c79e84d5b2fff private final class EntityCallbacks implements LevelCallback { diff --git a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java -index 3fb8d2626a1ef097c05fa5810bc1e051b4a6ad44..63d1a121a97a8dbc9b640d21580b084898a232bf 100644 +index 275b7f7dd36a2073a3eb9f89f4c832839e5aa9af..660693c6dc0ef86f4013df980b6d0c11c03e46cd 100644 --- a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java +++ b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java @@ -36,15 +36,14 @@ import net.minecraft.world.level.chunk.ChunkStatus; @@ -16194,7 +16195,7 @@ index 1a44c98b69398ba5dcb4115f0e8fdcf3f62fd920..1a2ee5824c6af6b548e7006d583b73f4 @Override diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java -index db4fa7355b1f834d0f8a0710c1c583dded184613..8938e04ffab2d31e64b80879d21d9f1eb90c20bb 100644 +index db4fa7355b1f834d0f8a0710c1c583dded184613..a98f4315b82919e4d90d74f5cd0e6f21e49353dc 100644 --- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java +++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java @@ -38,12 +38,28 @@ import net.minecraft.world.level.chunk.storage.SectionStorage; @@ -16328,8 +16329,8 @@ index db4fa7355b1f834d0f8a0710c1c583dded184613..8938e04ffab2d31e64b80879d21d9f1e + } + + public void onUnload(long coordinate) { // Paper - rewrite chunk system -+ int chunkX = net.minecraft.server.MCUtil.getCoordinateX(coordinate); -+ int chunkZ = net.minecraft.server.MCUtil.getCoordinateZ(coordinate); ++ int chunkX = io.papermc.paper.util.MCUtil.getCoordinateX(coordinate); ++ int chunkZ = io.papermc.paper.util.MCUtil.getCoordinateZ(coordinate); + io.papermc.paper.util.TickThread.ensureTickThread(this.world, chunkX, chunkZ, "Unloading poi chunk off-main"); + for (int section = this.levelHeightAccessor.getMinSection(); section < this.levelHeightAccessor.getMaxSection(); ++section) { + long sectionPos = SectionPos.asLong(chunkX, section, chunkZ); @@ -16674,7 +16675,7 @@ index e6240f891e396d91e31b02fdf3084be77e9d6697..00cb9dafc711607f28529ea9afbcdb49 public int getIndex() { 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 e75ec8f6aa597b5f3048d6269fba45eef057bc71..6a84e7524a246e234116a37349f30e01411e6787 100644 +index e75ec8f6aa597b5f3048d6269fba45eef057bc71..0e2a15d623e5ff5c34252e4b714713a6a670e755 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -183,6 +183,43 @@ public class LevelChunk extends ChunkAccess { @@ -16764,7 +16765,7 @@ index e75ec8f6aa597b5f3048d6269fba45eef057bc71..6a84e7524a246e234116a37349f30e01 + // the chunk load event // -> stays here + // any entity add to world events // -> in FULL status + this.loadCallback(); -+ net.minecraft.server.ChunkSystem.onChunkBorder(this, chunkHolder.vanillaChunkHolder); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkBorder(this, chunkHolder.vanillaChunkHolder); + } + + public void onChunkUnload(io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder) { @@ -16774,25 +16775,25 @@ index e75ec8f6aa597b5f3048d6269fba45eef057bc71..6a84e7524a246e234116a37349f30e01 + // any entity add to world events // -> goes into the unload logic, it will completely explode + // etc later + this.unloadCallback(); -+ net.minecraft.server.ChunkSystem.onChunkNotBorder(this, chunkHolder.vanillaChunkHolder); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkNotBorder(this, chunkHolder.vanillaChunkHolder); + } + + public void onChunkTicking(io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder) { + this.postProcessGeneration(); + this.level.startTickingChunk(this); -+ net.minecraft.server.ChunkSystem.onChunkTicking(this, chunkHolder.vanillaChunkHolder); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkTicking(this, chunkHolder.vanillaChunkHolder); + } + + public void onChunkNotTicking(io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder) { -+ net.minecraft.server.ChunkSystem.onChunkNotTicking(this, chunkHolder.vanillaChunkHolder); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkNotTicking(this, chunkHolder.vanillaChunkHolder); + } + + public void onChunkEntityTicking(io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder) { -+ net.minecraft.server.ChunkSystem.onChunkEntityTicking(this, chunkHolder.vanillaChunkHolder); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkEntityTicking(this, chunkHolder.vanillaChunkHolder); + } + + public void onChunkNotEntityTicking(io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder) { -+ net.minecraft.server.ChunkSystem.onChunkNotEntityTicking(this, chunkHolder.vanillaChunkHolder); ++ io.papermc.paper.chunk.system.ChunkSystem.onChunkNotEntityTicking(this, chunkHolder.vanillaChunkHolder); + } + // Paper end - new load callbacks + @@ -17758,7 +17759,7 @@ index eb5c7e15366ee5902d8c754a1e9daec50d26fb17..2103081cf6a8db00d78618340eef5140 // Paper start diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 9a6820b10e4164cc38d269853b5c2a49175cb890..e2c051dd0d639ba28da0f62d06259fcf0d3244ce 100644 +index e3d0a82387dfdcf65f1b07fd8ae2132be6e6d18f..fe2f5364e526cfe9e25760301165934b7fbbdd85 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -314,10 +314,14 @@ public class CraftWorld extends CraftRegionAccessor implements World { diff --git a/patches/server/0079-EntityPathfindEvent.patch b/patches/server/0079-EntityPathfindEvent.patch index 8567351f0..4e0de3f71 100644 --- a/patches/server/0079-EntityPathfindEvent.patch +++ b/patches/server/0079-EntityPathfindEvent.patch @@ -63,7 +63,7 @@ index 27b072943328aca4489a9565bda700e7e7dcbb6a..f0248d839255763005ba333b0bfcf691 private int getSurfaceY() { diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java -index eaf1653b14e5fdacae38abe75260a64d0ffbfc1d..30f58f1829d1b500ee49b543e3c15e5bfe63fade 100644 +index eaf1653b14e5fdacae38abe75260a64d0ffbfc1d..b6b6106ad2105c19273dc9f983fabd6573d35e5a 100644 --- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java +++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java @@ -108,7 +108,13 @@ public abstract class PathNavigation { @@ -115,7 +115,7 @@ index eaf1653b14e5fdacae38abe75260a64d0ffbfc1d..30f58f1829d1b500ee49b543e3c15e5b + boolean copiedSet = false; + for (BlockPos possibleTarget : positions) { + if (!new com.destroystokyo.paper.event.entity.EntityPathfindEvent(this.mob.getBukkitEntity(), -+ net.minecraft.server.MCUtil.toLocation(this.mob.level, possibleTarget), target == null ? null : target.getBukkitEntity()).callEvent()) { ++ io.papermc.paper.util.MCUtil.toLocation(this.mob.level, possibleTarget), target == null ? null : target.getBukkitEntity()).callEvent()) { + if (!copiedSet) { + copiedSet = true; + positions = new java.util.HashSet<>(positions); diff --git a/patches/server/0094-LootTable-API-Replenishable-Lootables-Feature.patch b/patches/server/0094-LootTable-API-Replenishable-Lootables-Feature.patch index 1bd3ae7f4..bea608329 100644 --- a/patches/server/0094-LootTable-API-Replenishable-Lootables-Feature.patch +++ b/patches/server/0094-LootTable-API-Replenishable-Lootables-Feature.patch @@ -415,13 +415,13 @@ index 0000000000000000000000000000000000000000..e5ea9f27a1936ed9e329e74317c91c5d +} diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java new file mode 100644 -index 0000000000000000000000000000000000000000..3377b86c337d0234bbb9b0349e4034a7cd450a97 +index 0000000000000000000000000000000000000000..9cfa5d36a6991067a3866e0d437749fafcc0158e --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java @@ -0,0 +1,65 @@ +package com.destroystokyo.paper.loottable; + -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity; +import org.bukkit.Bukkit; @@ -485,7 +485,7 @@ index 0000000000000000000000000000000000000000..3377b86c337d0234bbb9b0349e4034a7 + } +} diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 233c8950816521be5a9d099c29c99d0a421d30e4..77652939ccb3191c29b919170a06ef451b3fd74f 100644 +index dd5e9dc310f30c008f0c8c60ac4305160261bad9..a6b5527e97e8a5b2eeca762477a7b695223a0d4d 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -232,6 +232,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { diff --git a/patches/server/0097-Async-GameProfileCache-saving.patch b/patches/server/0097-Async-GameProfileCache-saving.patch index e0d7f93e3..7a9b7d0be 100644 --- a/patches/server/0097-Async-GameProfileCache-saving.patch +++ b/patches/server/0097-Async-GameProfileCache-saving.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Async GameProfileCache saving diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 7755d79e0dc01e8464f4ffda46db6dbde033aac4..f1d4a7a9e74adc18e18b2df960794ec8c05ce340 100644 +index e24bd9c2be84dd11bf109e65ea4e1e577fe647ca..f438056c74dd24142bd94b505160711d0f94a5d5 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -926,7 +926,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop pendingBlockEntityTickers = Lists.newArrayList(); private boolean tickingBlockEntities; diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index e2c051dd0d639ba28da0f62d06259fcf0d3244ce..a75f4a1ecfe2790d727f5dda792c5ab4bb45554e 100644 +index fe2f5364e526cfe9e25760301165934b7fbbdd85..2636ef8f827b30315693f1b406debcdea0716170 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -152,6 +152,56 @@ public class CraftWorld extends CraftRegionAccessor implements World { @@ -43,7 +43,7 @@ index e2c051dd0d639ba28da0f62d06259fcf0d3244ce..a75f4a1ecfe2790d727f5dda792c5ab4 + public int getTileEntityCount() { + // We don't use the full world tile entity list, so we must iterate chunks + int size = 0; -+ for (ChunkHolder playerchunk : net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.world)) { ++ for (ChunkHolder playerchunk : io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.world)) { + net.minecraft.world.level.chunk.LevelChunk chunk = playerchunk.getTickingChunk(); + if (chunk == null) { + continue; @@ -62,7 +62,7 @@ index e2c051dd0d639ba28da0f62d06259fcf0d3244ce..a75f4a1ecfe2790d727f5dda792c5ab4 + public int getChunkCount() { + int ret = 0; + -+ for (ChunkHolder chunkHolder : net.minecraft.server.ChunkSystem.getVisibleChunkHolders(this.world)) { ++ for (ChunkHolder chunkHolder : io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.world)) { + if (chunkHolder.getTickingChunk() != null) { + ++ret; + } diff --git a/patches/server/0126-Enforce-Sync-Player-Saves.patch b/patches/server/0126-Enforce-Sync-Player-Saves.patch index b13a65c6a..db22ab799 100644 --- a/patches/server/0126-Enforce-Sync-Player-Saves.patch +++ b/patches/server/0126-Enforce-Sync-Player-Saves.patch @@ -7,14 +7,14 @@ Saving players async is extremely dangerous. This will force it to main the same way we handle async chunk loads. diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 0d0b04775dc36c1749d8f19f5c8d2b9dd9bb5a1e..acb3d75f0777eab5aa117679d2328c22f46cf823 100644 +index 0d0b04775dc36c1749d8f19f5c8d2b9dd9bb5a1e..730f30b6ee5230cde784b7f0a2b20699968f7e15 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java @@ -1042,11 +1042,13 @@ public abstract class PlayerList { } public void saveAll() { -+ net.minecraft.server.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main ++ io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main MinecraftTimings.savePlayers.startTiming(); // Paper for (int i = 0; i < this.players.size(); ++i) { - this.save((ServerPlayer) this.players.get(i)); diff --git a/patches/server/0142-Basic-PlayerProfile-API.patch b/patches/server/0142-Basic-PlayerProfile-API.patch index cba9be043..cd3cc2229 100644 --- a/patches/server/0142-Basic-PlayerProfile-API.patch +++ b/patches/server/0142-Basic-PlayerProfile-API.patch @@ -554,19 +554,19 @@ index 0000000000000000000000000000000000000000..7ac27392a8647ef7d0dc78efe78703e9 + + @NotNull GameProfile buildGameProfile(); +} -diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java -index c9e169a6dca4dd8fe6e27a23deb410664a5d4466..e98276943e1690572b8f7bc54a259aa8340bae41 100644 ---- a/src/main/java/net/minecraft/server/MCUtil.java -+++ b/src/main/java/net/minecraft/server/MCUtil.java +diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java +index 3a0e4934af1f1c711e55ed6f439241364b7448f4..4c5ed3de410c740bcaca37d84b153af6a482bf89 100644 +--- a/src/main/java/io/papermc/paper/util/MCUtil.java ++++ b/src/main/java/io/papermc/paper/util/MCUtil.java @@ -1,5 +1,7 @@ - package net.minecraft.server; + package io.papermc.paper.util; +import com.destroystokyo.paper.profile.CraftPlayerProfile; +import com.destroystokyo.paper.profile.PlayerProfile; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonObject; -@@ -24,6 +26,7 @@ import net.minecraft.world.level.Level; +@@ -25,6 +27,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import org.apache.commons.lang.exception.ExceptionUtils; @@ -574,7 +574,7 @@ index c9e169a6dca4dd8fe6e27a23deb410664a5d4466..e98276943e1690572b8f7bc54a259aa8 import org.bukkit.Location; import org.bukkit.block.BlockFace; import org.bukkit.craftbukkit.CraftWorld; -@@ -371,6 +374,10 @@ public final class MCUtil { +@@ -372,6 +375,10 @@ public final class MCUtil { return run.get(); } @@ -599,7 +599,7 @@ index 45db9f1b1d19319e7f92bd4e61be9ea9b06dd5e5..151b13e257c09fc5c4bbccfc388b15ad String s = (String) Optional.ofNullable((String) optionset.valueOf("world")).orElse(dedicatedserversettings.getProperties().levelName); LevelStorageSource convertable = LevelStorageSource.createDefault(file.toPath()); diff --git a/src/main/java/net/minecraft/server/players/GameProfileCache.java b/src/main/java/net/minecraft/server/players/GameProfileCache.java -index 2a0cf0a8a79c09566c598197fc6f8c447d4bbd72..5e3bc0590e59770490b1c6c818d99be054214a8a 100644 +index 4038bb76339d43f18770624bd7fecc79b8d7f2a9..2456edc11b29a92b1648937cd3dd6a9a05706803 100644 --- a/src/main/java/net/minecraft/server/players/GameProfileCache.java +++ b/src/main/java/net/minecraft/server/players/GameProfileCache.java @@ -136,6 +136,17 @@ public class GameProfileCache { diff --git a/patches/server/0150-ProfileWhitelistVerifyEvent.patch b/patches/server/0150-ProfileWhitelistVerifyEvent.patch index 70f413bfc..150f0aa17 100644 --- a/patches/server/0150-ProfileWhitelistVerifyEvent.patch +++ b/patches/server/0150-ProfileWhitelistVerifyEvent.patch @@ -5,7 +5,7 @@ Subject: [PATCH] ProfileWhitelistVerifyEvent diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index f86d3dfcc19f6f9383d21044f61aa5246cf1f9e5..399735c923cfd52bd7b67beb9b974585ab507ca9 100644 +index 07a6b3e74600489f1076a73b3f02ad95891b22e7..808fd17a60c63ef96e702b0ffc9801f58bd0bde2 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java @@ -621,9 +621,9 @@ public abstract class PlayerList { @@ -33,7 +33,7 @@ index f86d3dfcc19f6f9383d21044f61aa5246cf1f9e5..399735c923cfd52bd7b67beb9b974585 + boolean isOp = this.ops.contains(gameprofile); + boolean isWhitelisted = !this.doWhiteList || isOp || this.whitelist.contains(gameprofile); + final com.destroystokyo.paper.event.profile.ProfileWhitelistVerifyEvent event; -+ event = new com.destroystokyo.paper.event.profile.ProfileWhitelistVerifyEvent(net.minecraft.server.MCUtil.toBukkit(gameprofile), this.doWhiteList, isWhitelisted, isOp, org.spigotmc.SpigotConfig.whitelistMessage); ++ event = new com.destroystokyo.paper.event.profile.ProfileWhitelistVerifyEvent(io.papermc.paper.util.MCUtil.toBukkit(gameprofile), this.doWhiteList, isWhitelisted, isOp, org.spigotmc.SpigotConfig.whitelistMessage); + event.callEvent(); + if (!event.isWhitelisted()) { + if (loginEvent != null) { diff --git a/patches/server/0168-AsyncTabCompleteEvent.patch b/patches/server/0168-AsyncTabCompleteEvent.patch index ddced4248..c55d2a5b5 100644 --- a/patches/server/0168-AsyncTabCompleteEvent.patch +++ b/patches/server/0168-AsyncTabCompleteEvent.patch @@ -89,7 +89,7 @@ index e40eeb5e04d96fb55283ded82cea0a5539a2fad5..90bd5c1a010a3a9d24328e5c71905360 @Override diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 7013b11fc0cd5fbb5a7e62be45d84d54d3052237..ca6bb66e8ba1e17f025b82091910ca223185ad3b 100644 +index 7013b11fc0cd5fbb5a7e62be45d84d54d3052237..bbf9550e7a7c78e961160ef09466e5f962172b6c 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -2086,7 +2086,7 @@ public final class CraftServer implements Server { @@ -97,7 +97,7 @@ index 7013b11fc0cd5fbb5a7e62be45d84d54d3052237..ca6bb66e8ba1e17f025b82091910ca22 } - TabCompleteEvent tabEvent = new TabCompleteEvent(player, message, offers); -+ TabCompleteEvent tabEvent = new TabCompleteEvent(player, message, offers, message.startsWith("/") || forceCommand, pos != null ? net.minecraft.server.MCUtil.toLocation(((CraftWorld) player.getWorld()).getHandle(), new BlockPos(pos)) : null); // Paper ++ TabCompleteEvent tabEvent = new TabCompleteEvent(player, message, offers, message.startsWith("/") || forceCommand, pos != null ? io.papermc.paper.util.MCUtil.toLocation(((CraftWorld) player.getWorld()).getHandle(), new BlockPos(pos)) : null); // Paper this.getPluginManager().callEvent(tabEvent); return tabEvent.isCancelled() ? Collections.EMPTY_LIST : tabEvent.getCompletions(); diff --git a/patches/server/0173-PreCreatureSpawnEvent.patch b/patches/server/0173-PreCreatureSpawnEvent.patch index 69bfbb5b3..3ad4668ba 100644 --- a/patches/server/0173-PreCreatureSpawnEvent.patch +++ b/patches/server/0173-PreCreatureSpawnEvent.patch @@ -15,7 +15,7 @@ instead and save a lot of server resources. See: https://github.com/PaperMC/Paper/issues/917 diff --git a/src/main/java/net/minecraft/util/SpawnUtil.java b/src/main/java/net/minecraft/util/SpawnUtil.java -index f4d1a3e861a8727d7f3efd75c0e83cc9418fa9bd..4f2952cb39be3644e81ae627b748b7916eed2304 100644 +index f4d1a3e861a8727d7f3efd75c0e83cc9418fa9bd..3fb910fadde4875c39523779ad24f381e45b6ab6 100644 --- a/src/main/java/net/minecraft/util/SpawnUtil.java +++ b/src/main/java/net/minecraft/util/SpawnUtil.java @@ -19,10 +19,10 @@ public class SpawnUtil { @@ -41,7 +41,7 @@ index f4d1a3e861a8727d7f3efd75c0e83cc9418fa9bd..4f2952cb39be3644e81ae627b748b791 + + com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event; + event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent( -+ net.minecraft.server.MCUtil.toLocation(worldserver, blockposition), ++ io.papermc.paper.util.MCUtil.toLocation(worldserver, blockposition), + type, + reason + ); @@ -59,7 +59,7 @@ index f4d1a3e861a8727d7f3efd75c0e83cc9418fa9bd..4f2952cb39be3644e81ae627b748b791 if (t0 != null) { diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java -index 2db27f5e3e3c1bb0502c055f78c4a81eb00fcf1b..4b8024f8f62caaa417de6798522c2beb98e00fc4 100644 +index 2db27f5e3e3c1bb0502c055f78c4a81eb00fcf1b..fdefccfa07227f315259f636076e36a120c72917 100644 --- a/src/main/java/net/minecraft/world/entity/EntityType.java +++ b/src/main/java/net/minecraft/world/entity/EntityType.java @@ -347,6 +347,20 @@ public class EntityType implements EntityTypeTest { @@ -71,7 +71,7 @@ index 2db27f5e3e3c1bb0502c055f78c4a81eb00fcf1b..4b8024f8f62caaa417de6798522c2beb + if (type != null) { + com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event; + event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent( -+ net.minecraft.server.MCUtil.toLocation(worldserver, blockposition), ++ io.papermc.paper.util.MCUtil.toLocation(worldserver, blockposition), + type, + spawnReason + ); @@ -97,7 +97,7 @@ index 25cd8a4101cf44955d95924c9794c238ddde2901..f957c0aca36b7228ac3a33ca04c948b1 } } diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java -index ac767d107ea0d856f3f8caccfe6f79b14e933005..ffb7a0b7c1ae53e1340f2cdb7840ee2c89982dbe 100644 +index ac767d107ea0d856f3f8caccfe6f79b14e933005..c41c1fa8085f502363c8273cd9fce1cf1743fe71 100644 --- a/src/main/java/net/minecraft/world/level/BaseSpawner.java +++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java @@ -124,6 +124,27 @@ public abstract class BaseSpawner { @@ -112,7 +112,7 @@ index ac767d107ea0d856f3f8caccfe6f79b14e933005..ffb7a0b7c1ae53e1340f2cdb7840ee2c + if (type != null) { + com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event; + event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent( -+ net.minecraft.server.MCUtil.toLocation(world, d0, d1, d2), ++ io.papermc.paper.util.MCUtil.toLocation(world, d0, d1, d2), + type, + org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER + ); @@ -129,7 +129,7 @@ index ac767d107ea0d856f3f8caccfe6f79b14e933005..ffb7a0b7c1ae53e1340f2cdb7840ee2c Entity entity = EntityType.loadEntityRecursive(nbttagcompound, world, (entity1) -> { entity1.moveTo(d0, d1, d2, entity1.getYRot(), entity1.getXRot()); diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -index c6ba7427b53398ddc8f0c942a810fad6e24561b4..08340299538f1adacddc6d5022482a5307c06f78 100644 +index c6ba7427b53398ddc8f0c942a810fad6e24561b4..c41390f5b9260bcfb843460904e1315695a1a972 100644 --- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java +++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java @@ -212,7 +212,13 @@ public final class NaturalSpawner { @@ -160,7 +160,7 @@ index c6ba7427b53398ddc8f0c942a810fad6e24561b4..08340299538f1adacddc6d5022482a53 + org.bukkit.entity.EntityType type = org.bukkit.entity.EntityType.fromName(EntityType.getKey(entitytypes).getPath()); + if (type != null) { + event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent( -+ net.minecraft.server.MCUtil.toLocation(world, pos), ++ io.papermc.paper.util.MCUtil.toLocation(world, pos), + type, SpawnReason.NATURAL + ); + if (!event.callEvent()) { diff --git a/patches/server/0234-Add-TNTPrimeEvent.patch b/patches/server/0234-Add-TNTPrimeEvent.patch index 95c3a89f2..805a9b380 100644 --- a/patches/server/0234-Add-TNTPrimeEvent.patch +++ b/patches/server/0234-Add-TNTPrimeEvent.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add TNTPrimeEvent diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java -index 1709126f0853edc6bece6f31d7c65a5f8955683a..6495b0421cab1b067b9483cc448222705c15578c 100644 +index 6eada8313e468e4ea851094976ac98c11710fb45..3f854bea2e6be82c7ad12b4d13064de8baec55c7 100644 --- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java +++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java @@ -532,6 +532,11 @@ public class EnderDragon extends Mob implements Enemy { @@ -21,7 +21,7 @@ index 1709126f0853edc6bece6f31d7c65a5f8955683a..6495b0421cab1b067b9483cc44822270 this.level.removeBlock(blockposition, false); diff --git a/src/main/java/net/minecraft/world/level/block/FireBlock.java b/src/main/java/net/minecraft/world/level/block/FireBlock.java -index 037902b3addd34dfc6b751ca225373a06c2d6a89..2188cfc34ab4bd67fac9aedd861a597c137a5c40 100644 +index 037902b3addd34dfc6b751ca225373a06c2d6a89..69903bad7b3e143b73b20624c06909458564396c 100644 --- a/src/main/java/net/minecraft/world/level/block/FireBlock.java +++ b/src/main/java/net/minecraft/world/level/block/FireBlock.java @@ -290,12 +290,19 @@ public class FireBlock extends BaseFireBlock { @@ -36,7 +36,7 @@ index 037902b3addd34dfc6b751ca225373a06c2d6a89..2188cfc34ab4bd67fac9aedd861a597c if (block instanceof TntBlock) { + // Paper start - TNTPrimeEvent -+ org.bukkit.block.Block tntBlock = net.minecraft.server.MCUtil.toBukkitBlock(world, blockposition); ++ org.bukkit.block.Block tntBlock = io.papermc.paper.util.MCUtil.toBukkitBlock(world, blockposition); + if (!new com.destroystokyo.paper.event.block.TNTPrimeEvent(tntBlock, com.destroystokyo.paper.event.block.TNTPrimeEvent.PrimeReason.FIRE, null).callEvent()) { + return; + } @@ -46,7 +46,7 @@ index 037902b3addd34dfc6b751ca225373a06c2d6a89..2188cfc34ab4bd67fac9aedd861a597c } } diff --git a/src/main/java/net/minecraft/world/level/block/TntBlock.java b/src/main/java/net/minecraft/world/level/block/TntBlock.java -index 9fcad0eb55a4a91a89ab8bce1f22d91127a94fb2..355448a08cca780f4f0b95e2abcdc87eb61de6dc 100644 +index 9fcad0eb55a4a91a89ab8bce1f22d91127a94fb2..dd0707bc0a9daf3cd5441a82e9d3502b53d2d0bf 100644 --- a/src/main/java/net/minecraft/world/level/block/TntBlock.java +++ b/src/main/java/net/minecraft/world/level/block/TntBlock.java @@ -38,6 +38,11 @@ public class TntBlock extends Block { @@ -54,7 +54,7 @@ index 9fcad0eb55a4a91a89ab8bce1f22d91127a94fb2..355448a08cca780f4f0b95e2abcdc87e if (!oldState.is(state.getBlock())) { if (world.hasNeighborSignal(pos)) { + // Paper start - TNTPrimeEvent -+ org.bukkit.block.Block tntBlock = net.minecraft.server.MCUtil.toBukkitBlock(world, pos);; ++ org.bukkit.block.Block tntBlock = io.papermc.paper.util.MCUtil.toBukkitBlock(world, pos);; + if(!new com.destroystokyo.paper.event.block.TNTPrimeEvent(tntBlock, com.destroystokyo.paper.event.block.TNTPrimeEvent.PrimeReason.REDSTONE, null).callEvent()) + return; + // Paper end @@ -66,7 +66,7 @@ index 9fcad0eb55a4a91a89ab8bce1f22d91127a94fb2..355448a08cca780f4f0b95e2abcdc87e public void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) { if (world.hasNeighborSignal(pos)) { + // Paper start - TNTPrimeEvent -+ org.bukkit.block.Block tntBlock = net.minecraft.server.MCUtil.toBukkitBlock(world, pos);; ++ org.bukkit.block.Block tntBlock = io.papermc.paper.util.MCUtil.toBukkitBlock(world, pos);; + if(!new com.destroystokyo.paper.event.block.TNTPrimeEvent(tntBlock, com.destroystokyo.paper.event.block.TNTPrimeEvent.PrimeReason.REDSTONE, null).callEvent()) + return; + // Paper end @@ -78,7 +78,7 @@ index 9fcad0eb55a4a91a89ab8bce1f22d91127a94fb2..355448a08cca780f4f0b95e2abcdc87e public void wasExploded(Level world, BlockPos pos, Explosion explosion) { if (!world.isClientSide) { + // Paper start - TNTPrimeEvent -+ org.bukkit.block.Block tntBlock = net.minecraft.server.MCUtil.toBukkitBlock(world, pos); ++ org.bukkit.block.Block tntBlock = io.papermc.paper.util.MCUtil.toBukkitBlock(world, pos); + org.bukkit.entity.Entity source = explosion.source != null ? explosion.source.getBukkitEntity() : null; + if(!new com.destroystokyo.paper.event.block.TNTPrimeEvent(tntBlock, com.destroystokyo.paper.event.block.TNTPrimeEvent.PrimeReason.EXPLOSION, source).callEvent()) + return; @@ -91,7 +91,7 @@ index 9fcad0eb55a4a91a89ab8bce1f22d91127a94fb2..355448a08cca780f4f0b95e2abcdc87e return super.use(state, world, pos, player, hand, hit); } else { + // Paper start - TNTPrimeEvent -+ org.bukkit.block.Block tntBlock = net.minecraft.server.MCUtil.toBukkitBlock(world, pos); ++ org.bukkit.block.Block tntBlock = io.papermc.paper.util.MCUtil.toBukkitBlock(world, pos); + if(!new com.destroystokyo.paper.event.block.TNTPrimeEvent(tntBlock, com.destroystokyo.paper.event.block.TNTPrimeEvent.PrimeReason.ITEM, player.getBukkitEntity()).callEvent()) + return InteractionResult.FAIL; + // Paper end @@ -103,7 +103,7 @@ index 9fcad0eb55a4a91a89ab8bce1f22d91127a94fb2..355448a08cca780f4f0b95e2abcdc87e } // CraftBukkit end + // Paper start - TNTPrimeEvent -+ org.bukkit.block.Block tntBlock = net.minecraft.server.MCUtil.toBukkitBlock(world, blockposition); ++ org.bukkit.block.Block tntBlock = io.papermc.paper.util.MCUtil.toBukkitBlock(world, blockposition); + if (!new com.destroystokyo.paper.event.block.TNTPrimeEvent(tntBlock, com.destroystokyo.paper.event.block.TNTPrimeEvent.PrimeReason.PROJECTILE, projectile.getBukkitEntity()).callEvent()) { + return; + } diff --git a/patches/server/0249-Add-PhantomPreSpawnEvent.patch b/patches/server/0249-Add-PhantomPreSpawnEvent.patch index f4862ce10..2f3dcd5f8 100644 --- a/patches/server/0249-Add-PhantomPreSpawnEvent.patch +++ b/patches/server/0249-Add-PhantomPreSpawnEvent.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add PhantomPreSpawnEvent diff --git a/src/main/java/net/minecraft/world/entity/monster/Phantom.java b/src/main/java/net/minecraft/world/entity/monster/Phantom.java -index c436476b3ec442b40a7ff122e6d3947a47ae163b..84400bb44d5deb7c79295a83c4c3c6aac88f3175 100644 +index c068eddb08898681735e483df5b9c36f5fef3878..0e96e9d7e4d636f4222f60cec556663f506c3906 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Phantom.java +++ b/src/main/java/net/minecraft/world/entity/monster/Phantom.java @@ -171,6 +171,11 @@ public class Phantom extends FlyingMob implements Enemy { @@ -48,14 +48,14 @@ index c436476b3ec442b40a7ff122e6d3947a47ae163b..84400bb44d5deb7c79295a83c4c3c6aa CIRCLE, SWOOP; diff --git a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java -index 573490a7c95746c3d372d258b2e592241258f6cf..e9d25aef08103ccdbc6a35c3ab67c1d921e9f45d 100644 +index 573490a7c95746c3d372d258b2e592241258f6cf..0dbb0c4d038379c6ffdae8528d98431e98faeb93 100644 --- a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java +++ b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java @@ -3,6 +3,7 @@ package net.minecraft.world.level.levelgen; import java.util.Iterator; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.stats.ServerStatsCounter; diff --git a/patches/server/0253-Add-ray-tracing-methods-to-LivingEntity.patch b/patches/server/0253-Add-ray-tracing-methods-to-LivingEntity.patch index b9856e2e2..e65b5a68c 100644 --- a/patches/server/0253-Add-ray-tracing-methods-to-LivingEntity.patch +++ b/patches/server/0253-Add-ray-tracing-methods-to-LivingEntity.patch @@ -4,11 +4,11 @@ Date: Mon, 3 Sep 2018 18:20:03 -0500 Subject: [PATCH] Add ray tracing methods to LivingEntity -diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java -index e98276943e1690572b8f7bc54a259aa8340bae41..c9b43d077727c22a9eca738e9a75e7f1a6a5a9ee 100644 ---- a/src/main/java/net/minecraft/server/MCUtil.java -+++ b/src/main/java/net/minecraft/server/MCUtil.java -@@ -509,6 +509,18 @@ public final class MCUtil { +diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java +index 4c5ed3de410c740bcaca37d84b153af6a482bf89..e9e1b9e4f487acad02e871c002f3d099c87766fb 100644 +--- a/src/main/java/io/papermc/paper/util/MCUtil.java ++++ b/src/main/java/io/papermc/paper/util/MCUtil.java +@@ -510,6 +510,18 @@ public final class MCUtil { return getNMSWorld(entity.getWorld()); } @@ -56,7 +56,7 @@ index 30983979f3501c693c7d1f96c47d9cfa1eaa243a..28a49c15c078b7afe1d3c9693c548f6a public int getShieldBlockingDelay() { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index 04829ced2048b07aa4b2dcf98a601d1fdd9431fb..40e777b859151d036ac7ec4e71ed896df4cd689b 100644 +index 04829ced2048b07aa4b2dcf98a601d1fdd9431fb..6c5cb2e5fb1f5bb7eb05a465a24d62e1dad57b93 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java @@ -200,6 +200,28 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { @@ -66,22 +66,22 @@ index 04829ced2048b07aa4b2dcf98a601d1fdd9431fb..40e777b859151d036ac7ec4e71ed896d + // Paper start + @Override + public Block getTargetBlock(int maxDistance, com.destroystokyo.paper.block.TargetBlockInfo.FluidMode fluidMode) { -+ net.minecraft.world.phys.HitResult rayTrace = getHandle().getRayTrace(maxDistance, net.minecraft.server.MCUtil.getNMSFluidCollisionOption(fluidMode)); ++ net.minecraft.world.phys.HitResult rayTrace = getHandle().getRayTrace(maxDistance, io.papermc.paper.util.MCUtil.getNMSFluidCollisionOption(fluidMode)); + return !(rayTrace instanceof net.minecraft.world.phys.BlockHitResult) ? null : org.bukkit.craftbukkit.block.CraftBlock.at(getHandle().level, ((net.minecraft.world.phys.BlockHitResult)rayTrace).getBlockPos()); + } + + @Override + public org.bukkit.block.BlockFace getTargetBlockFace(int maxDistance, com.destroystokyo.paper.block.TargetBlockInfo.FluidMode fluidMode) { -+ net.minecraft.world.phys.HitResult rayTrace = getHandle().getRayTrace(maxDistance, net.minecraft.server.MCUtil.getNMSFluidCollisionOption(fluidMode)); -+ return !(rayTrace instanceof net.minecraft.world.phys.BlockHitResult) ? null : net.minecraft.server.MCUtil.toBukkitBlockFace(((net.minecraft.world.phys.BlockHitResult)rayTrace).getDirection()); ++ net.minecraft.world.phys.HitResult rayTrace = getHandle().getRayTrace(maxDistance, io.papermc.paper.util.MCUtil.getNMSFluidCollisionOption(fluidMode)); ++ return !(rayTrace instanceof net.minecraft.world.phys.BlockHitResult) ? null : io.papermc.paper.util.MCUtil.toBukkitBlockFace(((net.minecraft.world.phys.BlockHitResult)rayTrace).getDirection()); + } + + @Override + public com.destroystokyo.paper.block.TargetBlockInfo getTargetBlockInfo(int maxDistance, com.destroystokyo.paper.block.TargetBlockInfo.FluidMode fluidMode) { -+ net.minecraft.world.phys.HitResult rayTrace = getHandle().getRayTrace(maxDistance, net.minecraft.server.MCUtil.getNMSFluidCollisionOption(fluidMode)); ++ net.minecraft.world.phys.HitResult rayTrace = getHandle().getRayTrace(maxDistance, io.papermc.paper.util.MCUtil.getNMSFluidCollisionOption(fluidMode)); + return !(rayTrace instanceof net.minecraft.world.phys.BlockHitResult) ? null : + new com.destroystokyo.paper.block.TargetBlockInfo(org.bukkit.craftbukkit.block.CraftBlock.at(getHandle().level, ((net.minecraft.world.phys.BlockHitResult)rayTrace).getBlockPos()), -+ net.minecraft.server.MCUtil.toBukkitBlockFace(((net.minecraft.world.phys.BlockHitResult)rayTrace).getDirection())); ++ io.papermc.paper.util.MCUtil.toBukkitBlockFace(((net.minecraft.world.phys.BlockHitResult)rayTrace).getDirection())); + } + // Paper end + diff --git a/patches/server/0263-Catch-JsonParseException-in-Entity-and-TE-names.patch b/patches/server/0263-Catch-JsonParseException-in-Entity-and-TE-names.patch index d823af915..7e49a60f5 100644 --- a/patches/server/0263-Catch-JsonParseException-in-Entity-and-TE-names.patch +++ b/patches/server/0263-Catch-JsonParseException-in-Entity-and-TE-names.patch @@ -12,20 +12,20 @@ Shulkers) may need to be changed in order for it to re-save properly No more crashing though. -diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java -index c9b43d077727c22a9eca738e9a75e7f1a6a5a9ee..99f56658c70f99592fb40c9df0ce3e47053d1bd5 100644 ---- a/src/main/java/net/minecraft/server/MCUtil.java -+++ b/src/main/java/net/minecraft/server/MCUtil.java -@@ -13,6 +13,8 @@ import java.lang.ref.Cleaner; - import it.unimi.dsi.fastutil.objects.ReferenceArrayList; +diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java +index e9e1b9e4f487acad02e871c002f3d099c87766fb..e63dc33250831428c2cef34e02238600231fb815 100644 +--- a/src/main/java/io/papermc/paper/util/MCUtil.java ++++ b/src/main/java/io/papermc/paper/util/MCUtil.java +@@ -14,6 +14,8 @@ import it.unimi.dsi.fastutil.objects.ReferenceArrayList; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; + import net.minecraft.server.MinecraftServer; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.DistanceManager; -@@ -540,6 +542,21 @@ public final class MCUtil { +@@ -541,6 +543,21 @@ public final class MCUtil { } } @@ -48,7 +48,7 @@ index c9b43d077727c22a9eca738e9a75e7f1a6a5a9ee..99f56658c70f99592fb40c9df0ce3e47 return chunk.getChunkHolderStatus(); } diff --git a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java -index a0728e95251e8110bcecd00512c7a266fe120794..da504702bc9423774b35dff792d2dbe7fc270fe3 100644 +index a0728e95251e8110bcecd00512c7a266fe120794..7dac559fd35e7ba646b84bb28315001375723643 100644 --- a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java +++ b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java @@ -72,7 +72,7 @@ public abstract class BaseCommandBlock implements CommandSource { @@ -56,12 +56,12 @@ index a0728e95251e8110bcecd00512c7a266fe120794..da504702bc9423774b35dff792d2dbe7 this.successCount = nbt.getInt("SuccessCount"); if (nbt.contains("CustomName", 8)) { - this.setName(Component.Serializer.fromJson(nbt.getString("CustomName"))); -+ this.setName(net.minecraft.server.MCUtil.getBaseComponentFromNbt("CustomName", nbt)); // Paper - Catch ParseException ++ this.setName(io.papermc.paper.util.MCUtil.getBaseComponentFromNbt("CustomName", nbt)); // Paper - Catch ParseException } if (nbt.contains("TrackOutput", 1)) { diff --git a/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java -index 601cf7b9aa4b3483a2134a2db0d617ed8938ea48..c6ce5dc5dafc15f1f12b0ea4c9d55325f6a76529 100644 +index 601cf7b9aa4b3483a2134a2db0d617ed8938ea48..cef6a9795b289b791db29f9018585e5912634b39 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java @@ -98,7 +98,7 @@ public class BannerBlockEntity extends BlockEntity implements Nameable { @@ -69,12 +69,12 @@ index 601cf7b9aa4b3483a2134a2db0d617ed8938ea48..c6ce5dc5dafc15f1f12b0ea4c9d55325 super.load(nbt); if (nbt.contains("CustomName", 8)) { - this.name = Component.Serializer.fromJson(nbt.getString("CustomName")); -+ this.name = net.minecraft.server.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException ++ this.name = io.papermc.paper.util.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException } this.itemPatterns = nbt.getList("Patterns", 10); diff --git a/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java -index a34ae15cd4048bda965fd1449c75f3bd8f0e530b..adf67868eef7d578b7858a5afd54e37ea0d5102f 100644 +index a34ae15cd4048bda965fd1449c75f3bd8f0e530b..f1b5a7e29d2a94c18c0d06b066b8cfbccabbc0a1 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java @@ -30,7 +30,7 @@ public abstract class BaseContainerBlockEntity extends BlockEntity implements Co @@ -82,12 +82,12 @@ index a34ae15cd4048bda965fd1449c75f3bd8f0e530b..adf67868eef7d578b7858a5afd54e37e this.lockKey = LockCode.fromTag(nbt); if (nbt.contains("CustomName", 8)) { - this.name = Component.Serializer.fromJson(nbt.getString("CustomName")); -+ this.name = net.minecraft.server.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException ++ this.name = io.papermc.paper.util.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException } } diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -index 0c699c08ef85ca3339ada5c869b571581092a11d..349b89dd4d34b92d1077ddadb30c36642fd85622 100644 +index 0c699c08ef85ca3339ada5c869b571581092a11d..12bb07ba7bcb37a26c0492e045b42289bfec70db 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java @@ -365,7 +365,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider { @@ -95,12 +95,12 @@ index 0c699c08ef85ca3339ada5c869b571581092a11d..349b89dd4d34b92d1077ddadb30c3664 // CraftBukkit end if (nbt.contains("CustomName", 8)) { - this.name = Component.Serializer.fromJson(nbt.getString("CustomName")); -+ this.name = net.minecraft.server.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException ++ this.name = io.papermc.paper.util.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException } this.lockKey = LockCode.fromTag(nbt); diff --git a/src/main/java/net/minecraft/world/level/block/entity/EnchantmentTableBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/EnchantmentTableBlockEntity.java -index 3a8bdb788b07b0a8cda3d4b872ede52ca9a005c4..2341a5a249d455628165fc6ba508fc6d70c3dbfb 100644 +index 3a8bdb788b07b0a8cda3d4b872ede52ca9a005c4..65e1381bb2d10bd212463feb602c60f8fdb9ade1 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/EnchantmentTableBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/EnchantmentTableBlockEntity.java @@ -42,7 +42,7 @@ public class EnchantmentTableBlockEntity extends BlockEntity implements Nameable @@ -108,7 +108,7 @@ index 3a8bdb788b07b0a8cda3d4b872ede52ca9a005c4..2341a5a249d455628165fc6ba508fc6d super.load(nbt); if (nbt.contains("CustomName", 8)) { - this.name = Component.Serializer.fromJson(nbt.getString("CustomName")); -+ this.name = net.minecraft.server.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException ++ this.name = io.papermc.paper.util.MCUtil.getBaseComponentFromNbt("CustomName", nbt); // Paper - Catch ParseException } } diff --git a/patches/server/0267-PreSpawnerSpawnEvent.patch b/patches/server/0267-PreSpawnerSpawnEvent.patch index ad93f9fba..a6c42252d 100644 --- a/patches/server/0267-PreSpawnerSpawnEvent.patch +++ b/patches/server/0267-PreSpawnerSpawnEvent.patch @@ -9,7 +9,7 @@ SpawnerSpawnEvent gets called instead of the CreatureSpawnEvent for spawners. diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java -index ffb7a0b7c1ae53e1340f2cdb7840ee2c89982dbe..0be0c7a323277093a6f8e476048eb9ee8712cbc9 100644 +index c41c1fa8085f502363c8273cd9fce1cf1743fe71..92e3bb8b59d79cbe79fa55a7db443bd7a1957914 100644 --- a/src/main/java/net/minecraft/world/level/BaseSpawner.java +++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java @@ -130,11 +130,11 @@ public abstract class BaseSpawner { @@ -20,10 +20,10 @@ index ffb7a0b7c1ae53e1340f2cdb7840ee2c89982dbe..0be0c7a323277093a6f8e476048eb9ee - event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent( + com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent event; + event = new com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent( - net.minecraft.server.MCUtil.toLocation(world, d0, d1, d2), + io.papermc.paper.util.MCUtil.toLocation(world, d0, d1, d2), type, - org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER -+ net.minecraft.server.MCUtil.toLocation(world, pos) ++ io.papermc.paper.util.MCUtil.toLocation(world, pos) ); if (!event.callEvent()) { flag = true; diff --git a/patches/server/0268-Add-LivingEntity-getTargetEntity.patch b/patches/server/0268-Add-LivingEntity-getTargetEntity.patch index 2842a11a1..4d7cddef8 100644 --- a/patches/server/0268-Add-LivingEntity-getTargetEntity.patch +++ b/patches/server/0268-Add-LivingEntity-getTargetEntity.patch @@ -56,7 +56,7 @@ index 1189ddcab5011d34a66356cde561fe7e2cecbfdd..8155421080761734c519042e1c24dd2e public int getShieldBlockingDelay() { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java -index 40e777b859151d036ac7ec4e71ed896df4cd689b..fb92f55ae3c8c54edce7565b27fb84f50ee85702 100644 +index 6c5cb2e5fb1f5bb7eb05a465a24d62e1dad57b93..bfa6b088f87117015791dc4ab25d8e8cf4c4cf28 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java @@ -1,5 +1,6 @@ @@ -68,7 +68,7 @@ index 40e777b859151d036ac7ec4e71ed896df4cd689b..fb92f55ae3c8c54edce7565b27fb84f5 import java.util.ArrayList; @@ -220,6 +221,33 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { new com.destroystokyo.paper.block.TargetBlockInfo(org.bukkit.craftbukkit.block.CraftBlock.at(getHandle().level, ((net.minecraft.world.phys.BlockHitResult)rayTrace).getBlockPos()), - net.minecraft.server.MCUtil.toBukkitBlockFace(((net.minecraft.world.phys.BlockHitResult)rayTrace).getDirection())); + io.papermc.paper.util.MCUtil.toBukkitBlockFace(((net.minecraft.world.phys.BlockHitResult)rayTrace).getDirection())); } + + public Entity getTargetEntity(int maxDistance, boolean ignoreBlocks) { diff --git a/patches/server/0270-Turtle-API.patch b/patches/server/0270-Turtle-API.patch index 1bc654471..9b44db2ee 100644 --- a/patches/server/0270-Turtle-API.patch +++ b/patches/server/0270-Turtle-API.patch @@ -18,7 +18,7 @@ index e3983370c09e3e3445c4557fcca50dd25f29cba0..6efba52c2e5d7811ee329ed22c1c76f7 private final int searchRange; private final int verticalSearchRange; diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java -index 37125ffe47fcd5fe93ab62ad8a46e8188f362436..69c98c2cb2fd8f149a39bbddcbfe0c5c5adc3904 100644 +index 37125ffe47fcd5fe93ab62ad8a46e8188f362436..0cea2eacfe3264a9b3500dc3a6a19d21d74d54e9 100644 --- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java +++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java @@ -480,14 +480,17 @@ public class Turtle extends Animal { @@ -26,7 +26,7 @@ index 37125ffe47fcd5fe93ab62ad8a46e8188f362436..69c98c2cb2fd8f149a39bbddcbfe0c5c if (!this.turtle.isInWater() && this.isReachedTarget()) { if (this.turtle.layEggCounter < 1) { - this.turtle.setLayingEgg(true); -+ this.turtle.setLayingEgg(new com.destroystokyo.paper.event.entity.TurtleStartDiggingEvent((org.bukkit.entity.Turtle) this.turtle.getBukkitEntity(), net.minecraft.server.MCUtil.toLocation(this.turtle.level, this.getTargetPosition())).callEvent()); // Paper ++ this.turtle.setLayingEgg(new com.destroystokyo.paper.event.entity.TurtleStartDiggingEvent((org.bukkit.entity.Turtle) this.turtle.getBukkitEntity(), io.papermc.paper.util.MCUtil.toLocation(this.turtle.level, this.getTargetPosition())).callEvent()); // Paper } else if (this.turtle.layEggCounter > this.adjustedTickDelay(200)) { Level world = this.turtle.level; @@ -34,7 +34,7 @@ index 37125ffe47fcd5fe93ab62ad8a46e8188f362436..69c98c2cb2fd8f149a39bbddcbfe0c5c - if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.turtle, this.blockPos.above(), (BlockState) Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, this.turtle.random.nextInt(4) + 1)).isCancelled()) { + // Paper start + int eggCount = this.turtle.random.nextInt(4) + 1; -+ com.destroystokyo.paper.event.entity.TurtleLayEggEvent layEggEvent = new com.destroystokyo.paper.event.entity.TurtleLayEggEvent((org.bukkit.entity.Turtle) this.turtle.getBukkitEntity(), net.minecraft.server.MCUtil.toLocation(this.turtle.level, this.blockPos.above()), eggCount); ++ com.destroystokyo.paper.event.entity.TurtleLayEggEvent layEggEvent = new com.destroystokyo.paper.event.entity.TurtleLayEggEvent((org.bukkit.entity.Turtle) this.turtle.getBukkitEntity(), io.papermc.paper.util.MCUtil.toLocation(this.turtle.level, this.blockPos.above()), eggCount); + if (layEggEvent.callEvent() && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.turtle, this.blockPos.above(), Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, layEggEvent.getEggCount())).isCancelled()) { world.playSound((Player) null, blockposition, SoundEvents.TURTLE_LAY_EGG, SoundSource.BLOCKS, 0.3F, 0.9F + world.random.nextFloat() * 0.2F); - world.setBlock(this.blockPos.above(), (BlockState) Blocks.TURTLE_EGG.defaultBlockState().setValue(TurtleEggBlock.EGGS, this.turtle.random.nextInt(4) + 1), 3); @@ -52,7 +52,7 @@ index 37125ffe47fcd5fe93ab62ad8a46e8188f362436..69c98c2cb2fd8f149a39bbddcbfe0c5c @Override diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTurtle.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTurtle.java -index 96462a29551c301d3c80029cab2bec3839914237..318f7bc921283ad83daebbf6080821cdc53b2257 100644 +index 96462a29551c301d3c80029cab2bec3839914237..a14d0a688b9054988b5c86c94738e4aaca9f9cfd 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTurtle.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTurtle.java @@ -34,4 +34,31 @@ public class CraftTurtle extends CraftAnimals implements Turtle { @@ -63,12 +63,12 @@ index 96462a29551c301d3c80029cab2bec3839914237..318f7bc921283ad83daebbf6080821cd + // Paper start + @Override + public org.bukkit.Location getHome() { -+ return net.minecraft.server.MCUtil.toLocation(getHandle().getLevel(), getHandle().getHomePos()); ++ return io.papermc.paper.util.MCUtil.toLocation(getHandle().getLevel(), getHandle().getHomePos()); + } + + @Override + public void setHome(org.bukkit.Location location) { -+ getHandle().setHomePos(net.minecraft.server.MCUtil.toBlockPosition(location)); ++ getHandle().setHomePos(io.papermc.paper.util.MCUtil.toBlockPosition(location)); + } + + @Override diff --git a/patches/server/0278-Improve-Server-Thread-Pool-and-Thread-Priorities.patch b/patches/server/0278-Improve-Server-Thread-Pool-and-Thread-Priorities.patch index fdb06e3b5..6534fddcb 100644 --- a/patches/server/0278-Improve-Server-Thread-Pool-and-Thread-Priorities.patch +++ b/patches/server/0278-Improve-Server-Thread-Pool-and-Thread-Priorities.patch @@ -11,8 +11,28 @@ server threads Allow usage of a single thread executor by not using ForkJoin so single core CPU's. +diff --git a/src/main/java/io/papermc/paper/util/ServerWorkerThread.java b/src/main/java/io/papermc/paper/util/ServerWorkerThread.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b60f59cf5cc8eb84a6055b7861857dece7f2501b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/util/ServerWorkerThread.java +@@ -0,0 +1,14 @@ ++package io.papermc.paper.util; ++ ++import java.util.concurrent.atomic.AtomicInteger; ++import net.minecraft.Util; ++ ++public class ServerWorkerThread extends Thread { ++ private static final AtomicInteger threadId = new AtomicInteger(1); ++ public ServerWorkerThread(Runnable target, String poolName, int prioritityModifier) { ++ super(target, "Worker-" + poolName + "-" + threadId.getAndIncrement()); ++ setPriority(Thread.NORM_PRIORITY+prioritityModifier); // Deprioritize over main ++ this.setDaemon(true); ++ this.setUncaughtExceptionHandler(Util::onThreadException); ++ } ++} diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java -index 336a26733b5bf73455f8ec10347c1e08b8e866f7..4fce18c52c8144460ebf0c1e336dce712d796cc6 100644 +index 336a26733b5bf73455f8ec10347c1e08b8e866f7..0773447354542925826369625f21e26aa30ebff4 100644 --- a/src/main/java/net/minecraft/Util.java +++ b/src/main/java/net/minecraft/Util.java @@ -79,8 +79,8 @@ public class Util { @@ -43,7 +63,7 @@ index 336a26733b5bf73455f8ec10347c1e08b8e866f7..4fce18c52c8144460ebf0c1e336dce71 } else { - executorService = new ForkJoinPool(i, (forkJoinPool) -> { - ForkJoinWorkerThread forkJoinWorkerThread = new ForkJoinWorkerThread(forkJoinPool) { -+ executorService = new java.util.concurrent.ThreadPoolExecutor(i, i,0L, TimeUnit.MILLISECONDS, new java.util.concurrent.LinkedBlockingQueue(), target -> new net.minecraft.server.ServerWorkerThread(target, s, priorityModifier)); ++ executorService = new java.util.concurrent.ThreadPoolExecutor(i, i,0L, TimeUnit.MILLISECONDS, new java.util.concurrent.LinkedBlockingQueue(), target -> new io.papermc.paper.util.ServerWorkerThread(target, s, priorityModifier)); + } + /* @Override @@ -58,7 +78,7 @@ index 336a26733b5bf73455f8ec10347c1e08b8e866f7..4fce18c52c8144460ebf0c1e336dce71 return executorService; } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index afce3acc552df092636b205964e06b399b7db8e2..5e1a0ab40d9d03844c6e0b962bb15d3b4b40d229 100644 +index 25aac194eb486a5b8707aa0a655fd8259ad7409c..6afa9ab5cb864ff286341582d6d70648d8a86efb 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -306,6 +306,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop> { @@ -115,7 +115,7 @@ index dd9c03611e410e601ba4a7769474fada8c28c104..a283cce82069bf5dfd64229d102a19df + } + packet.onPacketDispatch(getPlayer()); + if (connected && (InnerUtil.canSendImmediate(this, packet) || ( -+ net.minecraft.server.MCUtil.isMainThread() && packet.isReady() && this.queue.isEmpty() && ++ io.papermc.paper.util.MCUtil.isMainThread() && packet.isReady() && this.queue.isEmpty() && + (packet.getExtraPackets() == null || packet.getExtraPackets().isEmpty()) + ))) { this.sendPacket(packet, callbacks); @@ -194,7 +194,7 @@ index dd9c03611e410e601ba4a7769474fada8c28c104..a283cce82069bf5dfd64229d102a19df + if (!isConnected()) { + return true; + } -+ if (net.minecraft.server.MCUtil.isMainThread()) { ++ if (io.papermc.paper.util.MCUtil.isMainThread()) { + return processQueue(); + } else if (isPending) { + // Should only happen during login/status stages diff --git a/patches/server/0318-Configurable-Keep-Spawn-Loaded-range-per-world.patch b/patches/server/0318-Configurable-Keep-Spawn-Loaded-range-per-world.patch index 700270f15..b1bbb4112 100644 --- a/patches/server/0318-Configurable-Keep-Spawn-Loaded-range-per-world.patch +++ b/patches/server/0318-Configurable-Keep-Spawn-Loaded-range-per-world.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Configurable Keep Spawn Loaded range per world This lets you disable it for some worlds and lower it for others. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index f9a96a11764b66709a0d74122f9ecc06d0365a93..d6ca6ef7262e25620aceda589d21363193c70310 100644 +index 412380f4bfe8a2d50090904124242e8b2c7bfa1b..1a21f7e590aaeca131256dd7079b9546710ca9ad 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -729,31 +729,34 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { @@ -57,7 +57,7 @@ index 8390ce194ccc692139c0e870c16a7fb76ac8ba68..95e22c91bc701785f4804e5d4e0a6b42 } + // Paper start - ensure we don't load chunks + final @Nullable Entity source = this.context instanceof net.minecraft.world.phys.shapes.EntityCollisionContext entityContext ? entityContext.getEntity() : null; -+ boolean far = source != null && net.minecraft.server.MCUtil.distanceSq(source.getX(), y, source.getZ(), x, y, z) > 14; ++ boolean far = source != null && io.papermc.paper.util.MCUtil.distanceSq(source.getX(), y, source.getZ(), x, y, z) > 14; + this.pos.set(x, y, z); - BlockGetter blockGetter = this.getChunk(i, k); diff --git a/patches/server/0387-Load-Chunks-for-Login-Asynchronously.patch b/patches/server/0387-Load-Chunks-for-Login-Asynchronously.patch index 38078f50e..75ce446f8 100644 --- a/patches/server/0387-Load-Chunks-for-Login-Asynchronously.patch +++ b/patches/server/0387-Load-Chunks-for-Login-Asynchronously.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Load Chunks for Login Asynchronously diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 5a2797104d43d5981fe0d4599c0abbbf8658f153..c0e17bbf04723da76ea6952d9558dd4d34b00f6c 100644 +index 7cc21dab89dcb50ee4034e1e39b6a27478fd983b..652d30ce735aa265db848ca73a48d7b0b143103b 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -170,6 +170,7 @@ import org.bukkit.event.world.GenericGameEvent; @@ -103,7 +103,7 @@ index 6fd0e5a97d0ed9155b12dac94c075e1225a22e93..c16cb8ebe28987f1630fe659dfa43726 try { ServerPlayer entityplayer1 = this.server.getPlayerList().getPlayerForLogin(this.gameProfile, s); // CraftBukkit - add player reference diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 1096e24835194f20425f75228cafe62adebc2282..f37787b9d018a624b509612729f18ca077b55f55 100644 +index 36aef2836246a33b879b3da3e988539f8615efc5..f5705346debdc940e5b5b3b54a140e3dc0228cb0 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java @@ -139,6 +139,7 @@ public abstract class PlayerList { @@ -166,7 +166,7 @@ index 1096e24835194f20425f75228cafe62adebc2282..f37787b9d018a624b509612729f18ca0 + final net.minecraft.world.level.ChunkPos pos = new net.minecraft.world.level.ChunkPos(chunkX, chunkZ); + net.minecraft.server.level.ChunkMap playerChunkMap = worldserver1.getChunkSource().chunkMap; + net.minecraft.server.level.DistanceManager distanceManager = playerChunkMap.distanceManager; -+ net.minecraft.server.ChunkSystem.scheduleTickingState( ++ io.papermc.paper.chunk.system.ChunkSystem.scheduleTickingState( + worldserver1, chunkX, chunkZ, net.minecraft.server.level.ChunkHolder.FullChunkStatus.ENTITY_TICKING, true, + ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.HIGHEST, + (chunk) -> { @@ -266,7 +266,7 @@ index 1096e24835194f20425f75228cafe62adebc2282..f37787b9d018a624b509612729f18ca0 Iterator iterator = list.iterator(); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index b92dff790cfe699c3e6a036f1377c3052373fe05..237127907c3c8ddcd16bdc9645e84a2d0b922440 100644 +index a2750cba8540caa9f12f5d5179b51f7753d38bba..e5c5a514e6b7bdf663d33074557e34372f18ea77 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -1219,7 +1219,7 @@ public final class CraftServer implements Server { diff --git a/patches/server/0415-Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch b/patches/server/0415-Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch index 90f095a70..a4f92249c 100644 --- a/patches/server/0415-Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch +++ b/patches/server/0415-Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Optimize anyPlayerCloseEnoughForSpawning to use distance maps Use a distance map to find the players in range quickly diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java -index b550f302b1bb6ef92987c8c3431b94c3ba3a091d..2add24517d38708a84e7f8ec25fbe9c62309375e 100644 +index 2ba3bb4e5670ece798a8882801a856d82851c00a..a61f55ed1fbe5aac5289014cb95cb6950b4c77fa 100644 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java @@ -83,16 +83,29 @@ public class ChunkHolder { @@ -15,7 +15,7 @@ index b550f302b1bb6ef92987c8c3431b94c3ba3a091d..2add24517d38708a84e7f8ec25fbe9c6 public void onChunkAdd() { - + // Paper start - optimise anyPlayerCloseEnoughForSpawning -+ long key = net.minecraft.server.MCUtil.getCoordinateKey(this.pos); ++ long key = io.papermc.paper.util.MCUtil.getCoordinateKey(this.pos); + this.playersInMobSpawnRange = this.chunkMap.playerMobSpawnMap.getObjectsInRange(key); + this.playersInChunkTickRange = this.chunkMap.playerChunkTickRangeMap.getObjectsInRange(key); + // Paper end - optimise anyPlayerCloseEnoughForSpawning @@ -42,7 +42,7 @@ index b550f302b1bb6ef92987c8c3431b94c3ba3a091d..2add24517d38708a84e7f8ec25fbe9c6 this.newChunkHolder = newChunkHolder; // Paper - rewrite chunk system this.chunkToSaveHistory = null; diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 8dce24ae70057115feff193a1307eb2437e16773..50e9d29b5a0ea6d11a44c41c49d6f52bc464e6e2 100644 +index 999a675dd42c37b27e40d1a32b77641188b8d432..63536642f005b6936734397e2347c504084f3f6c 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -152,12 +152,24 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -69,7 +69,7 @@ index 8dce24ae70057115feff193a1307eb2437e16773..50e9d29b5a0ea6d11a44c41c49d6f52b + this.playerChunkTickRangeMap.add(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise ChunkMap#anyPlayerCloseEnoughForSpawning // Paper start - per player mob spawning if (this.playerMobDistanceMap != null) { - this.playerMobDistanceMap.add(player, chunkX, chunkZ, net.minecraft.server.ChunkSystem.getTickViewDistance(player)); + this.playerMobDistanceMap.add(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player)); @@ -168,6 +180,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider void removePlayerFromDistanceMaps(ServerPlayer player) { this.playerChunkManager.removePlayer(player); // Paper - replace chunk loader @@ -88,7 +88,7 @@ index 8dce24ae70057115feff193a1307eb2437e16773..50e9d29b5a0ea6d11a44c41c49d6f52b + this.playerChunkTickRangeMap.update(player, chunkX, chunkZ, DistanceManager.MOB_SPAWN_RANGE); // Paper - optimise ChunkMap#anyPlayerCloseEnoughForSpawning // Paper start - per player mob spawning if (this.playerMobDistanceMap != null) { - this.playerMobDistanceMap.update(player, chunkX, chunkZ, net.minecraft.server.ChunkSystem.getTickViewDistance(player)); + this.playerMobDistanceMap.update(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player)); @@ -267,6 +284,38 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.regionManagers.add(this.dataRegionManager); // Paper end @@ -262,7 +262,7 @@ index d3c3db919e9b0507e8543313d9028394e5163673..52cba8f68d274cce106304aef1249a95 public String getDebugStatus() { diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 60264feb656861d5a9474fe4285ac69d8d12269e..44766ea7e5dd8f8411b52cf259187d7557cc0c23 100644 +index 8a20fa6d1c357f6d9787032c31dd0d0f80bd74be..67bcda3e1d343b59dd1842f5eb982a71859d4d7b 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java @@ -657,6 +657,37 @@ public class ServerChunkCache extends ChunkSource { @@ -292,8 +292,8 @@ index 60264feb656861d5a9474fe4285ac69d8d12269e..44766ea7e5dd8f8411b52cf259187d75 + } + + int range = Math.min(event.getSpawnRadius(), 32); // limit to max view distance -+ int chunkX = net.minecraft.server.MCUtil.getChunkCoordinate(player.getX()); -+ int chunkZ = net.minecraft.server.MCUtil.getChunkCoordinate(player.getZ()); ++ int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX()); ++ int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ()); + + playerChunkMap.playerMobSpawnMap.addOrUpdate(player, chunkX, chunkZ, range); + player.lastEntitySpawnRadiusSquared = (double)((range << 4) * (range << 4)); // used in anyPlayerCloseEnoughForSpawning diff --git a/patches/server/0416-Use-distance-map-to-optimise-entity-tracker.patch b/patches/server/0416-Use-distance-map-to-optimise-entity-tracker.patch index 0f18b0a60..e77a5566d 100644 --- a/patches/server/0416-Use-distance-map-to-optimise-entity-tracker.patch +++ b/patches/server/0416-Use-distance-map-to-optimise-entity-tracker.patch @@ -6,13 +6,13 @@ Subject: [PATCH] Use distance map to optimise entity tracker Use the distance map to find candidate players for tracking. diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index a25ef2f2362b6f9b0cc8bfb33b6da66dc0f59347..e75b72d7bb51e50b46e639fbff4d9a01533f50c8 100644 +index 63536642f005b6936734397e2347c504084f3f6c..ed6e0a186dba26bee5ebcc02120c24ecb38d6892 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -66,6 +66,7 @@ import net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket; import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket; import net.minecraft.network.protocol.game.DebugPackets; - import net.minecraft.server.MCUtil; + import io.papermc.paper.util.MCUtil; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.server.network.ServerPlayerConnection; @@ -42,7 +42,7 @@ index a25ef2f2362b6f9b0cc8bfb33b6da66dc0f59347..e75b72d7bb51e50b46e639fbff4d9a01 void addPlayerToDistanceMaps(ServerPlayer player) { this.playerChunkManager.addPlayer(player); // Paper - replace chunk loader @@ -175,6 +193,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - this.playerMobDistanceMap.add(player, chunkX, chunkZ, net.minecraft.server.ChunkSystem.getTickViewDistance(player)); + this.playerMobDistanceMap.add(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player)); } // Paper end - per player mob spawning + // Paper start - use distance map to optimise entity tracker @@ -50,7 +50,7 @@ index a25ef2f2362b6f9b0cc8bfb33b6da66dc0f59347..e75b72d7bb51e50b46e639fbff4d9a01 + com.destroystokyo.paper.util.misc.PlayerAreaMap trackMap = this.playerEntityTrackerTrackMaps[i]; + int trackRange = this.entityTrackerTrackRanges[i]; + -+ trackMap.add(player, chunkX, chunkZ, Math.min(trackRange, net.minecraft.server.ChunkSystem.getSendViewDistance(player))); ++ trackMap.add(player, chunkX, chunkZ, Math.min(trackRange, io.papermc.paper.chunk.system.ChunkSystem.getSendViewDistance(player))); + } + // Paper end - use distance map to optimise entity tracker } @@ -69,7 +69,7 @@ index a25ef2f2362b6f9b0cc8bfb33b6da66dc0f59347..e75b72d7bb51e50b46e639fbff4d9a01 void updateMaps(ServerPlayer player) { @@ -202,6 +233,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - this.playerMobDistanceMap.update(player, chunkX, chunkZ, net.minecraft.server.ChunkSystem.getTickViewDistance(player)); + this.playerMobDistanceMap.update(player, chunkX, chunkZ, io.papermc.paper.chunk.system.ChunkSystem.getTickViewDistance(player)); } // Paper end - per player mob spawning + // Paper start - use distance map to optimise entity tracker @@ -77,7 +77,7 @@ index a25ef2f2362b6f9b0cc8bfb33b6da66dc0f59347..e75b72d7bb51e50b46e639fbff4d9a01 + com.destroystokyo.paper.util.misc.PlayerAreaMap trackMap = this.playerEntityTrackerTrackMaps[i]; + int trackRange = this.entityTrackerTrackRanges[i]; + -+ trackMap.update(player, chunkX, chunkZ, Math.min(trackRange, net.minecraft.server.ChunkSystem.getSendViewDistance(player))); ++ trackMap.update(player, chunkX, chunkZ, Math.min(trackRange, io.papermc.paper.chunk.system.ChunkSystem.getSendViewDistance(player))); + } + // Paper end - use distance map to optimise entity tracker } @@ -287,14 +287,14 @@ index a25ef2f2362b6f9b0cc8bfb33b6da66dc0f59347..e75b72d7bb51e50b46e639fbff4d9a01 return object instanceof ChunkMap.TrackedEntity ? ((ChunkMap.TrackedEntity) object).entity.getId() == this.entity.getId() : false; } diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 32623f90a5bc4fb6fe99897c682ef4f55f056dea..6a86125c6f6daa0a443601db4fea19531225ad33 100644 +index 32623f90a5bc4fb6fe99897c682ef4f55f056dea..26c8b19d484032f5d0935ba8672a3121a3197d67 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -57,6 +57,7 @@ import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; diff --git a/patches/server/0436-Add-Plugin-Tickets-to-API-Chunk-Methods.patch b/patches/server/0436-Add-Plugin-Tickets-to-API-Chunk-Methods.patch index a7cfa1542..966d38356 100644 --- a/patches/server/0436-Add-Plugin-Tickets-to-API-Chunk-Methods.patch +++ b/patches/server/0436-Add-Plugin-Tickets-to-API-Chunk-Methods.patch @@ -22,7 +22,7 @@ wants it to collect even faster, they can restore that setting back to 1 instead Not adding it to .getType() though to keep behavior consistent with vanilla for performance reasons. diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 262d550e739928fc5f203432138fdcaf6ccb8ddb..007b85cfda82d245ae336efc26aa38ad2f6d2c28 100644 +index 4c6c9aa8b3305f5ab4f7b8d356e860da169fb1db..2aab13270af76bcc1b62787e9910d23d5ab56add 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -360,7 +360,7 @@ public final class CraftServer implements Server { @@ -44,7 +44,7 @@ index 262d550e739928fc5f203432138fdcaf6ccb8ddb..007b85cfda82d245ae336efc26aa38ad this.printSaveWarning = false; console.autosavePeriod = this.configuration.getInt("ticks-per.autosave"); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 414522b641cd866822c13a753cc623c463004fd6..d83ea6113d3f2f7aaeac6e09473282434ec2fc67 100644 +index c3703933598ee96d856a18dcc0932061959c9791..20a08c79d4577d0eb36ab413b36811c828f4f084 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -282,8 +282,21 @@ public class CraftWorld extends CraftRegionAccessor implements World { @@ -64,7 +64,7 @@ index 414522b641cd866822c13a753cc623c463004fd6..d83ea6113d3f2f7aaeac6e0947328243 + + // Paper start + private void addTicket(int x, int z) { -+ net.minecraft.server.MCUtil.MAIN_EXECUTOR.execute(() -> world.getChunkSource().addRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 0, Unit.INSTANCE)); // Paper ++ io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> world.getChunkSource().addRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 0, Unit.INSTANCE)); // Paper } + // Paper end @@ -112,7 +112,7 @@ index 414522b641cd866822c13a753cc623c463004fd6..d83ea6113d3f2f7aaeac6e0947328243 return true; // Paper end @@ -2148,6 +2164,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - net.minecraft.server.ChunkSystem.scheduleChunkLoad(this.getHandle(), x, z, gen, ChunkStatus.FULL, true, priority, (c) -> { + io.papermc.paper.chunk.system.ChunkSystem.scheduleChunkLoad(this.getHandle(), x, z, gen, ChunkStatus.FULL, true, priority, (c) -> { net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> { net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk)c; + if (chunk != null) addTicket(x, z); // Paper diff --git a/patches/server/0437-incremental-chunk-and-player-saving.patch b/patches/server/0437-incremental-chunk-and-player-saving.patch index 0a9cdfbda..f7bce0f36 100644 --- a/patches/server/0437-incremental-chunk-and-player-saving.patch +++ b/patches/server/0437-incremental-chunk-and-player-saving.patch @@ -5,7 +5,7 @@ Subject: [PATCH] incremental chunk and player saving diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 1c39e141a392d96548f5ac62fb279ed1f105677d..922475997902dcc85ae42f351ace15e82b5aa638 100644 +index dda33bd52d9c527c37f67b829010c27dba4b667a..e42b12839faab0c040495b00368b107b35b93283 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -864,7 +864,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { // Paper - Ensure main + io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main MinecraftTimings.savePlayers.startTiming(); // Paper + int numSaved = 0; + long now = MinecraftServer.currentTick; diff --git a/patches/server/0470-Add-BellRingEvent.patch b/patches/server/0470-Add-BellRingEvent.patch index e6528721c..6b5fdae03 100644 --- a/patches/server/0470-Add-BellRingEvent.patch +++ b/patches/server/0470-Add-BellRingEvent.patch @@ -7,14 +7,14 @@ Add a new event, BellRingEvent, to trigger whenever a player rings a village bell. Passes along the bell block and the player who rang it. diff --git a/src/main/java/net/minecraft/world/level/block/BellBlock.java b/src/main/java/net/minecraft/world/level/block/BellBlock.java -index a4da6418c17e145333aa5efe427826ba53293e4d..14002e1f67e3dce421584c01e8f91769509638b7 100644 +index a4da6418c17e145333aa5efe427826ba53293e4d..3dfbc517e8867029b9821ec605dffb1ae476260a 100644 --- a/src/main/java/net/minecraft/world/level/block/BellBlock.java +++ b/src/main/java/net/minecraft/world/level/block/BellBlock.java @@ -3,6 +3,7 @@ package net.minecraft.world.level.block; import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -+import net.minecraft.server.MCUtil; ++import io.papermc.paper.util.MCUtil; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.stats.Stats; diff --git a/patches/server/0519-Add-PlayerShearBlockEvent.patch b/patches/server/0519-Add-PlayerShearBlockEvent.patch index 4004036b9..ad60c8efb 100644 --- a/patches/server/0519-Add-PlayerShearBlockEvent.patch +++ b/patches/server/0519-Add-PlayerShearBlockEvent.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add PlayerShearBlockEvent diff --git a/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java b/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java -index 8dff119fa83e44d71b10bb3ea6e5f4e886a48c9c..1aaab26c59bb9255955aff34ea1d057b88152768 100644 +index 8dff119fa83e44d71b10bb3ea6e5f4e886a48c9c..dd51ea83935028a083c9cf368e6826fa32c00462 100644 --- a/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java +++ b/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java @@ -113,7 +113,7 @@ public class BeehiveBlock extends BaseEntityBlock { @@ -22,7 +22,7 @@ index 8dff119fa83e44d71b10bb3ea6e5f4e886a48c9c..1aaab26c59bb9255955aff34ea1d057b if (itemstack.is(Items.SHEARS)) { + // Paper start - Add PlayerShearBlockEvent -+ io.papermc.paper.event.block.PlayerShearBlockEvent event = new io.papermc.paper.event.block.PlayerShearBlockEvent((org.bukkit.entity.Player) player.getBukkitEntity(), net.minecraft.server.MCUtil.toBukkitBlock(world, pos), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (hand == InteractionHand.OFF_HAND ? org.bukkit.inventory.EquipmentSlot.OFF_HAND : org.bukkit.inventory.EquipmentSlot.HAND), new java.util.ArrayList<>()); ++ io.papermc.paper.event.block.PlayerShearBlockEvent event = new io.papermc.paper.event.block.PlayerShearBlockEvent((org.bukkit.entity.Player) player.getBukkitEntity(), io.papermc.paper.util.MCUtil.toBukkitBlock(world, pos), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (hand == InteractionHand.OFF_HAND ? org.bukkit.inventory.EquipmentSlot.OFF_HAND : org.bukkit.inventory.EquipmentSlot.HAND), new java.util.ArrayList<>()); + event.getDrops().add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(new ItemStack(Items.HONEYCOMB, 3))); + if (!event.callEvent()) { + return InteractionResult.PASS; @@ -39,7 +39,7 @@ index 8dff119fa83e44d71b10bb3ea6e5f4e886a48c9c..1aaab26c59bb9255955aff34ea1d057b entityhuman1.broadcastBreakEvent(hand); }); diff --git a/src/main/java/net/minecraft/world/level/block/PumpkinBlock.java b/src/main/java/net/minecraft/world/level/block/PumpkinBlock.java -index 0e8cbe7a465edc31b78b7e47a928435f9c2b6bd9..f998598a34315389dd74b82e4b9c8448f0aae253 100644 +index 0e8cbe7a465edc31b78b7e47a928435f9c2b6bd9..4568d1659dda897de5f6c2059629a4718d401e63 100644 --- a/src/main/java/net/minecraft/world/level/block/PumpkinBlock.java +++ b/src/main/java/net/minecraft/world/level/block/PumpkinBlock.java @@ -27,13 +27,24 @@ public class PumpkinBlock extends StemGrownBlock { @@ -47,7 +47,7 @@ index 0e8cbe7a465edc31b78b7e47a928435f9c2b6bd9..f998598a34315389dd74b82e4b9c8448 if (itemStack.is(Items.SHEARS)) { if (!world.isClientSide) { + // Paper start - Add PlayerShearBlockEvent -+ io.papermc.paper.event.block.PlayerShearBlockEvent event = new io.papermc.paper.event.block.PlayerShearBlockEvent((org.bukkit.entity.Player) player.getBukkitEntity(), net.minecraft.server.MCUtil.toBukkitBlock(world, pos), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (hand == InteractionHand.OFF_HAND ? org.bukkit.inventory.EquipmentSlot.OFF_HAND : org.bukkit.inventory.EquipmentSlot.HAND), new java.util.ArrayList<>()); ++ io.papermc.paper.event.block.PlayerShearBlockEvent event = new io.papermc.paper.event.block.PlayerShearBlockEvent((org.bukkit.entity.Player) player.getBukkitEntity(), io.papermc.paper.util.MCUtil.toBukkitBlock(world, pos), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (hand == InteractionHand.OFF_HAND ? org.bukkit.inventory.EquipmentSlot.OFF_HAND : org.bukkit.inventory.EquipmentSlot.HAND), new java.util.ArrayList<>()); + event.getDrops().add(org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(new ItemStack(Items.PUMPKIN_SEEDS, 4))); + if (!event.callEvent()) { + return InteractionResult.PASS; diff --git a/patches/server/0556-Add-StructuresLocateEvent.patch b/patches/server/0556-Add-StructuresLocateEvent.patch index 42d31007c..f7bf54d7d 100644 --- a/patches/server/0556-Add-StructuresLocateEvent.patch +++ b/patches/server/0556-Add-StructuresLocateEvent.patch @@ -72,7 +72,7 @@ index 0000000000000000000000000000000000000000..423bf87ebda7ea266dc7b48cbfadbc85 + } +} diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -index 6e2185bbaac889d51a54ec97907da3b1faa465c4..50b9c2fbe3a5c12a43b4711d678ed2398dbdee58 100644 +index 6e2185bbaac889d51a54ec97907da3b1faa465c4..c35bf0709e83e05c2135d7a5c98bf44c48d0c31f 100644 --- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java @@ -295,6 +295,26 @@ public abstract class ChunkGenerator { @@ -81,7 +81,7 @@ index 6e2185bbaac889d51a54ec97907da3b1faa465c4..50b9c2fbe3a5c12a43b4711d678ed239 public Pair> findNearestMapStructure(ServerLevel world, HolderSet structures, BlockPos center, int radius, boolean skipReferencedStructures) { + // Paper start - StructureLocateEvent + final org.bukkit.World bukkitWorld = world.getWorld(); -+ final org.bukkit.Location origin = net.minecraft.server.MCUtil.toLocation(world, center); ++ final org.bukkit.Location origin = io.papermc.paper.util.MCUtil.toLocation(world, center); + final var paperRegistry = io.papermc.paper.registry.PaperRegistry.getRegistry(io.papermc.paper.registry.RegistryKey.CONFIGURED_STRUCTURE_REGISTRY); + final List configuredStructures = new ArrayList<>(); + paperRegistry.convertToApi(structures, configuredStructures::add, false); // gracefully handle missing api, use tests to check (or exclude) @@ -91,9 +91,9 @@ index 6e2185bbaac889d51a54ec97907da3b1faa465c4..50b9c2fbe3a5c12a43b4711d678ed239 + return null; + } + if (event.getResult() != null) { -+ return Pair.of(net.minecraft.server.MCUtil.toBlockPosition(event.getResult().position()), paperRegistry.getMinecraftHolder(event.getResult().configuredStructure())); ++ return Pair.of(io.papermc.paper.util.MCUtil.toBlockPosition(event.getResult().position()), paperRegistry.getMinecraftHolder(event.getResult().configuredStructure())); + } -+ center = net.minecraft.server.MCUtil.toBlockPosition(event.getOrigin()); ++ center = io.papermc.paper.util.MCUtil.toBlockPosition(event.getOrigin()); + radius = event.getRadius(); + skipReferencedStructures = event.shouldFindUnexplored(); + structures = HolderSet.direct(paperRegistry::getMinecraftHolder, event.getConfiguredStructures()); diff --git a/patches/server/0646-Add-BellRevealRaiderEvent.patch b/patches/server/0646-Add-BellRevealRaiderEvent.patch index 587e0f040..416490bb3 100644 --- a/patches/server/0646-Add-BellRevealRaiderEvent.patch +++ b/patches/server/0646-Add-BellRevealRaiderEvent.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add BellRevealRaiderEvent diff --git a/src/main/java/net/minecraft/world/level/block/entity/BellBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BellBlockEntity.java -index feaad48e9bbc1e658324ef9e1e7e73aca0b3bf48..b9d2c38e80924f52dcf76ec1042d2d746e77ffc6 100644 +index feaad48e9bbc1e658324ef9e1e7e73aca0b3bf48..648d8f3e72e30aacf68eb073a1ac30f8ec29503c 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/BellBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/BellBlockEntity.java @@ -138,7 +138,7 @@ public class BellBlockEntity extends BlockEntity { @@ -25,7 +25,7 @@ index feaad48e9bbc1e658324ef9e1e7e73aca0b3bf48..b9d2c38e80924f52dcf76ec1042d2d74 + // Paper start + private static void glow(LivingEntity entity) { glow(entity, null); } + private static void glow(LivingEntity entity, @javax.annotation.Nullable BlockPos pos) { -+ if (pos != null && !new io.papermc.paper.event.block.BellRevealRaiderEvent(entity.level.getWorld().getBlockAt(net.minecraft.server.MCUtil.toLocation(entity.level, pos)), entity.getBukkitEntity()).callEvent()) return; ++ if (pos != null && !new io.papermc.paper.event.block.BellRevealRaiderEvent(entity.level.getWorld().getBlockAt(io.papermc.paper.util.MCUtil.toLocation(entity.level, pos)), entity.getBukkitEntity()).callEvent()) return; + // Paper end entity.addEffect(new MobEffectInstance(MobEffects.GLOWING, 60)); } diff --git a/patches/server/0657-Missing-Entity-Behavior-API.patch b/patches/server/0657-Missing-Entity-Behavior-API.patch index 08e11a769..4b391ea8d 100644 --- a/patches/server/0657-Missing-Entity-Behavior-API.patch +++ b/patches/server/0657-Missing-Entity-Behavior-API.patch @@ -70,7 +70,7 @@ index 5ffae9d3be22b5e78645da57a6bd0e7350749ef1..9aec9f80c564fa3ae03e445423d9e50a public Llama(EntityType type, Level world) { super(type, world); diff --git a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java -index 1fc862a3b5d40a45cf91703051bcfb06ec1b177a..02d7cd9cd27ff9254c3e99e3e94309a8cb8b243d 100644 +index 0d36a903b7aa8d26232e6edcb0fdbba1defde660..d4d7830ab5b9944c38a301a0e2a2150063adf229 100644 --- a/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java +++ b/src/main/java/net/minecraft/world/entity/boss/wither/WitherBoss.java @@ -84,6 +84,11 @@ public class WitherBoss extends Monster implements PowerableMob, RangedAttackMob @@ -225,7 +225,7 @@ index 254d4f2e45d7c8f572a4368eccd84560d4d0d836..299ab868252c8f326e3a56e878c9ee23 + // Paper end - Horse API } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftBat.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftBat.java -index 3b960a832df1fe496ea036962083f1ac507a7db7..ee5534972a2b26402f29b146d1f3da69052672b0 100644 +index 3b960a832df1fe496ea036962083f1ac507a7db7..8f25bb253c2b22e1964afeae705901e926432ef0 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftBat.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftBat.java @@ -33,4 +33,25 @@ public class CraftBat extends CraftAmbient implements Bat { @@ -240,14 +240,14 @@ index 3b960a832df1fe496ea036962083f1ac507a7db7..ee5534972a2b26402f29b146d1f3da69 + return null; + } + -+ return net.minecraft.server.MCUtil.toLocation(this.getHandle().getLevel(), pos); ++ return io.papermc.paper.util.MCUtil.toLocation(this.getHandle().getLevel(), pos); + } + + @Override + public void setTargetLocation(org.bukkit.Location location) { + net.minecraft.core.BlockPos pos = null; + if (location != null) { -+ pos = net.minecraft.server.MCUtil.toBlockPosition(location); ++ pos = io.papermc.paper.util.MCUtil.toBlockPosition(location); + } + + this.getHandle().targetPosition = pos; @@ -663,7 +663,7 @@ index ff9f711b83a8ea1bf4135751a9ba865224bce787..1f6dcad764240e15083731d017f9bb1c @Override public boolean isRolling() { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java -index dce23f3878b1588c26b6116d80e597d08070edbc..eaa0358051c4ac32cc7e6a45039374dd5c036fa2 100644 +index dce23f3878b1588c26b6116d80e597d08070edbc..5a8fd2910204550537c04ae8754b50f70a445bb1 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java @@ -50,5 +50,25 @@ public class CraftPhantom extends CraftFlying implements Phantom { @@ -678,14 +678,14 @@ index dce23f3878b1588c26b6116d80e597d08070edbc..eaa0358051c4ac32cc7e6a45039374dd + return null; + } + -+ return net.minecraft.server.MCUtil.toLocation(this.getHandle().getLevel(), pos); ++ return io.papermc.paper.util.MCUtil.toLocation(this.getHandle().getLevel(), pos); + } + + @Override + public void setAnchorLocation(org.bukkit.Location location) { + net.minecraft.core.BlockPos pos = null; + if (location != null) { -+ pos = net.minecraft.server.MCUtil.toBlockPosition(location); ++ pos = io.papermc.paper.util.MCUtil.toBlockPosition(location); + } + + this.getHandle().anchorPoint = pos; @@ -884,7 +884,7 @@ index 8a0a905f6701c6e94cbbf15793788350958fb728..2a74e6ecb4f57bc6879b37f7bc067541 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWanderingTrader.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWanderingTrader.java -index fa7107593b20e0151d8d67104e4a92dcc697d461..d3618b2fd698552b2331f1114654b3339f3f066f 100644 +index fa7107593b20e0151d8d67104e4a92dcc697d461..ec6bbac3462ebe289b69f7a116802e34658b09c5 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWanderingTrader.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWanderingTrader.java @@ -55,5 +55,25 @@ public class CraftWanderingTrader extends CraftAbstractVillager implements Wande @@ -899,14 +899,14 @@ index fa7107593b20e0151d8d67104e4a92dcc697d461..d3618b2fd698552b2331f1114654b333 + return null; + } + -+ return net.minecraft.server.MCUtil.toLocation(this.getHandle().getLevel(), pos); ++ return io.papermc.paper.util.MCUtil.toLocation(this.getHandle().getLevel(), pos); + } + + @Override + public void setWanderingTowards(org.bukkit.Location location) { + net.minecraft.core.BlockPos pos = null; + if (location != null) { -+ pos = net.minecraft.server.MCUtil.toBlockPosition(location); ++ pos = io.papermc.paper.util.MCUtil.toBlockPosition(location); + } + + this.getHandle().wanderTarget = pos; diff --git a/patches/server/0661-Fix-commands-from-signs-not-firing-command-events.patch b/patches/server/0661-Fix-commands-from-signs-not-firing-command-events.patch index c66c6d829..67844b2f6 100644 --- a/patches/server/0661-Fix-commands-from-signs-not-firing-command-events.patch +++ b/patches/server/0661-Fix-commands-from-signs-not-firing-command-events.patch @@ -58,7 +58,7 @@ index 0000000000000000000000000000000000000000..01a2bc1feec808790bb93618ce46adb9 + } +} diff --git a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java -index 831db5ee21938d71e99bf9d17b92a6ca15531740..def4fdd2c7e4f925fa128692a744e5d10ae0203a 100644 +index 831db5ee21938d71e99bf9d17b92a6ca15531740..58599ead28c25a76d9f41d2d29ee8024c9afdccd 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java @@ -40,6 +40,7 @@ public class SignBlockEntity extends BlockEntity implements CommandSource { // C @@ -79,7 +79,7 @@ index 831db5ee21938d71e99bf9d17b92a6ca15531740..def4fdd2c7e4f925fa128692a744e5d1 + if (org.spigotmc.SpigotConfig.logCommands) { + LOGGER.info("{} issued server command: {}", player.getScoreboardName(), command); + } -+ io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent event = new io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent(player.getBukkitEntity(), command, new org.bukkit.craftbukkit.util.LazyPlayerSet(player.getServer()), (org.bukkit.block.Sign) net.minecraft.server.MCUtil.toBukkitBlock(this.level, this.worldPosition).getState()); ++ io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent event = new io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent(player.getBukkitEntity(), command, new org.bukkit.craftbukkit.util.LazyPlayerSet(player.getServer()), (org.bukkit.block.Sign) io.papermc.paper.util.MCUtil.toBukkitBlock(this.level, this.worldPosition).getState()); + if (!event.callEvent()) { + return false; + } diff --git a/patches/server/0677-Add-PlayerSetSpawnEvent.patch b/patches/server/0677-Add-PlayerSetSpawnEvent.patch index 4f372eda8..909d181d2 100644 --- a/patches/server/0677-Add-PlayerSetSpawnEvent.patch +++ b/patches/server/0677-Add-PlayerSetSpawnEvent.patch @@ -32,7 +32,7 @@ index ce1c7512cc368e196ae94ee22c6a228c975b4980..1e41de9523c5fa3b9cfced798a5c35a2 String string = resourceKey.location().toString(); if (targets.size() == 1) { diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index a02b02c71ac6dddcccb10a6aa7993337ed04b829..18f67094f0ce0902963a118744f9fd48f53273c8 100644 +index a02b02c71ac6dddcccb10a6aa7993337ed04b829..3fdb52e31e4e845ddf61fc3695c0c85362eab708 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -1272,7 +1272,7 @@ public class ServerPlayer extends Player { @@ -58,7 +58,7 @@ index a02b02c71ac6dddcccb10a6aa7993337ed04b829..18f67094f0ce0902963a118744f9fd48 + boolean willNotify = false; if (pos != null) { boolean flag2 = pos.equals(this.respawnPosition) && dimension.equals(this.respawnDimension); -+ spawnLoc = net.minecraft.server.MCUtil.toLocation(this.getServer().getLevel(dimension), pos); ++ spawnLoc = io.papermc.paper.util.MCUtil.toLocation(this.getServer().getLevel(dimension), pos); + spawnLoc.setYaw(angle); + willNotify = sendMessage && !flag2; + } @@ -68,7 +68,7 @@ index a02b02c71ac6dddcccb10a6aa7993337ed04b829..18f67094f0ce0902963a118744f9fd48 + } + if (event.getLocation() != null) { + dimension = event.getLocation().getWorld() != null ? ((CraftWorld) event.getLocation().getWorld()).getHandle().dimension() : dimension; -+ pos = net.minecraft.server.MCUtil.toBlockPosition(event.getLocation()); ++ pos = io.papermc.paper.util.MCUtil.toBlockPosition(event.getLocation()); + angle = (float) event.getLocation().getYaw(); + forced = event.isForced(); + // Paper end @@ -89,7 +89,7 @@ index a02b02c71ac6dddcccb10a6aa7993337ed04b829..18f67094f0ce0902963a118744f9fd48 public void trackChunk(ChunkPos chunkPos, Packet chunkDataPacket) { diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 627cf258312e5dc7a129286de6dcb4c028f846ac..456031783aa902c8fd40050aa2b8d051b996d71d 100644 +index f0fe73f53d26ed8a527d0791a41ca0c9773319ca..3b583f3070cecf1e9c751c9a80592aadb8376ba4 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java @@ -902,13 +902,13 @@ public abstract class PlayerList { diff --git a/patches/server/0693-Add-methods-to-find-targets-for-lightning-strikes.patch b/patches/server/0693-Add-methods-to-find-targets-for-lightning-strikes.patch index e8d285375..c586250be 100644 --- a/patches/server/0693-Add-methods-to-find-targets-for-lightning-strikes.patch +++ b/patches/server/0693-Add-methods-to-find-targets-for-lightning-strikes.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add methods to find targets for lightning strikes diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 6b1124ee45b40b49fdbf7e5d3b0349986112afc4..0070f82f7725f584a177464cc8dc543b7a5c78e1 100644 +index 56afb3c6a0c575e793e6c30cfb42596fcb83dd4f..c0dd56bc2eb8cdcf8a7dc20904f5a33f4a90f8a2 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -815,6 +815,11 @@ public class ServerLevel extends Level implements WorldGenLevel { @@ -29,7 +29,7 @@ index 6b1124ee45b40b49fdbf7e5d3b0349986112afc4..0070f82f7725f584a177464cc8dc543b blockposition1 = blockposition1.above(2); } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index b6aefca1ef13ddbe4f79b91cfed4fbc109b89475..5a3e498776a35770a19535751f9dfcc1573035d7 100644 +index cad1d4be462a53567dc56472f90d9aacdf82be99..31659cf6decac7cb83b83b09a17eaf91be656b53 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -686,6 +686,23 @@ public class CraftWorld extends CraftRegionAccessor implements World { @@ -39,8 +39,8 @@ index b6aefca1ef13ddbe4f79b91cfed4fbc109b89475..5a3e498776a35770a19535751f9dfcc1 + // Paper start + @Override + public Location findLightningRod(Location location) { -+ return this.world.findLightningRod(net.minecraft.server.MCUtil.toBlockPosition(location)) -+ .map(blockPos -> net.minecraft.server.MCUtil.toLocation(this.world, blockPos) ++ return this.world.findLightningRod(io.papermc.paper.util.MCUtil.toBlockPosition(location)) ++ .map(blockPos -> io.papermc.paper.util.MCUtil.toLocation(this.world, blockPos) + // get the actual rod pos + .subtract(0, 1, 0)) + .orElse(null); @@ -48,8 +48,8 @@ index b6aefca1ef13ddbe4f79b91cfed4fbc109b89475..5a3e498776a35770a19535751f9dfcc1 + + @Override + public Location findLightningTarget(Location location) { -+ final BlockPos pos = this.world.findLightningTargetAround(net.minecraft.server.MCUtil.toBlockPosition(location), true); -+ return pos == null ? null : net.minecraft.server.MCUtil.toLocation(this.world, pos); ++ final BlockPos pos = this.world.findLightningTargetAround(io.papermc.paper.util.MCUtil.toBlockPosition(location), true); ++ return pos == null ? null : io.papermc.paper.util.MCUtil.toLocation(this.world, pos); + } + // Paper end + diff --git a/patches/server/0710-Allow-controlled-flushing-for-network-manager.patch b/patches/server/0710-Allow-controlled-flushing-for-network-manager.patch index a88de7918..39d52d0a1 100644 --- a/patches/server/0710-Allow-controlled-flushing-for-network-manager.patch +++ b/patches/server/0710-Allow-controlled-flushing-for-network-manager.patch @@ -9,7 +9,7 @@ This patch will be used to optimise out flush calls in later patches. diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java -index 2f38d04b369b345c89f85cee32081df8baf4239f..13ab14b1fb3acfd245fbab35f84f5c30c97ed855 100644 +index 02cab94e208303a738adebaffe5929703d8bf0b3..af5d81778bf0dd3f227d64faeb814f2b234e7332 100644 --- a/src/main/java/net/minecraft/network/Connection.java +++ b/src/main/java/net/minecraft/network/Connection.java @@ -121,6 +121,39 @@ public class Connection extends SimpleChannelInboundHandler> { @@ -53,7 +53,7 @@ index 2f38d04b369b345c89f85cee32081df8baf4239f..13ab14b1fb3acfd245fbab35f84f5c30 this.receiving = side; } @@ -286,7 +319,7 @@ public class Connection extends SimpleChannelInboundHandler> { - net.minecraft.server.MCUtil.isMainThread() && packet.isReady() && this.queue.isEmpty() && + io.papermc.paper.util.MCUtil.isMainThread() && packet.isReady() && this.queue.isEmpty() && (packet.getExtraPackets() == null || packet.getExtraPackets().isEmpty()) ))) { - this.sendPacket(packet, callbacks); diff --git a/patches/server/0733-Optimise-nearby-player-lookups.patch b/patches/server/0733-Optimise-nearby-player-lookups.patch index 9cde1dc35..7a0d38249 100644 --- a/patches/server/0733-Optimise-nearby-player-lookups.patch +++ b/patches/server/0733-Optimise-nearby-player-lookups.patch @@ -9,7 +9,7 @@ since the penalty of a map lookup could outweigh the benefits of searching less players (as it basically did in the outside range patch). diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java -index dcb1318a3e676598f3b64279da77aa1170a94c42..10a5762e3d5540e24839f82ea875b4daeb9f0603 100644 +index e11ec87e8007979a1c6932b414bcd70c10db746c..bc46479fd0622a90fd98ac88f92b2840a22a2d04 100644 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java +++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java @@ -93,6 +93,12 @@ public class ChunkHolder { @@ -39,7 +39,7 @@ index dcb1318a3e676598f3b64279da77aa1170a94c42..10a5762e3d5540e24839f82ea875b4da // Paper end diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 134274a7e36f14d855f659df37e0ba24d93fdad7..2a7cdaabbb772520ced0eb1dcd827bd93ebbc59b 100644 +index 0abcc48cea5f0ca99d9ad5b753cc0c5bc91e97d9..43466ce2b9ce583a5af067937ce9c47f7635f56d 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -152,6 +152,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -56,7 +56,7 @@ index 134274a7e36f14d855f659df37e0ba24d93fdad7..2a7cdaabbb772520ced0eb1dcd827bd9 // Paper start - distance maps private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>(); @@ -204,6 +210,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - trackMap.add(player, chunkX, chunkZ, Math.min(trackRange, net.minecraft.server.ChunkSystem.getSendViewDistance(player))); + trackMap.add(player, chunkX, chunkZ, Math.min(trackRange, io.papermc.paper.chunk.system.ChunkSystem.getSendViewDistance(player))); } // Paper end - use distance map to optimise entity tracker + this.playerGeneralAreaMap.add(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS); // Paper - optimise checkDespawn @@ -72,7 +72,7 @@ index 134274a7e36f14d855f659df37e0ba24d93fdad7..2a7cdaabbb772520ced0eb1dcd827bd9 if (this.playerMobDistanceMap != null) { this.playerMobDistanceMap.remove(player); @@ -244,6 +252,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - trackMap.update(player, chunkX, chunkZ, Math.min(trackRange, net.minecraft.server.ChunkSystem.getSendViewDistance(player))); + trackMap.update(player, chunkX, chunkZ, Math.min(trackRange, io.papermc.paper.chunk.system.ChunkSystem.getSendViewDistance(player))); } // Paper end - use distance map to optimise entity tracker + this.playerGeneralAreaMap.update(player, chunkX, chunkZ, GENERAL_AREA_MAP_SQUARE_RADIUS); // Paper - optimise checkDespawn @@ -104,7 +104,7 @@ index 134274a7e36f14d855f659df37e0ba24d93fdad7..2a7cdaabbb772520ced0eb1dcd827bd9 protected ChunkGenerator generator() { diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 60d354bce53b5101dc986d0c35d82ac9dbbbd016..2112b7aef36054c9854c13cc5e9fb4c05bf18c6e 100644 +index 195c50c7ba10b784c372046d956b54fccf684812..48c5a62ea9c0441fa14300aff4dab44cc26090c5 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -442,6 +442,84 @@ public class ServerLevel extends Level implements WorldGenLevel { @@ -226,7 +226,7 @@ index b9685fa96bb59b4b080ffd0ac53e4c5581aaeb8b..fffa6ba329b38433a1df51df339df652 if (entityhuman != null) { double d0 = entityhuman.distanceToSqr((Entity) this); diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index aa90454e70e5c25eb331ceb212df3128d64b1567..c1a3bcc8d9df2bf25a9c73faeac84652756d430a 100644 +index b5fd3a9b58fb56db92d579d307edc99bbe344c79..09c2d318330e03d0230a82b30985bba3a4231615 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -205,6 +205,69 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @@ -300,7 +300,7 @@ index aa90454e70e5c25eb331ceb212df3128d64b1567..c1a3bcc8d9df2bf25a9c73faeac84652 public abstract ResourceKey getTypeKey(); diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -index e0b6f7da138776be2892821b32a099c2d0e45038..df83b6f0e217eec4c9e9707be0030c129fdeb545 100644 +index edd32b6d5a96a6fffe641a23c27921e6dcf37a54..272bdc088f440cf94850dff6e626331b4b5d6539 100644 --- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java +++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java @@ -259,7 +259,7 @@ public final class NaturalSpawner { @@ -322,7 +322,7 @@ index e0b6f7da138776be2892821b32a099c2d0e45038..df83b6f0e217eec4c9e9707be0030c12 private static Boolean isValidSpawnPostitionForType(ServerLevel world, MobCategory group, StructureManager structureAccessor, ChunkGenerator chunkGenerator, MobSpawnSettings.SpawnerData spawnEntry, BlockPos.MutableBlockPos pos, double squaredDistance) { // Paper 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 07eeea03796cd6330a9788ef357cf307a02b4ace..258d00692fa50e0932747a7a2f0ddae5ab659040 100644 +index 97a1972b8e4359b4327fa0b0ac1fb82966122a27..6c31e246b49dfa2447f3179b744b0b3842d1509e 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -269,6 +269,98 @@ public class LevelChunk extends ChunkAccess { diff --git a/patches/server/0804-Dolphin-API.patch b/patches/server/0804-Dolphin-API.patch index 4bb12a678..7b62597b9 100644 --- a/patches/server/0804-Dolphin-API.patch +++ b/patches/server/0804-Dolphin-API.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Dolphin API diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftDolphin.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftDolphin.java -index 938e141f161acf5de5d3361382b514caea02c6fb..75919bf87b6f5cad06ca76888e284e2548594f00 100644 +index 938e141f161acf5de5d3361382b514caea02c6fb..c1db88ceb65eb81c542171fc5465224ef613ce3b 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftDolphin.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftDolphin.java @@ -24,4 +24,34 @@ public class CraftDolphin extends CraftWaterMob implements Dolphin { @@ -35,11 +35,11 @@ index 938e141f161acf5de5d3361382b514caea02c6fb..75919bf87b6f5cad06ca76888e284e25 + + @Override + public org.bukkit.Location getTreasureLocation() { -+ return net.minecraft.server.MCUtil.toLocation(this.getHandle().level, this.getHandle().getTreasurePos()); ++ return io.papermc.paper.util.MCUtil.toLocation(this.getHandle().level, this.getHandle().getTreasurePos()); + } + + @Override + public void setTreasureLocation(org.bukkit.Location location) { -+ this.getHandle().setTreasurePos(net.minecraft.server.MCUtil.toBlockPosition(location)); ++ this.getHandle().setTreasurePos(io.papermc.paper.util.MCUtil.toBlockPosition(location)); + } }