diff --git a/build.gradle.kts b/build.gradle.kts index 2336fd226cbf..b68e134ff003 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -40,6 +40,7 @@ subprojects { } repositories { + mavenLocal() mavenCentral() maven(paperMavenPublicUrl) } diff --git a/gradle.properties b/gradle.properties index 99224ed0a3a6..1985598b777c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ apiVersion=26.1.2 channel=STABLE # Set to true while updating Minecraft version -updatingMinecraft=false +updatingMinecraft=true org.gradle.configuration-cache=true org.gradle.caching=true diff --git a/paper-server/build.gradle.kts b/paper-server/build.gradle.kts index 51c9f5460198..ebea2573deb8 100644 --- a/paper-server/build.gradle.kts +++ b/paper-server/build.gradle.kts @@ -1,5 +1,6 @@ import io.papermc.fill.model.BuildChannel import io.papermc.paperweight.attribute.DevBundleOutput +import io.papermc.paperweight.core.tasks.patchroulette.AbstractPatchRouletteTask import io.papermc.paperweight.util.* import java.time.Instant @@ -14,16 +15,19 @@ plugins { val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/" dependencies { - mache("io.papermc:mache:26.1.2+build.1") + mache("io.papermc:mache:26.1.2+build.local-SNAPSHOT") paperclip("io.papermc:paperclip:3.0.4") } +tasks.withType().configureEach { + endpoint = "http://127.0.0.1:8080/api" +} paperweight { minecraftVersion = providers.gradleProperty("mcVersion") gitFilePatches = false updatingMinecraft { - // oldPaperCommit = "7e80cef5198561d0db53406127e5b8bc7af51577" + oldPaperCommit = "711c5de2b05df39b72c44ff54e9f9381f8d153cb" } } diff --git a/paper-server/patches/features/0001-Moonrise-optimisation-patches.patch b/paper-server/patches/features/0001-Moonrise-optimisation-patches.patch index 2f5fc143544b..acb000449a4e 100644 --- a/paper-server/patches/features/0001-Moonrise-optimisation-patches.patch +++ b/paper-server/patches/features/0001-Moonrise-optimisation-patches.patch @@ -23689,7 +23689,7 @@ index 0000000000000000000000000000000000000000..8424cf9d4617b4732d44cc460d25b044 + +} diff --git a/net/minecraft/core/Direction.java b/net/minecraft/core/Direction.java -index 3f516ffd7a76f1d17daaa865f7446803b8217bcc..240fb1346b721e4aaf8517b01fa205760cee4bbd 100644 +index bb0c36283b4bdcfa10a4e1b5668b0c34c11cdced..46547155b817a89a8afe2f8d1a30bf881efc07bc 100644 --- a/net/minecraft/core/Direction.java +++ b/net/minecraft/core/Direction.java @@ -29,7 +29,7 @@ import org.joml.Vector3f; @@ -23746,7 +23746,7 @@ index 3f516ffd7a76f1d17daaa865f7446803b8217bcc..240fb1346b721e4aaf8517b01fa20576 + } + // Paper end - optimise collisions - private Direction( + Direction( final int data3d, @@ -153,14 +193,13 @@ public enum Direction implements StringRepresentable { } @@ -23798,7 +23798,7 @@ index 3f516ffd7a76f1d17daaa865f7446803b8217bcc..240fb1346b721e4aaf8517b01fa20576 + // Paper end - optimise collisions } diff --git a/net/minecraft/core/MappedRegistry.java b/net/minecraft/core/MappedRegistry.java -index 3c1490ac7c259da04031db2f170e0c0a5f512191..470d7c770ae9d045b97e2df145cfe3cf9d101deb 100644 +index 9d9fa99ff7694a3356421df711c7b1443047b057..c79206e0eb455081f63cf4de2c97413638fd6596 100644 --- a/net/minecraft/core/MappedRegistry.java +++ b/net/minecraft/core/MappedRegistry.java @@ -58,6 +58,19 @@ public class MappedRegistry implements WritableRegistry { @@ -23821,16 +23821,16 @@ index 3c1490ac7c259da04031db2f170e0c0a5f512191..470d7c770ae9d045b97e2df145cfe3cf public MappedRegistry(final ResourceKey> key, final Lifecycle lifecycle) { this(key, lifecycle, false); } -@@ -123,6 +136,7 @@ public class MappedRegistry implements WritableRegistry { - this.registrationInfos.put(key, registrationInfo); - this.registryLifecycle = this.registryLifecycle.add(registrationInfo.lifecycle()); - this.temporaryUnfrozenMap.put(key.identifier(), value); // Paper - support pre-filling in registry mod API -+ this.injectFluidRegister(key, value); // Paper - fluid method optimisations - return holder; - } +@@ -126,6 +139,7 @@ public class MappedRegistry implements WritableRegistry { + this.registrationInfos.put(key, registrationInfo); + this.registryLifecycle = this.registryLifecycle.add(registrationInfo.lifecycle()); + this.temporaryUnfrozenMap.put(key.identifier(), value); // Paper - support pre-filling in registry mod API ++ this.injectFluidRegister(key, value); // Paper - fluid method optimisations + return holder; } + diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index d22f55c63eb950e1b979280612eb9f155e986406..93690b360e5eb1b8d2f8ab2198aa087c9be7ffe2 100644 +index f18001d368d74b987b21521ac2ffe75479ba3a87..c809ea1f2620c543d9bc80afdd64489f2fb98744 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -191,7 +191,7 @@ import net.minecraft.world.scores.ScoreboardSaveData; @@ -23935,7 +23935,7 @@ index d22f55c63eb950e1b979280612eb9f155e986406..93690b360e5eb1b8d2f8ab2198aa087c public MinecraftServer( // CraftBukkit start -@@ -853,7 +939,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop l.getChunkSource().chunkMap.hasWork())) { // Paper - rewrite chunk system this.nextTickTimeNanos = Util.getNanos() + TimeUtil.NANOSECONDS_PER_MILLISECOND; - for (ServerLevel levelx : this.getAllLevels()) { -@@ -992,17 +1083,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop false : this::haveTime); @@ -24071,7 +24071,7 @@ index d22f55c63eb950e1b979280612eb9f155e986406..93690b360e5eb1b8d2f8ab2198aa087c this.tickFrame.end(); this.recordEndOfTick(); // Paper - improve tick loop profiler.pop(); -@@ -2618,6 +2737,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop r.map(List::of)); -- } else { -- int chunkCount = Mth.square(range * 2 + 1); -- List>> deps = new ArrayList<>(chunkCount); -- ChunkPos centerPos = centerChunk.getPos(); +- } - -- for (int z = -range; z <= range; z++) { -- for (int x = -range; x <= range; x++) { -- int distance = Math.max(Math.abs(x), Math.abs(z)); -- long chunkNode = ChunkPos.pack(centerPos.x() + x, centerPos.z() + z); -- ChunkHolder chunk = this.getUpdatingChunkIfPresent(chunkNode); -- if (chunk == null) { -- return UNLOADED_CHUNK_LIST_FUTURE; -- } +- int chunkCount = Mth.square(range * 2 + 1); +- List>> deps = new ArrayList<>(chunkCount); +- ChunkPos centerPos = centerChunk.getPos(); - -- ChunkStatus depStatus = distanceToStatus.apply(distance); -- deps.add(chunk.scheduleChunkGenerationTask(depStatus, this)); +- for (int z = -range; z <= range; z++) { +- for (int x = -range; x <= range; x++) { +- int distance = Math.max(Math.abs(x), Math.abs(z)); +- long chunkNode = ChunkPos.pack(centerPos.x() + x, centerPos.z() + z); +- ChunkHolder chunk = this.getUpdatingChunkIfPresent(chunkNode); +- if (chunk == null) { +- return UNLOADED_CHUNK_LIST_FUTURE; - } -- } - -- return Util.sequence(deps).thenApply(chunkResults -> { -- List chunks = new ArrayList<>(chunkResults.size()); +- ChunkStatus depStatus = distanceToStatus.apply(distance); +- deps.add(chunk.scheduleChunkGenerationTask(depStatus, this)); +- } +- } - -- for (ChunkResult chunkResult : chunkResults) { -- if (chunkResult == null) { -- throw this.debugFuturesAndCreateReportedException(new IllegalStateException("At least one of the chunk futures were null"), "n/a"); -- } +- return Util.sequence(deps).thenApply(chunkResults -> { +- List chunks = new ArrayList<>(chunkResults.size()); - -- ChunkAccess chunkx = chunkResult.orElse(null); -- if (chunkx == null) { -- return UNLOADED_CHUNK_LIST_RESULT; -- } +- for (ChunkResult chunkResult : chunkResults) { +- if (chunkResult == null) { +- throw this.debugFuturesAndCreateReportedException(new IllegalStateException("At least one of the chunk futures were null"), "n/a"); +- } - -- chunks.add(chunkx); +- ChunkAccess chunkx = chunkResult.orElse(null); +- if (chunkx == null) { +- return UNLOADED_CHUNK_LIST_RESULT; - } - -- return ChunkResult.of(chunks); -- }); -- } +- chunks.add(chunkx); +- } +- +- return ChunkResult.of(chunks); +- }); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -24796,34 +24796,34 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 private @Nullable ChunkHolder updateChunkScheduling(final long node, final int level, @Nullable ChunkHolder chunk, final int oldLevel) { - if (!ChunkLevel.isLoaded(oldLevel) && !ChunkLevel.isLoaded(level)) { - return chunk; -- } else { -- if (chunk != null) { -- chunk.setTicketLevel(level); -- } +- } - -- if (chunk != null) { -- if (!ChunkLevel.isLoaded(level)) { -- this.toDrop.add(node); -- } else { -- this.toDrop.remove(node); -- } -- } +- if (chunk != null) { +- chunk.setTicketLevel(level); +- } - -- if (ChunkLevel.isLoaded(level) && chunk == null) { -- chunk = this.pendingUnloads.remove(node); -- if (chunk != null) { -- chunk.setTicketLevel(level); -- } else { -- chunk = new ChunkHolder(ChunkPos.unpack(node), level, this.level, this.lightEngine, this::onLevelChange, this); -- ca.spottedleaf.moonrise.common.PlatformHooks.get().onChunkHolderCreate(this.level, chunk); // Paper -- } +- if (chunk != null) { +- if (!ChunkLevel.isLoaded(level)) { +- this.toDrop.add(node); +- } else { +- this.toDrop.remove(node); +- } +- } - -- this.updatingChunkMap.put(node, chunk); -- this.modified = true; +- if (ChunkLevel.isLoaded(level) && chunk == null) { +- chunk = this.pendingUnloads.remove(node); +- if (chunk != null) { +- chunk.setTicketLevel(level); +- } else { +- chunk = new ChunkHolder(ChunkPos.unpack(node), level, this.level, this.lightEngine, this::onLevelChange, this); +- ca.spottedleaf.moonrise.common.PlatformHooks.get().onChunkHolderCreate(this.level, chunk); // Paper - } - -- return chunk; +- this.updatingChunkMap.put(node, chunk); +- this.modified = true; - } +- +- return chunk; + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -24987,11 +24987,11 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 protected boolean promoteChunkMap() { - if (!this.modified) { - return false; -- } else { -- this.visibleChunkMap = this.updatingChunkMap.clone(); -- this.modified = false; -- return true; - } +- +- this.visibleChunkMap = this.updatingChunkMap.clone(); +- this.modified = false; +- return true; + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -25023,7 +25023,7 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 } private ChunkAccess handleChunkLoadFailure(final Throwable throwable, final ChunkPos pos) { -@@ -659,229 +436,139 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP +@@ -659,231 +436,139 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP @Override public GenerationChunkHolder acquireGeneration(final long chunkNode) { @@ -25046,25 +25046,25 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 - ChunkPos pos = chunkHolder.getPos(); - if (step.targetStatus() == ChunkStatus.EMPTY) { - return this.scheduleChunkLoad(pos); -- } else { -- try { -- GenerationChunkHolder holder = cache.get(pos.x(), pos.z()); -- ChunkAccess centerChunk = holder.getChunkIfPresentUnchecked(step.targetStatus().getParent()); -- if (centerChunk == null) { -- throw new IllegalStateException("Parent chunk missing"); -- } else { -- return step.apply(this.worldGenContext, cache, centerChunk); -- } -- } catch (Exception var8) { -- var8.getStackTrace(); -- CrashReport report = CrashReport.forThrowable(var8, "Exception generating new chunk"); -- CrashReportCategory category = report.addCategory("Chunk to be generated"); -- category.setDetail("Status being generated", () -> step.targetStatus().getName()); -- category.setDetail("Location", String.format(Locale.ROOT, "%d,%d", pos.x(), pos.z())); -- category.setDetail("Position hash", ChunkPos.pack(pos.x(), pos.z())); -- category.setDetail("Generator", this.generator()); -- throw new ReportedException(report); +- } +- +- try { +- GenerationChunkHolder holder = cache.get(pos.x(), pos.z()); +- ChunkAccess centerChunk = holder.getChunkIfPresentUnchecked(step.targetStatus().getParent()); +- if (centerChunk == null) { +- throw new IllegalStateException("Parent chunk missing"); +- } else { +- return step.apply(this.worldGenContext, cache, centerChunk); - } +- } catch (Exception e) { +- e.getStackTrace(); +- CrashReport report = CrashReport.forThrowable(e, "Exception generating new chunk"); +- CrashReportCategory category = report.addCategory("Chunk to be generated"); +- category.setDetail("Status being generated", () -> step.targetStatus().getName()); +- category.setDetail("Location", String.format(Locale.ROOT, "%d,%d", pos.x(), pos.z())); +- category.setDetail("Position hash", ChunkPos.pack(pos.x(), pos.z())); +- category.setDetail("Generator", this.generator()); +- throw new ReportedException(report); - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -25150,23 +25150,25 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 - ChunkAccess chunkAccess = chunk.getLatestChunk(); - if (!(chunkAccess instanceof ImposterProtoChunk) && !(chunkAccess instanceof LevelChunk)) { - return false; -- } else if (!chunkAccess.isUnsaved()) { +- } +- +- if (!chunkAccess.isUnsaved()) { - return false; -- } else { -- long chunkPos = chunkAccess.getPos().pack(); -- long nextSaveTime = this.nextChunkSaveTime.getOrDefault(chunkPos, -1L); -- if (now < nextSaveTime) { -- return false; -- } else { -- boolean saved = this.save(chunkAccess); -- chunk.refreshAccessibility(); -- if (saved) { -- this.nextChunkSaveTime.put(chunkPos, now + 10000L); -- } +- } - -- return saved; -- } +- long chunkPos = chunkAccess.getPos().pack(); +- long nextSaveTime = this.nextChunkSaveTime.getOrDefault(chunkPos, -1L); +- if (now < nextSaveTime) { +- return false; +- } +- +- boolean saved = this.save(chunkAccess); +- chunk.refreshAccessibility(); +- if (saved) { +- this.nextChunkSaveTime.put(chunkPos, now + 10000L); - } +- +- return saved; - } else { - return false; - } @@ -25177,39 +25179,39 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 - this.poiManager.flush(chunk.getPos()); - if (!chunk.tryMarkSaved()) { - return false; -- } else { -- ChunkPos pos = chunk.getPos(); +- } - -- try { -- ChunkStatus status = chunk.getPersistedStatus(); -- if (status.getChunkType() != ChunkType.LEVELCHUNK) { -- if (this.isExistingChunkFull(pos)) { -- return false; -- } +- ChunkPos pos = chunk.getPos(); - -- if (status == ChunkStatus.EMPTY && chunk.getAllStarts().values().stream().noneMatch(StructureStart::isValid)) { -- return false; -- } +- try { +- ChunkStatus status = chunk.getPersistedStatus(); +- if (status.getChunkType() != ChunkType.LEVELCHUNK) { +- if (this.isExistingChunkFull(pos)) { +- return false; - } - -- Profiler.get().incrementCounter("chunkSave"); -- this.activeChunkWrites.incrementAndGet(); -- SerializableChunkData data = SerializableChunkData.copyOf(this.level, chunk); -- CompletableFuture encodedData = CompletableFuture.supplyAsync(data::write, Util.backgroundExecutor()); -- this.write(pos, encodedData::join).handle((ignored, throwable) -> { -- if (throwable != null) { -- this.level.getServer().reportChunkSaveFailure(throwable, this.storageInfo(), pos); -- } -- -- this.activeChunkWrites.decrementAndGet(); -- return null; -- }); -- this.markPosition(pos, status.getChunkType()); -- return true; -- } catch (Exception var6) { -- this.level.getServer().reportChunkSaveFailure(var6, this.storageInfo(), pos); -- return false; +- if (status == ChunkStatus.EMPTY && chunk.getAllStarts().values().stream().noneMatch(StructureStart::isValid)) { +- return false; +- } - } +- +- Profiler.get().incrementCounter("chunkSave"); +- this.activeChunkWrites.incrementAndGet(); +- SerializableChunkData data = SerializableChunkData.copyOf(this.level, chunk); +- CompletableFuture encodedData = CompletableFuture.supplyAsync(data::write, Util.backgroundExecutor()); +- this.write(pos, encodedData::join).handle((ignored, throwable) -> { +- if (throwable != null) { +- this.level.getServer().reportChunkSaveFailure(throwable, this.storageInfo(), pos); +- } +- +- this.activeChunkWrites.decrementAndGet(); +- return null; +- }); +- this.markPosition(pos, status.getChunkType()); +- return true; +- } catch (Exception e) { +- this.level.getServer().reportChunkSaveFailure(e, this.storageInfo(), pos); +- return false; - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -25218,23 +25220,23 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 - byte cachedChunkType = this.chunkTypeCache.get(pos.pack()); - if (cachedChunkType != 0) { - return cachedChunkType == 1; -- } else { -- CompoundTag currentTag; -- try { -- currentTag = this.readChunk(pos).join().orElse(null); -- if (currentTag == null) { -- this.markPositionReplaceable(pos); -- return false; -- } -- } catch (Exception var5) { -- LOGGER.error("Failed to read chunk {}", pos, var5); +- } +- +- CompoundTag currentTag; +- try { +- currentTag = this.readChunk(pos).join().orElse(null); +- if (currentTag == null) { - this.markPositionReplaceable(pos); - return false; - } -- -- ChunkType chunkType = SerializableChunkData.getChunkStatusFromTag(currentTag).getChunkType(); -- return this.markPosition(pos, chunkType) == 1; +- } catch (Exception e) { +- LOGGER.error("Failed to read chunk {}", pos, e); +- this.markPositionReplaceable(pos); +- return false; - } +- +- ChunkType chunkType = SerializableChunkData.getChunkStatusFromTag(currentTag).getChunkType(); +- return this.markPosition(pos, chunkType) == 1; + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -25279,8 +25281,8 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 private static void dropChunk(final ServerPlayer player, final ChunkPos pos) { - player.connection.chunkSender.dropChunk(player, pos); + // Paper - rewrite chunk system - } - ++ } ++ + // Paper start - rewrite chunk system + @Override + public CompletableFuture> read(final ChunkPos pos) { @@ -25307,8 +25309,8 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 + ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionFileType.CHUNK_DATA + ); + return null; -+ } -+ + } + + @Override + public CompletableFuture synchronize(final boolean flush) { + try { @@ -25326,7 +25328,7 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 public @Nullable LevelChunk getChunkToSend(final long key) { ChunkHolder chunkHolder = this.getVisibleChunkIfPresent(key); return chunkHolder == null ? null : chunkHolder.getChunkToSend(); -@@ -963,7 +650,7 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP +@@ -965,7 +650,7 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP return this.read(pos).thenApplyAsync(chunkTag -> chunkTag.map(this::upgradeChunkTag), Util.backgroundExecutor().forName("upgradeChunk")); } @@ -25335,7 +25337,7 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 return this.upgradeChunkTag( tag, -1, -@@ -979,23 +666,66 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP +@@ -981,23 +666,66 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP return contextTag; } @@ -25411,7 +25413,7 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 if (holder != null) { LevelChunk chunk = holder.getTickingChunk(); if (chunk != null) { -@@ -1011,8 +741,8 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP +@@ -1013,8 +741,8 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP } boolean anyPlayerCloseEnoughForSpawning(final ChunkPos pos, boolean reducedRange) { @@ -25422,7 +25424,7 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 // Spigot end } -@@ -1036,7 +766,20 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP +@@ -1038,7 +766,20 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP private boolean anyPlayerCloseEnoughForSpawningInternal(final ChunkPos pos, final boolean reducedRange) { double blockRange; // Paper - use from event // Spigot end @@ -25444,7 +25446,7 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 // Paper start - PlayerNaturallySpawnCreaturesEvent com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event; blockRange = 16384.0; -@@ -1052,26 +795,41 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP +@@ -1054,26 +795,41 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP } return false; @@ -25455,24 +25457,23 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 - long key = pos.pack(); - if (!this.distanceManager.hasPlayersNearby(key).toBoolean(true)) { - return List.of(); -- } else { -- Builder builder = ImmutableList.builder(); + // Paper start - chunk tick iteration optimisation + final ca.spottedleaf.moonrise.common.list.ReferenceList players = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getNearbyPlayers().getPlayers( + pos, ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.SPAWN_RANGE + ); + if (players == null) { + return new ArrayList<>(); -+ } -+ + } + +- Builder builder = ImmutableList.builder(); + List ret = null; -+ + +- for (ServerPlayer player : this.playerMap.getAllPlayers()) { +- if (this.playerIsCloseEnoughForSpawning(player, pos, 16384.0)) { // Spigot +- builder.add(player); + final ServerPlayer[] raw = players.getRawDataUnchecked(); + final int len = players.size(); - -- for (ServerPlayer player : this.playerMap.getAllPlayers()) { -- if (this.playerIsCloseEnoughForSpawning(player, pos, 16384.0)) { // Spigot -- builder.add(player); ++ + Objects.checkFromIndexSize(0, len, raw.length); + for (int i = 0; i < len; ++i) { + final ServerPlayer player = raw[i]; @@ -25482,12 +25483,11 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 + ret.add(player); + } else { + ret.add(player); - } ++ } } -- -- return builder.build(); } -+ + +- return builder.build(); + return ret == null ? new ArrayList<>() : ret; + // Paper end - chunk tick iteration optimisation } @@ -25496,8 +25496,8 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 + public boolean playerIsCloseEnoughForSpawning(final ServerPlayer player, final ChunkPos pos, final double range) { // Spigot // Paper - chunk tick iteration optimisation - public if (player.isSpectator()) { return false; - } else { -@@ -1109,18 +867,20 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP + } +@@ -1111,18 +867,20 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP this.updatePlayerPos(player); if (!ignored) { this.distanceManager.addPlayer(SectionPos.of(player), player); @@ -25520,7 +25520,7 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 } } -@@ -1130,13 +890,7 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP +@@ -1132,13 +890,7 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP } public void move(final ServerPlayer player) { @@ -25535,7 +25535,7 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 SectionPos oldSection = player.getLastSectionPos(); SectionPos newSection = SectionPos.of(player); -@@ -1145,6 +899,7 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP +@@ -1147,6 +899,7 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP boolean positionChanged = oldSection.asLong() != newSection.asLong(); if (positionChanged || wasIgnored != ignored) { this.updatePlayerPos(player); @@ -25543,7 +25543,7 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 if (!wasIgnored) { this.distanceManager.removePlayer(oldSection, player); } -@@ -1161,47 +916,29 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP +@@ -1163,47 +916,29 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP this.playerMap.unIgnorePlayer(player); } @@ -25602,20 +25602,20 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 } public void addEntity(final Entity entity) { -@@ -1225,6 +962,12 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP - } else { - ChunkMap.TrackedEntity trackedEntity = new ChunkMap.TrackedEntity(entity, range, updateInterval, type.trackDeltas()); - this.entityMap.put(entity.getId(), trackedEntity); -+ // Paper start - optimise entity tracker -+ if (((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity)entity).moonrise$getTrackedEntity() != null) { -+ throw new IllegalStateException("Entity is already tracked"); -+ } -+ ((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity)entity).moonrise$setTrackedEntity(trackedEntity); -+ // Paper end - optimise entity tracker - trackedEntity.updatePlayers(this.level.players()); - if (entity instanceof ServerPlayer player) { - this.updatePlayerStatus(player, true); -@@ -1254,12 +997,38 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP +@@ -1228,6 +963,12 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP + + ChunkMap.TrackedEntity trackedEntity = new ChunkMap.TrackedEntity(entity, range, updateInterval, type.trackDeltas()); + this.entityMap.put(entity.getId(), trackedEntity); ++ // Paper start - optimise entity tracker ++ if (((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity)entity).moonrise$getTrackedEntity() != null) { ++ throw new IllegalStateException("Entity is already tracked"); ++ } ++ ((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity)entity).moonrise$setTrackedEntity(trackedEntity); ++ // Paper end - optimise entity tracker + trackedEntity.updatePlayers(this.level.players()); + if (entity instanceof ServerPlayer player) { + this.updatePlayerStatus(player, true); +@@ -1256,12 +997,38 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP if (trackedEntity != null) { trackedEntity.broadcastRemoved(); } @@ -25656,7 +25656,7 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 List movedPlayers = Lists.newArrayList(); List players = this.level.players(); -@@ -1359,17 +1128,11 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP +@@ -1361,17 +1128,11 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP } public void waitForLightBeforeSending(final ChunkPos centerChunk, final int chunkRadius) { @@ -25676,14 +25676,13 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 LevelChunk chunk = chunkHolder.getChunkToSend(); if (chunk != null) { consumer.accept(chunk); -@@ -1377,15 +1140,22 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP +@@ -1379,14 +1140,21 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP } } - public class DistanceManager extends net.minecraft.server.level.DistanceManager { + public class DistanceManager extends net.minecraft.server.level.DistanceManager implements ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemDistanceManager { // Paper - rewrite chunk system protected DistanceManager(final TicketStorage ticketStorage, final Executor executor, final Executor mainThreadExecutor) { - Objects.requireNonNull(ChunkMap.this); super(ticketStorage, executor, mainThreadExecutor); } @@ -25701,7 +25700,7 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 } @Override -@@ -1399,13 +1169,96 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP +@@ -1400,13 +1168,96 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP } } @@ -25711,7 +25710,7 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 private final Entity entity; private final int range; private SectionPos lastSectionPos; - public final Set seenBy; + public final Set seenBy = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl + // Paper start - optimise entity tracker + private long lastChunkUpdate = -1L; @@ -25797,9 +25796,9 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 + // Paper end - optimise entity tracker + public TrackedEntity(final Entity entity, final int range, final int updateInterval, final boolean trackDelta) { - Objects.requireNonNull(ChunkMap.this); - super(); -@@ -1520,17 +1373,24 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP + this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, updateInterval, trackDelta, this, this.seenBy); // Paper + this.entity = entity; +@@ -1518,17 +1369,24 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP } private int getEffectiveRange() { @@ -25833,10 +25832,10 @@ index c129d7a0823d7eaae677ca3b54839e299a9c3408..0b28fdd0a2fb5b45457f92192a712797 public void updatePlayers(final List players) { diff --git a/net/minecraft/server/level/DistanceManager.java b/net/minecraft/server/level/DistanceManager.java -index abc610594c3d37993df8762783baaae0c053a5cc..f1fa6c7169635724e202c10adafe7d70e14ac7de 100644 +index 31badcd3a478f770e1a8d296dbb5d9e4b529ae7d..63cc7970b9df5e84743084ca99650bc3d13b970e 100644 --- a/net/minecraft/server/level/DistanceManager.java +++ b/net/minecraft/server/level/DistanceManager.java -@@ -32,94 +32,79 @@ import net.minecraft.world.level.chunk.LevelChunk; +@@ -31,94 +31,79 @@ import net.minecraft.world.level.chunk.LevelChunk; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; @@ -25980,7 +25979,7 @@ index abc610594c3d37993df8762783baaae0c053a5cc..f1fa6c7169635724e202c10adafe7d70 } public void removePlayer(final SectionPos pos, final ServerPlayer player) { -@@ -131,71 +116,79 @@ public abstract class DistanceManager { +@@ -130,71 +115,79 @@ public abstract class DistanceManager { if (chunkPlayers == null || chunkPlayers.isEmpty()) { // Paper end - some state corruption happens here, don't crash, clean up gracefully this.playersPerChunk.remove(chunkPos); @@ -26090,15 +26089,15 @@ index abc610594c3d37993df8762783baaae0c053a5cc..f1fa6c7169635724e202c10adafe7d70 } public boolean hasTickets() { -@@ -249,6 +242,7 @@ public abstract class DistanceManager { +@@ -246,6 +239,7 @@ public abstract class DistanceManager { } } +/* // Paper - rewrite chunk system private class PlayerTicketTracker extends DistanceManager.FixedPlayerDistanceChunkTracker { private int viewDistance; - private final Long2IntMap queueLevels; -@@ -330,5 +324,5 @@ public abstract class DistanceManager { + private final Long2IntMap queueLevels = Long2IntMaps.synchronize(new Long2IntOpenHashMap()); +@@ -324,5 +318,5 @@ public abstract class DistanceManager { private boolean haveTicketFor(final int level) { return level <= this.viewDistance; } @@ -26106,7 +26105,7 @@ index abc610594c3d37993df8762783baaae0c053a5cc..f1fa6c7169635724e202c10adafe7d70 + }*/ // Paper - rewrite chunk system } diff --git a/net/minecraft/server/level/GenerationChunkHolder.java b/net/minecraft/server/level/GenerationChunkHolder.java -index 531cc9b4375f7eb7c1ca6dcd40c29b74b600ec63..75686eb990d7275b442e16df39b7b2e181c0048f 100644 +index bd140f2d39307d4f909b11cc78da84e03aa4c3ca..75686eb990d7275b442e16df39b7b2e181c0048f 100644 --- a/net/minecraft/server/level/GenerationChunkHolder.java +++ b/net/minecraft/server/level/GenerationChunkHolder.java @@ -26,12 +26,7 @@ public abstract class GenerationChunkHolder { @@ -26129,19 +26128,19 @@ index 531cc9b4375f7eb7c1ca6dcd40c29b74b600ec63..75686eb990d7275b442e16df39b7b2e1 public CompletableFuture> scheduleChunkGenerationTask(final ChunkStatus status, final ChunkMap scheduler) { - if (this.isStatusDisallowed(status)) { - return UNLOADED_CHUNK_FUTURE; -- } else { -- CompletableFuture> future = this.getOrCreateFuture(status); -- if (future.isDone()) { -- return future; -- } else { -- ChunkGenerationTask task = this.task.get(); -- if (task == null || status.isAfter(task.targetStatus)) { -- this.rescheduleChunkTask(scheduler, status); -- } +- } - -- return future; -- } +- CompletableFuture> future = this.getOrCreateFuture(status); +- if (future.isDone()) { +- return future; +- } +- +- ChunkGenerationTask task = this.task.get(); +- if (task == null || status.isAfter(task.targetStatus)) { +- this.rescheduleChunkTask(scheduler, status); - } +- +- return future; + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -26220,25 +26219,25 @@ index 531cc9b4375f7eb7c1ca6dcd40c29b74b600ec63..75686eb990d7275b442e16df39b7b2e1 private CompletableFuture> getOrCreateFuture(final ChunkStatus status) { - if (this.isStatusDisallowed(status)) { - return UNLOADED_CHUNK_FUTURE; -- } else { -- int index = status.getIndex(); -- CompletableFuture> future = this.futures.get(index); +- } - -- while (future == null) { -- CompletableFuture> newValue = new CompletableFuture<>(); -- future = this.futures.compareAndExchange(index, null, newValue); -- if (future == null) { -- if (this.isStatusDisallowed(status)) { -- this.failAndClearPendingFuture(index, newValue); -- return UNLOADED_CHUNK_FUTURE; -- } +- int index = status.getIndex(); +- CompletableFuture> future = this.futures.get(index); - -- return newValue; +- while (future == null) { +- CompletableFuture> newValue = new CompletableFuture<>(); +- future = this.futures.compareAndExchange(index, null, newValue); +- if (future == null) { +- if (this.isStatusDisallowed(status)) { +- this.failAndClearPendingFuture(index, newValue); +- return UNLOADED_CHUNK_FUTURE; - } -- } - -- return future; +- return newValue; +- } - } +- +- return future; + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -26290,24 +26289,24 @@ index 531cc9b4375f7eb7c1ca6dcd40c29b74b600ec63..75686eb990d7275b442e16df39b7b2e1 private @Nullable ChunkStatus findHighestStatusWithPendingFuture(final @Nullable ChunkStatus newStatus) { - if (newStatus == null) { - return null; -- } else { -- ChunkStatus highestStatus = newStatus; +- } - -- for (ChunkStatus alreadyStarted = this.startedWork.get(); -- alreadyStarted == null || highestStatus.isAfter(alreadyStarted); -- highestStatus = highestStatus.getParent() -- ) { -- if (this.futures.get(highestStatus.getIndex()) != null) { -- return highestStatus; -- } +- ChunkStatus highestStatus = newStatus; - -- if (highestStatus == ChunkStatus.EMPTY) { -- break; -- } +- for (ChunkStatus alreadyStarted = this.startedWork.get(); +- alreadyStarted == null || highestStatus.isAfter(alreadyStarted); +- highestStatus = highestStatus.getParent() +- ) { +- if (this.futures.get(highestStatus.getIndex()) != null) { +- return highestStatus; - } - -- return null; +- if (highestStatus == ChunkStatus.EMPTY) { +- break; +- } - } +- +- return null; + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } @@ -26372,10 +26371,10 @@ index 531cc9b4375f7eb7c1ca6dcd40c29b74b600ec63..75686eb990d7275b442e16df39b7b2e1 - ChunkStatus status = this.startedWork.get(); - if (status == null) { - return null; -- } else { -- ChunkAccess chunk = this.getChunkIfPresentUnchecked(status); -- return chunk != null ? chunk : this.getChunkIfPresentUnchecked(status.getParent()); - } +- +- ChunkAccess chunk = this.getChunkIfPresentUnchecked(status); +- return chunk != null ? chunk : this.getChunkIfPresentUnchecked(status.getParent()); + // Paper start - rewrite chunk system + final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder.ChunkCompletion lastCompletion = ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkHolder)(Object)this).moonrise$getRealChunkHolder().getLastChunkCompletion(); + return lastCompletion == null ? null : lastCompletion.chunk(); @@ -26421,10 +26420,10 @@ index 531cc9b4375f7eb7c1ca6dcd40c29b74b600ec63..75686eb990d7275b442e16df39b7b2e1 - ChunkStatus status = this.startedWork.get(); - if (status == null) { - return null; -- } else { -- ChunkAccess chunk = this.getChunkIfPresentUnchecked(status); -- return chunk != null ? status : status.getParent(); - } +- +- ChunkAccess chunk = this.getChunkIfPresentUnchecked(status); +- return chunk != null ? status : status.getParent(); + // Paper start - rewrite chunk system + final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder.ChunkCompletion lastCompletion = ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkHolder)(Object)this).moonrise$getRealChunkHolder().getLastChunkCompletion(); + return lastCompletion == null ? null : lastCompletion.genStatus(); @@ -26445,7 +26444,7 @@ index b107715893fc5329ae4a27967780d3587166b6dd..15cd107d347ee01c809938684bf90cc2 } } diff --git a/net/minecraft/server/level/PlayerSpawnFinder.java b/net/minecraft/server/level/PlayerSpawnFinder.java -index 045d4b0ab26622e2763d1583e1e8fcb83ba44427..ddffd36d8213a40dc3f6cbb0ef0f33a0a7490ac1 100644 +index 8e02980d29a15086805a93f1f1a416f0308c70b9..a7799e8c12713e00124f2caf69f74a616b1af3e7 100644 --- a/net/minecraft/server/level/PlayerSpawnFinder.java +++ b/net/minecraft/server/level/PlayerSpawnFinder.java @@ -115,9 +115,9 @@ public class PlayerSpawnFinder { @@ -26471,7 +26470,7 @@ index 045d4b0ab26622e2763d1583e1e8fcb83ba44427..ddffd36d8213a40dc3f6cbb0ef0f33a0 } diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index bf8496c8cadb29db9c46015e202e7d59e2ed2f5e..f4e033fb5e5b116245dd4a381366c4e749a73f93 100644 +index ca9e965a200ae4e9e5e8d53823918a24a56cb742..a5685e0b50610cc8213f34c5db62b475bd54789b 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java @@ -54,7 +54,7 @@ import net.minecraft.world.level.storage.SavedDataStorage; @@ -26483,7 +26482,7 @@ index bf8496c8cadb29db9c46015e202e7d59e2ed2f5e..f4e033fb5e5b116245dd4a381366c4e7 private static final Logger LOGGER = LogUtils.getLogger(); private final DistanceManager distanceManager; private final ServerLevel level; -@@ -82,6 +82,106 @@ public class ServerChunkCache extends ChunkSource { +@@ -82,6 +82,105 @@ public class ServerChunkCache extends ChunkSource { } long chunkFutureAwaitCounter; // Paper end @@ -26586,11 +26585,10 @@ index bf8496c8cadb29db9c46015e202e7d59e2ed2f5e..f4e033fb5e5b116245dd4a381366c4e7 + } + } + // Paper end - chunk tick iteration optimisations -+ public ServerChunkCache( final ServerLevel level, -@@ -141,13 +241,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -141,13 +240,7 @@ public class ServerChunkCache extends ChunkSource { } // CraftBukkit end // Paper start @@ -26605,47 +26603,44 @@ index bf8496c8cadb29db9c46015e202e7d59e2ed2f5e..f4e033fb5e5b116245dd4a381366c4e7 @Nullable public ChunkAccess getChunkAtImmediately(int x, int z) { -@@ -212,67 +306,42 @@ public class ServerChunkCache extends ChunkSource { +@@ -212,66 +305,41 @@ public class ServerChunkCache extends ChunkSource { @Override public @Nullable ChunkAccess getChunk(final int x, final int z, final ChunkStatus targetStatus, final boolean loadOrGenerate) { - if (Thread.currentThread() != this.mainThread) { - return CompletableFuture.supplyAsync(() -> this.getChunk(x, z, targetStatus, loadOrGenerate), this.mainThreadProcessor).join(); -- } else { -- ProfilerFiller profiler = Profiler.get(); -- profiler.incrementCounter("getChunk"); -- long pos = ChunkPos.pack(x, z); -- -- for (int i = 0; i < 4; i++) { -- if (pos == this.lastChunkPos[i] && targetStatus == this.lastChunkStatus[i]) { -- ChunkAccess chunkAccess = this.lastChunk[i]; -- if (chunkAccess != null) { // CraftBukkit - the chunk can become accessible in the meantime TODO for non-null chunks it might also make sense to check that the chunk's state hasn't changed in the meantime -- return chunkAccess; -- } -- } -- } +- } + // Paper start - rewrite chunk system + if (targetStatus == ChunkStatus.FULL) { + final LevelChunk ret = this.fullChunks.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(x, z)); -- profiler.incrementCounter("getChunkCacheMiss"); -- CompletableFuture> serverFuture = this.getChunkFutureMainThread(x, z, targetStatus, loadOrGenerate); -- this.mainThreadProcessor.managedBlock(serverFuture::isDone); -- // com.destroystokyo.paper.io.SyncLoadFinder.logSyncLoad(this.level, x, z); // Paper - Add debug for sync chunk loads -- ChunkResult chunkResult = serverFuture.join(); -- ChunkAccess chunk = chunkResult.orElse(null); -- if (chunk == null && loadOrGenerate) { -- throw (IllegalStateException)Util.pauseInIde(new IllegalStateException("Chunk not there when requested: " + chunkResult.getError())); -- } else { -- this.storeInCache(pos, chunk, targetStatus); -- return chunk; +- ProfilerFiller profiler = Profiler.get(); +- profiler.incrementCounter("getChunk"); +- long pos = ChunkPos.pack(x, z); +- +- for (int i = 0; i < 4; i++) { +- if (pos == this.lastChunkPos[i] && targetStatus == this.lastChunkStatus[i]) { +- ChunkAccess chunkAccess = this.lastChunk[i]; +- if (chunkAccess != null) { // CraftBukkit - the chunk can become accessible in the meantime TODO for non-null chunks it might also make sense to check that the chunk's state hasn't changed in the meantime +- return chunkAccess; +- } + if (ret != null) { + return ret; } -+ +- } + +- profiler.incrementCounter("getChunkCacheMiss"); +- CompletableFuture> serverFuture = this.getChunkFutureMainThread(x, z, targetStatus, loadOrGenerate); +- this.mainThreadProcessor.managedBlock(serverFuture::isDone); +- ChunkResult chunkResult = serverFuture.join(); +- ChunkAccess chunk = chunkResult.orElse(null); +- if (chunk == null && loadOrGenerate) { +- throw (IllegalStateException)Util.pauseInIde(new IllegalStateException("Chunk not there when requested: " + chunkResult.getError())); + return loadOrGenerate ? this.getChunkFallback(x, z, targetStatus, loadOrGenerate) : null; } -+ + +- this.storeInCache(pos, chunk, targetStatus); +- return chunk; + return this.getChunkFallback(x, z, targetStatus, loadOrGenerate); + // Paper end - rewrite chunk system } @@ -26654,51 +26649,48 @@ index bf8496c8cadb29db9c46015e202e7d59e2ed2f5e..f4e033fb5e5b116245dd4a381366c4e7 public @Nullable LevelChunk getChunkNow(final int x, final int z) { - if (Thread.currentThread() != this.mainThread) { - return null; -- } else { -- Profiler.get().incrementCounter("getChunkNow"); -- long pos = ChunkPos.pack(x, z); + // Paper start - rewrite chunk system + final LevelChunk ret = this.fullChunks.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(x, z)); + if (!ca.spottedleaf.moonrise.common.PlatformHooks.get().hasCurrentlyLoadingChunk()) { + return ret; + } -- for (int i = 0; i < 4; i++) { -- if (pos == this.lastChunkPos[i] && this.lastChunkStatus[i] == ChunkStatus.FULL) { -- ChunkAccess chunkAccess = this.lastChunk[i]; -- return chunkAccess instanceof LevelChunk ? (LevelChunk)chunkAccess : null; -- } +- Profiler.get().incrementCounter("getChunkNow"); +- long pos = ChunkPos.pack(x, z); +- +- for (int i = 0; i < 4; i++) { +- if (pos == this.lastChunkPos[i] && this.lastChunkStatus[i] == ChunkStatus.FULL) { +- ChunkAccess chunkAccess = this.lastChunk[i]; +- return chunkAccess instanceof LevelChunk ? (LevelChunk)chunkAccess : null; - } -+ } - -- ChunkHolder chunkHolder = this.getVisibleChunkIfPresent(pos); -- if (chunkHolder == null) { -- return null; -- } else { -- ChunkAccess chunk = chunkHolder.getChunkIfPresent(ChunkStatus.FULL); -- if (chunk != null) { -- this.storeInCache(pos, chunk, ChunkStatus.FULL); -- if (chunk instanceof LevelChunk) { -- return (LevelChunk)chunk; -- } -- } + if (ret != null || !ca.spottedleaf.moonrise.common.util.TickThread.isTickThread()) { + return ret; -+ } + } -- return null; +- ChunkHolder chunkHolder = this.getVisibleChunkIfPresent(pos); +- if (chunkHolder == null) { +- return null; +- } +- +- ChunkAccess chunk = chunkHolder.getChunkIfPresent(ChunkStatus.FULL); +- if (chunk != null) { +- this.storeInCache(pos, chunk, ChunkStatus.FULL); +- if (chunk instanceof LevelChunk) { +- return (LevelChunk)chunk; - } + final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder holder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler() + .chunkHolderManager.getChunkHolder(x, z); + if (holder == null) { + return ret; } -+ + +- return null; + return ca.spottedleaf.moonrise.common.PlatformHooks.get().getCurrentlyLoadingChunk(holder.vanillaChunkHolder); + // Paper end - rewrite chunk system } private void clearCache() { -@@ -300,53 +369,62 @@ public class ServerChunkCache extends ChunkSource { +@@ -299,53 +367,62 @@ public class ServerChunkCache extends ChunkSource { private CompletableFuture> getChunkFutureMainThread( final int x, final int z, final ChunkStatus targetStatus, final boolean loadOrGenerate ) { @@ -26795,7 +26787,7 @@ index bf8496c8cadb29db9c46015e202e7d59e2ed2f5e..f4e033fb5e5b116245dd4a381366c4e7 } @Override -@@ -359,28 +437,18 @@ public class ServerChunkCache extends ChunkSource { +@@ -358,28 +435,18 @@ public class ServerChunkCache extends ChunkSource { } public boolean runDistanceManagerUpdates() { @@ -26804,20 +26796,20 @@ index bf8496c8cadb29db9c46015e202e7d59e2ed2f5e..f4e033fb5e5b116245dd4a381366c4e7 - this.chunkMap.runGenerationTasks(); - if (!updated && !promoted) { - return false; -- } else { -- this.clearCache(); -- return true; - } +- +- this.clearCache(); +- return true; + return ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.processTicketUpdates(); // Paper - rewrite chunk system } public boolean isPositionTicking(final long chunkKey) { - if (!this.level.shouldTickBlocksAt(chunkKey)) { - return false; -- } else { -- ChunkHolder holder = this.getVisibleChunkIfPresent(chunkKey); -- return holder != null && holder.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).isSuccess(); - } +- +- ChunkHolder holder = this.getVisibleChunkIfPresent(chunkKey); +- return holder != null && holder.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).isSuccess(); + // Paper start - rewrite chunk system + final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder newChunkHolder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkKey); + return newChunkHolder != null && newChunkHolder.isTickingReady(); @@ -26830,7 +26822,7 @@ index bf8496c8cadb29db9c46015e202e7d59e2ed2f5e..f4e033fb5e5b116245dd4a381366c4e7 this.chunkMap.saveAllChunks(flushStorage); } -@@ -391,17 +459,15 @@ public class ServerChunkCache extends ChunkSource { +@@ -390,17 +457,15 @@ public class ServerChunkCache extends ChunkSource { } public void close(boolean save) throws IOException { @@ -26851,7 +26843,7 @@ index bf8496c8cadb29db9c46015e202e7d59e2ed2f5e..f4e033fb5e5b116245dd4a381366c4e7 ProfilerFiller gameprofilerfiller = Profiler.get(); gameprofilerfiller.push("purge"); -@@ -425,6 +491,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -424,6 +489,7 @@ public class ServerChunkCache extends ChunkSource { this.runDistanceManagerUpdates(); profiler.popPush("chunks"); if (tickChunks) { @@ -26859,7 +26851,7 @@ index bf8496c8cadb29db9c46015e202e7d59e2ed2f5e..f4e033fb5e5b116245dd4a381366c4e7 this.tickChunks(); this.chunkMap.tick(); } -@@ -457,7 +524,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -456,7 +522,7 @@ public class ServerChunkCache extends ChunkSource { profiler.push("broadcast"); for (ChunkHolder chunkHolder : this.chunkHoldersToBroadcast) { @@ -26868,7 +26860,7 @@ index bf8496c8cadb29db9c46015e202e7d59e2ed2f5e..f4e033fb5e5b116245dd4a381366c4e7 if (chunk != null) { chunkHolder.broadcastChanges(chunk); } -@@ -498,7 +565,10 @@ public class ServerChunkCache extends ChunkSource { +@@ -497,7 +563,10 @@ public class ServerChunkCache extends ChunkSource { profiler.popPush("filteringSpawningChunks"); this.chunkMap.collectSpawningChunks(spawningChunks); profiler.popPush("shuffleSpawningChunks"); @@ -26879,7 +26871,7 @@ index bf8496c8cadb29db9c46015e202e7d59e2ed2f5e..f4e033fb5e5b116245dd4a381366c4e7 profiler.popPush("tickSpawningChunks"); for (LevelChunk chunk : spawningChunks) { -@@ -509,7 +579,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -508,7 +577,7 @@ public class ServerChunkCache extends ChunkSource { } profiler.popPush("tickTickingChunks"); @@ -26888,7 +26880,7 @@ index bf8496c8cadb29db9c46015e202e7d59e2ed2f5e..f4e033fb5e5b116245dd4a381366c4e7 if (doMobSpawning) { profiler.popPush("customSpawners"); this.level.tickCustomSpawners(this.spawnEnemies); -@@ -523,22 +593,25 @@ public class ServerChunkCache extends ChunkSource { +@@ -522,22 +591,25 @@ public class ServerChunkCache extends ChunkSource { ) { ChunkPos chunkPos = chunk.getPos(); chunk.incrementInhabitedTime(timeDiff); @@ -26919,21 +26911,23 @@ index bf8496c8cadb29db9c46015e202e7d59e2ed2f5e..f4e033fb5e5b116245dd4a381366c4e7 } @Override -@@ -596,17 +669,11 @@ public class ServerChunkCache extends ChunkSource { +@@ -595,19 +667,11 @@ public class ServerChunkCache extends ChunkSource { } public CompletableFuture addTicketAndLoadWithRadius(final TicketType type, final ChunkPos pos, final int radius) { - if (!type.doesLoad()) { - throw new IllegalStateException("Ticket type " + type + " does not trigger chunk loading"); -- } else if (type.canExpireIfUnloaded()) { +- } +- +- if (type.canExpireIfUnloaded()) { - throw new IllegalStateException("Ticket type " + type + " can expire before it loads, cannot fetch asynchronously"); -- } else { -- this.addTicketWithRadius(type, pos, radius); -- this.runDistanceManagerUpdates(); -- ChunkHolder chunkHolder = this.getVisibleChunkIfPresent(pos.pack()); -- Objects.requireNonNull(chunkHolder, "No chunk was scheduled for loading"); -- return this.chunkMap.getChunkRangeFuture(chunkHolder, radius, distance -> ChunkStatus.FULL); - } +- +- this.addTicketWithRadius(type, pos, radius); +- this.runDistanceManagerUpdates(); +- ChunkHolder chunkHolder = this.getVisibleChunkIfPresent(pos.pack()); +- Objects.requireNonNull(chunkHolder, "No chunk was scheduled for loading"); +- return this.chunkMap.getChunkRangeFuture(chunkHolder, radius, distance -> ChunkStatus.FULL); + // Paper start - rewrite chunk system + return ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.addTicketAndLoadWithRadius( + type, pos, radius, ChunkStatus.FULL, ca.spottedleaf.concurrentutil.util.Priority.NORMAL @@ -26942,7 +26936,7 @@ index bf8496c8cadb29db9c46015e202e7d59e2ed2f5e..f4e033fb5e5b116245dd4a381366c4e7 } public void addTicketWithRadius(final TicketType type, final ChunkPos pos, final int radius) { -@@ -656,6 +723,12 @@ public class ServerChunkCache extends ChunkSource { +@@ -657,6 +721,12 @@ public class ServerChunkCache extends ChunkSource { this.chunkMap.setServerViewDistance(newDistance); } @@ -26955,32 +26949,29 @@ index bf8496c8cadb29db9c46015e202e7d59e2ed2f5e..f4e033fb5e5b116245dd4a381366c4e7 public void setSimulationDistance(final int simulationDistance) { this.distanceManager.updateSimulationDistance(simulationDistance); } -@@ -736,18 +809,14 @@ public class ServerChunkCache extends ChunkSource { +@@ -736,18 +806,12 @@ public class ServerChunkCache extends ChunkSource { @Override protected boolean pollTask() { - try { // CraftBukkit - process pending Chunk loadCallback() and unloadCallback() after each run task -- if (ServerChunkCache.this.runDistanceManagerUpdates()) { -+ // Paper start - rewrite chunk system -+ final ServerChunkCache serverChunkCache = ServerChunkCache.this; -+ if (serverChunkCache.runDistanceManagerUpdates()) { + if (ServerChunkCache.this.runDistanceManagerUpdates()) { return true; - } else { -- ServerChunkCache.this.lightEngine.tryScheduleUpdate(); -- return super.pollTask(); -- } + } + +- ServerChunkCache.this.lightEngine.tryScheduleUpdate(); +- return super.pollTask(); - // CraftBukkit start - process pending Chunk loadCallback() and unloadCallback() after each run task - } finally { - ServerChunkCache.this.chunkMap.callbackExecutor.run(); -+ return super.pollTask() | ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)serverChunkCache.level).moonrise$getChunkTaskScheduler().executeMainThreadTask(); - } +- } - // CraftBukkit end - process pending Chunk loadCallback() and unloadCallback() after each run task -+ // Paper end - rewrite chunk system ++ // Paper - rewrite chunk system ++ return super.pollTask() | ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)ServerChunkCache.this.level).moonrise$getChunkTaskScheduler().executeMainThreadTask(); // Paper - rewrite chunk system } } } diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java -index de75dda2e6f17f0ae6e7f6a5620fd3eac9d389e5..6774d12d04fa848624fb8bf7a3c2b8bcb88f6e8f 100644 +index 160eeda06cd6bfcec60bac43235760d92fe8d63d..a62ec41b1319857f0d6cd223d013a92b1e2c2b0d 100644 --- a/net/minecraft/server/level/ServerEntity.java +++ b/net/minecraft/server/level/ServerEntity.java @@ -90,6 +90,11 @@ public class ServerEntity { @@ -26996,7 +26987,7 @@ index de75dda2e6f17f0ae6e7f6a5620fd3eac9d389e5..6774d12d04fa848624fb8bf7a3c2b8bc List passengers = this.entity.getPassengers(); if (!passengers.equals(this.lastPassengers)) { diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index f39d48821d728232472ebc5bd6868e6a0d644721..91d27b90a9c9c348d3f93624ff8dbff8a70f522c 100644 +index d2eac2935a16a9127958b94414668ce408880319..0fabe7fe4d302695505bed2cef4ce580358b8b82 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java @@ -182,7 +182,7 @@ import net.minecraft.world.waypoints.WaypointTransmitter; @@ -27525,7 +27516,7 @@ index f39d48821d728232472ebc5bd6868e6a0d644721..91d27b90a9c9c348d3f93624ff8dbff8 - int sectionY = chunk.getSectionYFromSectionIndex(sectionIndex); - int minYInSection = SectionPos.sectionToBlockCoord(sectionY); - -- for (int ix = 0; ix < tickSpeed; ix++) { +- for (int i = 0; i < tickSpeed; i++) { - BlockPos pos = this.getBlockRandomPos(minX, minYInSection, minZ, 15); - profiler.push("randomTick"); - BlockState blockState = section.getBlockState(pos.getX() - minX, pos.getY() - minYInSection, pos.getZ() - minZ); @@ -27633,8 +27624,8 @@ index f39d48821d728232472ebc5bd6868e6a0d644721..91d27b90a9c9c348d3f93624ff8dbff8 - if (entity.getSelfAndPassengers().map(Entity::getUUID).anyMatch(this.entityManager::isLoaded)) { + if (entity.getSelfAndPassengers().map(Entity::getUUID).anyMatch(this.moonrise$getEntityLookup()::hasEntity)) { // Paper - rewrite chunk system return false; - } else { - this.addFreshEntityWithPassengers(entity, reason); // CraftBukkit + } + @@ -2112,7 +2423,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet } } @@ -27778,10 +27769,10 @@ index f39d48821d728232472ebc5bd6868e6a0d644721..91d27b90a9c9c348d3f93624ff8dbff8 "Server weather", () -> String.format( diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index 2ffb9c7388e15ec3e3afd3fa50cc0149c0c8910d..41816ca8d4ef3d959d2b88cd4b2eedaaa541e612 100644 +index 020b63f9d356aadf0bdaf2e34067d15bacd0177a..f35f88da81abb14b393d6fce04054ee40e8d8397 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java -@@ -203,7 +203,7 @@ import net.minecraft.world.scores.criteria.ObjectiveCriteria; +@@ -202,7 +202,7 @@ import net.minecraft.world.scores.criteria.ObjectiveCriteria; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; @@ -27790,7 +27781,7 @@ index 2ffb9c7388e15ec3e3afd3fa50cc0149c0c8910d..41816ca8d4ef3d959d2b88cd4b2eedaa private static final Logger LOGGER = LogUtils.getLogger(); private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32; private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10; -@@ -449,6 +449,36 @@ public class ServerPlayer extends Player { +@@ -430,6 +430,36 @@ public class ServerPlayer extends Player { public com.destroystokyo.paper.event.entity.@Nullable PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper - PlayerNaturallySpawnCreaturesEvent public org.bukkit.event.player.PlayerQuitEvent.@Nullable QuitReason quitReason = null; // Paper - Add API for quit reason; there are a lot of changes to do if we change all methods leading to the event @@ -27827,7 +27818,7 @@ index 2ffb9c7388e15ec3e3afd3fa50cc0149c0c8910d..41816ca8d4ef3d959d2b88cd4b2eedaa public ServerPlayer(final MinecraftServer server, final ServerLevel level, final GameProfile gameProfile, final ClientInformation clientInformation) { super(level, gameProfile); this.server = server; -@@ -471,7 +501,7 @@ public class ServerPlayer extends Player { +@@ -452,7 +482,7 @@ public class ServerPlayer extends Player { @Override public BlockPos adjustSpawnLocation(final ServerLevel level, final BlockPos spawnSuggestion) { CompletableFuture future = PlayerSpawnFinder.findSpawn(level, spawnSuggestion); @@ -27837,7 +27828,7 @@ index 2ffb9c7388e15ec3e3afd3fa50cc0149c0c8910d..41816ca8d4ef3d959d2b88cd4b2eedaa } diff --git a/net/minecraft/server/level/ThreadedLevelLightEngine.java b/net/minecraft/server/level/ThreadedLevelLightEngine.java -index 46ce24ea601b1525834c1165075fc89d7ed8c69b..c050f208f485f67061fe5bf617915cd83860e5f3 100644 +index 9579dd385417752b07c2ad8d074025f9143bfe85..948a8a2b38d8ba3a2ea61cb2c85c3039bb938f2d 100644 --- a/net/minecraft/server/level/ThreadedLevelLightEngine.java +++ b/net/minecraft/server/level/ThreadedLevelLightEngine.java @@ -23,15 +23,144 @@ import net.minecraft.world.level.lighting.LevelLightEngine; @@ -28187,7 +28178,7 @@ index 46ce24ea601b1525834c1165075fc89d7ed8c69b..c050f208f485f67061fe5bf617915cd8 + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private static enum TaskType { + private enum TaskType { diff --git a/net/minecraft/server/level/Ticket.java b/net/minecraft/server/level/Ticket.java index 40f97e3657a1672d3865ab915c7f36d3dbf88c6e..b075d7f68a263422cfa1f35b1f896038d3c712dd 100644 --- a/net/minecraft/server/level/Ticket.java @@ -28399,7 +28390,7 @@ index 4de90a597bd5c5ac639fd228b3494e70a945d7ff..147cd0458d719be6679b6bac2b6617b4 return this == PLUGIN ? PLUGIN_TYPE_TIMEOUT : this.timeout; } diff --git a/net/minecraft/server/level/WorldGenRegion.java b/net/minecraft/server/level/WorldGenRegion.java -index 690bb45bc91e4ca76754ca8f125c844a54484caf..f288ac0ddc60841ea263c74e15a2060e070c84a0 100644 +index f4a426af2e638b79b783f5181da665d4e0552949..692f8684b9bccd76ab03edbc2ef31149d8a67cc8 100644 --- a/net/minecraft/server/level/WorldGenRegion.java +++ b/net/minecraft/server/level/WorldGenRegion.java @@ -76,6 +76,36 @@ public class WorldGenRegion implements WorldGenLevel { @@ -28453,36 +28444,36 @@ index c974b6cafb1f6aa2a57cfdc8a39c887f02f42b1d..ec40f02032f965f548b0c0a29aa9d9bb // Paper start - PlayerChunkLoadEvent if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) { diff --git a/net/minecraft/server/network/config/PrepareSpawnTask.java b/net/minecraft/server/network/config/PrepareSpawnTask.java -index 83af9ee3ba150da85b9b694cd76a5fabb5b2d8ef..1fb40837bd02672850ec9adc2797190df22b33fc 100644 +index 5576bfd83e101aa81b6f79f7144be69f2fbfda08..f087b290ffbb2cd719b68de98b5381b789f442df 100644 --- a/net/minecraft/server/network/config/PrepareSpawnTask.java +++ b/net/minecraft/server/network/config/PrepareSpawnTask.java -@@ -171,7 +171,7 @@ public class PrepareSpawnTask implements ConfigurationTask { +@@ -165,7 +165,7 @@ public class PrepareSpawnTask implements ConfigurationTask { + private Vec2 spawnAngle; // Paper - remove final + private @Nullable CompletableFuture chunkLoadFuture; + private @Nullable CompletableFuture eventFuture; // Paper +- private final ChunkLoadCounter chunkLoadCounter = new ChunkLoadCounter(); ++ private final ChunkLoadCounter chunkLoadCounter = new ca.spottedleaf.moonrise.patches.chunk_system.MoonriseChunkLoadCounter(); // Paper - rewrite chunk system + private Preparing(final ServerLevel spawnLevel, final CompletableFuture spawnPosition, final Vec2 spawnAngle) { - Objects.requireNonNull(PrepareSpawnTask.this); - super(); -- this.chunkLoadCounter = new ChunkLoadCounter(); -+ this.chunkLoadCounter = new ca.spottedleaf.moonrise.patches.chunk_system.MoonriseChunkLoadCounter(); // Paper - rewrite chunk system this.spawnLevel = spawnLevel; - this.spawnPosition = spawnPosition; - this.spawnAngle = spawnAngle; -@@ -236,11 +236,7 @@ public class PrepareSpawnTask implements ConfigurationTask { - } - // Paper end - PlayerSpawnLocationEvent - ChunkPos spawnChunk = ChunkPos.containing(BlockPos.containing(spawnPosition)); -- this.chunkLoadCounter -- .track( -- this.spawnLevel, -- () -> this.chunkLoadFuture = this.spawnLevel.getChunkSource().addTicketAndLoadWithRadius(TicketType.PLAYER_SPAWN, spawnChunk, 3) -- ); -+ this.chunkLoadFuture = ((ca.spottedleaf.moonrise.patches.chunk_system.MoonriseChunkLoadCounter)this.chunkLoadCounter).trackLoadWithRadius(this.spawnLevel, spawnChunk, 3, net.minecraft.world.level.chunk.status.ChunkStatus.FULL, ca.spottedleaf.concurrentutil.util.Priority.HIGH, () -> { Preparing.this.spawnLevel.getChunkSource().addTicketWithRadius(TicketType.PLAYER_SPAWN, spawnChunk, 3); }); // Paper - rewrite chunk system - PrepareSpawnTask.this.loadListener.start(LevelLoadListener.Stage.LOAD_PLAYER_CHUNKS, this.chunkLoadCounter.totalChunks()); - PrepareSpawnTask.this.loadListener.updateFocus(this.spawnLevel.dimension(), spawnChunk); +@@ -233,11 +233,7 @@ public class PrepareSpawnTask implements ConfigurationTask { } + // Paper end - PlayerSpawnLocationEvent + ChunkPos spawnChunk = ChunkPos.containing(BlockPos.containing(spawnPosition)); +- this.chunkLoadCounter +- .track( +- this.spawnLevel, +- () -> this.chunkLoadFuture = this.spawnLevel.getChunkSource().addTicketAndLoadWithRadius(TicketType.PLAYER_SPAWN, spawnChunk, 3) +- ); ++ this.chunkLoadFuture = ((ca.spottedleaf.moonrise.patches.chunk_system.MoonriseChunkLoadCounter)this.chunkLoadCounter).trackLoadWithRadius(this.spawnLevel, spawnChunk, 3, net.minecraft.world.level.chunk.status.ChunkStatus.FULL, ca.spottedleaf.concurrentutil.util.Priority.HIGH, () -> { Preparing.this.spawnLevel.getChunkSource().addTicketWithRadius(TicketType.PLAYER_SPAWN, spawnChunk, 3); }); // Paper - rewrite chunk system + PrepareSpawnTask.this.loadListener.start(LevelLoadListener.Stage.LOAD_PLAYER_CHUNKS, this.chunkLoadCounter.totalChunks()); + PrepareSpawnTask.this.loadListener.updateFocus(this.spawnLevel.dimension(), spawnChunk); + } diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java -index eff42b94fd182abace988d9649952e04dc35b268..02605ebe6ef10727badadbf7fc4cec52583df965 100644 +index 58fb206651471c7fe9781733bf6d489814a68b5d..eb41400b8948d3eecc6fd89e2fefbe638ccbaad1 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java -@@ -982,8 +982,8 @@ public abstract class PlayerList { +@@ -979,8 +979,8 @@ public abstract class PlayerList { player.connection.send(level.clockManager().createFullSyncPacket(player)); // Paper - per-world time; per-player time player.connection.send(new ClientboundSetDefaultSpawnPositionPacket(level.getRespawnData())); // Paper start - view distances @@ -28493,7 +28484,7 @@ index eff42b94fd182abace988d9649952e04dc35b268..02605ebe6ef10727badadbf7fc4cec52 // Paper end - view distances if (level.isRaining()) { // CraftBukkit start - handle player weather -@@ -1200,7 +1200,7 @@ public abstract class PlayerList { +@@ -1197,7 +1197,7 @@ public abstract class PlayerList { public void setViewDistance(final int viewDistance) { this.viewDistance = viewDistance; @@ -28502,7 +28493,7 @@ index eff42b94fd182abace988d9649952e04dc35b268..02605ebe6ef10727badadbf7fc4cec52 for (ServerLevel level : this.server.getAllLevels()) { level.getChunkSource().setViewDistance(viewDistance); -@@ -1209,7 +1209,7 @@ public abstract class PlayerList { +@@ -1206,7 +1206,7 @@ public abstract class PlayerList { public void setSimulationDistance(final int simulationDistance) { this.simulationDistance = simulationDistance; @@ -28548,7 +28539,7 @@ index a7fb2632bd55ed422dea2a559272645c5b422cc1..48f6671ecabfd5a8c9f8151ccb59f9ea + // Paper end - block counting } diff --git a/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java b/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java -index 8df91fc917c22f3b633fe6df2f5311151c1cc54e..8cfb6a17b10130b5ad809698f5b021096e20dca8 100644 +index 1086960c32e4b02d06a09ec8ebc80444c8c4b6cd..444aa788b4f8265fb675230000e606d746aeed42 100644 --- a/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java +++ b/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java @@ -7,7 +7,7 @@ import java.util.Iterator; @@ -28591,7 +28582,7 @@ index 8df91fc917c22f3b633fe6df2f5311151c1cc54e..8cfb6a17b10130b5ad809698f5b02109 public void addMapping(final K key, final int id) { diff --git a/net/minecraft/util/SimpleBitStorage.java b/net/minecraft/util/SimpleBitStorage.java -index cd9b408afdabb632ceba265c8de6035e1276024f..5e0e33cdbd590e5aee8044f49a562434c230a426 100644 +index 74dcdbb1f701c600cb5aca247a5a832fd05d7f03..851363603a3f8180f841c6f1b08dbac2db70f97a 100644 --- a/net/minecraft/util/SimpleBitStorage.java +++ b/net/minecraft/util/SimpleBitStorage.java @@ -208,6 +208,20 @@ public class SimpleBitStorage implements BitStorage { @@ -28764,11 +28755,11 @@ index cd9b408afdabb632ceba265c8de6035e1276024f..5e0e33cdbd590e5aee8044f49a562434 private InitializationException(final String message) { super(message); diff --git a/net/minecraft/util/SortedArraySet.java b/net/minecraft/util/SortedArraySet.java -index b36eda8e0176ec52eff318d868b7a4cc39d93759..f996f95f42f8afabcfdaffccc61bd3906a63e604 100644 +index c08c8388b6a81f861caf6716c0c999205e1ae487..295b29ba4e46aa438813180802e6c452392c7109 100644 --- a/net/minecraft/util/SortedArraySet.java +++ b/net/minecraft/util/SortedArraySet.java -@@ -9,12 +9,88 @@ import java.util.NoSuchElementException; - import java.util.Objects; +@@ -8,12 +8,88 @@ import java.util.Iterator; + import java.util.NoSuchElementException; import org.jspecify.annotations.Nullable; -public class SortedArraySet extends AbstractSet { @@ -28858,7 +28849,7 @@ index b36eda8e0176ec52eff318d868b7a4cc39d93759..f996f95f42f8afabcfdaffccc61bd390 this.comparator = comparator; if (initialCapacity < 0) { diff --git a/net/minecraft/util/ZeroBitStorage.java b/net/minecraft/util/ZeroBitStorage.java -index 1ceb7e4a3abd4d9de5133d182d3267d2164918f6..eb2fa32cff6824c14f865c8731df7d082122f62b 100644 +index 09b6da207530987b483444cebeadc2f1c9a15247..3666c3efd188508153b6482db425648e3ca77dc7 100644 --- a/net/minecraft/util/ZeroBitStorage.java +++ b/net/minecraft/util/ZeroBitStorage.java @@ -62,4 +62,22 @@ public class ZeroBitStorage implements BitStorage { @@ -28885,7 +28876,7 @@ index 1ceb7e4a3abd4d9de5133d182d3267d2164918f6..eb2fa32cff6824c14f865c8731df7d08 + // Paper end - block counting } diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 29896cb17fcf8ab967a937e9b0e102a8354b6889..e087d5596979044fe7fbcf7f2cccdae4e81a3d3a 100644 +index 666bd12677e62046d5f56544cadcbf1164211e0d..516ceeb6c0706528775676f9e9b8bb18d73ec7f8 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -167,7 +167,7 @@ public abstract class Entity @@ -29236,25 +29227,24 @@ index 29896cb17fcf8ab967a937e9b0e102a8354b6889..e087d5596979044fe7fbcf7f2cccdae4 } private static float[] collectCandidateStepUpHeights( -@@ -2738,21 +2886,110 @@ public abstract class Entity +@@ -2737,21 +2885,110 @@ public abstract class Entity } public boolean isInWall() { + // Paper start - optimise collisions if (this.noPhysics) { return false; -- } else { -- float checkWidth = this.dimensions.width() * 0.8F; -- AABB eyeBb = AABB.ofSize(this.getEyePosition(), checkWidth, 1.0E-6, checkWidth); -- return BlockPos.betweenClosedStream(eyeBb) -- .anyMatch( -- pos -> { -- BlockState state = this.level().getBlockState(pos); -- return !state.isAir() -- && state.isSuffocating(this.level(), pos) -- && Shapes.joinIsNotEmpty(state.getCollisionShape(this.level(), pos).move(pos), Shapes.create(eyeBb), BooleanOp.AND); -+ } -+ + } + +- float checkWidth = this.dimensions.width() * 0.8F; +- AABB eyeBb = AABB.ofSize(this.getEyePosition(), checkWidth, 1.0E-6, checkWidth); +- return BlockPos.betweenClosedStream(eyeBb) +- .anyMatch( +- pos -> { +- BlockState state = this.level().getBlockState(pos); +- return !state.isAir() +- && state.isSuffocating(this.level(), pos) +- && Shapes.joinIsNotEmpty(state.getCollisionShape(this.level(), pos).move(pos), Shapes.create(eyeBb), BooleanOp.AND); + final double reducedWith = (double)(this.dimensions.width() * 0.8F); + final AABB boundingBox = AABB.ofSize(this.getEyePosition(), reducedWith, 1.0E-6D, reducedWith); + final Level world = this.level; @@ -29291,8 +29281,7 @@ index 29896cb17fcf8ab967a937e9b0e102a8354b6889..e087d5596979044fe7fbcf7f2cccdae4 + final int sectionIdx = currChunkY - minSection; + if (sectionIdx < 0 || sectionIdx >= sections.length) { + continue; - } -- ); ++ } + final net.minecraft.world.level.chunk.LevelChunkSection section = sections[sectionIdx]; + if (section.hasOnlyAir()) { + // empty @@ -29349,16 +29338,17 @@ index 29896cb17fcf8ab967a937e9b0e102a8354b6889..e087d5596979044fe7fbcf7f2cccdae4 + } + } + } -+ } + } +- ); + } - } ++ } + + return false; + // Paper end - optimise collisions } public InteractionResult interact(final Player player, final InteractionHand hand, final Vec3 location) { -@@ -4363,15 +4600,17 @@ public abstract class Entity +@@ -4365,15 +4602,17 @@ public abstract class Entity } public Iterable getIndirectPassengers() { @@ -29384,7 +29374,7 @@ index 29896cb17fcf8ab967a937e9b0e102a8354b6889..e087d5596979044fe7fbcf7f2cccdae4 } public int countPlayerPassengers() { -@@ -4682,6 +4921,15 @@ public abstract class Entity +@@ -4684,6 +4923,15 @@ public abstract class Entity } public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) { @@ -29400,7 +29390,7 @@ index 29896cb17fcf8ab967a937e9b0e102a8354b6889..e087d5596979044fe7fbcf7f2cccdae4 if (!checkPosition(this, x, y, z)) { return; } -@@ -4831,6 +5079,12 @@ public abstract class Entity +@@ -4833,6 +5081,12 @@ public abstract class Entity @Override public final void setRemoved(final Entity.RemovalReason reason, org.bukkit.event.entity.EntityRemoveEvent.@Nullable Cause cause) { // CraftBukkit - add Bukkit remove cause @@ -29413,7 +29403,7 @@ index 29896cb17fcf8ab967a937e9b0e102a8354b6889..e087d5596979044fe7fbcf7f2cccdae4 org.bukkit.craftbukkit.event.CraftEventFactory.callEntityRemoveEvent(this, cause); // CraftBukkit final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers if (this.removalReason == null) { -@@ -4841,7 +5095,7 @@ public abstract class Entity +@@ -4843,7 +5097,7 @@ public abstract class Entity this.stopRiding(); } @@ -29422,7 +29412,7 @@ index 29896cb17fcf8ab967a937e9b0e102a8354b6889..e087d5596979044fe7fbcf7f2cccdae4 this.levelCallback.onRemove(reason); this.onRemoval(reason); // Paper start - Folia schedulers -@@ -4875,7 +5129,7 @@ public abstract class Entity +@@ -4877,7 +5131,7 @@ public abstract class Entity public boolean shouldBeSaved() { return (this.removalReason == null || this.removalReason.shouldSave()) && !this.isPassenger() @@ -29432,37 +29422,37 @@ index 29896cb17fcf8ab967a937e9b0e102a8354b6889..e087d5596979044fe7fbcf7f2cccdae4 @Override diff --git a/net/minecraft/world/entity/ai/behavior/AcquirePoi.java b/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -index 3325e7d4827067a65b176c5ba01aa491abd222a5..a8f2b22436ff0f4bff06b2c5cf01375da755cfde 100644 +index 3e71b3d17ffa02ce82040958c83f419121a1830e..2940dbc31a20eb49e24418ec84b73f2bfbdcfc32 100644 --- a/net/minecraft/world/entity/ai/behavior/AcquirePoi.java +++ b/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -@@ -88,12 +88,16 @@ public class AcquirePoi { - return true; - } - }; -- Set, BlockPos>> poiPositions = poiManager.findAllClosestFirstWithType( -- poiType, cacheTest, body.blockPosition(), SCAN_RANGE, PoiManager.Occupancy.HAS_SPACE -- ) -- .limit(5L) -- .filter(px -> validPoi.test(level, (BlockPos)px.getSecond())) -- .collect(Collectors.toSet()); -+ // Paper start - optimise POI searches -+ java.util.List, BlockPos>> poiPositionsRaw = new java.util.ArrayList<>(); -+ ca.spottedleaf.moonrise.patches.poi_lookup.PoiAccess.findNearestPoiPositions(poiManager, poiType, cacheTest, body.blockPosition(), SCAN_RANGE, Double.MAX_VALUE, PoiManager.Occupancy.HAS_SPACE, ca.spottedleaf.moonrise.patches.poi_lookup.PoiAccess.LOAD_FOR_SEARCHING, 5, poiPositionsRaw); -+ Set, BlockPos>> poiPositions = new java.util.HashSet<>(poiPositionsRaw.size()); -+ for (Pair, BlockPos> pair : poiPositionsRaw) { -+ if (validPoi.test(level, pair.getSecond())) { -+ poiPositions.add(pair); -+ } -+ } -+ // Paper end - optimise POI searches - Path path = findPathToPois(body, poiPositions); - if (path != null && path.canReach()) { - BlockPos targetPos = path.getTarget(); +@@ -94,12 +94,16 @@ public class AcquirePoi { + retryMarker.markAttempt(timestamp); + return true; + }; +- Set, BlockPos>> poiPositions = poiManager.findAllClosestFirstWithType( +- poiType, cacheTest, body.blockPosition(), SCAN_RANGE, PoiManager.Occupancy.HAS_SPACE +- ) +- .limit(5L) +- .filter(px -> validPoi.test(level, (BlockPos)px.getSecond())) +- .collect(Collectors.toSet()); ++ // Paper start - optimise POI searches ++ java.util.List, BlockPos>> poiPositionsRaw = new java.util.ArrayList<>(); ++ ca.spottedleaf.moonrise.patches.poi_lookup.PoiAccess.findNearestPoiPositions(poiManager, poiType, cacheTest, body.blockPosition(), SCAN_RANGE, Double.MAX_VALUE, PoiManager.Occupancy.HAS_SPACE, ca.spottedleaf.moonrise.patches.poi_lookup.PoiAccess.LOAD_FOR_SEARCHING, 5, poiPositionsRaw); ++ Set, BlockPos>> poiPositions = new java.util.HashSet<>(poiPositionsRaw.size()); ++ for (Pair, BlockPos> pair : poiPositionsRaw) { ++ if (validPoi.test(level, pair.getSecond())) { ++ poiPositions.add(pair); ++ } ++ } ++ // Paper end - optimise POI searches + Path path = findPathToPois(body, poiPositions); + if (path != null && path.canReach()) { + BlockPos targetPos = path.getTarget(); diff --git a/net/minecraft/world/entity/ai/village/poi/PoiManager.java b/net/minecraft/world/entity/ai/village/poi/PoiManager.java -index a6f79e022af17de6e58e9a80805b607d674c6b85..ab92bb9a3c5c1900e5d77fd3885e2c9dde64d339 100644 +index 96d28b513d39c4bc364d97bef7bd6024349c1bd9..a67c3ccfd24172df1bd2e440a48d7e5f262af82f 100644 --- a/net/minecraft/world/entity/ai/village/poi/PoiManager.java +++ b/net/minecraft/world/entity/ai/village/poi/PoiManager.java -@@ -41,12 +41,137 @@ import net.minecraft.world.level.chunk.storage.SectionStorage; +@@ -40,12 +40,137 @@ import net.minecraft.world.level.chunk.storage.SectionStorage; import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; import org.jspecify.annotations.Nullable; @@ -29601,7 +29591,7 @@ index a6f79e022af17de6e58e9a80805b607d674c6b85..ab92bb9a3c5c1900e5d77fd3885e2c9d public PoiManager( final RegionStorageInfo info, final Path folder, -@@ -67,6 +192,7 @@ public class PoiManager extends SectionStorage { +@@ -66,6 +191,7 @@ public class PoiManager extends SectionStorage { levelHeightAccessor ); this.distanceTracker = new PoiManager.DistanceTracker(); @@ -29609,7 +29599,7 @@ index a6f79e022af17de6e58e9a80805b607d674c6b85..ab92bb9a3c5c1900e5d77fd3885e2c9d } public @Nullable PoiRecord add(final BlockPos pos, final Holder type) { -@@ -88,18 +214,29 @@ public class PoiManager extends SectionStorage { +@@ -87,18 +213,29 @@ public class PoiManager extends SectionStorage { public Stream getInSquare( final Predicate> predicate, final BlockPos center, final int radius, final PoiManager.Occupancy occupancy ) { @@ -29646,7 +29636,7 @@ index a6f79e022af17de6e58e9a80805b607d674c6b85..ab92bb9a3c5c1900e5d77fd3885e2c9d } @VisibleForDebug -@@ -118,7 +255,15 @@ public class PoiManager extends SectionStorage { +@@ -117,7 +254,15 @@ public class PoiManager extends SectionStorage { final int radius, final PoiManager.Occupancy occupancy ) { @@ -29663,7 +29653,7 @@ index a6f79e022af17de6e58e9a80805b607d674c6b85..ab92bb9a3c5c1900e5d77fd3885e2c9d } public Stream, BlockPos>> findAllWithType( -@@ -128,7 +273,17 @@ public class PoiManager extends SectionStorage { +@@ -127,7 +272,17 @@ public class PoiManager extends SectionStorage { final int radius, final PoiManager.Occupancy occupancy ) { @@ -29682,7 +29672,7 @@ index a6f79e022af17de6e58e9a80805b607d674c6b85..ab92bb9a3c5c1900e5d77fd3885e2c9d } public Stream, BlockPos>> findAllClosestFirstWithType( -@@ -138,7 +293,21 @@ public class PoiManager extends SectionStorage { +@@ -137,7 +292,21 @@ public class PoiManager extends SectionStorage { final int radius, final PoiManager.Occupancy occupancy ) { @@ -29705,7 +29695,7 @@ index a6f79e022af17de6e58e9a80805b607d674c6b85..ab92bb9a3c5c1900e5d77fd3885e2c9d } public Optional find( -@@ -148,21 +317,31 @@ public class PoiManager extends SectionStorage { +@@ -147,21 +316,31 @@ public class PoiManager extends SectionStorage { final int radius, final PoiManager.Occupancy occupancy ) { @@ -29742,7 +29732,7 @@ index a6f79e022af17de6e58e9a80805b607d674c6b85..ab92bb9a3c5c1900e5d77fd3885e2c9d } public Optional findClosest( -@@ -172,22 +351,29 @@ public class PoiManager extends SectionStorage { +@@ -171,22 +350,29 @@ public class PoiManager extends SectionStorage { final int radius, final PoiManager.Occupancy occupancy ) { @@ -29783,7 +29773,7 @@ index a6f79e022af17de6e58e9a80805b607d674c6b85..ab92bb9a3c5c1900e5d77fd3885e2c9d } public Optional getRandom( -@@ -198,8 +384,21 @@ public class PoiManager extends SectionStorage { +@@ -197,8 +383,21 @@ public class PoiManager extends SectionStorage { final int radius, final RandomSource random ) { @@ -29807,7 +29797,7 @@ index a6f79e022af17de6e58e9a80805b607d674c6b85..ab92bb9a3c5c1900e5d77fd3885e2c9d } public boolean release(final BlockPos pos) { -@@ -222,8 +421,10 @@ public class PoiManager extends SectionStorage { +@@ -221,8 +420,10 @@ public class PoiManager extends SectionStorage { } public int sectionsToVillage(final SectionPos sectionPos) { @@ -29820,7 +29810,7 @@ index a6f79e022af17de6e58e9a80805b607d674c6b85..ab92bb9a3c5c1900e5d77fd3885e2c9d } private boolean isVillageCenter(final long sectionPos) { -@@ -234,19 +435,26 @@ public class PoiManager extends SectionStorage { +@@ -233,19 +434,26 @@ public class PoiManager extends SectionStorage { @Override public void tick(final BooleanSupplier haveTime) { @@ -29853,7 +29843,7 @@ index a6f79e022af17de6e58e9a80805b607d674c6b85..ab92bb9a3c5c1900e5d77fd3885e2c9d } public void checkConsistencyWithBlocks(final SectionPos sectionPos, final LevelChunkSection blockSection) { -@@ -285,7 +493,7 @@ public class PoiManager extends SectionStorage { +@@ -284,7 +492,7 @@ public class PoiManager extends SectionStorage { .map(pos -> Pair.of(pos, this.getOrLoad(pos.asLong()))) .filter(poiSection -> !poiSection.getSecond().map(PoiSection::isValid).orElse(false)) .map(p -> p.getFirst().chunk()) @@ -29863,7 +29853,7 @@ index a6f79e022af17de6e58e9a80805b607d674c6b85..ab92bb9a3c5c1900e5d77fd3885e2c9d } diff --git a/net/minecraft/world/entity/ai/village/poi/PoiSection.java b/net/minecraft/world/entity/ai/village/poi/PoiSection.java -index 9423fab0cefba9c1d48ab5e8f39fe91c1c3a2022..e9fd001d96ba9f80e5131a940c46562f896dac41 100644 +index cf03617840bf13c6045526eba14f71e0647ffec2..263c64f340417c0b49691a350b4bec592d58739d 100644 --- a/net/minecraft/world/entity/ai/village/poi/PoiSection.java +++ b/net/minecraft/world/entity/ai/village/poi/PoiSection.java @@ -25,13 +25,27 @@ import net.minecraft.util.debug.DebugPoiInfo; @@ -29897,7 +29887,7 @@ index 9423fab0cefba9c1d48ab5e8f39fe91c1c3a2022..e9fd001d96ba9f80e5131a940c46562f this(setDirty, true, ImmutableList.of()); } diff --git a/net/minecraft/world/entity/decoration/ArmorStand.java b/net/minecraft/world/entity/decoration/ArmorStand.java -index b9cd4bdd48d3c9fc96838d051d18d1c264b25fee..fc4fce0b1d57a62c1e5c80a5b91c2b1a77d4bace 100644 +index 758b667530ba1e14e9a56fbe609a6438439dd8f2..f42fd10847a1dfbcbb2790aa90da4a49585e25a8 100644 --- a/net/minecraft/world/entity/decoration/ArmorStand.java +++ b/net/minecraft/world/entity/decoration/ArmorStand.java @@ -206,7 +206,7 @@ public class ArmorStand extends LivingEntity { @@ -29910,7 +29900,7 @@ index b9cd4bdd48d3c9fc96838d051d18d1c264b25fee..fc4fce0b1d57a62c1e5c80a5b91c2b1a entity.push(this); } diff --git a/net/minecraft/world/level/ClipContext.java b/net/minecraft/world/level/ClipContext.java -index 53dc55780adc88e4857cd1fe72c81535f5e0fd26..35cf8c2caf8b17d233d77b4baa1ea161f0bbfefa 100644 +index fbaefb396745cc985d4c25f3cbea17d646391948..fc7900fcb391b6fe61f7d6200f7d2656579b97a1 100644 --- a/net/minecraft/world/level/ClipContext.java +++ b/net/minecraft/world/level/ClipContext.java @@ -22,7 +22,7 @@ public class ClipContext { @@ -29923,7 +29913,7 @@ index 53dc55780adc88e4857cd1fe72c81535f5e0fd26..35cf8c2caf8b17d233d77b4baa1ea161 public ClipContext(final Vec3 from, final Vec3 to, final ClipContext.Block block, final ClipContext.Fluid fluid, final Entity entity) { diff --git a/net/minecraft/world/level/EntityGetter.java b/net/minecraft/world/level/EntityGetter.java -index e07a7bda45146686a6ac2d20507df9fc8630514f..f84e651e2a34e76a0a71993332e4be1b7ef53424 100644 +index 892b338a2b0a185511c352ca2bb76ee3890836fd..f84e651e2a34e76a0a71993332e4be1b7ef53424 100644 --- a/net/minecraft/world/level/EntityGetter.java +++ b/net/minecraft/world/level/EntityGetter.java @@ -15,7 +15,7 @@ import net.minecraft.world.phys.shapes.Shapes; @@ -29950,15 +29940,14 @@ index e07a7bda45146686a6ac2d20507df9fc8630514f..f84e651e2a34e76a0a71993332e4be1b + // Paper start - optimise collisions if (shape.isEmpty()) { return true; -- } else { -- for (Entity entity : this.getEntities(source, shape.bounds())) { -- if (!entity.isRemoved() -- && entity.blocksBuilding -- && (source == null || !entity.isPassengerOfSameVehicle(source)) -- && Shapes.joinIsNotEmpty(shape, Shapes.create(entity.getBoundingBox()), BooleanOp.AND)) { -- return false; -+ } -+ + } + +- for (Entity entity : this.getEntities(source, shape.bounds())) { +- if (!entity.isRemoved() +- && entity.blocksBuilding +- && (source == null || !entity.isPassengerOfSameVehicle(source)) +- && Shapes.joinIsNotEmpty(shape, Shapes.create(entity.getBoundingBox()), BooleanOp.AND)) { +- return false; + final AABB singleAABB = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)shape).moonrise$getSingleAABBRepresentation(); + final List entities = this.getEntities( + source, @@ -29976,14 +29965,13 @@ index e07a7bda45146686a6ac2d20507df9fc8630514f..f84e651e2a34e76a0a71993332e4be1b + final AABB entityBB = otherEntity.getBoundingBox(); + if (ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isEmpty(entityBB) || !ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.voxelShapeIntersectNoEmpty(shape, entityBB)) { + continue; - } ++ } } - -- return true; ++ + return false; } -+ -+ return true; + + return true; + // Paper end - optimise collisions } @@ -30000,8 +29988,12 @@ index e07a7bda45146686a6ac2d20507df9fc8630514f..f84e651e2a34e76a0a71993332e4be1b + if (ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isEmpty(testArea)) { + // reduce indirection by always returning type with same class + return new java.util.ArrayList<>(); -+ } -+ + } + +- Predicate canCollide = source == null ? EntitySelector.CAN_BE_COLLIDED_WITH : EntitySelector.NO_SPECTATORS.and(source::canCollideWith); +- List collidingEntities = this.getEntities(source, testArea.inflate(1.0E-7), canCollide); +- if (collidingEntities.isEmpty()) { +- return List.of(); + // to comply with vanilla intersection rules, expand by -epsilon so that we only get stuff we definitely collide with. + // Vanilla for hard collisions has this backwards, and they expand by +epsilon but this causes terrible problems + // specifically with boat collisions. @@ -30010,42 +30002,35 @@ index e07a7bda45146686a6ac2d20507df9fc8630514f..f84e651e2a34e76a0a71993332e4be1b + final List entities; + if (source != null && ((ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity)source).moonrise$isHardColliding()) { + entities = this.getEntities(source, testArea, null); - } else { -- Predicate canCollide = source == null ? EntitySelector.CAN_BE_COLLIDED_WITH : EntitySelector.NO_SPECTATORS.and(source::canCollideWith); -- List collidingEntities = this.getEntities(source, testArea.inflate(1.0E-7), canCollide); -- if (collidingEntities.isEmpty()) { -- return List.of(); -- } else { -- Builder shapes = ImmutableList.builderWithExpectedSize(collidingEntities.size()); -- -- for (Entity entity : collidingEntities) { -- shapes.add(Shapes.create(entity.getBoundingBox())); -- } ++ } else { + entities = ((ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemEntityGetter)this).moonrise$getHardCollidingEntities(source, testArea, null); -+ } + } -- return shapes.build(); +- Builder shapes = ImmutableList.builderWithExpectedSize(collidingEntities.size()); + final List ret = new java.util.ArrayList<>(Math.min(25, entities.size())); + + for (int i = 0, len = entities.size(); i < len; ++i) { + final Entity otherEntity = entities.get(i); -+ + +- for (Entity entity : collidingEntities) { +- shapes.add(Shapes.create(entity.getBoundingBox())); + if (otherEntity.isSpectator()) { + continue; + } + + if ((source == null && otherEntity.canBeCollidedWith(source)) || (source != null && source.canCollideWith(otherEntity))) { + ret.add(Shapes.create(otherEntity.getBoundingBox())); - } ++ } } -+ + +- return shapes.build(); + return ret; + // Paper end - optimise collisions } // Paper start - Affects Spawning API diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 838bad640b7f8e42fc8972918cfc7c1d9807e2b3..c0f901c4ac61a0aa2b480f102feb3669b111f4c0 100644 +index d7edeb01a9842e7cbe4d2ba40360c5604c69001c..85922fd54c703ce8a12452b2b3c5a00f716f79ad 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java @@ -87,6 +87,7 @@ import net.minecraft.world.level.storage.LevelData; @@ -30728,16 +30713,16 @@ index 838bad640b7f8e42fc8972918cfc7c1d9807e2b3..c0f901c4ac61a0aa2b480f102feb3669 } // Paper start - Cancel hit for vanished players -@@ -512,7 +1146,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - this.setBlocksDirty(pos, blockState, blockState1); +@@ -511,7 +1145,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + this.setBlocksDirty(pos, oldState, newState); } -- if ((flags & Block.UPDATE_CLIENTS) != 0 && (!this.isClientSide() || (flags & Block.UPDATE_INVISIBLE) == 0) && (this.isClientSide() || chunkAt == null || (chunkAt.getFullStatus() != null && chunkAt.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING)))) { // allow chunk to be null here as chunk.isReady() is false when we send our notification during block placement -+ if ((flags & Block.UPDATE_CLIENTS) != 0 && (!this.isClientSide() || (flags & Block.UPDATE_INVISIBLE) == 0) && (this.isClientSide() || chunkAt == null || (chunkAt.getFullStatus() != null && chunkAt.getFullStatus().isOrAfter(FullChunkStatus.FULL)))) { // allow chunk to be null here as chunk.isReady() is false when we send our notification during block placement // Paper - rewrite chunk system - change from ticking to full - this.sendBlockUpdated(pos, blockState, state, flags); +- if ((updateFlags & Block.UPDATE_CLIENTS) != 0 && (!this.isClientSide() || (updateFlags & Block.UPDATE_INVISIBLE) == 0) && (this.isClientSide() || chunk == null || (chunk.getFullStatus() != null && chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING)))) { // allow chunk to be null here as chunk.isReady() is false when we send our notification during block placement ++ if ((updateFlags & Block.UPDATE_CLIENTS) != 0 && (!this.isClientSide() || (updateFlags & Block.UPDATE_INVISIBLE) == 0) && (this.isClientSide() || chunk == null || (chunk.getFullStatus() != null && chunk.getFullStatus().isOrAfter(FullChunkStatus.FULL)))) { // allow chunk to be null here as chunk.isReady() is false when we send our notification during block placement // Paper - rewrite chunk system - change from ticking to full + this.sendBlockUpdated(pos, oldState, blockState, updateFlags); } -@@ -846,6 +1480,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -845,6 +1479,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { // Paper - Fix MC-117075 use removeAll - remove iterator in favour of indexed for loop, ensuring compile error if something uses iter incorrectly boolean tickBlockEntities = this.tickRateManager().runsNormally(); @@ -30745,7 +30730,7 @@ index 838bad640b7f8e42fc8972918cfc7c1d9807e2b3..c0f901c4ac61a0aa2b480f102feb3669 // Paper start - Fix MC-117075 use removeAll final it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<@Nullable TickingBlockEntity> toRemove = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); toRemove.add(null); -@@ -856,6 +1491,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -855,6 +1490,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable { toRemove.add(ticker); // Paper - Fix MC-117075 use removeAll } else if (tickBlockEntities && this.shouldTickBlocksAt(ticker.getPos())) { ticker.tick(); @@ -30757,7 +30742,7 @@ index 838bad640b7f8e42fc8972918cfc7c1d9807e2b3..c0f901c4ac61a0aa2b480f102feb3669 } } -@@ -874,6 +1514,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -873,6 +1513,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); // Paper end - Prevent block entity and entity crashes } @@ -30765,7 +30750,7 @@ index 838bad640b7f8e42fc8972918cfc7c1d9807e2b3..c0f901c4ac61a0aa2b480f102feb3669 } // Paper start - Option to prevent armor stands from doing entity lookups -@@ -881,7 +1522,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -880,7 +1521,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public boolean noCollision(@Nullable Entity entity, AABB box) { if (entity instanceof net.minecraft.world.entity.decoration.ArmorStand && !entity.level().paperConfig().entities.armorStands.doCollisionEntityLookups) return false; @@ -30781,7 +30766,7 @@ index 838bad640b7f8e42fc8972918cfc7c1d9807e2b3..c0f901c4ac61a0aa2b480f102feb3669 } // Paper end - Option to prevent armor stands from doing entity lookups -@@ -1026,7 +1674,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1025,7 +1673,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { if (!this.isInValidBounds(pos)) { return null; } else { @@ -30790,7 +30775,7 @@ index 838bad640b7f8e42fc8972918cfc7c1d9807e2b3..c0f901c4ac61a0aa2b480f102feb3669 ? null : this.getChunkAt(pos).getBlockEntity(pos, LevelChunk.EntityCreationType.IMMEDIATE); } -@@ -1106,20 +1754,15 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1105,20 +1753,15 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @Override public List getEntities(final @Nullable Entity except, final AABB bb, final Predicate selector) { Profiler.get().incrementCounter("getEntities"); @@ -30818,7 +30803,7 @@ index 838bad640b7f8e42fc8972918cfc7c1d9807e2b3..c0f901c4ac61a0aa2b480f102feb3669 } @Override -@@ -1135,33 +1778,94 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1134,33 +1777,94 @@ public abstract class Level implements LevelAccessor, AutoCloseable { this.getEntities(type, bb, selector, output, Integer.MAX_VALUE); } @@ -30933,7 +30918,7 @@ index 838bad640b7f8e42fc8972918cfc7c1d9807e2b3..c0f901c4ac61a0aa2b480f102feb3669 public boolean hasEntities(final EntityTypeTest type, final AABB bb, final Predicate selector) { Profiler.get().incrementCounter("hasEntities"); -@@ -1466,13 +2170,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1469,13 +2173,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { // Paper start - allow patching this logic public final int getEntityCount() { @@ -30949,7 +30934,7 @@ index 838bad640b7f8e42fc8972918cfc7c1d9807e2b3..c0f901c4ac61a0aa2b480f102feb3669 // Paper end - allow patching this logic } diff --git a/net/minecraft/world/level/LevelReader.java b/net/minecraft/world/level/LevelReader.java -index 5ae72685665701905df6047ba76e39819d9af0c6..c0074df792f578a1fd828ace9f7a64caa25f3273 100644 +index 254a967292938a9ed6a0291bbc9cf6e971eeaf01..416646f15ceea04fbbb5a5b0044c2a4927a39ba2 100644 --- a/net/minecraft/world/level/LevelReader.java +++ b/net/minecraft/world/level/LevelReader.java @@ -23,7 +23,17 @@ import net.minecraft.world.level.levelgen.Heightmap; @@ -30972,7 +30957,7 @@ index 5ae72685665701905df6047ba76e39819d9af0c6..c0074df792f578a1fd828ace9f7a64ca @Nullable ChunkAccess getChunkIfLoadedImmediately(int x, int z); // Paper - ifLoaded api (we need this since current impl blocks if the chunk is loading) diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java -index 0cf47956a699c679259a920572efd3bea2b19a61..0ef64fcf11d6cd0e25227fe6053ca8cb2125bfff 100644 +index 26a6c4b49b0c7737935d152ff941604c712b50a2..34d7eef8b2540172bd4dcdbf80df45e9cbfcb43c 100644 --- a/net/minecraft/world/level/ServerExplosion.java +++ b/net/minecraft/world/level/ServerExplosion.java @@ -54,6 +54,249 @@ public class ServerExplosion implements Explosion { @@ -31225,7 +31210,7 @@ index 0cf47956a699c679259a920572efd3bea2b19a61..0ef64fcf11d6cd0e25227fe6053ca8cb public ServerExplosion( final ServerLevel level, -@@ -128,62 +371,102 @@ public class ServerExplosion implements Explosion { +@@ -128,64 +371,102 @@ public class ServerExplosion implements Explosion { } private List calculateExplodedPositions() { @@ -31247,8 +31232,9 @@ index 0cf47956a699c679259a920572efd3bea2b19a61..0ef64fcf11d6cd0e25227fe6053ca8cb - double xp = this.center.x; - double yp = this.center.y; - double zp = this.center.z; +- float stepSize = 0.3F; - -- for (float stepSize = 0.3F; remainingPower > 0.0F; remainingPower -= 0.22500001F) { +- while (remainingPower > 0.0F) { - BlockPos pos = BlockPos.containing(xp, yp, zp); - BlockState block = this.level.getBlockState(pos); - if (!block.isDestroyable()) continue; // Paper - Protect Bedrock and End Portal/Frames from being destroyed @@ -31355,6 +31341,7 @@ index 0cf47956a699c679259a920572efd3bea2b19a61..0ef64fcf11d6cd0e25227fe6053ca8cb - xp += xd * 0.3F; - yp += yd * 0.3F; - zp += zd * 0.3F; +- remainingPower -= 0.22500001F; + // Paper end - prevent headless pistons from forming } } @@ -31374,7 +31361,7 @@ index 0cf47956a699c679259a920572efd3bea2b19a61..0ef64fcf11d6cd0e25227fe6053ca8cb } private void hurtEntities() { -@@ -340,6 +623,14 @@ public class ServerExplosion implements Explosion { +@@ -342,6 +623,14 @@ public class ServerExplosion implements Explosion { } public int explode() { @@ -31389,7 +31376,7 @@ index 0cf47956a699c679259a920572efd3bea2b19a61..0ef64fcf11d6cd0e25227fe6053ca8cb this.level.gameEvent(this.source, GameEvent.EXPLODE, this.center); List toBlow = this.calculateExplodedPositions(); this.hurtEntities(); -@@ -354,6 +645,13 @@ public class ServerExplosion implements Explosion { +@@ -356,6 +645,13 @@ public class ServerExplosion implements Explosion { this.createFire(toBlow); } @@ -31403,7 +31390,7 @@ index 0cf47956a699c679259a920572efd3bea2b19a61..0ef64fcf11d6cd0e25227fe6053ca8cb return toBlow.size(); } -@@ -436,12 +734,12 @@ public class ServerExplosion implements Explosion { +@@ -438,12 +734,12 @@ public class ServerExplosion implements Explosion { // Paper start - Optimize explosions private float getBlockDensity(Vec3 vec3d, Entity entity) { if (!this.level.paperConfig().environment.optimizeExplosions) { @@ -31419,7 +31406,7 @@ index 0cf47956a699c679259a920572efd3bea2b19a61..0ef64fcf11d6cd0e25227fe6053ca8cb } diff --git a/net/minecraft/world/level/TicketStorage.java b/net/minecraft/world/level/TicketStorage.java -index 312d2eeda6b413d3b2d10ee58bd154bbddc88451..3d2fc3809ec8a1d8bda47da4fd631bb0fe712ca5 100644 +index 5d6e4e74483068bdf17ecf0623f0ae1dc9d2002c..d966a073ba74ff881941aba79d23d8135bac119b 100644 --- a/net/minecraft/world/level/TicketStorage.java +++ b/net/minecraft/world/level/TicketStorage.java @@ -30,7 +30,7 @@ import net.minecraft.world.level.saveddata.SavedDataType; @@ -31600,52 +31587,51 @@ index 312d2eeda6b413d3b2d10ee58bd154bbddc88451..3d2fc3809ec8a1d8bda47da4fd631bb0 - List tickets = this.tickets.get(key); - if (tickets == null) { - return false; -- } else { -- boolean found = false; -- Iterator iterator = tickets.iterator(); -- -- while (iterator.hasNext()) { -- Ticket t = iterator.next(); -- if (isTicketSameTypeAndLevel(ticket, t)) { -- iterator.remove(); -- if (SharedConstants.DEBUG_VERBOSE_SERVER_EVENTS) { -- LOGGER.debug("RTI {} {}", ChunkPos.unpack(key), t); -- } -- -- found = true; -- break; -- } -- } -- -- if (!found) { -- return false; -- } else { -- if (tickets.isEmpty()) { -- this.tickets.remove(key); -- } +- } - -- if (ticket.getType().doesSimulate() && this.simulationChunkUpdatedListener != null) { -- this.simulationChunkUpdatedListener.update(key, getTicketLevelAt(tickets, true), false); -- } +- boolean found = false; +- Iterator iterator = tickets.iterator(); + // Paper start - rewrite chunk system + final boolean ret = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.chunkMap.level).moonrise$getChunkTaskScheduler().chunkHolderManager + .removeTicketAtLevel(ticket.getType(), key, ticket.getTicketLevel(), ((ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicket)ticket).moonrise$getIdentifier()); -- if (ticket.getType().doesLoad() && this.loadingChunkUpdatedListener != null) { -- this.loadingChunkUpdatedListener.update(key, getTicketLevelAt(tickets, false), false); -- } -- -- if (ticket.getType().equals(TicketType.FORCED)) { -- this.updateForcedChunks(); +- while (iterator.hasNext()) { +- Ticket t = iterator.next(); +- if (isTicketSameTypeAndLevel(ticket, t)) { +- iterator.remove(); +- if (SharedConstants.DEBUG_VERBOSE_SERVER_EVENTS) { +- LOGGER.debug("RTI {} {}", ChunkPos.unpack(key), t); - } - -- this.setDirty(); -- return true; +- found = true; +- break; - } + if (ret) { + this.setDirty(); } -+ + +- if (!found) { +- return false; +- } +- +- if (tickets.isEmpty()) { +- this.tickets.remove(key); +- } +- +- if (ticket.getType().doesSimulate() && this.simulationChunkUpdatedListener != null) { +- this.simulationChunkUpdatedListener.update(key, getTicketLevelAt(tickets, true), false); +- } +- +- if (ticket.getType().doesLoad() && this.loadingChunkUpdatedListener != null) { +- this.loadingChunkUpdatedListener.update(key, getTicketLevelAt(tickets, false), false); +- } +- +- if (ticket.getType().equals(TicketType.FORCED)) { +- this.updateForcedChunks(); +- } +- +- this.setDirty(); +- return true; + return ret; + // Paper end - rewrite chunk system } @@ -31672,7 +31658,7 @@ index 312d2eeda6b413d3b2d10ee58bd154bbddc88451..3d2fc3809ec8a1d8bda47da4fd631bb0 this.setDirty(); } -@@ -300,82 +274,15 @@ public class TicketStorage extends SavedData { +@@ -302,82 +276,15 @@ public class TicketStorage extends SavedData { } public void deactivateTicketsOnClosing() { @@ -31749,28 +31735,28 @@ index 312d2eeda6b413d3b2d10ee58bd154bbddc88451..3d2fc3809ec8a1d8bda47da4fd631bb0 - - for (Pair pair : affectedTickets) { - Long key = pair.getSecond(); -- Ticket ticketx = pair.getFirst(); -- this.removeTicket(key, ticketx); -- TicketType type = ticketx.getType(); +- Ticket ticket = pair.getFirst(); +- this.removeTicket(key, ticket); +- TicketType type = ticket.getType(); - this.addTicket(key, new Ticket(type, newLevel)); - } + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } public boolean updateChunkForced(final ChunkPos chunkPos, final boolean forced) { -@@ -384,22 +291,29 @@ public class TicketStorage extends SavedData { +@@ -386,22 +293,29 @@ public class TicketStorage extends SavedData { } public LongSet getForceLoadedChunks() { - return this.chunksWithForcedTickets; - } +- +- private LongSet getAllChunksWithTicketThat(final Predicate ticketCheck) { +- LongOpenHashSet chunks = new LongOpenHashSet(); + // Paper start - rewrite chunk system + final ca.spottedleaf.concurrentutil.map.concurrent.longs.ConcurrentChainedLong2LongHashTable forced = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.chunkMap.level).moonrise$getChunkTaskScheduler() + .chunkHolderManager.getTicketCounters(ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType.COUNTER_TYPE_FORCED); -- private LongSet getAllChunksWithTicketThat(final Predicate ticketCheck) { -- LongOpenHashSet chunks = new LongOpenHashSet(); -- - for (Entry> entry : Long2ObjectMaps.fastIterable(this.tickets)) { - for (Ticket ticket : entry.getValue()) { - if (ticketCheck.test(ticket)) { @@ -31801,7 +31787,7 @@ index 312d2eeda6b413d3b2d10ee58bd154bbddc88451..3d2fc3809ec8a1d8bda47da4fd631bb0 } @FunctionalInterface -@@ -423,7 +337,7 @@ public class TicketStorage extends SavedData { +@@ -425,7 +339,7 @@ public class TicketStorage extends SavedData { } public void removeAllPluginRegionTickets(TicketType ticketType, int ticketLevel, org.bukkit.plugin.Plugin ticketIdentifier) { @@ -31811,10 +31797,10 @@ index 312d2eeda6b413d3b2d10ee58bd154bbddc88451..3d2fc3809ec8a1d8bda47da4fd631bb0 // Paper end } diff --git a/net/minecraft/world/level/biome/Biome.java b/net/minecraft/world/level/biome/Biome.java -index 7645e677e331f6aea404fb5ae1264690ffb1d212..96f2e3359774460091177068302ff0faf4671373 100644 +index fbb3ad54acb170f3a4b8ec4ed931bd60ad0ab55d..afa97f1c8a0fcd49aec962eaa6f5c9cda0e0cefa 100644 --- a/net/minecraft/world/level/biome/Biome.java +++ b/net/minecraft/world/level/biome/Biome.java -@@ -128,20 +128,7 @@ public final class Biome { +@@ -123,20 +123,7 @@ public final class Biome { @Deprecated public float getTemperature(final BlockPos pos, final int seaLevel) { @@ -31823,24 +31809,24 @@ index 7645e677e331f6aea404fb5ae1264690ffb1d212..96f2e3359774460091177068302ff0fa - float cached = cache.get(key); - if (!Float.isNaN(cached)) { - return cached; -- } else { -- float temp = this.getHeightAdjustedTemperature(pos, seaLevel); -- if (cache.size() == 1024) { -- cache.removeFirstFloat(); -- } +- } - -- cache.put(key, temp); -- return temp; +- float temp = this.getHeightAdjustedTemperature(pos, seaLevel); +- if (cache.size() == 1024) { +- cache.removeFirstFloat(); - } +- +- cache.put(key, temp); +- return temp; + return this.getHeightAdjustedTemperature(pos, seaLevel); // Paper - optimise random ticking } public boolean shouldFreeze(final LevelReader level, final BlockPos pos) { diff --git a/net/minecraft/world/level/biome/BiomeManager.java b/net/minecraft/world/level/biome/BiomeManager.java -index 9404f0b0b03dce54e2c9ad6ca2c36354888cc9f5..a0d7f6f8ecbc320267bdad27315fc2e2e1ff3702 100644 +index d9849dfbe792128390941403220110fe87eb9fe3..c139f70bf9ddd3f995c0524dad15487e632cd432 100644 --- a/net/minecraft/world/level/biome/BiomeManager.java +++ b/net/minecraft/world/level/biome/BiomeManager.java -@@ -100,8 +100,7 @@ public class BiomeManager { +@@ -101,8 +101,7 @@ public class BiomeManager { } private static double getFiddle(final long rval) { @@ -31851,10 +31837,10 @@ index 9404f0b0b03dce54e2c9ad6ca2c36354888cc9f5..a0d7f6f8ecbc320267bdad27315fc2e2 public interface NoiseBiomeSource { diff --git a/net/minecraft/world/level/block/Block.java b/net/minecraft/world/level/block/Block.java -index 7678701a578d2dc45b35da072a0bb2c027522043..41aab9a526be77b400bed7a74614eceec95345b5 100644 +index 991d6261fd8a19d1c367e518666acb298dbd7abe..a8625939a4220050990b09097d5e3bfd2d8473d5 100644 --- a/net/minecraft/world/level/block/Block.java +++ b/net/minecraft/world/level/block/Block.java -@@ -366,7 +366,7 @@ public class Block extends BlockBehaviour implements ItemLike { +@@ -370,7 +370,7 @@ public class Block extends BlockBehaviour implements ItemLike { } public static boolean isShapeFullBlock(final VoxelShape shape) { @@ -31864,7 +31850,7 @@ index 7678701a578d2dc45b35da072a0bb2c027522043..41aab9a526be77b400bed7a74614ecee public void animateTick(final BlockState state, final Level level, final BlockPos pos, final RandomSource random) { diff --git a/net/minecraft/world/level/block/state/BlockBehaviour.java b/net/minecraft/world/level/block/state/BlockBehaviour.java -index e66b04c89c5155f660e3274ebb205cfb72190b1b..ca77680b645c352456744b148e0ff4ac31b05aa2 100644 +index 2004f5479f78f41c5af31f87f54c6529091f5cab..7093613a09a79d7ffce34f1cb54ec2605c5af384 100644 --- a/net/minecraft/world/level/block/state/BlockBehaviour.java +++ b/net/minecraft/world/level/block/state/BlockBehaviour.java @@ -435,7 +435,7 @@ public abstract class BlockBehaviour implements FeatureElement { @@ -31953,7 +31939,7 @@ index e66b04c89c5155f660e3274ebb205cfb72190b1b..ca77680b645c352456744b148e0ff4ac protected BlockStateBase(final Block owner, final Property[] propertyKeys, final Comparable[] propertyValues) { super(owner, propertyKeys, propertyValues); BlockBehaviour.Properties properties = owner.properties; -@@ -547,6 +617,41 @@ public abstract class BlockBehaviour implements FeatureElement { +@@ -551,6 +621,41 @@ public abstract class BlockBehaviour implements FeatureElement { this.propagatesSkylightDown = this.owner.propagatesSkylightDown(this.asState()); this.lightDampening = this.owner.getLightDampening(this.asState()); @@ -31996,7 +31982,7 @@ index e66b04c89c5155f660e3274ebb205cfb72190b1b..ca77680b645c352456744b148e0ff4ac public Block getBlock() { diff --git a/net/minecraft/world/level/block/state/StateDefinition.java b/net/minecraft/world/level/block/state/StateDefinition.java -index 792f3016554dbb69ca1c67c03ea59fa2351e3db5..c9d21990d1506087b7f7dbbfcf4127c4c99d14d2 100644 +index e6953b5371aa94be4173857d5bae48c41cec6b7c..a93b55f5543d3624c39a4335c52e025e5675fa14 100644 --- a/net/minecraft/world/level/block/state/StateDefinition.java +++ b/net/minecraft/world/level/block/state/StateDefinition.java @@ -66,10 +66,19 @@ public class StateDefinition> { @@ -32020,7 +32006,7 @@ index 792f3016554dbb69ca1c67c03ea59fa2351e3db5..c9d21990d1506087b7f7dbbfcf4127c4 } private static > ImmutableList createSinglePropertyStates( -@@ -99,7 +108,7 @@ public class StateDefinition> { +@@ -97,7 +106,7 @@ public class StateDefinition> { blockState.initializeNeighbors(neighbours); } @@ -32029,7 +32015,7 @@ index 792f3016554dbb69ca1c67c03ea59fa2351e3db5..c9d21990d1506087b7f7dbbfcf4127c4 } private static > ImmutableList createMultiPropertyStates( -@@ -125,7 +134,7 @@ public class StateDefinition> { +@@ -123,7 +132,7 @@ public class StateDefinition> { StateDefinition.StateCollection stateCollection = new StateDefinition.StateCollection<>(statesByValues, new HashMap<>()); statesByValues.forEach((valuesx, state) -> state.initializeNeighbors(stateCollection.fillNeighborsForState(propertyKeys, valuesx))); @@ -32039,10 +32025,10 @@ index 792f3016554dbb69ca1c67c03ea59fa2351e3db5..c9d21990d1506087b7f7dbbfcf4127c4 private static > S[][] emptyNeighbors() { diff --git a/net/minecraft/world/level/block/state/StateHolder.java b/net/minecraft/world/level/block/state/StateHolder.java -index 7d0d5e8e6c951be025183f7b1712d34aeb48b110..b72861c0164ebb13b6fc3e78cd7ce0a2c484f22d 100644 +index 747dd6f962fd42a08ed32ab23790477e0844592b..47a4aa4a45978dfec52ea995d197022f4fe32808 100644 --- a/net/minecraft/world/level/block/state/StateHolder.java +++ b/net/minecraft/world/level/block/state/StateHolder.java -@@ -13,21 +13,49 @@ import java.util.stream.Stream; +@@ -13,20 +13,48 @@ import java.util.stream.Stream; import net.minecraft.world.level.block.state.properties.Property; import org.jspecify.annotations.Nullable; @@ -32083,7 +32069,6 @@ index 7d0d5e8e6c951be025183f7b1712d34aeb48b110..b72861c0164ebb13b6fc3e78cd7ce0a2 + protected StateHolder(final O owner, final Property[] propertyKeys, final Comparable[] propertyValues) { assert propertyKeys.length == propertyValues.length; - this.owner = owner; this.propertyKeys = propertyKeys; this.propertyValues = propertyValues; @@ -32095,7 +32080,7 @@ index 7d0d5e8e6c951be025183f7b1712d34aeb48b110..b72861c0164ebb13b6fc3e78cd7ce0a2 } public > S cycle(final Property property) { -@@ -63,7 +91,7 @@ public abstract class StateHolder { +@@ -62,7 +90,7 @@ public abstract class StateHolder { } public Collection> getProperties() { @@ -32104,7 +32089,7 @@ index 7d0d5e8e6c951be025183f7b1712d34aeb48b110..b72861c0164ebb13b6fc3e78cd7ce0a2 } private int valueIndex(final Property property) { -@@ -77,21 +105,21 @@ public abstract class StateHolder { +@@ -76,21 +104,21 @@ public abstract class StateHolder { } public boolean hasProperty(final Property property) { @@ -32134,7 +32119,7 @@ index 7d0d5e8e6c951be025183f7b1712d34aeb48b110..b72861c0164ebb13b6fc3e78cd7ce0a2 } public > Optional getOptionalValue(final Property property) { -@@ -103,17 +131,26 @@ public abstract class StateHolder { +@@ -102,17 +130,26 @@ public abstract class StateHolder { } public , V extends T> S setValue(final Property property, final V value) { @@ -32168,7 +32153,7 @@ index 7d0d5e8e6c951be025183f7b1712d34aeb48b110..b72861c0164ebb13b6fc3e78cd7ce0a2 } private , V extends T> S setValueInternal(final Property property, final int propertyIndex, final V value) { -@@ -134,12 +171,15 @@ public abstract class StateHolder { +@@ -133,12 +170,15 @@ public abstract class StateHolder { } public boolean isSingletonState() { @@ -32217,7 +32202,7 @@ index 87b922c2aa4ef44a2a3469314f599dd63ee97baa..eac3775777060809b0e2ed118c12e647 @Override diff --git a/net/minecraft/world/level/block/state/properties/EnumProperty.java b/net/minecraft/world/level/block/state/properties/EnumProperty.java -index b718c4f81740b34e4321654d26e45f4c5bdb2450..09ccb96400aa25bd7fbcc1564fcc9b2b0e518bd6 100644 +index d00bb7c0e2dcfa75a2a62ad99bb843d9fc24e49c..665915290911a2a9390062c109103d9a1a6e4bde 100644 --- a/net/minecraft/world/level/block/state/properties/EnumProperty.java +++ b/net/minecraft/world/level/block/state/properties/EnumProperty.java @@ -10,11 +10,39 @@ import java.util.function.Predicate; @@ -32262,15 +32247,15 @@ index b718c4f81740b34e4321654d26e45f4c5bdb2450..09ccb96400aa25bd7fbcc1564fcc9b2b super(name, clazz); if (values.isEmpty()) { @@ -37,6 +65,7 @@ public final class EnumProperty & StringRepresentable> extends - - this.names = names.buildOrThrow(); } + + this.names = names.buildOrThrow(); + this.init(); // Paper - optimise blockstate property access } @Override diff --git a/net/minecraft/world/level/block/state/properties/IntegerProperty.java b/net/minecraft/world/level/block/state/properties/IntegerProperty.java -index f837d8029127e74f7181aa183e341a47ee8125a9..b0f90ce47b60cc775cece33ec7d2d30101574b16 100644 +index 1338213c0c918301a8fbc232b25d55804bda9cf9..954e61059e07bf4bc36270d64c6aa513ecbabc26 100644 --- a/net/minecraft/world/level/block/state/properties/IntegerProperty.java +++ b/net/minecraft/world/level/block/state/properties/IntegerProperty.java @@ -5,11 +5,33 @@ import java.util.List; @@ -32308,16 +32293,16 @@ index f837d8029127e74f7181aa183e341a47ee8125a9..b0f90ce47b60cc775cece33ec7d2d301 private IntegerProperty(final String name, final int min, final int max) { super(name, Integer.class); if (min < 0) { -@@ -21,6 +43,7 @@ public final class IntegerProperty extends Property { - this.max = max; - this.values = IntImmutableList.toList(IntStream.range(min, max + 1)); - } +@@ -23,6 +45,7 @@ public final class IntegerProperty extends Property { + this.min = min; + this.max = max; + this.values = IntImmutableList.toList(IntStream.range(min, max + 1)); + this.init(); // Paper - optimise blockstate property access } @Override diff --git a/net/minecraft/world/level/block/state/properties/Property.java b/net/minecraft/world/level/block/state/properties/Property.java -index 8970be0f45631e0710ccfbf45a25caf7717d0988..22d309410f5752a5f6b356e4f5cbda86444423f6 100644 +index b95665559d646ab8de313a19dadc197a1e8be02c..b82b935272efbc7a7518e148f665f4f24fa96814 100644 --- a/net/minecraft/world/level/block/state/properties/Property.java +++ b/net/minecraft/world/level/block/state/properties/Property.java @@ -10,7 +10,7 @@ import java.util.stream.Stream; @@ -32369,7 +32354,7 @@ index 8970be0f45631e0710ccfbf45a25caf7717d0988..22d309410f5752a5f6b356e4f5cbda86 public Property.Value value(final T value) { diff --git a/net/minecraft/world/level/chunk/ChunkAccess.java b/net/minecraft/world/level/chunk/ChunkAccess.java -index 28a0f11af688c8bca4b1132b4de2977ee32e19db..c974b1c276d29610cb59566afaad19f5bcf0c602 100644 +index b23c29459a59c136ccd2f8d6bde5464c94206792..c974b1c276d29610cb59566afaad19f5bcf0c602 100644 --- a/net/minecraft/world/level/chunk/ChunkAccess.java +++ b/net/minecraft/world/level/chunk/ChunkAccess.java @@ -57,7 +57,7 @@ import net.minecraft.world.ticks.TickContainerAccess; @@ -32484,8 +32469,8 @@ index 28a0f11af688c8bca4b1132b4de2977ee32e19db..c974b1c276d29610cb59566afaad19f5 - int clampedQuartY = Mth.clamp(quartY, quartMinY, quartMaxY); - int sectionIndex = this.getSectionIndex(QuartPos.toBlock(clampedQuartY)); - return this.sections[sectionIndex].getNoiseBiome(quartX & 3, clampedQuartY & 3, quartZ & 3); -- } catch (Throwable var8) { -- CrashReport report = CrashReport.forThrowable(var8, "Getting biome"); +- } catch (Throwable t) { +- CrashReport report = CrashReport.forThrowable(t, "Getting biome"); - CrashReportCategory category = report.addCategory("Biome being got"); - category.setDetail("Location", () -> CrashReportCategory.formatLocation(this, quartX, quartY, quartZ)); - throw new ReportedException(report); @@ -32524,7 +32509,7 @@ index 28a0f11af688c8bca4b1132b4de2977ee32e19db..c974b1c276d29610cb59566afaad19f5 public static ProblemReporter.PathElement problemPath(final ChunkPos pos) { diff --git a/net/minecraft/world/level/chunk/ChunkGenerator.java b/net/minecraft/world/level/chunk/ChunkGenerator.java -index 1b0eb74970c4d89ce8de4ca7bb86d420e396540d..a5d61f84dbf2937162abdfc1692f0848b971a4ce 100644 +index a2015a6e4e4ab87fe474d388dc3058ec57ff8dac..aed69011d7e1a7819276d4bcd14ec47d367cbeb1 100644 --- a/net/minecraft/world/level/chunk/ChunkGenerator.java +++ b/net/minecraft/world/level/chunk/ChunkGenerator.java @@ -119,7 +119,7 @@ public abstract class ChunkGenerator { @@ -32536,7 +32521,7 @@ index 1b0eb74970c4d89ce8de4ca7bb86d420e396540d..a5d61f84dbf2937162abdfc1692f0848 } public abstract void applyCarvers( -@@ -316,7 +316,7 @@ public abstract class ChunkGenerator { +@@ -314,7 +314,7 @@ public abstract class ChunkGenerator { return Pair.of(config.getLocatePos(chunkTarget), structure); } @@ -32685,10 +32670,10 @@ index 54d57f80b1cca351cac2aa59477a0e57334816e7..94652b00e18ffcbe02f1ad0578d671e2 public @Nullable BlockEntity getBlockEntity(final BlockPos pos) { return this.wrapped.getBlockEntity(pos); diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java -index d747e7058f78ac1fd02f3dc8e06670ed484cd42b..c0c212fd50cf97ae311035b370e8b4d40d82229e 100644 +index ed3bc67e7a659c88b199870836383f150415f8bc..1b364f99d728e177e7d4b5b706690a0b1c324fa8 100644 --- a/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java -@@ -64,7 +64,7 @@ import net.minecraft.world.ticks.TickContainerAccess; +@@ -63,7 +63,7 @@ import net.minecraft.world.ticks.TickContainerAccess; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; @@ -32697,7 +32682,7 @@ index d747e7058f78ac1fd02f3dc8e06670ed484cd42b..c0c212fd50cf97ae311035b370e8b4d4 private static final Logger LOGGER = LogUtils.getLogger(); private static final TickingBlockEntity NULL_TICKER = new TickingBlockEntity() { @Override -@@ -103,6 +103,39 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource { +@@ -102,6 +102,39 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource { // Paper start boolean loadedTicketLevel; // Paper end @@ -32737,7 +32722,7 @@ index d747e7058f78ac1fd02f3dc8e06670ed484cd42b..c0c212fd50cf97ae311035b370e8b4d4 public LevelChunk(final Level level, final ChunkPos pos) { this(level, pos, UpgradeData.EMPTY, new LevelChunkTicks<>(), new LevelChunkTicks<>(), 0L, null, null, null); -@@ -132,6 +165,14 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource { +@@ -131,6 +164,14 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource { this.postLoad = postLoad; this.blockTicks = blockTicks; this.fluidTicks = fluidTicks; @@ -32752,7 +32737,7 @@ index d747e7058f78ac1fd02f3dc8e06670ed484cd42b..c0c212fd50cf97ae311035b370e8b4d4 } public LevelChunk(final ServerLevel level, final ProtoChunk protoChunk, final LevelChunk.@Nullable PostLoadProcessor postLoad) { -@@ -169,13 +210,19 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource { +@@ -168,13 +209,19 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource { } } @@ -32773,16 +32758,16 @@ index d747e7058f78ac1fd02f3dc8e06670ed484cd42b..c0c212fd50cf97ae311035b370e8b4d4 } public void setUnsavedListener(final LevelChunk.UnsavedListener unsavedListener) { -@@ -346,7 +393,7 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource { - if (LightEngine.hasDifferentLightProperties(oldState, state)) { - ProfilerFiller profiler = Profiler.get(); - profiler.push("updateSkyLightSources"); -- this.skyLightSources.update(this, localX, y, localZ); -+ // Paper - rewrite chunk system - profiler.popPush("queueCheckLight"); - this.level.getChunkSource().getLightEngine().checkBlock(pos); - profiler.pop(); -@@ -584,11 +631,12 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource { +@@ -347,7 +394,7 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource { + if (LightEngine.hasDifferentLightProperties(oldState, state)) { + ProfilerFiller profiler = Profiler.get(); + profiler.push("updateSkyLightSources"); +- this.skyLightSources.update(this, localX, y, localZ); ++ // Paper - rewrite chunk system + profiler.popPush("queueCheckLight"); + this.level.getChunkSource().getLightEngine().checkBlock(pos); + profiler.pop(); +@@ -583,11 +630,12 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource { // CraftBukkit start public void loadCallback() { @@ -32796,7 +32781,7 @@ index d747e7058f78ac1fd02f3dc8e06670ed484cd42b..c0c212fd50cf97ae311035b370e8b4d4 if (server != null) { /* * If it's a new world, the first few chunks are generated inside -@@ -597,6 +645,7 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource { +@@ -596,6 +644,7 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource { */ org.bukkit.Chunk bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this); server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(bukkitChunk, this.needsDecoration)); @@ -32804,7 +32789,7 @@ index d747e7058f78ac1fd02f3dc8e06670ed484cd42b..c0c212fd50cf97ae311035b370e8b4d4 if (this.needsDecoration) { this.needsDecoration = false; -@@ -623,13 +672,15 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource { +@@ -622,13 +671,15 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource { } public void unloadCallback() { @@ -32822,7 +32807,7 @@ index d747e7058f78ac1fd02f3dc8e06670ed484cd42b..c0c212fd50cf97ae311035b370e8b4d4 // Paper start this.loadedTicketLevel = false; // Paper end -@@ -637,8 +688,31 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource { +@@ -636,8 +687,31 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource { @Override public boolean isUnsaved() { @@ -32855,7 +32840,7 @@ index d747e7058f78ac1fd02f3dc8e06670ed484cd42b..c0c212fd50cf97ae311035b370e8b4d4 // CraftBukkit end public boolean isEmpty() { -@@ -721,6 +795,7 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource { +@@ -720,6 +794,7 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource { this.pendingBlockEntities.clear(); this.upgradeData.upgrade(this); @@ -32864,10 +32849,10 @@ index d747e7058f78ac1fd02f3dc8e06670ed484cd42b..c0c212fd50cf97ae311035b370e8b4d4 private @Nullable BlockEntity promotePendingBlockEntity(final BlockPos pos, final CompoundTag tag) { diff --git a/net/minecraft/world/level/chunk/LevelChunkSection.java b/net/minecraft/world/level/chunk/LevelChunkSection.java -index edfd4c7b089e69c1237db71fa0f13d6ed9565394..398018ad7037669a756f804403fd76cf333a06de 100644 +index e247b51fe49fe5cf1dfa475b16ba0805e47d50af..0e7bb7db9e46b2cade771fa5e94469023d8b47b0 100644 --- a/net/minecraft/world/level/chunk/LevelChunkSection.java +++ b/net/minecraft/world/level/chunk/LevelChunkSection.java -@@ -10,7 +10,7 @@ import net.minecraft.world.level.biome.Climate; +@@ -9,7 +9,7 @@ import net.minecraft.world.level.biome.Climate; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.FluidState; @@ -32876,7 +32861,7 @@ index edfd4c7b089e69c1237db71fa0f13d6ed9565394..398018ad7037669a756f804403fd76cf public static final int SECTION_WIDTH = 16; public static final int SECTION_HEIGHT = 16; public static final int SECTION_SIZE = 4096; -@@ -22,6 +22,30 @@ public class LevelChunkSection { +@@ -21,6 +21,30 @@ public class LevelChunkSection { public final PalettedContainer states; private PalettedContainer> biomes; // CraftBukkit - read/write @@ -32907,7 +32892,7 @@ index edfd4c7b089e69c1237db71fa0f13d6ed9565394..398018ad7037669a756f804403fd76cf private LevelChunkSection(final LevelChunkSection source) { this.nonEmptyBlockCount = source.nonEmptyBlockCount; this.fluidCount = source.fluidCount; -@@ -62,6 +86,45 @@ public class LevelChunkSection { +@@ -61,6 +85,45 @@ public class LevelChunkSection { return this.setBlockState(sectionX, sectionY, sectionZ, state, true); } @@ -32953,7 +32938,7 @@ index edfd4c7b089e69c1237db71fa0f13d6ed9565394..398018ad7037669a756f804403fd76cf public BlockState setBlockState(final int sectionX, final int sectionY, final int sectionZ, final BlockState state, final boolean checkThreading) { BlockState previous; if (checkThreading) { -@@ -100,6 +163,8 @@ public class LevelChunkSection { +@@ -99,6 +162,8 @@ public class LevelChunkSection { } } @@ -32962,7 +32947,7 @@ index edfd4c7b089e69c1237db71fa0f13d6ed9565394..398018ad7037669a756f804403fd76cf return previous; } -@@ -124,42 +189,71 @@ public class LevelChunkSection { +@@ -123,37 +188,71 @@ public class LevelChunkSection { } public void recalcBlockCounts() { @@ -32972,9 +32957,12 @@ index edfd4c7b089e69c1237db71fa0f13d6ed9565394..398018ad7037669a756f804403fd76cf - public int tickingBlockCount; - public int tickingFluidCount; - -- BlockCounter() { -- Objects.requireNonNull(LevelChunkSection.this); -- super(); +- @Override +- public void accept(final BlockState state, final int count) { +- if (!state.isAir()) { +- this.nonEmptyBlockCount += count; +- if (state.isRandomlyTicking()) { +- this.tickingBlockCount += count; + // Paper start - block counting + // reset, then recalculate + this.nonEmptyBlockCount = (short)0; @@ -32996,14 +32984,8 @@ index edfd4c7b089e69c1237db71fa0f13d6ed9565394..398018ad7037669a756f804403fd76cf + counts.put(0, FULL_LIST); + } else { + counts = ((ca.spottedleaf.moonrise.patches.block_counting.BlockCountingBitStorage)storage).moonrise$countEntries(); - } - -- @Override -- public void accept(final BlockState state, final int count) { -- if (!state.isAir()) { -- this.nonEmptyBlockCount += count; -- if (state.isRandomlyTicking()) { -- this.tickingBlockCount += count; ++ } ++ + for (final java.util.Iterator> iterator = counts.int2ObjectEntrySet().fastIterator(); iterator.hasNext();) { + final it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry entry = iterator.next(); + final int paletteIdx = entry.getIntKey(); @@ -33062,7 +33044,7 @@ index edfd4c7b089e69c1237db71fa0f13d6ed9565394..398018ad7037669a756f804403fd76cf } public PalettedContainer getStates() { -@@ -177,6 +271,11 @@ public class LevelChunkSection { +@@ -171,6 +270,11 @@ public class LevelChunkSection { PalettedContainer> biomes = this.biomes.recreate(); biomes.read(buffer); this.biomes = biomes; @@ -33099,7 +33081,7 @@ index 51761bba718b5bc58524454137d7e526c74ce5d3..58f03cf8b32b141dc7df72568ef902ee this.values = (T[])(new Object[1 << bits]); this.bits = bits; diff --git a/net/minecraft/world/level/chunk/Palette.java b/net/minecraft/world/level/chunk/Palette.java -index 89f2176747094340565e579d6106b3a702150b4b..2c53d464df5f141b83b3a589de597d82eeb42ddb 100644 +index 9b9119afd89f60cd88c3d1e6ec4857b92e95ff11..eec56782be6e6e2c483e7435ff136bf885011eaf 100644 --- a/net/minecraft/world/level/chunk/Palette.java +++ b/net/minecraft/world/level/chunk/Palette.java @@ -5,7 +5,7 @@ import java.util.function.Predicate; @@ -33112,7 +33094,7 @@ index 89f2176747094340565e579d6106b3a702150b4b..2c53d464df5f141b83b3a589de597d82 boolean maybeHas(Predicate predicate); diff --git a/net/minecraft/world/level/chunk/PalettedContainer.java b/net/minecraft/world/level/chunk/PalettedContainer.java -index 7337cbd5ee2cba2cd0cf21f2b9628e9f8e1e70fc..edf2990bfbe3d6b64eed85446eef207d2506efc5 100644 +index a04bc4efcb68c049bb9ac47ad378ecb6fec2c370..4eeb920e4e71ab91cdb5a41f1eabdd47182c80fb 100644 --- a/net/minecraft/world/level/chunk/PalettedContainer.java +++ b/net/minecraft/world/level/chunk/PalettedContainer.java @@ -24,7 +24,7 @@ import org.jspecify.annotations.Nullable; @@ -33183,7 +33165,7 @@ index 7337cbd5ee2cba2cd0cf21f2b9628e9f8e1e70fc..edf2990bfbe3d6b64eed85446eef207d return newData.palette.idFor(lastAddedValue, PaletteResize.noResizeExpected()); } -@@ -120,9 +151,12 @@ public class PalettedContainer implements PaletteResize, PalettedContainer +@@ -117,9 +148,12 @@ public class PalettedContainer implements PaletteResize, PalettedContainer } private T getAndSet(final int index, final T value) { @@ -33199,7 +33181,7 @@ index 7337cbd5ee2cba2cd0cf21f2b9628e9f8e1e70fc..edf2990bfbe3d6b64eed85446eef207d } public synchronized void set(final int x, final int y, final int z, final T value) { // Paper - synchronize -@@ -145,9 +179,11 @@ public class PalettedContainer implements PaletteResize, PalettedContainer +@@ -142,9 +176,11 @@ public class PalettedContainer implements PaletteResize, PalettedContainer return this.get(this.strategy.getIndex(x, y, z)); } @@ -33214,7 +33196,7 @@ index 7337cbd5ee2cba2cd0cf21f2b9628e9f8e1e70fc..edf2990bfbe3d6b64eed85446eef207d } @Override -@@ -167,6 +203,7 @@ public class PalettedContainer implements PaletteResize, PalettedContainer +@@ -164,6 +200,7 @@ public class PalettedContainer implements PaletteResize, PalettedContainer newData.palette.read(buffer, this.strategy.globalMap()); buffer.readFixedSizeLongArray(newData.storage.getRaw()); this.data = newData; @@ -33222,7 +33204,7 @@ index 7337cbd5ee2cba2cd0cf21f2b9628e9f8e1e70fc..edf2990bfbe3d6b64eed85446eef207d } finally { this.release(); } -@@ -316,7 +353,44 @@ public class PalettedContainer implements PaletteResize, PalettedContainer +@@ -310,7 +347,44 @@ public class PalettedContainer implements PaletteResize, PalettedContainer void accept(final T entry, final int count); } @@ -33269,20 +33251,20 @@ index 7337cbd5ee2cba2cd0cf21f2b9628e9f8e1e70fc..edf2990bfbe3d6b64eed85446eef207d PaletteResize dummyResizer = PaletteResize.noResizeExpected(); diff --git a/net/minecraft/world/level/chunk/ProtoChunk.java b/net/minecraft/world/level/chunk/ProtoChunk.java -index e2208bc7b58b0241192b1b79e3ac1aa0bb35f354..d3bde6eb0edd24d5e5352388788d30938712a9c7 100644 +index 26c8a51c94b51a1ef8f5a3392f9c85a62af7f7f4..50fe95f472f143ef381557f8675e427f20aa9d09 100644 --- a/net/minecraft/world/level/chunk/ProtoChunk.java +++ b/net/minecraft/world/level/chunk/ProtoChunk.java -@@ -154,7 +154,7 @@ public class ProtoChunk extends ChunkAccess { - } +@@ -156,7 +156,7 @@ public class ProtoChunk extends ChunkAccess { + } - if (LightEngine.hasDifferentLightProperties(oldState, state)) { -- this.skyLightSources.update(this, localX, y, localZ); -+ // Paper - rewrite chunk system - this.lightEngine.checkBlock(pos); - } - } + if (LightEngine.hasDifferentLightProperties(oldState, state)) { +- this.skyLightSources.update(this, localX, y, localZ); ++ // Paper - rewrite chunk system + this.lightEngine.checkBlock(pos); + } + } diff --git a/net/minecraft/world/level/chunk/SingleValuePalette.java b/net/minecraft/world/level/chunk/SingleValuePalette.java -index 7a9f737d03b5bf61c857e28539d7e09cb36be46f..c180673b37b07282419e315e8449e2ab73bbbc98 100644 +index 1e3ae1ae9dac0c98f6840658d690f63deac5c406..06a7f795739df3ccb7cae0aa00c88eb8ceea8073 100644 --- a/net/minecraft/world/level/chunk/SingleValuePalette.java +++ b/net/minecraft/world/level/chunk/SingleValuePalette.java @@ -8,9 +8,21 @@ import net.minecraft.network.VarInt; @@ -33307,19 +33289,19 @@ index 7a9f737d03b5bf61c857e28539d7e09cb36be46f..c180673b37b07282419e315e8449e2ab + public SingleValuePalette(final List paletteEntries) { if (!paletteEntries.isEmpty()) { - Validate.isTrue(paletteEntries.size() <= 1, "Can't initialize SingleValuePalette with %d values.", (long)paletteEntries.size()); -@@ -28,6 +40,11 @@ public class SingleValuePalette implements Palette { - return resizeHandler.onResize(1, value); - } else { - this.value = value; -+ // Paper start - optimise palette reads -+ if (this.rawPalette != null) { -+ this.rawPalette[0] = value; -+ } -+ // Paper end - optimise palette reads - return 0; + Validate.isTrue(paletteEntries.size() <= 1, "Can't initialize SingleValuePalette with %d values.", paletteEntries.size()); +@@ -29,6 +41,11 @@ public class SingleValuePalette implements Palette { } + + this.value = value; ++ // Paper start - optimise palette reads ++ if (this.rawPalette != null) { ++ this.rawPalette[0] = value; ++ } ++ // Paper end - optimise palette reads + return 0; } + @@ -53,6 +70,11 @@ public class SingleValuePalette implements Palette { @Override public void read(final FriendlyByteBuf buffer, final IdMap globalMap) { @@ -33458,7 +33440,7 @@ index 8d3eb23eb607c862e15fb9e2e7f71a2019b02d04..6eb1a3a83c5bae8935c042396d676f7a } } diff --git a/net/minecraft/world/level/chunk/status/ChunkStep.java b/net/minecraft/world/level/chunk/status/ChunkStep.java -index 3e381c26fe9a646c73704515f57ba09d9533f37e..554faa6ebfc7c7db11634fc9a8cac846df9b92fb 100644 +index 81837925c0a0fac18ea9d477e82ace10e32e932c..9208924f54d5024bc50ad4501fbff9eb2a289181 100644 --- a/net/minecraft/world/level/chunk/status/ChunkStep.java +++ b/net/minecraft/world/level/chunk/status/ChunkStep.java @@ -11,9 +11,50 @@ import net.minecraft.world.level.chunk.ChunkAccess; @@ -33572,7 +33554,7 @@ index 3e381c26fe9a646c73704515f57ba09d9533f37e..554faa6ebfc7c7db11634fc9a8cac846 private final ChunkStatus status; private final @Nullable ChunkStep parent; diff --git a/net/minecraft/world/level/chunk/storage/IOWorker.java b/net/minecraft/world/level/chunk/storage/IOWorker.java -index cc5d366f7b485f98901572b1aaf57d8b650d521f..7adb4be57bd9fdc9980b5b7e91e9d9ca4d24a726 100644 +index ecc3d06a3e61b1de001e77ac35fa282e61e4d517..cd2ac98e1910c8c6222db084a1d2dffc6f9519c9 100644 --- a/net/minecraft/world/level/chunk/storage/IOWorker.java +++ b/net/minecraft/world/level/chunk/storage/IOWorker.java @@ -31,7 +31,7 @@ public class IOWorker implements AutoCloseable, ChunkScanAccess { @@ -33585,10 +33567,10 @@ index cc5d366f7b485f98901572b1aaf57d8b650d521f..7adb4be57bd9fdc9980b5b7e91e9d9ca private final Long2ObjectLinkedOpenHashMap> regionCacheForBlender = new Long2ObjectLinkedOpenHashMap<>(); private static final int REGION_CACHE_SIZE = 1024; diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java -index 9409cc5c8dbd12ce6bdf34843da70170ebce41bd..c9acbdce97cb605a45124bb9d3944070396adc03 100644 +index 0113fdf0b346f1dbea3856690ca8c389a2bae0a9..026b1f31d5041786e90ba372a228732aee094c16 100644 --- a/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/net/minecraft/world/level/chunk/storage/RegionFile.java -@@ -23,7 +23,7 @@ import net.minecraft.world.level.ChunkPos; +@@ -22,7 +22,7 @@ import net.minecraft.world.level.ChunkPos; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; @@ -33597,7 +33579,7 @@ index 9409cc5c8dbd12ce6bdf34843da70170ebce41bd..c9acbdce97cb605a45124bb9d3944070 private static final Logger LOGGER = LogUtils.getLogger(); private static final int SECTOR_BYTES = 4096; @VisibleForTesting -@@ -46,6 +46,21 @@ public class RegionFile implements AutoCloseable { +@@ -45,6 +45,21 @@ public class RegionFile implements AutoCloseable { @VisibleForTesting protected final RegionBitmap usedSectors = new RegionBitmap(); @@ -33619,7 +33601,7 @@ index 9409cc5c8dbd12ce6bdf34843da70170ebce41bd..c9acbdce97cb605a45124bb9d3944070 public RegionFile(final RegionStorageInfo info, final Path path, final Path externalFileDir, final boolean sync) throws IOException { this(info, path, externalFileDir, RegionFileVersion.getSelected(), sync); } -@@ -201,6 +216,15 @@ public class RegionFile implements AutoCloseable { +@@ -200,6 +215,15 @@ public class RegionFile implements AutoCloseable { } private @Nullable DataInputStream createExternalChunkInputStream(final ChunkPos pos, final byte versionId) throws IOException { @@ -33635,7 +33617,7 @@ index 9409cc5c8dbd12ce6bdf34843da70170ebce41bd..c9acbdce97cb605a45124bb9d3944070 Path externalFile = this.getExternalChunkPath(pos); if (!Files.isRegularFile(externalFile)) { LOGGER.error("External chunk path {} is not file", externalFile); -@@ -395,9 +419,28 @@ public class RegionFile implements AutoCloseable { +@@ -394,9 +418,28 @@ public class RegionFile implements AutoCloseable { } } @@ -33663,9 +33645,9 @@ index 9409cc5c8dbd12ce6bdf34843da70170ebce41bd..c9acbdce97cb605a45124bb9d3944070 + // Paper end - rewrite chunk system + public ChunkBuffer(final ChunkPos pos) { - Objects.requireNonNull(RegionFile.this); super(8096); -@@ -415,7 +458,7 @@ public class RegionFile implements AutoCloseable { + super.write(0); +@@ -413,7 +456,7 @@ public class RegionFile implements AutoCloseable { int streamLength = this.count - 5 + 1; JvmProfiler.INSTANCE.onRegionFileWrite(RegionFile.this.info, this.pos, RegionFile.this.version, streamLength); result.putInt(0, streamLength); @@ -33675,7 +33657,7 @@ index 9409cc5c8dbd12ce6bdf34843da70170ebce41bd..c9acbdce97cb605a45124bb9d3944070 } diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index 4473503da2459016859b2d72ecd7825df23f4be4..e9316cc08fe4cb4af28583a8cb1ec658243bffd0 100644 +index f2f1b9132754b3e04fbaae4fc6499a7119540b90..694689c5e0ca65b1b8724b689f3817753dd74834 100644 --- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java @@ -15,7 +15,7 @@ import net.minecraft.util.FileUtil; @@ -33881,49 +33863,51 @@ index 4473503da2459016859b2d72ecd7825df23f4be4..e9316cc08fe4cb4af28583a8cb1ec658 - RegionFile region = this.regionCache.getAndMoveToFirst(key); - if (region != null) { - return region; -- } else { -- int cacheSize = io.papermc.paper.configuration.GlobalConfiguration.get() == null ? 256 : io.papermc.paper.configuration.GlobalConfiguration.get().misc.regionFileCacheSize; // Paper - Sanitise RegionFileCache and make configurable - Config not available during initial FileFixerUpper run -- if (this.regionCache.size() >= cacheSize) { // Paper - Sanitise RegionFileCache and make configurable + // Paper start - rewrite chunk system + if (existingOnly) { + return this.moonrise$getRegionFileIfExists(pos.x(), pos.z()); -+ } + } + synchronized (this) { + final long key = ChunkPos.pack(pos.x() >> REGION_SHIFT, pos.z() >> REGION_SHIFT); -+ + +- int cacheSize = io.papermc.paper.configuration.GlobalConfiguration.get() == null ? 256 : io.papermc.paper.configuration.GlobalConfiguration.get().misc.regionFileCacheSize; // Paper - Sanitise RegionFileCache and make configurable - Config not available during initial FileFixerUpper run +- if (this.regionCache.size() >= cacheSize) { // Paper - Sanitise RegionFileCache and make configurable +- this.regionCache.removeLast().close(); +- } + RegionFile ret = this.regionCache.getAndMoveToFirst(key); + if (ret != null) { + return ret; + } -+ + +- FileUtil.createDirectoriesSafe(this.folder); +- Path file = this.folder.resolve("r." + pos.getRegionX() + "." + pos.getRegionZ() + ".mca"); +- if (existingOnly && !java.nio.file.Files.exists(file)) return null; // CraftBukkit +- RegionFile newRegion = new RegionFile(this.info, file, this.folder, this.sync); +- this.regionCache.putAndMoveToFirst(key, newRegion); +- return newRegion; + final int cacheSize = io.papermc.paper.configuration.GlobalConfiguration.get() == null ? 256 : io.papermc.paper.configuration.GlobalConfiguration.get().misc.regionFileCacheSize; // Paper - Sanitise RegionFileCache and make configurable - Config not available during initial FileFixerUpper run + + if (this.regionCache.size() >= cacheSize) { - this.regionCache.removeLast().close(); - } - ++ this.regionCache.removeLast().close(); ++ } ++ + final Path regionPath = this.folder.resolve(getRegionFileName(pos.x(), pos.z())); + + this.createRegionFile(key); + - FileUtil.createDirectoriesSafe(this.folder); -- Path file = this.folder.resolve("r." + pos.getRegionX() + "." + pos.getRegionZ() + ".mca"); -- if (existingOnly && !java.nio.file.Files.exists(file)) return null; // CraftBukkit -- RegionFile newRegion = new RegionFile(this.info, file, this.folder, this.sync); -- this.regionCache.putAndMoveToFirst(key, newRegion); -- return newRegion; ++ FileUtil.createDirectoriesSafe(this.folder); + + ret = new RegionFile(this.info, regionPath, this.folder, this.sync); + + this.regionCache.putAndMoveToFirst(key, ret); + + return ret; - } ++ } + // Paper end - rewrite chunk system } public @Nullable CompoundTag read(final ChunkPos pos) throws IOException { -@@ -84,9 +276,15 @@ public final class RegionFileStorage implements AutoCloseable { +@@ -77,9 +269,15 @@ public final class RegionFileStorage implements AutoCloseable { } } @@ -33941,7 +33925,7 @@ index 4473503da2459016859b2d72ecd7825df23f4be4..e9316cc08fe4cb4af28583a8cb1ec658 if (value == null) { region.clear(pos); } else { -@@ -99,23 +297,36 @@ public final class RegionFileStorage implements AutoCloseable { +@@ -92,23 +290,36 @@ public final class RegionFileStorage implements AutoCloseable { @Override public void close() throws IOException { @@ -33950,8 +33934,8 @@ index 4473503da2459016859b2d72ecd7825df23f4be4..e9316cc08fe4cb4af28583a8cb1ec658 - for (RegionFile regionFile : this.regionCache.values()) { - try { - regionFile.close(); -- } catch (IOException var5) { -- exception.add(var5); +- } catch (IOException e) { +- exception.add(e); + // Paper start - rewrite chunk system + synchronized (this) { + final ExceptionCollector exceptionCollector = new ExceptionCollector<>(); @@ -33990,7 +33974,7 @@ index 4473503da2459016859b2d72ecd7825df23f4be4..e9316cc08fe4cb4af28583a8cb1ec658 public RegionStorageInfo info() { diff --git a/net/minecraft/world/level/chunk/storage/SectionStorage.java b/net/minecraft/world/level/chunk/storage/SectionStorage.java -index b0b7af7e541eef20063c11ee94d7a6ceaec1626a..18be8647455dee182622f3bbefa9122547fe86ca 100644 +index 2412c31426bbf0a4f8102bf7ce307a4a93935f52..4bc70852449459037d293d2813c1c73345149b4e 100644 --- a/net/minecraft/world/level/chunk/storage/SectionStorage.java +++ b/net/minecraft/world/level/chunk/storage/SectionStorage.java @@ -40,10 +40,10 @@ import net.minecraft.world.level.LevelHeightAccessor; @@ -34148,39 +34132,39 @@ index b0b7af7e541eef20063c11ee94d7a6ceaec1626a..18be8647455dee182622f3bbefa91225 private record PackedChunk(Int2ObjectMap sectionsByY, boolean versionChanged) { diff --git a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java -index 480623c30777fd230bf8428b16364db09806562b..1e0afa9590de7fe492cf29aded96be3db498c51e 100644 +index 760eda9e45a3f31a68a3b2b2dc13479c7db0d3cc..2d326c3090a5d7621350347e131ee31d4715d3a7 100644 --- a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java +++ b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java -@@ -145,7 +145,7 @@ public record SerializableChunkData( - long inhabitedTime = chunkData.getLongOr("InhabitedTime", 0L); - ChunkStatus status = chunkData.read("Status", ChunkStatus.CODEC).orElse(ChunkStatus.EMPTY); - UpgradeData upgradeData = chunkData.getCompound("UpgradeData").map(tag -> new UpgradeData(tag, levelHeight)).orElse(UpgradeData.EMPTY); -- boolean lightCorrect = chunkData.getBooleanOr("isLightOn", false); -+ boolean lightCorrect = status.isOrAfter(ChunkStatus.LIGHT) && (chunkData.get("isLightOn") != null && chunkData.getIntOr(ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.STARLIGHT_VERSION_TAG, -1) == ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.STARLIGHT_LIGHT_VERSION); // Paper - starlight - BlendingData.Packed blendingData = chunkData.read("blending_data", BlendingData.Packed.CODEC).orElse(null); - BelowZeroRetrogen belowZeroRetrogen = chunkData.read("below_zero_retrogen", BelowZeroRetrogen.CODEC).orElse(null); - long[] carvingMask = chunkData.getLongArray("carving_mask").orElse(null); -@@ -210,7 +210,17 @@ public record SerializableChunkData( - - DataLayer blockLight = sectionTag.getByteArray("BlockLight").map(DataLayer::new).orElse(null); - DataLayer skyLight = sectionTag.getByteArray("SkyLight").map(DataLayer::new).orElse(null); -- sectionData.add(new SerializableChunkData.SectionData(y, section, blockLight, skyLight)); -+ // Paper start - starlight -+ SerializableChunkData.SectionData serializableChunkData = new SerializableChunkData.SectionData(y, section, blockLight, skyLight); -+ if (sectionTag.contains(ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.BLOCKLIGHT_STATE_TAG)) { -+ ((ca.spottedleaf.moonrise.patches.starlight.storage.StarlightSectionData)(Object)serializableChunkData).starlight$setBlockLightState(sectionTag.getIntOr(ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.BLOCKLIGHT_STATE_TAG, 0)); -+ } -+ -+ if (sectionTag.contains(ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.SKYLIGHT_STATE_TAG)) { -+ ((ca.spottedleaf.moonrise.patches.starlight.storage.StarlightSectionData)(Object)serializableChunkData).starlight$setSkyLightState(sectionTag.getIntOr(ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.SKYLIGHT_STATE_TAG, 0)); -+ } -+ sectionData.add(serializableChunkData); -+ // Paper end - starlight - } +@@ -146,7 +146,7 @@ public record SerializableChunkData( + long inhabitedTime = chunkData.getLongOr("InhabitedTime", 0L); + ChunkStatus status = chunkData.read("Status", ChunkStatus.CODEC).orElse(ChunkStatus.EMPTY); + UpgradeData upgradeData = chunkData.getCompound("UpgradeData").map(tag -> new UpgradeData(tag, levelHeight)).orElse(UpgradeData.EMPTY); +- boolean lightCorrect = chunkData.getBooleanOr("isLightOn", false); ++ boolean lightCorrect = status.isOrAfter(ChunkStatus.LIGHT) && (chunkData.get("isLightOn") != null && chunkData.getIntOr(ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.STARLIGHT_VERSION_TAG, -1) == ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.STARLIGHT_LIGHT_VERSION); // Paper - starlight + BlendingData.Packed blendingData = chunkData.read("blending_data", BlendingData.Packed.CODEC).orElse(null); + BelowZeroRetrogen belowZeroRetrogen = chunkData.read("below_zero_retrogen", BelowZeroRetrogen.CODEC).orElse(null); + long[] carvingMask = chunkData.getLongArray("carving_mask").orElse(null); +@@ -211,7 +211,17 @@ public record SerializableChunkData( + + DataLayer blockLight = sectionTag.getByteArray("BlockLight").map(DataLayer::new).orElse(null); + DataLayer skyLight = sectionTag.getByteArray("SkyLight").map(DataLayer::new).orElse(null); +- sectionData.add(new SerializableChunkData.SectionData(y, section, blockLight, skyLight)); ++ // Paper start - starlight ++ SerializableChunkData.SectionData serializableChunkData = new SerializableChunkData.SectionData(y, section, blockLight, skyLight); ++ if (sectionTag.contains(ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.BLOCKLIGHT_STATE_TAG)) { ++ ((ca.spottedleaf.moonrise.patches.starlight.storage.StarlightSectionData)(Object)serializableChunkData).starlight$setBlockLightState(sectionTag.getIntOr(ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.BLOCKLIGHT_STATE_TAG, 0)); ++ } ++ ++ if (sectionTag.contains(ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.SKYLIGHT_STATE_TAG)) { ++ ((ca.spottedleaf.moonrise.patches.starlight.storage.StarlightSectionData)(Object)serializableChunkData).starlight$setSkyLightState(sectionTag.getIntOr(ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil.SKYLIGHT_STATE_TAG, 0)); ++ } ++ sectionData.add(serializableChunkData); ++ // Paper end - starlight } + } @@ -238,6 +248,59 @@ public record SerializableChunkData( - } + ); } + // Paper start - starlight @@ -34254,77 +34238,77 @@ index 480623c30777fd230bf8428b16364db09806562b..1e0afa9590de7fe492cf29aded96be3d if (chunkType == ChunkType.LEVELCHUNK) { - return new ImposterProtoChunk((LevelChunk)chunk, false); + return this.loadStarlightLightData(level, new ImposterProtoChunk((LevelChunk)chunk, false)); // Paper - starlight - } else { - ProtoChunk protoChunkx = (ProtoChunk)chunk; - -@@ -357,7 +420,7 @@ public record SerializableChunkData( - protoChunkx.setCarvingMask(new CarvingMask(this.carvingMask, chunk.getMinY())); - } + } -- return protoChunkx; -+ return this.loadStarlightLightData(level, protoChunkx); // Paper - starlight + ProtoChunk protoChunk = (ProtoChunk)chunk; +@@ -358,7 +421,7 @@ public record SerializableChunkData( + protoChunk.setCarvingMask(new CarvingMask(this.carvingMask, chunk.getMinY())); } + +- return protoChunk; ++ return this.loadStarlightLightData(level, protoChunk); // Paper - starlight } -@@ -371,21 +434,44 @@ public record SerializableChunkData( - } else { - ChunkPos pos = chunk.getPos(); - List sectionData = new ArrayList<>(); -- LevelChunkSection[] chunkSections = chunk.getSections(); -- LevelLightEngine lightEngine = level.getChunkSource().getLightEngine(); + private static void logErrors(final ChunkPos pos, final int sectionY, final String message) { +@@ -372,21 +435,44 @@ public record SerializableChunkData( + + ChunkPos pos = chunk.getPos(); + List sectionData = new ArrayList<>(); +- LevelChunkSection[] chunkSections = chunk.getSections(); +- LevelLightEngine lightEngine = level.getChunkSource().getLightEngine(); - -- for (int sectionY = lightEngine.getMinLightSection(); sectionY < lightEngine.getMaxLightSection(); sectionY++) { -- int sectionIndex = chunk.getSectionIndexFromSectionY(sectionY); -- boolean hasSection = sectionIndex >= 0 && sectionIndex < chunkSections.length; -- DataLayer sourceBlockLight = lightEngine.getLayerListener(LightLayer.BLOCK).getDataLayerData(SectionPos.of(pos, sectionY)); -- DataLayer sourceSkyLight = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(pos, sectionY)); -- DataLayer blockLight = sourceBlockLight != null && !sourceBlockLight.isEmpty() ? sourceBlockLight.copy() : null; -- DataLayer skyLight = sourceSkyLight != null && !sourceSkyLight.isEmpty() ? sourceSkyLight.copy() : null; -- if (hasSection || blockLight != null || skyLight != null) { -- LevelChunkSection section = hasSection ? chunkSections[sectionIndex].copy() : null; -- sectionData.add(new SerializableChunkData.SectionData(sectionY, section, blockLight, skyLight)); -+ // Paper start - starlight -+ final int minLightSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinLightSection(level); -+ final int maxLightSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMaxLightSection(level); -+ final int minBlockSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection(level); -+ -+ final LevelChunkSection[] chunkSections = chunk.getSections(); -+ final ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray[] blockNibbles = ((ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk)chunk).starlight$getBlockNibbles(); -+ final ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray[] skyNibbles = ((ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk)chunk).starlight$getSkyNibbles(); +- for (int sectionY = lightEngine.getMinLightSection(); sectionY < lightEngine.getMaxLightSection(); sectionY++) { +- int sectionIndex = chunk.getSectionIndexFromSectionY(sectionY); +- boolean hasSection = sectionIndex >= 0 && sectionIndex < chunkSections.length; +- DataLayer sourceBlockLight = lightEngine.getLayerListener(LightLayer.BLOCK).getDataLayerData(SectionPos.of(pos, sectionY)); +- DataLayer sourceSkyLight = lightEngine.getLayerListener(LightLayer.SKY).getDataLayerData(SectionPos.of(pos, sectionY)); +- DataLayer blockLight = sourceBlockLight != null && !sourceBlockLight.isEmpty() ? sourceBlockLight.copy() : null; +- DataLayer skyLight = sourceSkyLight != null && !sourceSkyLight.isEmpty() ? sourceSkyLight.copy() : null; +- if (hasSection || blockLight != null || skyLight != null) { +- LevelChunkSection section = hasSection ? chunkSections[sectionIndex].copy() : null; +- sectionData.add(new SerializableChunkData.SectionData(sectionY, section, blockLight, skyLight)); ++ // Paper start - starlight ++ final int minLightSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinLightSection(level); ++ final int maxLightSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMaxLightSection(level); ++ final int minBlockSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection(level); + -+ for (int lightSection = minLightSection; lightSection <= maxLightSection; ++lightSection) { -+ final int lightSectionIdx = lightSection - minLightSection; -+ final int blockSectionIdx = lightSection - minBlockSection; ++ final LevelChunkSection[] chunkSections = chunk.getSections(); ++ final ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray[] blockNibbles = ((ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk)chunk).starlight$getBlockNibbles(); ++ final ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray[] skyNibbles = ((ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk)chunk).starlight$getSkyNibbles(); + -+ final LevelChunkSection chunkSection = (blockSectionIdx >= 0 && blockSectionIdx < chunkSections.length) ? chunkSections[blockSectionIdx].copy() : null; -+ final ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray.SaveState blockNibble = blockNibbles[lightSectionIdx].getSaveState(); -+ final ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray.SaveState skyNibble = skyNibbles[lightSectionIdx].getSaveState(); ++ for (int lightSection = minLightSection; lightSection <= maxLightSection; ++lightSection) { ++ final int lightSectionIdx = lightSection - minLightSection; ++ final int blockSectionIdx = lightSection - minBlockSection; + -+ if (chunkSection == null && blockNibble == null && skyNibble == null) { -+ continue; - } ++ final LevelChunkSection chunkSection = (blockSectionIdx >= 0 && blockSectionIdx < chunkSections.length) ? chunkSections[blockSectionIdx].copy() : null; ++ final ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray.SaveState blockNibble = blockNibbles[lightSectionIdx].getSaveState(); ++ final ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray.SaveState skyNibble = skyNibbles[lightSectionIdx].getSaveState(); + -+ final SerializableChunkData.SectionData section = new SerializableChunkData.SectionData( -+ lightSection, chunkSection, -+ blockNibble == null ? null : (blockNibble.data == null ? null : new DataLayer(blockNibble.data)), -+ skyNibble == null ? null : (skyNibble.data == null ? null : new DataLayer(skyNibble.data)) -+ ); ++ if (chunkSection == null && blockNibble == null && skyNibble == null) { ++ continue; ++ } + -+ if (blockNibble != null) { -+ ((ca.spottedleaf.moonrise.patches.starlight.storage.StarlightSectionData)(Object)section).starlight$setBlockLightState(blockNibble.state); -+ } ++ final SerializableChunkData.SectionData section = new SerializableChunkData.SectionData( ++ lightSection, chunkSection, ++ blockNibble == null ? null : (blockNibble.data == null ? null : new DataLayer(blockNibble.data)), ++ skyNibble == null ? null : (skyNibble.data == null ? null : new DataLayer(skyNibble.data)) ++ ); + -+ if (skyNibble != null) { -+ ((ca.spottedleaf.moonrise.patches.starlight.storage.StarlightSectionData)(Object)section).starlight$setSkyLightState(skyNibble.state); -+ } ++ if (blockNibble != null) { ++ ((ca.spottedleaf.moonrise.patches.starlight.storage.StarlightSectionData)(Object)section).starlight$setBlockLightState(blockNibble.state); ++ } + -+ sectionData.add(section); ++ if (skyNibble != null) { ++ ((ca.spottedleaf.moonrise.patches.starlight.storage.StarlightSectionData)(Object)section).starlight$setSkyLightState(skyNibble.state); } -+ // Paper end - starlight ++ ++ sectionData.add(section); + } ++ // Paper end - starlight - List blockEntities = new ArrayList<>(chunk.getBlockEntitiesPos().size()); + List blockEntities = new ArrayList<>(chunk.getBlockEntitiesPos().size()); -@@ -487,6 +573,19 @@ public record SerializableChunkData( +@@ -485,6 +571,19 @@ public record SerializableChunkData( sectionTag.putByteArray("SkyLight", section.skyLight.getData()); } @@ -34344,7 +34328,7 @@ index 480623c30777fd230bf8428b16364db09806562b..1e0afa9590de7fe492cf29aded96be3d if (!sectionTag.isEmpty()) { sectionTag.putByte("Y", (byte)section.y); sectionTags.add(sectionTag); -@@ -521,6 +620,14 @@ public record SerializableChunkData( +@@ -519,6 +618,14 @@ public record SerializableChunkData( tag.put("ChunkBukkitValues", this.persistentDataContainer); } // CraftBukkit end @@ -34359,7 +34343,7 @@ index 480623c30777fd230bf8428b16364db09806562b..1e0afa9590de7fe492cf29aded96be3d return tag; } -@@ -668,6 +775,60 @@ public record SerializableChunkData( +@@ -666,6 +773,60 @@ public record SerializableChunkData( } } @@ -34422,7 +34406,7 @@ index 480623c30777fd230bf8428b16364db09806562b..1e0afa9590de7fe492cf29aded96be3d } } diff --git a/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java b/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java -index c5ac299e4a23d51a7777a678a0e1735bfb194f09..79ed9b6e8c6cb0029f25bb4b83a5d9e1bab13919 100644 +index ebb94d87e3b659e9049cbe5a3d5375274773fe57..4346f3bace176e09d9ffb02e9af29a1281071e2a 100644 --- a/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java +++ b/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java @@ -18,25 +18,39 @@ import net.minecraft.util.datafix.DataFixTypes; @@ -34529,7 +34513,7 @@ index c5ac299e4a23d51a7777a678a0e1735bfb194f09..79ed9b6e8c6cb0029f25bb4b83a5d9e1 } } diff --git a/net/minecraft/world/level/entity/EntityTickList.java b/net/minecraft/world/level/entity/EntityTickList.java -index b857b705d919c529f8ea62c3cece22fff9f832ae..a30409eddfaded878a3ac54bb526fd2e4b887c57 100644 +index 1fe402ed7e273063e32ed4d164c4098ee764703a..a30409eddfaded878a3ac54bb526fd2e4b887c57 100644 --- a/net/minecraft/world/level/entity/EntityTickList.java +++ b/net/minecraft/world/level/entity/EntityTickList.java @@ -9,51 +9,38 @@ import net.minecraft.world.entity.Entity; @@ -34576,24 +34560,22 @@ index b857b705d919c529f8ea62c3cece22fff9f832ae..a30409eddfaded878a3ac54bb526fd2e public void forEach(final Consumer output) { - if (this.iterated != null) { - throw new UnsupportedOperationException("Only one concurrent iteration supported"); -- } else { -- this.iterated = this.active; +- } +- +- this.iterated = this.active; - -- try { -- for (Entity entity : this.active.values()) { -- output.accept(entity); -- } -- } finally { -- this.iterated = null; + // Paper start - rewrite chunk system + // To ensure nothing weird happens with dimension travelling, do not iterate over new entries... + // (by dfl iterator() is configured to not iterate over new entries) + final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet.Iterator iterator = this.entities.iterator(); -+ try { + try { +- for (Entity entity : this.active.values()) { +- output.accept(entity); + while (iterator.hasNext()) { + output.accept(iterator.next()); } -+ } finally { + } finally { +- this.iterated = null; + iterator.finishedIterating(); } + // Paper end - rewrite chunk system @@ -34619,7 +34601,7 @@ index c31f66710036cb68500ed936b8a4b89a2cf57574..4d5e3cf76b64e57c22e2717ca395e23a public void move(final ServerLevel level) { diff --git a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java b/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java -index d74c887d2fdc39e09233eba47464868dfa846b64..39e9a1c39b5312aaa2ca6d2a1ffd8ed17b9933e6 100644 +index db190b3b2bcc386d6e01c9b8d694efe4ac5e54af..83bc0f6fa7624a0df546726fa8ccc9744173ff88 100644 --- a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java +++ b/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java @@ -87,7 +87,7 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator { @@ -34631,17 +34613,17 @@ index d74c887d2fdc39e09233eba47464868dfa846b64..39e9a1c39b5312aaa2ca6d2a1ffd8ed1 } private void doCreateBiomes(final Blender blender, final RandomState randomState, final StructureManager structureManager, final ChunkAccess protoChunk) { -@@ -376,7 +376,7 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator { +@@ -373,7 +373,7 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator { + section.release(); + } } - - return var20; - }, Util.backgroundExecutor().forName("wgen_fill_noise")); + }, Runnable::run); // Paper - rewrite chunk system } private ChunkAccess doFill( diff --git a/net/minecraft/world/level/levelgen/structure/StructureCheck.java b/net/minecraft/world/level/levelgen/structure/StructureCheck.java -index 469fb7695b46420b5817928b8f905c4df3aa9bfe..2ab055d5cdfb1e2e7cfb6f8a769c3d571acb2861 100644 +index d7d98399cddb2d78eda492ab177ad770e1e083a4..0d4c26d8a086e54f84413dab9595e210e52a43bf 100644 --- a/net/minecraft/world/level/levelgen/structure/StructureCheck.java +++ b/net/minecraft/world/level/levelgen/structure/StructureCheck.java @@ -50,8 +50,13 @@ public class StructureCheck { @@ -34668,23 +34650,23 @@ index 469fb7695b46420b5817928b8f905c4df3aa9bfe..2ab055d5cdfb1e2e7cfb6f8a769c3d57 + Object2IntMap cachedResult = this.loadedChunksSafe.get(posKey); // Paper - rewrite chunk system if (cachedResult != null) { return this.checkStructureInfo(cachedResult, structure, requireUnreferenced); - } else { -@@ -103,9 +108,11 @@ public class StructureCheck { - } else if (!placement.applyAdditionalChunkRestrictions(pos.x(), pos.z(), this.seed, this.getSaltOverride(structure))) { // Paper - add missing structure seed configs - return StructureCheckResult.START_NOT_PRESENT; - } else { -- boolean isFeatureChunk = this.featureChecks -- .computeIfAbsent(structure, k -> new Long2BooleanOpenHashMap()) -- .computeIfAbsent(posKey, k -> this.canCreateStructure(pos, structure)); -+ // Paper start - rewrite chunk system -+ boolean isFeatureChunk = this.featureChecksSafe -+ .computeIfAbsent(structure, structure1 -> new ca.spottedleaf.moonrise.common.map.SynchronisedLong2BooleanMap(PER_FEATURE_CHECK_LIMIT)) -+ .getOrCompute(posKey, l -> this.canCreateStructure(pos, structure)); -+ // Paper end - rewrite chunk system - return !isFeatureChunk ? StructureCheckResult.START_NOT_PRESENT : StructureCheckResult.CHUNK_LOAD_NEEDED; - } } -@@ -222,15 +229,25 @@ public class StructureCheck { +@@ -107,9 +112,11 @@ public class StructureCheck { + return StructureCheckResult.START_NOT_PRESENT; + } + +- boolean isFeatureChunk = this.featureChecks +- .computeIfAbsent(structure, k -> new Long2BooleanOpenHashMap()) +- .computeIfAbsent(posKey, k -> this.canCreateStructure(pos, structure)); ++ // Paper start - rewrite chunk system ++ boolean isFeatureChunk = this.featureChecksSafe ++ .computeIfAbsent(structure, structure1 -> new ca.spottedleaf.moonrise.common.map.SynchronisedLong2BooleanMap(PER_FEATURE_CHECK_LIMIT)) ++ .getOrCompute(posKey, l -> this.canCreateStructure(pos, structure)); ++ // Paper end - rewrite chunk system + return !isFeatureChunk ? StructureCheckResult.START_NOT_PRESENT : StructureCheckResult.CHUNK_LOAD_NEEDED; + } + +@@ -224,15 +231,25 @@ public class StructureCheck { } private void storeFullResults(final long posKey, final Object2IntMap starts) { @@ -34715,7 +34697,7 @@ index 469fb7695b46420b5817928b8f905c4df3aa9bfe..2ab055d5cdfb1e2e7cfb6f8a769c3d57 counts.computeInt(structure, (k, value) -> value == null ? 1 : value + 1); return counts; diff --git a/net/minecraft/world/level/lighting/LevelLightEngine.java b/net/minecraft/world/level/lighting/LevelLightEngine.java -index de10c0bb009fdbd6f24d1db5c9266270027e8863..c6825283ad1787fcf4bfb93b32ca8396ac44f503 100644 +index 64194984fa30038b5bd53140511faf2b5784ead5..c6825283ad1787fcf4bfb93b32ca8396ac44f503 100644 --- a/net/minecraft/world/level/lighting/LevelLightEngine.java +++ b/net/minecraft/world/level/lighting/LevelLightEngine.java @@ -9,149 +9,113 @@ import net.minecraft.world.level.chunk.DataLayer; @@ -34851,9 +34833,9 @@ index de10c0bb009fdbd6f24d1db5c9266270027e8863..c6825283ad1787fcf4bfb93b32ca8396 public LayerLightEventListener getLayerListener(final LightLayer layer) { - if (layer == LightLayer.BLOCK) { -- return (LayerLightEventListener)(this.blockEngine == null ? LayerLightEventListener.DummyLightLayerEventListener.INSTANCE : this.blockEngine); +- return this.blockEngine == null ? LayerLightEventListener.DummyLightLayerEventListener.INSTANCE : this.blockEngine; - } else { -- return (LayerLightEventListener)(this.skyEngine == null ? LayerLightEventListener.DummyLightLayerEventListener.INSTANCE : this.skyEngine); +- return this.skyEngine == null ? LayerLightEventListener.DummyLightLayerEventListener.INSTANCE : this.skyEngine; - } + return layer == LightLayer.BLOCK ? this.lightEngine.getBlockReader() : this.lightEngine.getSkyReader(); // Paper - rewrite chunk system } @@ -34921,10 +34903,10 @@ index de10c0bb009fdbd6f24d1db5c9266270027e8863..c6825283ad1787fcf4bfb93b32ca8396 public int getLightSectionCount() { diff --git a/net/minecraft/world/level/material/FlowingFluid.java b/net/minecraft/world/level/material/FlowingFluid.java -index 27aa4e640ee29d96a854846bb906c30ebf4854f6..d7270de83fa13618d8f94de6eff63ffa37b823cc 100644 +index ee960c0b1e7f510b77949db2a57a53357a00f62d..e93c900385994d391242def7d022d06e6ef23861 100644 --- a/net/minecraft/world/level/material/FlowingFluid.java +++ b/net/minecraft/world/level/material/FlowingFluid.java -@@ -47,6 +47,48 @@ public abstract class FlowingFluid extends Fluid { +@@ -46,6 +46,48 @@ public abstract class FlowingFluid extends Fluid { }); private final Map shapes = Maps.newIdentityHashMap(); @@ -34973,8 +34955,8 @@ index 27aa4e640ee29d96a854846bb906c30ebf4854f6..d7270de83fa13618d8f94de6eff63ffa @Override protected void createFluidStateDefinition(final StateDefinition.Builder builder) { builder.add(FALLING); -@@ -212,70 +254,70 @@ public abstract class FlowingFluid extends Fluid { - } +@@ -211,72 +253,70 @@ public abstract class FlowingFluid extends Fluid { + return amount <= 0 ? Fluids.EMPTY.defaultFluidState() : this.getFlowing(amount, false); } - private static boolean canPassThroughWall( @@ -34989,19 +34971,7 @@ index 27aa4e640ee29d96a854846bb906c30ebf4854f6..d7270de83fa13618d8f94de6eff63ffa - VoxelShape targetShape = targetState.getCollisionShape(level, targetPos); - if (targetShape == Shapes.block()) { - return false; -- } else { -- VoxelShape sourceShape = sourceState.getCollisionShape(level, sourcePos); -- if (sourceShape == Shapes.block()) { -- return false; -- } else if (sourceShape == Shapes.empty() && targetShape == Shapes.empty()) { -- return true; -- } else { -- Object2ByteLinkedOpenHashMap cache; -- if (!sourceState.getBlock().hasDynamicShape() && !targetState.getBlock().hasDynamicShape()) { -- cache = OCCLUSION_CACHE.get(); -- } else { -- cache = null; -- } +- } + // Paper start - fluid method optimisations + private static boolean canPassThroughWall(final Direction direction, final BlockGetter level, + final BlockPos fromPos, final BlockState fromState, @@ -35011,55 +34981,66 @@ index 27aa4e640ee29d96a854846bb906c30ebf4854f6..d7270de83fa13618d8f94de6eff63ffa + return true; + } -- FlowingFluid.BlockStatePairKey key; -- if (cache != null) { -- key = new FlowingFluid.BlockStatePairKey(sourceState, targetState, direction); -- byte cached = cache.getAndMoveToFirst(key); -- if (cached != 127) { -- return cached != 0; -- } -- } else { -- key = null; -- } +- VoxelShape sourceShape = sourceState.getCollisionShape(level, sourcePos); +- if (sourceShape == Shapes.block()) { +- return false; +- } + if (((ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState)fromState).moonrise$occludesFullBlock() | ((ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState)toState).moonrise$occludesFullBlock()) { + // don't even try to cache simple cases + return false; + } -- boolean result = !Shapes.mergedFaceOccludes(sourceShape, targetShape, direction); -- if (cache != null) { -- if (cache.size() == 200) { -- cache.removeLastByte(); -- } +- if (sourceShape == Shapes.empty() && targetShape == Shapes.empty()) { +- return true; +- } + final ca.spottedleaf.moonrise.patches.collisions.util.FluidOcclusionCacheKey[] cache = ((ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState)fromState).moonrise$hasCache() & ((ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState)toState).moonrise$hasCache() ? + COLLISION_OCCLUSION_CACHE.get() : null; -- cache.putAndMoveToFirst(key, (byte)(result ? 1 : 0)); -- } +- Object2ByteLinkedOpenHashMap cache; +- if (!sourceState.getBlock().hasDynamicShape() && !targetState.getBlock().hasDynamicShape()) { +- cache = OCCLUSION_CACHE.get(); +- } else { +- cache = null; +- } + final int keyIndex + = (((ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState)fromState).moonrise$uniqueId1() ^ ((ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState)toState).moonrise$uniqueId2() ^ ((ca.spottedleaf.moonrise.patches.collisions.util.CollisionDirection)(Object)direction).moonrise$uniqueId()) + & (COLLISION_OCCLUSION_CACHE_SIZE - 1); -- return result; +- FlowingFluid.BlockStatePairKey key; +- if (cache != null) { +- key = new FlowingFluid.BlockStatePairKey(sourceState, targetState, direction); +- byte cached = cache.getAndMoveToFirst(key); +- if (cached != 127) { +- return cached != 0; - } +- } else { +- key = null; + if (cache != null) { + final ca.spottedleaf.moonrise.patches.collisions.util.FluidOcclusionCacheKey cached = cache[keyIndex]; + if (cached != null && cached.first() == fromState && cached.second() == toState && cached.direction() == direction) { + return cached.result(); } -- } else { -- return false; - } -+ ++ } + +- boolean result = !Shapes.mergedFaceOccludes(sourceShape, targetShape, direction); +- if (cache != null) { +- if (cache.size() == 200) { +- cache.removeLastByte(); +- } + final VoxelShape shape1 = fromState.getCollisionShape(level, fromPos); + final VoxelShape shape2 = toState.getCollisionShape(level, toPos); -+ + +- cache.putAndMoveToFirst(key, (byte)(result ? 1 : 0)); +- } + final boolean result = !Shapes.mergedFaceOccludes(shape1, shape2, direction); -+ + +- return result; +- } else { +- return false; + if (cache != null) { + // we can afford to replace in-use keys more often due to the excessive caching the collision patch does in mergedFaceOccludes + cache[keyIndex] = new ca.spottedleaf.moonrise.patches.collisions.util.FluidOcclusionCacheKey(fromState, toState, direction, result); -+ } + } + + return result; } @@ -35184,7 +35165,7 @@ index 2e10d9d3850c18cf1bf625aac1dcacab1792e162..c835ae31a965b92780b7130a24c63ac2 public @Nullable ParticleOptions getDripParticle() { diff --git a/net/minecraft/world/level/portal/PortalForcer.java b/net/minecraft/world/level/portal/PortalForcer.java -index 08ac4ce3f34f2dc955ef2bfb2401f469f7a500a3..4e4903d38d705dca6ff16418e54a7a367074aa08 100644 +index 924a14caaef153a68afaced26b613d47f5fd5453..a468a1013058089115d023e8957f976ae34935ad 100644 --- a/net/minecraft/world/level/portal/PortalForcer.java +++ b/net/minecraft/world/level/portal/PortalForcer.java @@ -49,13 +49,46 @@ public class PortalForcer { @@ -35242,11 +35223,11 @@ index 08ac4ce3f34f2dc955ef2bfb2401f469f7a500a3..4e4903d38d705dca6ff16418e54a7a36 public Optional createPortal(final BlockPos origin, final Direction.Axis portalAxis) { diff --git a/net/minecraft/world/phys/AABB.java b/net/minecraft/world/phys/AABB.java -index 1a1b775b4675603a9f5d492d6c9977af2ebbb72c..259a19cbcf9a42c5f48e5d03448729283baf36a7 100644 +index 8a1524836e2573f879108b6708ca307fba756d3e..efb79617cebe7234d85721da7b7f1fd6ef1a6a73 100644 --- a/net/minecraft/world/phys/AABB.java +++ b/net/minecraft/world/phys/AABB.java @@ -319,7 +319,7 @@ public class AABB { - } + return new BlockHitResult(from.add(scale * dx, scale * dy, scale * dz), direction, pos, false); } - private static @Nullable Direction getDirection( @@ -35438,7 +35419,7 @@ index 73364066033aa722db0e8ab6c7e6cc0d93f7ecfd..f229a9247f9887dd8b01116f135e1db1 private boolean isZStripFull(final int startZ, final int endZ, final int x, final int y) { return x < this.xSize && y < this.ySize && this.storage.nextClearBit(this.getIndex(x, y, startZ)) >= this.getIndex(x, y, endZ); diff --git a/net/minecraft/world/phys/shapes/CubeVoxelShape.java b/net/minecraft/world/phys/shapes/CubeVoxelShape.java -index fa27f840cc9f17563701934cc504e40865e1670b..f6f2417ae6549802559e2307c293a1310ff1515f 100644 +index 77acd78861cceacd52cdcd3b5db94624b993d848..cdd7af6ed50567934763e666f9a7b0c82ffe1a1f 100644 --- a/net/minecraft/world/phys/shapes/CubeVoxelShape.java +++ b/net/minecraft/world/phys/shapes/CubeVoxelShape.java @@ -7,6 +7,7 @@ import net.minecraft.util.Mth; @@ -35450,7 +35431,7 @@ index fa27f840cc9f17563701934cc504e40865e1670b..f6f2417ae6549802559e2307c293a131 @Override diff --git a/net/minecraft/world/phys/shapes/DiscreteVoxelShape.java b/net/minecraft/world/phys/shapes/DiscreteVoxelShape.java -index 4631e6e8397676b30a7a9b04786e8abfdcc4549d..cdeff630372a998982f485424f0d3348f30c5291 100644 +index f5789f45091410beffc69d0de47d381c51c7fa85..34536dee9576d35e15145ccbadb81192fe1646c3 100644 --- a/net/minecraft/world/phys/shapes/DiscreteVoxelShape.java +++ b/net/minecraft/world/phys/shapes/DiscreteVoxelShape.java @@ -5,12 +5,79 @@ import net.minecraft.core.AxisCycle; @@ -35550,7 +35531,7 @@ index 66085f0e57fd2e2fae3967aab7f6835d23fced07..7c1e93123371d0d1b371243c132b54d4 public OffsetDoubleList(final DoubleList delegate, final double offset) { this.delegate = delegate; diff --git a/net/minecraft/world/phys/shapes/Shapes.java b/net/minecraft/world/phys/shapes/Shapes.java -index b9ed92ee991727efd0e8f9ed6cf302eb364788f2..de10ce3faa86d6ed6d528575a083722a8feedf8d 100644 +index 6978aa31d0901d8126cd9c19f8171275fe922584..ccdaf6043f667b6983e4492cf570947ed5179df1 100644 --- a/net/minecraft/world/phys/shapes/Shapes.java +++ b/net/minecraft/world/phys/shapes/Shapes.java @@ -21,9 +21,15 @@ public final class Shapes { @@ -35620,7 +35601,7 @@ index b9ed92ee991727efd0e8f9ed6cf302eb364788f2..de10ce3faa86d6ed6d528575a083722a public static VoxelShape box(final double minX, final double minY, final double minZ, final double maxX, final double maxY, final double maxZ) { if (!(minX > maxX) && !(minY > maxY) && !(minZ > maxZ)) { return create(minX, minY, minZ, maxX, maxY, maxZ); -@@ -58,39 +106,42 @@ public final class Shapes { +@@ -58,41 +106,42 @@ public final class Shapes { } public static VoxelShape create(final double minX, final double minY, final double minZ, final double maxX, final double maxY, final double maxZ) { @@ -35662,25 +35643,27 @@ index b9ed92ee991727efd0e8f9ed6cf302eb364788f2..de10ce3faa86d6ed6d528575a083722a + minY == 0.0 && maxY == 1.0 ? ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.ZERO_ONE : DoubleArrayList.wrap(new double[] { minY, maxY }), + minZ == 0.0 && maxZ == 1.0 ? ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.ZERO_ONE : DoubleArrayList.wrap(new double[] { minZ, maxZ }) ); -- } else if (xBits == 0 && yBits == 0 && zBits == 0) { -- return block(); -- } else { -- int xSize = 1 << xBits; -- int ySize = 1 << yBits; -- int zSize = 1 << zBits; -- BitSetDiscreteVoxelShape voxelShape = BitSetDiscreteVoxelShape.withFilledBounds( -- xSize, -- ySize, -- zSize, -- (int)Math.round(minX * xSize), -- (int)Math.round(minY * ySize), -- (int)Math.round(minZ * zSize), -- (int)Math.round(maxX * xSize), -- (int)Math.round(maxY * ySize), -- (int)Math.round(maxZ * zSize) -- ); -- return new CubeVoxelShape(voxelShape); } +- +- if (xBits == 0 && yBits == 0 && zBits == 0) { +- return block(); +- } +- +- int xSize = 1 << xBits; +- int ySize = 1 << yBits; +- int zSize = 1 << zBits; +- BitSetDiscreteVoxelShape voxelShape = BitSetDiscreteVoxelShape.withFilledBounds( +- xSize, +- ySize, +- zSize, +- (int)Math.round(minX * xSize), +- (int)Math.round(minY * ySize), +- (int)Math.round(minZ * zSize), +- (int)Math.round(maxX * xSize), +- (int)Math.round(maxY * ySize), +- (int)Math.round(maxZ * zSize) +- ); +- return new CubeVoxelShape(voxelShape); } else { - return empty(); + return EMPTY; @@ -35689,19 +35672,30 @@ index b9ed92ee991727efd0e8f9ed6cf302eb364788f2..de10ce3faa86d6ed6d528575a083722a } public static VoxelShape create(final AABB aabb) { -@@ -125,90 +176,54 @@ public final class Shapes { +@@ -127,92 +176,54 @@ public final class Shapes { return join(first, second, BooleanOp.OR); } - public static VoxelShape or(final VoxelShape first, final VoxelShape... tail) { - return Arrays.stream(tail).reduce(first, Shapes::or); +- } +- +- public static VoxelShape join(final VoxelShape first, final VoxelShape second, final BooleanOp op) { +- return joinUnoptimized(first, second, op).optimize(); +- } +- +- public static VoxelShape joinUnoptimized(final VoxelShape first, final VoxelShape second, final BooleanOp op) { +- if (op.apply(false, false)) { +- throw (IllegalArgumentException)Util.pauseInIde(new IllegalArgumentException()); + // Paper start - optimise collisions + public static VoxelShape or(final VoxelShape shape1, final VoxelShape... others) { + int size = others.length; + if (size == 0) { + return shape1; -+ } -+ + } + +- if (first == second) { +- return op.apply(true, true) ? first : empty(); + // reduce complexity of joins by splitting the merges + + // add extra slot for first shape @@ -35727,99 +35721,90 @@ index b9ed92ee991727efd0e8f9ed6cf302eb364788f2..de10ce3faa86d6ed6d528575a083722a + } + } + size = newSize; -+ } -+ + } + +- boolean firstOnlyMatters = op.apply(true, false); +- boolean secondOnlyMatters = op.apply(false, true); +- if (first.isEmpty()) { +- return secondOnlyMatters ? second : empty(); +- } + return tmp[0].optimize(); + // Paper end - optimise collisions - } ++ } - public static VoxelShape join(final VoxelShape first, final VoxelShape second, final BooleanOp op) { -- return joinUnoptimized(first, second, op).optimize(); +- if (second.isEmpty()) { +- return firstOnlyMatters ? first : empty(); +- } ++ public static VoxelShape join(final VoxelShape first, final VoxelShape second, final BooleanOp op) { + return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.joinOptimized(first, second, op); // Paper - optimise collisions - } ++ } - public static VoxelShape joinUnoptimized(final VoxelShape first, final VoxelShape second, final BooleanOp op) { -- if (op.apply(false, false)) { -- throw (IllegalArgumentException)Util.pauseInIde(new IllegalArgumentException()); -- } else if (first == second) { -- return op.apply(true, true) ? first : empty(); -- } else { -- boolean firstOnlyMatters = op.apply(true, false); -- boolean secondOnlyMatters = op.apply(false, true); -- if (first.isEmpty()) { -- return secondOnlyMatters ? second : empty(); -- } else if (second.isEmpty()) { -- return firstOnlyMatters ? first : empty(); -- } else { -- IndexMerger xMerger = createIndexMerger( -- 1, first.getCoords(Direction.Axis.X), second.getCoords(Direction.Axis.X), firstOnlyMatters, secondOnlyMatters -- ); -- IndexMerger yMerger = createIndexMerger( -- xMerger.size() - 1, first.getCoords(Direction.Axis.Y), second.getCoords(Direction.Axis.Y), firstOnlyMatters, secondOnlyMatters -- ); -- IndexMerger zMerger = createIndexMerger( -- (xMerger.size() - 1) * (yMerger.size() - 1), -- first.getCoords(Direction.Axis.Z), -- second.getCoords(Direction.Axis.Z), -- firstOnlyMatters, -- secondOnlyMatters -- ); -- BitSetDiscreteVoxelShape voxelShape = BitSetDiscreteVoxelShape.join(first.shape, second.shape, xMerger, yMerger, zMerger, op); -- return (VoxelShape)(xMerger instanceof DiscreteCubeMerger && yMerger instanceof DiscreteCubeMerger && zMerger instanceof DiscreteCubeMerger -- ? new CubeVoxelShape(voxelShape) -- : new ArrayVoxelShape(voxelShape, xMerger.getList(), yMerger.getList(), zMerger.getList())); -- } -- } +- IndexMerger xMerger = createIndexMerger(1, first.getCoords(Direction.Axis.X), second.getCoords(Direction.Axis.X), firstOnlyMatters, secondOnlyMatters); +- IndexMerger yMerger = createIndexMerger( +- xMerger.size() - 1, first.getCoords(Direction.Axis.Y), second.getCoords(Direction.Axis.Y), firstOnlyMatters, secondOnlyMatters +- ); +- IndexMerger zMerger = createIndexMerger( +- (xMerger.size() - 1) * (yMerger.size() - 1), +- first.getCoords(Direction.Axis.Z), +- second.getCoords(Direction.Axis.Z), +- firstOnlyMatters, +- secondOnlyMatters +- ); +- BitSetDiscreteVoxelShape voxelShape = BitSetDiscreteVoxelShape.join(first.shape, second.shape, xMerger, yMerger, zMerger, op); +- return xMerger instanceof DiscreteCubeMerger && yMerger instanceof DiscreteCubeMerger && zMerger instanceof DiscreteCubeMerger +- ? new CubeVoxelShape(voxelShape) +- : new ArrayVoxelShape(voxelShape, xMerger.getList(), yMerger.getList(), zMerger.getList()); ++ public static VoxelShape joinUnoptimized(final VoxelShape first, final VoxelShape second, final BooleanOp op) { + return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.joinUnoptimized(first, second, op); // Paper - optimise collisions } public static boolean joinIsNotEmpty(final VoxelShape first, final VoxelShape second, final BooleanOp op) { - if (op.apply(false, false)) { - throw (IllegalArgumentException)Util.pauseInIde(new IllegalArgumentException()); -- } else { -- boolean firstEmpty = first.isEmpty(); -- boolean secondEmpty = second.isEmpty(); -- if (!firstEmpty && !secondEmpty) { -- if (first == second) { -- return op.apply(true, true); -- } else { -- boolean firstOnlyMatters = op.apply(true, false); -- boolean secondOnlyMatters = op.apply(false, true); +- } - -- for (Direction.Axis axis : AxisCycle.AXIS_VALUES) { -- if (first.max(axis) < second.min(axis) - 1.0E-7) { -- return firstOnlyMatters || secondOnlyMatters; -- } +- boolean firstEmpty = first.isEmpty(); +- boolean secondEmpty = second.isEmpty(); +- if (!firstEmpty && !secondEmpty) { +- if (first == second) { +- return op.apply(true, true); +- } - -- if (second.max(axis) < first.min(axis) - 1.0E-7) { -- return firstOnlyMatters || secondOnlyMatters; -- } -- } +- boolean firstOnlyMatters = op.apply(true, false); +- boolean secondOnlyMatters = op.apply(false, true); - -- IndexMerger xMerger = createIndexMerger( -- 1, first.getCoords(Direction.Axis.X), second.getCoords(Direction.Axis.X), firstOnlyMatters, secondOnlyMatters -- ); -- IndexMerger yMerger = createIndexMerger( -- xMerger.size() - 1, first.getCoords(Direction.Axis.Y), second.getCoords(Direction.Axis.Y), firstOnlyMatters, secondOnlyMatters -- ); -- IndexMerger zMerger = createIndexMerger( -- (xMerger.size() - 1) * (yMerger.size() - 1), -- first.getCoords(Direction.Axis.Z), -- second.getCoords(Direction.Axis.Z), -- firstOnlyMatters, -- secondOnlyMatters -- ); -- return joinIsNotEmpty(xMerger, yMerger, zMerger, first.shape, second.shape, op); +- for (Direction.Axis axis : AxisCycle.AXIS_VALUES) { +- if (first.max(axis) < second.min(axis) - 1.0E-7) { +- return firstOnlyMatters || secondOnlyMatters; +- } +- +- if (second.max(axis) < first.min(axis) - 1.0E-7) { +- return firstOnlyMatters || secondOnlyMatters; - } -- } else { -- return op.apply(!firstEmpty, !secondEmpty); - } +- +- IndexMerger xMerger = createIndexMerger( +- 1, first.getCoords(Direction.Axis.X), second.getCoords(Direction.Axis.X), firstOnlyMatters, secondOnlyMatters +- ); +- IndexMerger yMerger = createIndexMerger( +- xMerger.size() - 1, first.getCoords(Direction.Axis.Y), second.getCoords(Direction.Axis.Y), firstOnlyMatters, secondOnlyMatters +- ); +- IndexMerger zMerger = createIndexMerger( +- (xMerger.size() - 1) * (yMerger.size() - 1), +- first.getCoords(Direction.Axis.Z), +- second.getCoords(Direction.Axis.Z), +- firstOnlyMatters, +- secondOnlyMatters +- ); +- return joinIsNotEmpty(xMerger, yMerger, zMerger, first.shape, second.shape, op); +- } else { +- return op.apply(!firstEmpty, !secondEmpty); - } + return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isJoinNonEmpty(first, second, op); // Paper - optimise collisions } private static boolean joinIsNotEmpty( -@@ -238,51 +253,93 @@ public final class Shapes { +@@ -242,53 +253,93 @@ public final class Shapes { return distance; } @@ -35829,37 +35814,23 @@ index b9ed92ee991727efd0e8f9ed6cf302eb364788f2..de10ce3faa86d6ed6d528575a083722a + public static boolean blockOccludes(final VoxelShape first, final VoxelShape second, final Direction direction) { + if (first == BLOCK & second == BLOCK) { return true; -- } else if (occluder.isEmpty()) { -+ } -+ + } + +- if (occluder.isEmpty()) { + if (first.isEmpty() | second.isEmpty()) { -+ return false; -+ } -+ -+ // we optimise getOpposite, so we can use it -+ // secondly, use our cache to retrieve sliced shape -+ final VoxelShape newFirst = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$getFaceShapeClamped(direction); -+ if (newFirst.isEmpty()) { return false; -- } else { -- Direction.Axis axis = direction.getAxis(); -- Direction.AxisDirection sign = direction.getAxisDirection(); -- VoxelShape first = sign == Direction.AxisDirection.POSITIVE ? shape : occluder; -- VoxelShape second = sign == Direction.AxisDirection.POSITIVE ? occluder : shape; -- BooleanOp op = sign == Direction.AxisDirection.POSITIVE ? BooleanOp.ONLY_FIRST : BooleanOp.ONLY_SECOND; -- return DoubleMath.fuzzyEquals(first.max(axis), 1.0, 1.0E-7) -- && DoubleMath.fuzzyEquals(second.min(axis), 0.0, 1.0E-7) -- && !joinIsNotEmpty(new SliceShape(first, axis, first.shape.getSize(axis) - 1), new SliceShape(second, axis, 0), op); } -+ final VoxelShape newSecond = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$getFaceShapeClamped(direction.getOpposite()); -+ if (newSecond.isEmpty()) { -+ return false; -+ } -+ -+ return !joinIsNotEmpty(newFirst, newSecond, BooleanOp.ONLY_FIRST); -+ // Paper end - optimise collisions - } +- Direction.Axis axis = direction.getAxis(); +- Direction.AxisDirection sign = direction.getAxisDirection(); +- VoxelShape first = sign == Direction.AxisDirection.POSITIVE ? shape : occluder; +- VoxelShape second = sign == Direction.AxisDirection.POSITIVE ? occluder : shape; +- BooleanOp op = sign == Direction.AxisDirection.POSITIVE ? BooleanOp.ONLY_FIRST : BooleanOp.ONLY_SECOND; +- return DoubleMath.fuzzyEquals(first.max(axis), 1.0, 1.0E-7) +- && DoubleMath.fuzzyEquals(second.min(axis), 0.0, 1.0E-7) +- && !joinIsNotEmpty(new SliceShape(first, axis, first.shape.getSize(axis) - 1), new SliceShape(second, axis, 0), op); +- } +- - public static boolean mergedFaceOccludes(final VoxelShape shape, final VoxelShape occluder, final Direction direction) { - if (shape != block() && occluder != block()) { - Direction.Axis axis = direction.getAxis(); @@ -35869,19 +35840,23 @@ index b9ed92ee991727efd0e8f9ed6cf302eb364788f2..de10ce3faa86d6ed6d528575a083722a - if (!DoubleMath.fuzzyEquals(first.max(axis), 1.0, 1.0E-7)) { - first = empty(); - } -+ // Paper start - optimise collisions -+ public static boolean mergedFaceOccludes(final VoxelShape first, final VoxelShape second, final Direction direction) { -+ // see if any of the shapes on their own occludes, only if cached -+ if (((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$occludesFullBlockIfCached() || ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$occludesFullBlockIfCached()) { -+ return true; ++ // we optimise getOpposite, so we can use it ++ // secondly, use our cache to retrieve sliced shape ++ final VoxelShape newFirst = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$getFaceShapeClamped(direction); ++ if (newFirst.isEmpty()) { ++ return false; ++ } ++ final VoxelShape newSecond = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$getFaceShapeClamped(direction.getOpposite()); ++ if (newSecond.isEmpty()) { ++ return false; + } - if (!DoubleMath.fuzzyEquals(second.min(axis), 0.0, 1.0E-7)) { - second = empty(); - } -+ if (first.isEmpty() & second.isEmpty()) { -+ return false; -+ } ++ return !joinIsNotEmpty(newFirst, newSecond, BooleanOp.ONLY_FIRST); ++ // Paper end - optimise collisions ++ } - return !joinIsNotEmpty( - block(), @@ -35889,6 +35864,17 @@ index b9ed92ee991727efd0e8f9ed6cf302eb364788f2..de10ce3faa86d6ed6d528575a083722a - BooleanOp.ONLY_FIRST - ); - } else { ++ // Paper start - optimise collisions ++ public static boolean mergedFaceOccludes(final VoxelShape first, final VoxelShape second, final Direction direction) { ++ // see if any of the shapes on their own occludes, only if cached ++ if (((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$occludesFullBlockIfCached() || ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)second).moonrise$occludesFullBlockIfCached()) { ++ return true; ++ } ++ ++ if (first.isEmpty() & second.isEmpty()) { ++ return false; ++ } ++ + // we optimise getOpposite, so we can use it + // secondly, use our cache to retrieve sliced shape + final VoxelShape newFirst = ((ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape)first).moonrise$getFaceShapeClamped(direction); @@ -35960,7 +35946,7 @@ index ec7834b53788f95ab7956c22bddfa38c4ee4e2f2..a612ace0b4e128c05196400b125a12a8 private static DiscreteVoxelShape makeSlice(final DiscreteVoxelShape delegate, final Direction.Axis axis, final int point) { diff --git a/net/minecraft/world/phys/shapes/VoxelShape.java b/net/minecraft/world/phys/shapes/VoxelShape.java -index 60a64339cd3b378f6f04cf5fe29a3ea8c18ec480..26619ecad88175cf76a62a5794aa58996968edb7 100644 +index 9b210edf1f28285fc206644c5d81c7d05ea5a578..ddc562fbdeb2070212019bb23962538795d05ff6 100644 --- a/net/minecraft/world/phys/shapes/VoxelShape.java +++ b/net/minecraft/world/phys/shapes/VoxelShape.java @@ -18,60 +18,545 @@ import net.minecraft.world.phys.Vec3; @@ -36458,11 +36444,11 @@ index 60a64339cd3b378f6f04cf5fe29a3ea8c18ec480..26619ecad88175cf76a62a5794aa5899 + // Paper start - optimise collisions + if (this.isEmpty) { + throw Util.pauseInIde(new UnsupportedOperationException("No bounds for empty shape.")); - } ++ } + AABB cached = this.cachedBounds; + if (cached != null) { + return cached; -+ } + } + + final ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData shapeData = this.cachedShapeData; + @@ -36542,14 +36528,14 @@ index 60a64339cd3b378f6f04cf5fe29a3ea8c18ec480..26619ecad88175cf76a62a5794aa5899 } public VoxelShape move(final double dx, final double dy, final double dz) { -- return (VoxelShape)(this.isEmpty() +- return this.isEmpty() - ? Shapes.empty() - : new ArrayVoxelShape( - this.shape, - new OffsetDoubleList(this.getCoords(Direction.Axis.X), dx), - new OffsetDoubleList(this.getCoords(Direction.Axis.Y), dy), - new OffsetDoubleList(this.getCoords(Direction.Axis.Z), dz) -- )); +- ); + // Paper start - optimise collisions + if (this.isEmpty) { + return Shapes.empty(); @@ -36712,27 +36698,24 @@ index 60a64339cd3b378f6f04cf5fe29a3ea8c18ec480..26619ecad88175cf76a62a5794aa5899 + // Paper start - optimise collisions + if (this.isEmpty) { return null; -- } else { -- Vec3 diff = to.subtract(from); -- if (diff.lengthSqr() < 1.0E-7) { -- return null; -- } else { -- Vec3 testPoint = from.add(diff.scale(0.001)); -- return this.shape -- .isFullWide( -- this.findIndex(Direction.Axis.X, testPoint.x - pos.getX()), -- this.findIndex(Direction.Axis.Y, testPoint.y - pos.getY()), -- this.findIndex(Direction.Axis.Z, testPoint.z - pos.getZ()) -- ) -- ? new BlockHitResult(testPoint, Direction.getApproximateNearest(diff.x, diff.y, diff.z).getOpposite(), pos, true) -- : AABB.clip(this.toAabbs(), from, to, pos); -+ } -+ + } + +- Vec3 diff = to.subtract(from); +- if (diff.lengthSqr() < 1.0E-7) { + final Vec3 directionOpposite = to.subtract(from); + if (directionOpposite.lengthSqr() < ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON) { -+ return null; -+ } -+ + return null; + } + +- Vec3 testPoint = from.add(diff.scale(0.001)); +- return this.shape +- .isFullWide( +- this.findIndex(Direction.Axis.X, testPoint.x - pos.getX()), +- this.findIndex(Direction.Axis.Y, testPoint.y - pos.getY()), +- this.findIndex(Direction.Axis.Z, testPoint.z - pos.getZ()) +- ) +- ? new BlockHitResult(testPoint, Direction.getApproximateNearest(diff.x, diff.y, diff.z).getOpposite(), pos, true) +- : AABB.clip(this.toAabbs(), from, to, pos); + final Vec3 fromBehind = from.add(directionOpposite.scale(0.001)); + final double fromBehindOffsetX = fromBehind.x - (double) pos.getX(); + final double fromBehindOffsetY = fromBehind.y - (double) pos.getY(); @@ -36742,13 +36725,13 @@ index 60a64339cd3b378f6f04cf5fe29a3ea8c18ec480..26619ecad88175cf76a62a5794aa5899 + if (singleAABB != null) { + if (singleAABB.contains(fromBehindOffsetX, fromBehindOffsetY, fromBehindOffsetZ)) { + return new BlockHitResult(fromBehind, Direction.getApproximateNearest(directionOpposite.x, directionOpposite.y, directionOpposite.z).getOpposite(), pos, true); - } ++ } + return clip(singleAABB, from, to, pos); + } + + if (ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.strictlyContains((VoxelShape) (Object) this, fromBehindOffsetX, fromBehindOffsetY, fromBehindOffsetZ)) { + return new BlockHitResult(fromBehind, Direction.getApproximateNearest(directionOpposite.x, directionOpposite.y, directionOpposite.z).getOpposite(), pos, true); - } ++ } + + return AABB.clip(((VoxelShape) (Object) this).toAabbs(), from, to, pos); + // Paper end - optimise collisions @@ -36759,20 +36742,16 @@ index 60a64339cd3b378f6f04cf5fe29a3ea8c18ec480..26619ecad88175cf76a62a5794aa5899 + // Paper start - optimise collisions + if (this.isEmpty) { return Optional.empty(); -- } else { -- MutableObject closest = new MutableObject<>(); -- this.forAllBoxes((x1, y1, z1, x2, y2, z2) -> { -- double x = Mth.clamp(point.x(), x1, x2); -- double y = Mth.clamp(point.y(), y1, y2); -- double z = Mth.clamp(point.z(), z1, z2); -- Vec3 currentClosest = closest.get(); -- if (currentClosest == null || point.distanceToSqr(x, y, z) < point.distanceToSqr(currentClosest)) { -- closest.setValue(new Vec3(x, y, z)); -- } -- }); -- return Optional.of(Objects.requireNonNull(closest.get())); } -+ + +- MutableObject closest = new MutableObject<>(); +- this.forAllBoxes((x1, y1, z1, x2, y2, z2) -> { +- double x = Mth.clamp(point.x(), x1, x2); +- double y = Mth.clamp(point.y(), y1, y2); +- double z = Mth.clamp(point.z(), z1, z2); +- Vec3 currentClosest = closest.get(); +- if (currentClosest == null || point.distanceToSqr(x, y, z) < point.distanceToSqr(currentClosest)) { +- closest.setValue(new Vec3(x, y, z)); + Vec3 ret = null; + double retDistance = Double.MAX_VALUE; + @@ -36787,7 +36766,9 @@ index 60a64339cd3b378f6f04cf5fe29a3ea8c18ec480..26619ecad88175cf76a62a5794aa5899 + if (dist < retDistance) { + ret = new Vec3(x, y, z); + retDistance = dist; -+ } + } +- }); +- return Optional.of(Objects.requireNonNull(closest.get())); + } + + return Optional.ofNullable(ret); @@ -36809,7 +36790,7 @@ index 60a64339cd3b378f6f04cf5fe29a3ea8c18ec480..26619ecad88175cf76a62a5794aa5899 - if (slice.isEmpty()) { - return Shapes.empty(); - } else { -- return (VoxelShape)(slice.isCubeLike() ? Shapes.block() : slice); +- return slice.isCubeLike() ? Shapes.block() : slice; + // Paper start - optimise collisions + final Direction.Axis axis = direction.getAxis(); + switch (axis) { @@ -36949,7 +36930,7 @@ index 082258e7d8270d4026a70a5c0a9e1228d70a2e8d..c3825e91504f5df6bfd8e41de1f5dc4a for (SavedTick pendingTick : this.pendingTicks) { diff --git a/net/minecraft/world/waypoints/WaypointTransmitter.java b/net/minecraft/world/waypoints/WaypointTransmitter.java -index d785e9a69a109d1d7ce7a7e182c215f3d6a35b64..d6f842cbd2060eb56a1e4384b3ea97feea3e73ba 100644 +index e822b8429e8ea2b113ef83310223bc7edb12aad9..2866b750a28cc32c2913d3c1afee95f05956982c 100644 --- a/net/minecraft/world/waypoints/WaypointTransmitter.java +++ b/net/minecraft/world/waypoints/WaypointTransmitter.java @@ -34,7 +34,10 @@ public interface WaypointTransmitter extends Waypoint { diff --git a/paper-server/patches/features/0002-Rewrite-dataconverter-system.patch b/paper-server/patches/features/0002-Rewrite-dataconverter-system.patch index 603941224410..9d8dd84ddc02 100644 --- a/paper-server/patches/features/0002-Rewrite-dataconverter-system.patch +++ b/paper-server/patches/features/0002-Rewrite-dataconverter-system.patch @@ -33491,7 +33491,7 @@ index 109d7b563ee799d998a5773c5a36e61ca3607d46..747755082639436731989d3ee4b3c30a return structureTemplate.save(new CompoundTag()); } diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index e11862c7e0617acfb36212cfe349bdade3a5164b..7ae2d491a3b2f379df99ccc649b8bb8cbf2304b9 100644 +index 5bdb7d130cc2e47c9b55f85acae64e83d6ee2546..c3b14d51240b5f6edfc3ecdea04f50774615b98c 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -299,6 +299,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop serverReference.get().runServer(), "Server thread"); thread.setUncaughtExceptionHandler((t, e) -> LOGGER.error("Uncaught exception in server thread", e)); diff --git a/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java b/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java -index c206c74acc80c281d06a669eb668239dc61018eb..884fa9545a93008fa92863c845aef8f18d88e25a 100644 +index 4346f3bace176e09d9ffb02e9af29a1281071e2a..df4f03f3a346e0ab0074757b3a077b2407135ac3 100644 --- a/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java +++ b/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java -@@ -99,7 +99,7 @@ public class SimpleRegionStorage implements ca.spottedleaf.moonrise.patches.chun - } - // Spigot end - injectDatafixingContext(chunkTag, dataFixContextTag); -- chunkTag = this.dataFixType.update(this.fixerUpper, chunkTag, version, targetVersion); -+ chunkTag = ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(this.getDataConverterType(), chunkTag, version, targetVersion); // Paper - rewrite dataconverter system - // Spigot start - if (stopBelowZero) { - chunkTag.putString("Status", net.minecraft.core.registries.BuiltInRegistries.CHUNK_STATUS.getKey(net.minecraft.world.level.chunk.status.ChunkStatus.SPAWN).toString()); +@@ -100,7 +100,7 @@ public class SimpleRegionStorage implements ca.spottedleaf.moonrise.patches.chun + } + // Spigot end + injectDatafixingContext(chunkTag, dataFixContextTag); +- chunkTag = this.dataFixType.update(this.fixerUpper, chunkTag, version, targetVersion); ++ chunkTag = ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(this.getDataConverterType(), chunkTag, version, targetVersion); // Paper - rewrite dataconverter system + // Spigot start + if (stopBelowZero) { + chunkTag.putString("Status", net.minecraft.core.registries.BuiltInRegistries.CHUNK_STATUS.getKey(net.minecraft.world.level.chunk.status.ChunkStatus.SPAWN).toString()); @@ -118,6 +118,20 @@ public class SimpleRegionStorage implements ca.spottedleaf.moonrise.patches.chun } } @@ -33537,23 +33537,23 @@ index c206c74acc80c281d06a669eb668239dc61018eb..884fa9545a93008fa92863c845aef8f1 return this.upgradeChunkTag(chunkTag, defaultVersion, null, SharedConstants.getCurrentVersion().dataVersion().version()); } diff --git a/net/minecraft/world/level/levelgen/structure/StructureCheck.java b/net/minecraft/world/level/levelgen/structure/StructureCheck.java -index 2ab055d5cdfb1e2e7cfb6f8a769c3d571acb2861..a45da98735045d55d3da14271c9bbb7a37f3151c 100644 +index 0d4c26d8a086e54f84413dab9595e210e52a43bf..a725a769f865e9f4506394b2fe57f560837720df 100644 --- a/net/minecraft/world/level/levelgen/structure/StructureCheck.java +++ b/net/minecraft/world/level/levelgen/structure/StructureCheck.java -@@ -161,7 +161,7 @@ public class StructureCheck { +@@ -163,7 +163,7 @@ public class StructureCheck { CompoundTag fixedChunkTag; try { - fixedChunkTag = DataFixTypes.CHUNK.updateToCurrentVersion(this.fixerUpper, chunkTag, version); -+ fixedChunkTag = ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.CHUNK, chunkTag, version, ca.spottedleaf.dataconverter.minecraft.util.Version.getCurrentVersion()); // Paper - replace chunk converter - } catch (Exception var12) { - LOGGER.warn("Failed to partially datafix chunk {}", pos, var12); ++ fixedChunkTag = ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.CHUNK, chunkTag, version, ca.spottedleaf.dataconverter.minecraft.util.Version.getCurrentVersion()); // Paper - replace chunk converter + } catch (Exception e) { + LOGGER.warn("Failed to partially datafix chunk {}", pos, e); return StructureCheckResult.CHUNK_LOAD_NEEDED; diff --git a/net/minecraft/world/level/levelgen/structure/templatesystem/loader/TemplateSource.java b/net/minecraft/world/level/levelgen/structure/templatesystem/loader/TemplateSource.java -index 780a3eb08b7fb2c385c8e75e2e5f02a9d67297f4..2c7e4a6288f0c7101755de4be8f14449cdc4e01e 100644 +index e61076a9ff3d9bce5c44e548158716db105db3ee..fe1500ebbfb09bef18989c891a19608ec9d4661c 100644 --- a/net/minecraft/world/level/levelgen/structure/templatesystem/loader/TemplateSource.java +++ b/net/minecraft/world/level/levelgen/structure/templatesystem/loader/TemplateSource.java -@@ -79,7 +79,7 @@ public abstract class TemplateSource { +@@ -71,7 +71,7 @@ public abstract class TemplateSource { public StructureTemplate readStructure(final CompoundTag tag) { StructureTemplate structureTemplate = new StructureTemplate(); int version = NbtUtils.getDataVersion(tag, 500); @@ -33563,7 +33563,7 @@ index 780a3eb08b7fb2c385c8e75e2e5f02a9d67297f4..2c7e4a6288f0c7101755de4be8f14449 } } diff --git a/net/minecraft/world/level/storage/PlayerDataStorage.java b/net/minecraft/world/level/storage/PlayerDataStorage.java -index 41cbb27861f33ad8d7523f3b2fef9a30a69693a9..c5898bfb8b4f075b08090cba2e9f980174e0a326 100644 +index 8eda63e1f07f7998875713447c5f39eea3f85ca4..eddb6ebe3fa50a818e54079b73ba117be0abd195 100644 --- a/net/minecraft/world/level/storage/PlayerDataStorage.java +++ b/net/minecraft/world/level/storage/PlayerDataStorage.java @@ -98,7 +98,7 @@ public class PlayerDataStorage { diff --git a/paper-server/patches/features/0003-Optimize-Connection-and-add-advanced-packet-support.patch b/paper-server/patches/features/0003-Optimize-Connection-and-add-advanced-packet-support.patch index 93dd0dcfb222..224216985f3e 100644 --- a/paper-server/patches/features/0003-Optimize-Connection-and-add-advanced-packet-support.patch +++ b/paper-server/patches/features/0003-Optimize-Connection-and-add-advanced-packet-support.patch @@ -28,10 +28,10 @@ and then catch exceptions and close if they fire. Part of this commit was authored by: Spottedleaf, sandtechnology diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java -index 1511cbd2e6123a00d22694353ee4989d539fe0f0..104976b3eb04d80e5be5bd020cf16c647b1cde27 100644 +index 13faa13a9d3120cdeaca63d6eb3a0feb8019fb3a..d14aea970ce98edfe3dc3692e707334e7e150804 100644 --- a/net/minecraft/network/Connection.java +++ b/net/minecraft/network/Connection.java -@@ -65,7 +65,7 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -64,7 +64,7 @@ public class Connection extends SimpleChannelInboundHandler> { private static final ProtocolInfo INITIAL_PROTOCOL = HandshakeProtocols.SERVERBOUND; private final PacketFlow receiving; private volatile boolean sendLoginDisconnect = true; @@ -40,7 +40,7 @@ index 1511cbd2e6123a00d22694353ee4989d539fe0f0..104976b3eb04d80e5be5bd020cf16c64 public Channel channel; public SocketAddress address; // Spigot start -@@ -124,6 +124,10 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -123,6 +123,10 @@ public class Connection extends SimpleChannelInboundHandler> { public boolean handledLegacyLoginEvent; // Paper - playerloginevent public net.minecraft.server.level.@Nullable ServerPlayer savedPlayerForLegacyEvents; // Paper - playerloginevent & PlayerSpawnLocationEvent public org.bukkit.event.player.PlayerResourcePackStatusEvent.@Nullable Status resourcePackStatus; // Paper @@ -51,7 +51,7 @@ index 1511cbd2e6123a00d22694353ee4989d539fe0f0..104976b3eb04d80e5be5bd020cf16c64 public Connection(final PacketFlow receiving) { this.receiving = receiving; -@@ -394,11 +398,38 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -392,11 +396,38 @@ public class Connection extends SimpleChannelInboundHandler> { } public void send(final Packet packet, final @Nullable ChannelFutureListener listener, final boolean flush) { @@ -93,7 +93,7 @@ index 1511cbd2e6123a00d22694353ee4989d539fe0f0..104976b3eb04d80e5be5bd020cf16c64 } } -@@ -407,7 +438,7 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -405,7 +436,7 @@ public class Connection extends SimpleChannelInboundHandler> { this.flushQueue(); action.accept(this); } else { @@ -102,7 +102,7 @@ index 1511cbd2e6123a00d22694353ee4989d539fe0f0..104976b3eb04d80e5be5bd020cf16c64 } } -@@ -421,21 +452,42 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -419,21 +450,42 @@ public class Connection extends SimpleChannelInboundHandler> { } private void doSendPacket(final Packet packet, final @Nullable ChannelFutureListener listener, final boolean flush) { @@ -149,7 +149,7 @@ index 1511cbd2e6123a00d22694353ee4989d539fe0f0..104976b3eb04d80e5be5bd020cf16c64 } } -@@ -447,16 +499,57 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -445,16 +497,57 @@ public class Connection extends SimpleChannelInboundHandler> { } } @@ -212,7 +212,7 @@ index 1511cbd2e6123a00d22694353ee4989d539fe0f0..104976b3eb04d80e5be5bd020cf16c64 private static final int MAX_PER_TICK = io.papermc.paper.configuration.GlobalConfiguration.get().misc.maxJoinsPerTick; // Paper - Buffer joins to world private static int joinAttemptsThisTick; // Paper - Buffer joins to world -@@ -526,6 +619,7 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -524,6 +617,7 @@ public class Connection extends SimpleChannelInboundHandler> { public void disconnect(final DisconnectionDetails details) { this.preparing = false; // Spigot @@ -220,7 +220,7 @@ index 1511cbd2e6123a00d22694353ee4989d539fe0f0..104976b3eb04d80e5be5bd020cf16c64 if (this.channel == null) { this.delayedDisconnect = details; } -@@ -715,7 +809,7 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -705,7 +799,7 @@ public class Connection extends SimpleChannelInboundHandler> { public void handleDisconnection() { if (this.channel != null && !this.channel.isOpen()) { if (this.disconnectionHandled) { @@ -229,7 +229,7 @@ index 1511cbd2e6123a00d22694353ee4989d539fe0f0..104976b3eb04d80e5be5bd020cf16c64 } else { this.disconnectionHandled = true; PacketListener packetListener = this.getPacketListener(); -@@ -726,7 +820,7 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -716,7 +810,7 @@ public class Connection extends SimpleChannelInboundHandler> { ); disconnectListener.onDisconnect(details); } @@ -238,7 +238,7 @@ index 1511cbd2e6123a00d22694353ee4989d539fe0f0..104976b3eb04d80e5be5bd020cf16c64 // Paper start - Add PlayerConnectionCloseEvent if (packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl commonPacketListener) { /* Player was logged in, either game listener or configuration listener */ -@@ -761,4 +855,96 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -751,4 +845,96 @@ public class Connection extends SimpleChannelInboundHandler> { public void setBandwidthLogger(final LocalSampleLogger bandwidthLogger) { this.bandwidthDebugMonitor = new BandwidthDebugMonitor(bandwidthLogger); } @@ -372,10 +372,10 @@ index 1480d0db90f5797e3dee19503e52d1e783493ac3..bd76e55ea56dd7c1e232806d1d13a747 + // Paper end } diff --git a/net/minecraft/server/network/ServerConnectionListener.java b/net/minecraft/server/network/ServerConnectionListener.java -index 387ac8a4e67ef07df73ce98d0add0937314ee497..9ae7c79e5088d9e1e3fb7e0dca00bb15fee118b6 100644 +index 77e1c02b74c1f6597fbb5a457bf463fe52de019e..6d506004583b2415ab356e34e2f8d6ac0e39cca2 100644 --- a/net/minecraft/server/network/ServerConnectionListener.java +++ b/net/minecraft/server/network/ServerConnectionListener.java -@@ -52,11 +52,13 @@ public class ServerConnectionListener { +@@ -51,11 +51,13 @@ public class ServerConnectionListener { // Paper start - prevent blocking on adding a new connection while the server is ticking private final java.util.Queue pending = new java.util.concurrent.ConcurrentLinkedQueue<>(); @@ -389,7 +389,7 @@ index 387ac8a4e67ef07df73ce98d0add0937314ee497..9ae7c79e5088d9e1e3fb7e0dca00bb15 } } // Paper end - prevent blocking on adding a new connection while the server is ticking -@@ -92,6 +94,7 @@ public class ServerConnectionListener { +@@ -87,6 +89,7 @@ public class ServerConnectionListener { } catch (ChannelException var5) { } diff --git a/paper-server/patches/features/0004-Allow-Saving-of-Oversized-Chunks.patch b/paper-server/patches/features/0004-Allow-Saving-of-Oversized-Chunks.patch index 2aea52bcb239..c54d9031b901 100644 --- a/paper-server/patches/features/0004-Allow-Saving-of-Oversized-Chunks.patch +++ b/paper-server/patches/features/0004-Allow-Saving-of-Oversized-Chunks.patch @@ -31,18 +31,18 @@ this fix, as the data will remain in the oversized file. Once the server returns to a jar with this fix, the data will be restored. diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java -index 5149635679ec03d881e63effbd79fc193d7e52c8..d628e06a8dbf11b491b323c10a512fde22e72a12 100644 +index 026b1f31d5041786e90ba372a228732aee094c16..dd05d166a3f995e40a16c11c8cfbf86776157fa4 100644 --- a/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/net/minecraft/world/level/chunk/storage/RegionFile.java -@@ -69,6 +69,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche +@@ -68,6 +68,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche this.info = info; this.path = path; this.version = version; + this.initOversizedState(); // Paper if (!Files.isDirectory(externalFileDir)) { throw new IllegalArgumentException("Expected directory, got " + externalFileDir.toAbsolutePath()); - } else { -@@ -465,4 +466,75 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche + } +@@ -463,4 +464,75 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche private interface CommitOp { void run() throws IOException; } @@ -119,7 +119,7 @@ index 5149635679ec03d881e63effbd79fc193d7e52c8..d628e06a8dbf11b491b323c10a512fde + // Paper end } diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index e9316cc08fe4cb4af28583a8cb1ec658243bffd0..aa36e241d49725eb13f00e57d020d4da24add53d 100644 +index 694689c5e0ca65b1b8724b689f3817753dd74834..54e6c67ca05ef1f1350873196dede122f5c911c5 100644 --- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java @@ -241,6 +241,43 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise @@ -177,9 +177,9 @@ index e9316cc08fe4cb4af28583a8cb1ec658243bffd0..aa36e241d49725eb13f00e57d020d4da + } + // Paper end - CompoundTag var4; try (DataInputStream regionChunkInputStream = region.getChunkDataInputStream(pos)) { -@@ -290,6 +333,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise + return regionChunkInputStream == null ? null : NbtIo.read(regionChunkInputStream); +@@ -283,6 +326,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise } else { try (DataOutputStream output = region.getChunkDataOutputStream(pos)) { NbtIo.write(value, output); diff --git a/paper-server/patches/features/0005-Entity-Activation-Range-2.0.patch b/paper-server/patches/features/0005-Entity-Activation-Range-2.0.patch index 84c65b9c31ec..565f83bbc7d2 100644 --- a/paper-server/patches/features/0005-Entity-Activation-Range-2.0.patch +++ b/paper-server/patches/features/0005-Entity-Activation-Range-2.0.patch @@ -354,7 +354,7 @@ index 0000000000000000000000000000000000000000..ce6b57eeeeb1bd652f4bb53c19dcfbc0 + } +} diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 91d27b90a9c9c348d3f93624ff8dbff8a70f522c..f4bbccee849ee3711a3b838884e4bcf4e24da039 100644 +index 89da20b0682708ba8bfc0d10381eb9784d80c395..b5d63d7b848c11ed322d512adeee102886cbb6fd 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java @@ -864,6 +864,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet @@ -462,7 +462,7 @@ index 0df8332933203a904bd9ef9efb3c9bce21e65441..1a502cbd8acea9420fa6dd8d716018b5 public void tick() { super.tick(); diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index e087d5596979044fe7fbcf7f2cccdae4e81a3d3a..fea6c3b48c4eb162fbdc099fa775bc3161a4dd4e 100644 +index 593265d78564b60bacbb4899f18a6e74bf56601d..84c664711658eb83b5ff9d4c8470fd8ec54a5473 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -382,6 +382,15 @@ public abstract class Entity @@ -521,10 +521,10 @@ index e087d5596979044fe7fbcf7f2cccdae4e81a3d3a..fea6c3b48c4eb162fbdc099fa775bc31 delta = this.maybeBackOffFromEdge(delta, moverType); Vec3 movement = this.collide(delta); diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java -index 8b0abe9c7a3907419f6e4d55ea22fb9bc749f28b..36c0081e3e8f8776293ae619156cd0828fe5b21d 100644 +index f62e535b62d249dd3be19d7c1b02fae8dad31c10..6eb95b979ffe37d78fd68eb57ebe71891beb0d28 100644 --- a/net/minecraft/world/entity/LivingEntity.java +++ b/net/minecraft/world/entity/LivingEntity.java -@@ -3372,6 +3372,14 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin +@@ -3380,6 +3380,14 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin protected void playAttackSound() { } @@ -540,7 +540,7 @@ index 8b0abe9c7a3907419f6e4d55ea22fb9bc749f28b..36c0081e3e8f8776293ae619156cd082 public void tick() { super.tick(); diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java -index c7c53ef16e104ebc48aeb8719783fb4c45d39fc2..5bbb5cbb51953399c7bce547cd6968eb3c6bd130 100644 +index e63ac861b785cf3dccac25404454289c44b7ec9d..8b036640be655c65852e0862e30962e443d3024d 100644 --- a/net/minecraft/world/entity/Mob.java +++ b/net/minecraft/world/entity/Mob.java @@ -211,6 +211,20 @@ public abstract class Mob extends LivingEntity implements Targeting, EquipmentUs @@ -565,7 +565,7 @@ index c7c53ef16e104ebc48aeb8719783fb4c45d39fc2..5bbb5cbb51953399c7bce547cd6968eb return this.getControlledVehicle() instanceof Mob riding ? riding.getMoveControl() : this.moveControl; } diff --git a/net/minecraft/world/entity/PathfinderMob.java b/net/minecraft/world/entity/PathfinderMob.java -index c4b4a135f61955c2b87801772a2b31eeeb77bf45..9d12cc2d169f243ba23485e2782bca7064282a36 100644 +index a19d8d4c0075340e8d187d5f8b6ce989567d3163..c661311dfdc1e21e3d6ec65e1e8b953637149675 100644 --- a/net/minecraft/world/entity/PathfinderMob.java +++ b/net/minecraft/world/entity/PathfinderMob.java @@ -17,6 +17,8 @@ public abstract class PathfinderMob extends Mob { @@ -578,7 +578,7 @@ index c4b4a135f61955c2b87801772a2b31eeeb77bf45..9d12cc2d169f243ba23485e2782bca70 return this.getWalkTargetValue(pos, this.level()); } diff --git a/net/minecraft/world/entity/ai/goal/GoalSelector.java b/net/minecraft/world/entity/ai/goal/GoalSelector.java -index 6bc2d38fb990628784deb5ee615e34a0fc320a47..844ced7a271ffb557f3c8f2fcd6a4c6ad499aeae 100644 +index c918154444a05917a3622947d0ddbc29bdb9bead..b13bdc2852504903fa054c42f89299a5d33dfbd3 100644 --- a/net/minecraft/world/entity/ai/goal/GoalSelector.java +++ b/net/minecraft/world/entity/ai/goal/GoalSelector.java @@ -24,6 +24,7 @@ public class GoalSelector { @@ -640,7 +640,7 @@ index d46e0e3a4a7fc3bb3f1dd695d4cc563778b99db0..c6e9b155c2341c13d569f28f54f0c1d2 } } diff --git a/net/minecraft/world/entity/item/ItemEntity.java b/net/minecraft/world/entity/item/ItemEntity.java -index c482c3348267ca2b88109e34291aa860e0cde916..b11b59d80e37d272770ab51a63028fdddfe800d6 100644 +index ca0b7ce4ab535d7112b315a7de1dc5130797ea2d..974d1d7b283aace71f0ea8ef07ba68a17b75af8a 100644 --- a/net/minecraft/world/entity/item/ItemEntity.java +++ b/net/minecraft/world/entity/item/ItemEntity.java @@ -124,6 +124,29 @@ public class ItemEntity extends Entity implements TraceableEntity { @@ -674,7 +674,7 @@ index c482c3348267ca2b88109e34291aa860e0cde916..b11b59d80e37d272770ab51a63028fdd public void tick() { if (this.getItem().isEmpty()) { diff --git a/net/minecraft/world/entity/npc/villager/Villager.java b/net/minecraft/world/entity/npc/villager/Villager.java -index a80e6a23cf29cb44943339101f15565dbc19af1f..26108ac0543c7b4195f149c07d8348b5b15b8bdb 100644 +index 084a4a945d4fc6a76878da00e5015c79fc88b47f..e4ba6e200e85f4e226d6a3e68db734f277b89226 100644 --- a/net/minecraft/world/entity/npc/villager/Villager.java +++ b/net/minecraft/world/entity/npc/villager/Villager.java @@ -244,11 +244,35 @@ public class Villager extends AbstractVillager implements VillagerDataHolder, Re @@ -779,7 +779,7 @@ index f3861c936855a0d9c9170585f4da4ce1cd77b854..3b4cbbc4c8ca1cd3110d1d6ba9e35312 public void tick() { super.tick(); diff --git a/net/minecraft/world/entity/vehicle/minecart/MinecartHopper.java b/net/minecraft/world/entity/vehicle/minecart/MinecartHopper.java -index 3a590d4dc980a2912e9cc043d8c8db4cf9d60803..06ab7c48b18c03af494ab10fc2b584cefc776749 100644 +index f46cca0467bb4da5511bc953ce5b43fa606bf978..445c5cafad71028171c1f261939661775dd7f2bd 100644 --- a/net/minecraft/world/entity/vehicle/minecart/MinecartHopper.java +++ b/net/minecraft/world/entity/vehicle/minecart/MinecartHopper.java @@ -50,6 +50,7 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper @@ -790,20 +790,21 @@ index 3a590d4dc980a2912e9cc043d8c8db4cf9d60803..06ab7c48b18c03af494ab10fc2b584ce } public boolean isEnabled() { -@@ -103,11 +104,13 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper +@@ -103,12 +104,14 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper public boolean suckInItems() { if (HopperBlockEntity.suckInItems(this.level(), this)) { + this.immunize(); // Paper return true; - } else { - for (ItemEntity entity : this.level() - .getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(0.25, 0.0, 0.25), EntitySelector.ENTITY_STILL_ALIVE)) { - if (HopperBlockEntity.addItem(this, entity)) { -+ this.immunize(); // Paper - return true; - } + } + + for (ItemEntity entity : this.level() + .getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(0.25, 0.0, 0.25), EntitySelector.ENTITY_STILL_ALIVE)) { + if (HopperBlockEntity.addItem(this, entity)) { ++ this.immunize(); // Paper + return true; } + } @@ -142,4 +145,11 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper public AbstractContainerMenu createMenu(final int containerId, final Inventory inventory) { return new HopperMenu(containerId, inventory, this); @@ -817,7 +818,7 @@ index 3a590d4dc980a2912e9cc043d8c8db4cf9d60803..06ab7c48b18c03af494ab10fc2b584ce + } diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index c0f901c4ac61a0aa2b480f102feb3669b111f4c0..07c301ba02c7f2c032a29a0ae3bdf95fc522c03b 100644 +index cc492445307ddc08446484d272866f01646cf7b3..a5d46832d4f8a13b0bf67b523c21d5c3b44209a9 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java @@ -155,6 +155,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl @@ -834,7 +835,7 @@ index c0f901c4ac61a0aa2b480f102feb3669b111f4c0..07c301ba02c7f2c032a29a0ae3bdf95f public final org.spigotmc.SpigotWorldConfig spigotConfig; // Spigot // Paper start - add paper world config diff --git a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java -index ec01093094f1d4de2708791ae6a5545268a021ae..f904c587fafe7395473450f766354d874e36ebac 100644 +index ef78f286ca14512c3dfccdb8fb06ebe9affa1589..c5c0b01c41055a82e49c1546d4525da0acce13a4 100644 --- a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java +++ b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java @@ -159,6 +159,10 @@ public class PistonMovingBlockEntity extends BlockEntity { diff --git a/paper-server/patches/features/0006-Optimize-Voxel-Shape-Merging.patch b/paper-server/patches/features/0006-Optimize-Voxel-Shape-Merging.patch index 29e36520b431..c927369ad44c 100644 --- a/paper-server/patches/features/0006-Optimize-Voxel-Shape-Merging.patch +++ b/paper-server/patches/features/0006-Optimize-Voxel-Shape-Merging.patch @@ -30,7 +30,7 @@ Additionally, this lets us avoid even allocating new objects for this too, furth reducing memory usage. diff --git a/net/minecraft/world/phys/shapes/IndirectMerger.java b/net/minecraft/world/phys/shapes/IndirectMerger.java -index 7e525297aaca8c18cf1669ab80040475029ff652..b342e4c0260fc5a64e5943e6342de0703233a99b 100644 +index 6c637af546a411d5790ceba9936aa9128d05d97e..e18f24a3941e1102648bac841851a8749f2d9438 100644 --- a/net/minecraft/world/phys/shapes/IndirectMerger.java +++ b/net/minecraft/world/phys/shapes/IndirectMerger.java @@ -10,12 +10,32 @@ public class IndirectMerger implements IndexMerger { @@ -67,7 +67,7 @@ index 7e525297aaca8c18cf1669ab80040475029ff652..b342e4c0260fc5a64e5943e6342de070 this.firstIndices = new int[capacity]; this.secondIndices = new int[capacity]; diff --git a/net/minecraft/world/phys/shapes/Shapes.java b/net/minecraft/world/phys/shapes/Shapes.java -index de10ce3faa86d6ed6d528575a083722a8feedf8d..7574443bc098c1a0958b64f1f54e76322e48a2e7 100644 +index ccdaf6043f667b6983e4492cf570947ed5179df1..5c552f618d09fa9456195bbfa643ce4a1a03bd84 100644 --- a/net/minecraft/world/phys/shapes/Shapes.java +++ b/net/minecraft/world/phys/shapes/Shapes.java @@ -343,11 +343,26 @@ public final class Shapes { @@ -117,9 +117,9 @@ index de10ce3faa86d6ed6d528575a083722a8feedf8d..7574443bc098c1a0958b64f1f54e7632 } else if (second.getDouble(secondSize) < first.getDouble(0) - 1.0E-7) { return new NonOverlappingMerger(second, first, true); } else { -- return (IndexMerger)(firstSize == secondSize && Objects.equals(first, second) +- return firstSize == secondSize && Objects.equals(first, second) - ? new IdenticalMerger(first) -- : new IndirectMerger(first, second, firstOnlyMatters, secondOnlyMatters)); +- : new IndirectMerger(first, second, firstOnlyMatters, secondOnlyMatters); + return new IndirectMerger(first, second, firstOnlyMatters, secondOnlyMatters); // Paper - Identical happens more often than Disjoint } } diff --git a/paper-server/patches/features/0007-optimize-dirt-and-snow-spreading.patch b/paper-server/patches/features/0007-optimize-dirt-and-snow-spreading.patch index c09fba8774d1..8605b4256514 100644 --- a/paper-server/patches/features/0007-optimize-dirt-and-snow-spreading.patch +++ b/paper-server/patches/features/0007-optimize-dirt-and-snow-spreading.patch @@ -5,7 +5,7 @@ Subject: [PATCH] optimize dirt and snow spreading diff --git a/net/minecraft/world/level/block/SpreadingSnowyBlock.java b/net/minecraft/world/level/block/SpreadingSnowyBlock.java -index 6695d7f76daf45ed3e73c4984326b8b59e5a76cc..f868b1ccfa0e373c47344d000f26fbe8507c3510 100644 +index 85666946f8cb23255360bca8efde2ce13abcbc0a..839bfdda7f54e6aabe401db6da1856544b032bf8 100644 --- a/net/minecraft/world/level/block/SpreadingSnowyBlock.java +++ b/net/minecraft/world/level/block/SpreadingSnowyBlock.java @@ -27,8 +27,13 @@ public abstract class SpreadingSnowyBlock extends SnowyBlock { @@ -22,8 +22,8 @@ index 6695d7f76daf45ed3e73c4984326b8b59e5a76cc..f868b1ccfa0e373c47344d000f26fbe8 + BlockState aboveState = chunk.getBlockState(above); // Paper - Perf: optimize dirt and snow spreading if (aboveState.is(Blocks.SNOW) && aboveState.getValue(SnowLayerBlock.LAYERS) == 1) { return true; - } else if (aboveState.getFluidState().isFull()) { -@@ -40,8 +45,14 @@ public abstract class SpreadingSnowyBlock extends SnowyBlock { + } +@@ -42,8 +47,14 @@ public abstract class SpreadingSnowyBlock extends SnowyBlock { } private static boolean canPropagate(final BlockState state, final LevelReader level, final BlockPos pos) { @@ -39,7 +39,7 @@ index 6695d7f76daf45ed3e73c4984326b8b59e5a76cc..f868b1ccfa0e373c47344d000f26fbe8 } @Override -@@ -50,7 +61,14 @@ public abstract class SpreadingSnowyBlock extends SnowyBlock { +@@ -52,7 +63,14 @@ public abstract class SpreadingSnowyBlock extends SnowyBlock { Registry blocks = level.registryAccess().lookupOrThrow(Registries.BLOCK); Optional baseBlock = blocks.getOptional(this.baseBlock); if (!baseBlock.isEmpty()) { @@ -55,7 +55,7 @@ index 6695d7f76daf45ed3e73c4984326b8b59e5a76cc..f868b1ccfa0e373c47344d000f26fbe8 // CraftBukkit start if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(level, pos, baseBlock.get().defaultBlockState()).isCancelled()) { return; -@@ -63,8 +81,20 @@ public abstract class SpreadingSnowyBlock extends SnowyBlock { +@@ -65,8 +83,20 @@ public abstract class SpreadingSnowyBlock extends SnowyBlock { for (int i = 0; i < 4; i++) { BlockPos testPos = pos.offset(random.nextInt(3) - 1, random.nextInt(5) - 3, random.nextInt(3) - 1); diff --git a/paper-server/patches/features/0008-Use-Velocity-compression-and-cipher-natives.patch b/paper-server/patches/features/0008-Use-Velocity-compression-and-cipher-natives.patch index 717e499cd9b0..fdb6b9a8c8d8 100644 --- a/paper-server/patches/features/0008-Use-Velocity-compression-and-cipher-natives.patch +++ b/paper-server/patches/features/0008-Use-Velocity-compression-and-cipher-natives.patch @@ -86,7 +86,7 @@ index 0003a548fe4a48ecfe3534f3de309a920568b773..fae764ffd6858c920cafd2fba4444793 + // Paper end - Use Velocity cipher } diff --git a/net/minecraft/network/CompressionDecoder.java b/net/minecraft/network/CompressionDecoder.java -index 2f660186f00414b37fa5c01d00c048173feaef13..fe3f0b59561e7b7236aba9cca2a13cee8955a933 100644 +index 8497561d90bf6165d1e56a044b3b409c234e1ef8..ddd5daf92d03dd343e6164d55fff638509175e6d 100644 --- a/net/minecraft/network/CompressionDecoder.java +++ b/net/minecraft/network/CompressionDecoder.java @@ -12,14 +12,22 @@ import java.util.zip.Inflater; @@ -169,7 +169,7 @@ index 2f660186f00414b37fa5c01d00c048173feaef13..fe3f0b59561e7b7236aba9cca2a13cee this.validateDecompressed = validateDecompressed; } diff --git a/net/minecraft/network/CompressionEncoder.java b/net/minecraft/network/CompressionEncoder.java -index 319325e741cc314b84844bb49ea569aaf014f319..20b5cfe1ce36d74cd6b2f95566a1bc34fc0aaa7f 100644 +index 595db570b0ade9cad7de77d2ab7b10d9e68699df..ac095f59d9f17d8239d6493d1c1e3942139b039f 100644 --- a/net/minecraft/network/CompressionEncoder.java +++ b/net/minecraft/network/CompressionEncoder.java @@ -6,17 +6,30 @@ import io.netty.handler.codec.MessageToByteEncoder; @@ -207,33 +207,34 @@ index 319325e741cc314b84844bb49ea569aaf014f319..20b5cfe1ce36d74cd6b2f95566a1bc34 int uncompressedLength = uncompressed.readableBytes(); if (uncompressedLength > 8388608) { throw new IllegalArgumentException("Packet too big (is " + uncompressedLength + ", should be less than 8388608)"); -@@ -25,6 +38,7 @@ public class CompressionEncoder extends MessageToByteEncoder { - VarInt.write(out, 0); - out.writeBytes(uncompressed); - } else { -+ if (this.deflater != null) { // Paper - Use Velocity cipher - byte[] input = new byte[uncompressedLength]; - uncompressed.readBytes(input); - VarInt.write(out, input.length); -@@ -37,6 +51,17 @@ public class CompressionEncoder extends MessageToByteEncoder { - } +@@ -26,6 +39,7 @@ public class CompressionEncoder extends MessageToByteEncoder { + VarInt.write(out, 0); + out.writeBytes(uncompressed); + } else { ++ if (this.deflater != null) { // Paper - Use Velocity cipher + byte[] input = new byte[uncompressedLength]; + uncompressed.readBytes(input); + VarInt.write(out, input.length); +@@ -38,6 +52,18 @@ public class CompressionEncoder extends MessageToByteEncoder { + } - this.deflater.reset(); -+ // Paper start - Use Velocity cipher -+ return; -+ } + this.deflater.reset(); ++ // Paper start - Use Velocity cipher ++ return; ++ } + -+ VarInt.write(out, uncompressedLength); -+ final ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(ctx.alloc(), this.compressor, uncompressed); -+ try { -+ this.compressor.deflate(compatibleIn, out); -+ } finally { -+ compatibleIn.release(); -+ } - } ++ VarInt.write(out, uncompressedLength); ++ final ByteBuf compatibleIn = com.velocitypowered.natives.util.MoreByteBufUtils.ensureCompatible(ctx.alloc(), this.compressor, uncompressed); ++ try { ++ this.compressor.deflate(compatibleIn, out); ++ } finally { ++ compatibleIn.release(); ++ } ++ // Paper end - Use Velocity cipher } } -@@ -48,4 +73,31 @@ public class CompressionEncoder extends MessageToByteEncoder { + +@@ -48,4 +74,31 @@ public class CompressionEncoder extends MessageToByteEncoder { public void setThreshold(final int threshold) { this.threshold = threshold; } @@ -266,10 +267,10 @@ index 319325e741cc314b84844bb49ea569aaf014f319..20b5cfe1ce36d74cd6b2f95566a1bc34 + // Paper end - Use Velocity cipher } diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java -index 104976b3eb04d80e5be5bd020cf16c647b1cde27..5a23f95aff982ecc58d2e2bc994f4e495285069c 100644 +index d14aea970ce98edfe3dc3692e707334e7e150804..0f06d509125e72ec11d263d0d5c2179d65f6d8dd 100644 --- a/net/minecraft/network/Connection.java +++ b/net/minecraft/network/Connection.java -@@ -740,11 +740,22 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -730,11 +730,22 @@ public class Connection extends SimpleChannelInboundHandler> { return connection; } @@ -296,7 +297,7 @@ index 104976b3eb04d80e5be5bd020cf16c647b1cde27..5a23f95aff982ecc58d2e2bc994f4e49 public boolean isEncrypted() { return this.encrypted; -@@ -782,16 +793,17 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -772,16 +783,17 @@ public class Connection extends SimpleChannelInboundHandler> { public void setupCompression(final int threshold, final boolean validateDecompressed) { if (threshold >= 0) { @@ -318,10 +319,10 @@ index 104976b3eb04d80e5be5bd020cf16c647b1cde27..5a23f95aff982ecc58d2e2bc994f4e49 this.channel.pipeline().fireUserEventTriggered(io.papermc.paper.network.ConnectionEvent.COMPRESSION_THRESHOLD_SET); // Paper - Add Channel initialization listeners } else { diff --git a/net/minecraft/server/network/ServerConnectionListener.java b/net/minecraft/server/network/ServerConnectionListener.java -index 391435cf3d279c8f5a889702b50f57626864c7bb..19a77c8269c3f1998985d533d9099c7e6cf76af4 100644 +index 6d506004583b2415ab356e34e2f8d6ac0e39cca2..474b7f06223514d95bad3d91356dfaa5435b77f5 100644 --- a/net/minecraft/server/network/ServerConnectionListener.java +++ b/net/minecraft/server/network/ServerConnectionListener.java -@@ -77,6 +77,10 @@ public class ServerConnectionListener { +@@ -76,6 +76,10 @@ public class ServerConnectionListener { LOGGER.warn("Using HAProxy, please ensure the server port is adequately firewalled."); } // Paper end - Warn people with console access that HAProxy is in use. @@ -333,7 +334,7 @@ index 391435cf3d279c8f5a889702b50f57626864c7bb..19a77c8269c3f1998985d533d9099c7e .add( new ServerBootstrap() diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index c1edad046cbdd1627edba58bc06aef5c058e79eb..3a0d47a716ce5c5345640ed67ac306101791892b 100644 +index 50e4f4037702875fe7755b169947abd800b06e7b..722c832ce18fd930d9fdb4f718dc13bfc962e5dd 100644 --- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java @@ -251,11 +251,9 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, @@ -346,6 +347,6 @@ index c1edad046cbdd1627edba58bc06aef5c058e79eb..3a0d47a716ce5c5345640ed67ac30610 this.state = ServerLoginPacketListenerImpl.State.AUTHENTICATING; - this.connection.setEncryptionKey(decryptCipher, encryptCipher); + this.connection.setEncryptionKey(secretKey); // Paper - Use Velocity cipher - } catch (CryptException var7) { - throw new IllegalStateException("Protocol error", var7); + } catch (CryptException e) { + throw new IllegalStateException("Protocol error", e); } diff --git a/paper-server/patches/features/0009-Optimize-GoalSelector-Goal.Flag-Set-operations.patch b/paper-server/patches/features/0009-Optimize-GoalSelector-Goal.Flag-Set-operations.patch index 21a8d5e24dda..e4da422f54ff 100644 --- a/paper-server/patches/features/0009-Optimize-GoalSelector-Goal.Flag-Set-operations.patch +++ b/paper-server/patches/features/0009-Optimize-GoalSelector-Goal.Flag-Set-operations.patch @@ -7,7 +7,7 @@ Optimise the stream.anyMatch statement to move to a bitset where we can replace the call with a single bitwise operation. diff --git a/net/minecraft/world/entity/ai/goal/Goal.java b/net/minecraft/world/entity/ai/goal/Goal.java -index 5746eefd9e8fa851e74ccf6b5d889a9f8e6fc1e0..81fa892212f586e8cd7938556eeaa9f9dc2654aa 100644 +index aa5f0e00daf26650b943a24676638581e494a112..60e0d618c603caef5e3516c9fdfc63ff45a7cdff 100644 --- a/net/minecraft/world/entity/ai/goal/Goal.java +++ b/net/minecraft/world/entity/ai/goal/Goal.java @@ -7,7 +7,15 @@ import net.minecraft.world.entity.Entity; @@ -69,7 +69,7 @@ index 5746eefd9e8fa851e74ccf6b5d889a9f8e6fc1e0..81fa892212f586e8cd7938556eeaa9f9 // Paper end - Mob Goal API diff --git a/net/minecraft/world/entity/ai/goal/GoalSelector.java b/net/minecraft/world/entity/ai/goal/GoalSelector.java -index 844ced7a271ffb557f3c8f2fcd6a4c6ad499aeae..75d8953845b2e9acb62b19a859d0e39fd63533eb 100644 +index b13bdc2852504903fa054c42f89299a5d33dfbd3..1ddf8796d14d472bec48546f25ac4583d483c8e9 100644 --- a/net/minecraft/world/entity/ai/goal/GoalSelector.java +++ b/net/minecraft/world/entity/ai/goal/GoalSelector.java @@ -23,7 +23,8 @@ public class GoalSelector { @@ -119,27 +119,24 @@ index 844ced7a271ffb557f3c8f2fcd6a4c6ad499aeae..75d8953845b2e9acb62b19a859d0e39f goal.stop(); } } -@@ -95,11 +96,14 @@ public class GoalSelector { +@@ -95,8 +96,14 @@ public class GoalSelector { profiler.push("goalUpdate"); - for (WrappedGoal goalx : this.availableGoals) { -- if (!goalx.isRunning() -- && !goalContainsAnyFlags(goalx, this.disabledFlags) -- && goalCanBeReplacedForAllFlags(goalx, this.lockedFlags) -- && goalx.canUse()) { -- for (Goal.Flag flag : goalx.getFlags()) { + for (WrappedGoal goal : this.availableGoals) { +- if (!goal.isRunning() && !goalContainsAnyFlags(goal, this.disabledFlags) && goalCanBeReplacedForAllFlags(goal, this.lockedFlags) && goal.canUse()) { +- for (Goal.Flag flag : goal.getFlags()) { + // Paper start -+ if (!goalx.isRunning() && !goalContainsAnyFlags(goalx, this.goalTypes) && goalCanBeReplacedForAllFlags(goalx, this.lockedFlags) && goalx.canUse()) { -+ long flagIterator = goalx.getFlags().getBackingSet(); -+ int wrappedGoalSize = goalx.getFlags().size(); ++ if (!goal.isRunning() && !goalContainsAnyFlags(goal, this.goalTypes) && goalCanBeReplacedForAllFlags(goal, this.lockedFlags) && goal.canUse()) { ++ long flagIterator = goal.getFlags().getBackingSet(); ++ int wrappedGoalSize = goal.getFlags().size(); + for (int i = 0; i < wrappedGoalSize; ++i) { + final Goal.Flag flag = GOAL_FLAG_VALUES[Long.numberOfTrailingZeros(flagIterator)]; + flagIterator ^= ca.spottedleaf.concurrentutil.util.IntegerUtil.getTrailingBit(flagIterator); + // Paper end WrappedGoal currentGoal = this.lockedFlags.getOrDefault(flag, NO_GOAL); currentGoal.stop(); - this.lockedFlags.put(flag, goalx); -@@ -131,11 +135,11 @@ public class GoalSelector { + this.lockedFlags.put(flag, goal); +@@ -128,11 +135,11 @@ public class GoalSelector { } public void disableControlFlag(final Goal.Flag flag) { diff --git a/paper-server/patches/features/0012-Remove-streams-from-hot-code.patch b/paper-server/patches/features/0012-Remove-streams-from-hot-code.patch index 1676c4705eaf..74fba9a629e2 100644 --- a/paper-server/patches/features/0012-Remove-streams-from-hot-code.patch +++ b/paper-server/patches/features/0012-Remove-streams-from-hot-code.patch @@ -7,7 +7,7 @@ Co-authored-by: Bjarne Koll Co-authored-by: Spottedleaf diff --git a/net/minecraft/world/entity/ai/behavior/GateBehavior.java b/net/minecraft/world/entity/ai/behavior/GateBehavior.java -index 135d932a31a557ff06643fb563262423d48cd540..9fb025b05cacc901d72d93c16cf2b7e48d4dd9a6 100644 +index c16463febcf74e20e8e984bc19e3179a0f5f4ed1..3adfb334068d3722329f91011c41d5e59b1956c9 100644 --- a/net/minecraft/world/entity/ai/behavior/GateBehavior.java +++ b/net/minecraft/world/entity/ai/behavior/GateBehavior.java @@ -69,7 +69,7 @@ public class GateBehavior implements BehaviorControl @@ -57,7 +57,7 @@ index 135d932a31a557ff06643fb563262423d48cd540..9fb025b05cacc901d72d93c16cf2b7e4 @Override @@ -118,24 +132,36 @@ public class GateBehavior implements BehaviorControl - public static enum RunningPolicy { + public enum RunningPolicy { RUN_ONE { + // Paper start - Perf: Remove streams from hot code @Override @@ -98,7 +98,7 @@ index 135d932a31a557ff06643fb563262423d48cd540..9fb025b05cacc901d72d93c16cf2b7e4 } } diff --git a/net/minecraft/world/entity/ai/gossip/GossipContainer.java b/net/minecraft/world/entity/ai/gossip/GossipContainer.java -index 75233df622242db6c23f7a1a5812bf25942bca41..133aab614b102419ec731e901858c0347076bae9 100644 +index 600633670eb269ab1f4f50865942c46ed4c66fc6..9008b12745628fdcc225415e20e740192185bdd8 100644 --- a/net/minecraft/world/entity/ai/gossip/GossipContainer.java +++ b/net/minecraft/world/entity/ai/gossip/GossipContainer.java @@ -28,7 +28,7 @@ import net.minecraft.util.VisibleForDebug; @@ -133,7 +133,7 @@ index 75233df622242db6c23f7a1a5812bf25942bca41..133aab614b102419ec731e901858c034 + List entries = this.decompress(); // Paper - Perf: Remove streams from hot code if (entries.isEmpty()) { return Collections.emptyList(); - } else { + } @@ -176,7 +190,23 @@ public class GossipContainer { private final Object2IntMap entries = new Object2IntOpenHashMap<>(); diff --git a/paper-server/patches/features/0013-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch b/paper-server/patches/features/0013-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch index b1512ccfe900..bfbab45f3293 100644 --- a/paper-server/patches/features/0013-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch +++ b/paper-server/patches/features/0013-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch @@ -16,25 +16,24 @@ This lets us get faster foreach iteration, as well as avoids map lookups on the values when needed. diff --git a/net/minecraft/world/level/pathfinder/PathFinder.java b/net/minecraft/world/level/pathfinder/PathFinder.java -index bb36ebf3a57cf1de98506a6391d3273b0f8e0f76..7564a67d2d63c3a7f95e1d6008e7308620653774 100644 +index 53aa6995d18cae5663d392e606c049e2e9138a99..2809bf033f37559ea66f9d6d61130926679d75cc 100644 --- a/net/minecraft/world/level/pathfinder/PathFinder.java +++ b/net/minecraft/world/level/pathfinder/PathFinder.java -@@ -54,8 +54,12 @@ public class PathFinder { - if (from == null) { +@@ -55,20 +55,24 @@ public class PathFinder { return null; - } else { -- Map tos = targets.stream() -- .collect(Collectors.toMap(pos -> this.nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), Function.identity())); -+ // Paper start - Perf: remove streams and optimize collection -+ List> tos = Lists.newArrayList(); -+ for (BlockPos pos : targets) { -+ tos.add(new java.util.AbstractMap.SimpleEntry<>(this.nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), pos)); -+ } -+ // Paper end - Perf: remove streams and optimize collection - Path path = this.findPath(from, tos, maxPathLength, reachRange, maxVisitedNodesMultiplier); - this.nodeEvaluator.done(); - return path; -@@ -63,12 +67,12 @@ public class PathFinder { + } + +- Map tos = targets.stream() +- .collect(Collectors.toMap(pos -> this.nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), Function.identity())); ++ // Paper start - Perf: remove streams and optimize collection ++ List> tos = Lists.newArrayList(); ++ for (BlockPos pos : targets) { ++ tos.add(new java.util.AbstractMap.SimpleEntry<>(this.nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), pos)); ++ } ++ // Paper end - Perf: remove streams and optimize collection + Path path = this.findPath(from, tos, maxPathLength, reachRange, maxVisitedNodesMultiplier); + this.nodeEvaluator.done(); + return path; } private @Nullable Path findPath( @@ -81,11 +80,14 @@ index bb36ebf3a57cf1de98506a6391d3273b0f8e0f76..7564a67d2d63c3a7f95e1d6008e73086 - Optional optPath = !reachedTargets.isEmpty() - ? reachedTargets.stream() -- .map(targetx -> this.reconstructPath(targetx.getBestNode(), targetMap.get(targetx), true)) +- .map(target -> this.reconstructPath(target.getBestNode(), targetMap.get(target), true)) - .min(Comparator.comparingInt(Path::getNodeCount)) - : targets.stream() -- .map(targetx -> this.reconstructPath(targetx.getBestNode(), targetMap.get(targetx), false)) +- .map(target -> this.reconstructPath(target.getBestNode(), targetMap.get(target), false)) - .min(Comparator.comparingDouble(Path::getDistToTarget).thenComparingInt(Path::getNodeCount)); +- profiler.pop(); +- if (optPath.isEmpty()) { +- return null; + Path best = null; + boolean entryListIsEmpty = reachedTargets.isEmpty(); + Comparator comparator = entryListIsEmpty @@ -96,23 +98,21 @@ index bb36ebf3a57cf1de98506a6391d3273b0f8e0f76..7564a67d2d63c3a7f95e1d6008e73086 + if (best == null || comparator.compare(path, best) < 0) { + best = path; + } -+ } - profiler.pop(); -- if (optPath.isEmpty()) { -- return null; -- } else { -- Path path = optPath.get(); -- if (captureDebug) { -- path.setDebug(this.openSet.getHeap(), closedSet.toArray(Node[]::new), targets); + } +- +- Path path = optPath.get(); +- if (captureDebug) { +- path.setDebug(this.openSet.getHeap(), closedSet.toArray(Node[]::new), targets); ++ profiler.pop(); + if (captureDebug && best != null) { + Set set = Sets.newHashSet(); + for(Map.Entry entry : targets) { + set.add(entry.getKey()); - } -- -- return path; ++ } + best.setDebug(this.openSet.getHeap(), closedSet.toArray(Node[]::new), set); } +- +- return path; + return best; + // Paper end - Perf: remove streams and optimize collection } diff --git a/paper-server/patches/features/0014-Fix-entity-tracker-desync-when-new-players-are-added.patch b/paper-server/patches/features/0014-Fix-entity-tracker-desync-when-new-players-are-added.patch index cee2bb03b86a..944b36731026 100644 --- a/paper-server/patches/features/0014-Fix-entity-tracker-desync-when-new-players-are-added.patch +++ b/paper-server/patches/features/0014-Fix-entity-tracker-desync-when-new-players-are-added.patch @@ -48,10 +48,10 @@ index cff05f64af7f425b77cbbd7680c5cc592faa798c..0ab4080c8e30d5ee14ce5fcbac64b031 serverEntity.getLastSentYRot(), entity.getType(), diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java -index 23ae1694c3d5fffdb2277316f66c5fd59157f5ca..be28a41084d656c44b611cf3a01ba89de610d5b2 100644 +index 7f879bc44354c9fac0238208db12b55a948982fb..55cfe38c0daa3ca71a71bf8c7d88fd613fabd82d 100644 --- a/net/minecraft/server/level/ChunkMap.java +++ b/net/minecraft/server/level/ChunkMap.java -@@ -1361,6 +1361,7 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP +@@ -1357,6 +1357,7 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP ChunkMap.this.level.debugSynchronizers().startTrackingEntity(player, this.entity); } // Paper end - entity tracking events @@ -60,7 +60,7 @@ index 23ae1694c3d5fffdb2277316f66c5fd59157f5ca..be28a41084d656c44b611cf3a01ba89d } else { this.removePlayer(player); diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java -index 6774d12d04fa848624fb8bf7a3c2b8bcb88f6e8f..19bb751d3e9c347fe2446412f85c9f28ec8212e6 100644 +index a62ec41b1319857f0d6cd223d013a92b1e2c2b0d..5fad52157fc22755196ce9eaddaa2bc23c5bb86b 100644 --- a/net/minecraft/server/level/ServerEntity.java +++ b/net/minecraft/server/level/ServerEntity.java @@ -89,6 +89,13 @@ public class ServerEntity { diff --git a/paper-server/patches/features/0016-Add-Alternate-Current-redstone-implementation.patch b/paper-server/patches/features/0016-Add-Alternate-Current-redstone-implementation.patch index 721b1748e12f..e9123d2691af 100644 --- a/paper-server/patches/features/0016-Add-Alternate-Current-redstone-implementation.patch +++ b/paper-server/patches/features/0016-Add-Alternate-Current-redstone-implementation.patch @@ -2321,7 +2321,7 @@ index 0000000000000000000000000000000000000000..298076a0db4e6ee6e4775ac43bf749d9 + } +} diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index f4bbccee849ee3711a3b838884e4bcf4e24da039..0b9fbf0ae658f0b3e9c6106a42fb70948b6fb9be 100644 +index 9fc39230f52f4cf6b44edd34aa9542b9d500538e..965d9f515d0410df3395d07c6cf5e6349c75c923 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java @@ -233,6 +233,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet @@ -2347,10 +2347,10 @@ index f4bbccee849ee3711a3b838884e4bcf4e24da039..0b9fbf0ae658f0b3e9c6106a42fb7094 return toLevel.dimension() != Level.NETHER || this.getGameRules().get(GameRules.ALLOW_ENTERING_NETHER_USING_PORTALS); } diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 07c301ba02c7f2c032a29a0ae3bdf95fc522c03b..7e4cf8a13e0ff2198cb7b6d80fb3fa343339943b 100644 +index 8d1d7582730e05bf605db31e13ee24242592074e..3d20ef3bc4e891e3e6e5f9f6f5efc6c0367369ea 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java -@@ -2153,6 +2153,17 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -2156,6 +2156,17 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl return this.palettedContainerFactory; } @@ -2365,11 +2365,11 @@ index 07c301ba02c7f2c032a29a0ae3bdf95fc522c03b..7e4cf8a13e0ff2198cb7b6d80fb3fa34 + } + // Paper end - optimize redstone (Alternate Current) + - public static enum ExplosionInteraction implements StringRepresentable { + public enum ExplosionInteraction implements StringRepresentable { NONE("none"), BLOCK("block"), diff --git a/net/minecraft/world/level/block/RedStoneWireBlock.java b/net/minecraft/world/level/block/RedStoneWireBlock.java -index a00002774755eb90a0b772fe742b30a5e09452cf..1e863e97bd1dc99ed6e2c0602f78f457ac618965 100644 +index 5bdeaa9ae20de9f42e760d2207219d5f22d95e9b..0e285f38d282b29f625c5578ee1871a6c2b8585d 100644 --- a/net/minecraft/world/level/block/RedStoneWireBlock.java +++ b/net/minecraft/world/level/block/RedStoneWireBlock.java @@ -269,7 +269,7 @@ public class RedStoneWireBlock extends Block { diff --git a/paper-server/patches/features/0017-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch b/paper-server/patches/features/0017-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch index e8d5af42de9b..596b1934c9ab 100644 --- a/paper-server/patches/features/0017-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch +++ b/paper-server/patches/features/0017-Only-write-chunk-data-to-disk-if-it-serializes-witho.patch @@ -8,10 +8,10 @@ This ensures at least a valid version of the chunk exists on disk, even if outdated diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java -index d628e06a8dbf11b491b323c10a512fde22e72a12..fc712f9dbc893a6dee8ccecc54d0af07659dee62 100644 +index dd05d166a3f995e40a16c11c8cfbf86776157fa4..9cbf5b9b2ebedb9e33cd84a8237708df2829a94d 100644 --- a/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/net/minecraft/world/level/chunk/storage/RegionFile.java -@@ -25,6 +25,7 @@ import org.slf4j.Logger; +@@ -24,6 +24,7 @@ import org.slf4j.Logger; public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile { // Paper - rewrite chunk system private static final Logger LOGGER = LogUtils.getLogger(); @@ -19,7 +19,7 @@ index d628e06a8dbf11b491b323c10a512fde22e72a12..fc712f9dbc893a6dee8ccecc54d0af07 private static final int SECTOR_BYTES = 4096; @VisibleForTesting protected static final int SECTOR_INTS = 1024; -@@ -453,6 +454,24 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche +@@ -451,6 +452,24 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche this.pos = pos; } @@ -45,7 +45,7 @@ index d628e06a8dbf11b491b323c10a512fde22e72a12..fc712f9dbc893a6dee8ccecc54d0af07 public void close() throws IOException { ByteBuffer result = ByteBuffer.wrap(this.buf, 0, this.count); diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index aa36e241d49725eb13f00e57d020d4da24add53d..5fa64ff30b8252f139ca7f77c14352c384c8c0e5 100644 +index 54e6c67ca05ef1f1350873196dede122f5c911c5..6875c3728544bd3b5172c9a3c3f01d033f158d50 100644 --- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java @@ -16,6 +16,7 @@ import net.minecraft.world.level.ChunkPos; @@ -81,7 +81,7 @@ index aa36e241d49725eb13f00e57d020d4da24add53d..5fa64ff30b8252f139ca7f77c14352c3 return writeData; } -@@ -331,9 +345,18 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -324,9 +338,18 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise if (value == null) { region.clear(pos); } else { @@ -101,7 +101,7 @@ index aa36e241d49725eb13f00e57d020d4da24add53d..5fa64ff30b8252f139ca7f77c14352c3 } } } -@@ -376,4 +399,13 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -369,4 +392,13 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise public RegionStorageInfo info() { return this.info; } diff --git a/paper-server/patches/features/0018-Entity-load-save-limit-per-chunk.patch b/paper-server/patches/features/0018-Entity-load-save-limit-per-chunk.patch index 8aad6f7a88e2..f33ad87facea 100644 --- a/paper-server/patches/features/0018-Entity-load-save-limit-per-chunk.patch +++ b/paper-server/patches/features/0018-Entity-load-save-limit-per-chunk.patch @@ -33,10 +33,10 @@ index 0cfdbdee091f43ca011bc68f7479eb7b84801b09..8d9ce3d301d5f7e4106587ae00adb8dd scopedCollector.forChild(entity.problemPath()), entity.registryAccess() ); diff --git a/net/minecraft/world/entity/EntityType.java b/net/minecraft/world/entity/EntityType.java -index 2cdbb5f9bace96a8c4ad7fc4de17678ec0db8a6c..6b19f8cd8655cc52a0d8deadb9ca9f24473637a4 100644 +index a1ee86c18c17e14ebf98f0e72680543addc4c7fa..1ee78f52205cbb0b254a28999f3707ccccbe998e 100644 --- a/net/minecraft/world/entity/EntityType.java +++ b/net/minecraft/world/entity/EntityType.java -@@ -1647,7 +1647,18 @@ public class EntityType implements EntityTypeTest, +@@ -1641,7 +1641,18 @@ public class EntityType implements EntityTypeTest, } public static Stream loadEntitiesRecursive(final ValueInput.ValueInputList entities, final Level level, final EntitySpawnReason reason) { @@ -56,10 +56,10 @@ index 2cdbb5f9bace96a8c4ad7fc4de17678ec0db8a6c..6b19f8cd8655cc52a0d8deadb9ca9f24 return entity; })); diff --git a/net/minecraft/world/level/chunk/storage/EntityStorage.java b/net/minecraft/world/level/chunk/storage/EntityStorage.java -index 04045397dff89870316d0d374b9e472540c3298d..b1cd822c114b99a25fad2e649ca44596109aa0e5 100644 +index 0326b79fea3f563c3cdfa8f7cf1a3af0e4f08d38..4bd083ecdea207ee5689760fccc9ce8a5a958d57 100644 --- a/net/minecraft/world/level/chunk/storage/EntityStorage.java +++ b/net/minecraft/world/level/chunk/storage/EntityStorage.java -@@ -95,7 +95,18 @@ public class EntityStorage implements EntityPersistentStorage { +@@ -92,7 +92,18 @@ public class EntityStorage implements EntityPersistentStorage { } else { try (ProblemReporter.ScopedCollector reporter = new ProblemReporter.ScopedCollector(ChunkAccess.problemPath(pos), LOGGER)) { ListTag entities = new ListTag(); diff --git a/paper-server/patches/features/0019-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch b/paper-server/patches/features/0019-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch index 7e2c6bbe7598..7f6dca4d88cb 100644 --- a/paper-server/patches/features/0019-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch +++ b/paper-server/patches/features/0019-Attempt-to-recalculate-regionfile-header-if-it-is-co.patch @@ -55,10 +55,10 @@ index a6f9435a8e2a6c8cc05bd3873cb6fc0ec98973b8..d44fd9eea0ccb09c894d6431ede8a4c2 this.used.set(position, position + size); } diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java -index 5e77906d77da82b23fbd6e8d16fbd0847c83f4da..e077797cefffcb9db627cab12c7d88245e5baa69 100644 +index 9cbf5b9b2ebedb9e33cd84a8237708df2829a94d..a4030f8306843eb4a0feb79776ce505faa099b8d 100644 --- a/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/net/minecraft/world/level/chunk/storage/RegionFile.java -@@ -47,6 +47,363 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche +@@ -46,6 +46,363 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche @VisibleForTesting protected final RegionBitmap usedSectors = new RegionBitmap(); @@ -423,75 +423,58 @@ index 5e77906d77da82b23fbd6e8d16fbd0847c83f4da..e077797cefffcb9db627cab12c7d8824 @Override public final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(final net.minecraft.nbt.CompoundTag data, final ChunkPos pos) throws IOException { @@ -75,6 +432,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche - throw new IllegalArgumentException("Expected directory, got " + externalFileDir.toAbsolutePath()); - } else { - this.externalFileDir = externalFileDir; -+ this.canRecalcHeader = info.dfuType()[0] == net.minecraft.util.datafix.DataFixTypes.CHUNK; // Paper - add can recalc flag - this.offsets = this.header.asIntBuffer(); - this.offsets.limit(1024); - this.header.position(4096); + } + + this.externalFileDir = externalFileDir; ++ this.canRecalcHeader = info.dfuType()[0] == net.minecraft.util.datafix.DataFixTypes.CHUNK; // Paper - add can recalc flag + this.offsets = this.header.asIntBuffer(); + this.offsets.limit(1024); + this.header.position(4096); @@ -95,11 +453,13 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche - long size = Files.size(path); + long size = Files.size(path); -- for (int i = 0; i < 1024; i++) { -+ boolean needsHeaderRecalc = false; // Paper - recalculate header on header corruption -+ boolean hasBackedUp = false; // Paper - recalculate header on header corruption -+ for (int i = 0; i < 1024; i++) { final int headerLocation = i; // Paper - we expect this to be the header location - int offset = this.offsets.get(i); - if (offset != 0) { -- int sectorNumber = getSectorNumber(offset); -- int numSectors = getNumSectors(offset); -+ int sectorNumber = getSectorNumber(offset); // Paper - we expect this to be offset in file in sectors -+ int numSectors = getNumSectors(offset); // Paper - diff on change, we expect this to be sector length of region - watch out for reassignments - // Spigot start - if (numSectors == 255) { - // We're maxed out, so we need to read the proper length from the section +- for (int i = 0; i < 1024; i++) { ++ boolean needsHeaderRecalc = false; // Paper - recalculate header on header corruption ++ boolean hasBackedUp = false; // Paper - recalculate header on header corruption ++ for (int i = 0; i < 1024; i++) { final int headerLocation = i; // Paper - we expect this to be the header location + int offset = this.offsets.get(i); + if (offset != 0) { +- int sectorNumber = getSectorNumber(offset); +- int numSectors = getNumSectors(offset); ++ int sectorNumber = getSectorNumber(offset); // Paper - we expect this to be offset in file in sectors ++ int numSectors = getNumSectors(offset); // Paper - diff on change, we expect this to be sector length of region - watch out for reassignments + // Spigot start + if (numSectors == 255) { + // We're maxed out, so we need to read the proper length from the section @@ -110,18 +470,62 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche - // Spigot end - if (sectorNumber < 2) { - LOGGER.warn("Region file {} has invalid sector at index: {}; sector {} overlaps with header", path, i, sectorNumber); -- this.offsets.put(i, 0); -+ //this.offsets.put(i, 0); // Paper - we catch this, but need it in the header for the summary change - } else if (numSectors == 0) { - LOGGER.warn("Region file {} has an invalid sector at index: {}; size has to be > 0", path, i); -- this.offsets.put(i, 0); -+ //this.offsets.put(i, 0); // Paper - we catch this, but need it in the header for the summary change - } else if (sectorNumber * 4096L > size) { - LOGGER.warn("Region file {} has an invalid sector at index: {}; sector {} is out of bounds", path, i, sectorNumber); -- this.offsets.put(i, 0); -+ //this.offsets.put(i, 0); // Paper - we catch this, but need it in the header for the summary change - } else { -- this.usedSectors.force(sectorNumber, numSectors); -+ //this.usedSectors.force(sectorNumber, numSectors); // Paper - move this down so we can check if it fails to allocate -+ } -+ // Paper start - recalculate header on header corruption -+ if (sectorNumber < 2 || numSectors <= 0 || ((long)sectorNumber * 4096L) > size) { -+ if (this.canRecalcHeader) { -+ LOGGER.error("Detected invalid header for regionfile " + this.path.toAbsolutePath() + "! Recalculating header..."); -+ needsHeaderRecalc = true; -+ break; -+ } else { -+ // location = chunkX | (chunkZ << 5); -+ LOGGER.error("Detected invalid header for regionfile " + this.path.toAbsolutePath() + -+ "! Cannot recalculate, removing local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") from header"); -+ if (!hasBackedUp) { -+ hasBackedUp = true; -+ this.backupRegionFile(); -+ } -+ this.timestamps.put(headerLocation, 0); // be consistent, delete the timestamp too -+ this.offsets.put(headerLocation, 0); // delete the entry from header -+ continue; -+ } - } -+ boolean failedToAllocate = !this.usedSectors.tryAllocate(sectorNumber, numSectors); -+ if (failedToAllocate) { -+ LOGGER.error("Overlapping allocation by local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") in regionfile " + this.path.toAbsolutePath()); -+ } -+ if (failedToAllocate & !this.canRecalcHeader) { + // Spigot end + if (sectorNumber < 2) { + LOGGER.warn("Region file {} has invalid sector at index: {}; sector {} overlaps with header", path, i, sectorNumber); +- this.offsets.put(i, 0); ++ //this.offsets.put(i, 0); // Paper - we catch this, but need it in the header for the summary change + } else if (numSectors == 0) { + LOGGER.warn("Region file {} has an invalid sector at index: {}; size has to be > 0", path, i); +- this.offsets.put(i, 0); ++ //this.offsets.put(i, 0); // Paper - we catch this, but need it in the header for the summary change + } else if (sectorNumber * 4096L > size) { + LOGGER.warn("Region file {} has an invalid sector at index: {}; sector {} is out of bounds", path, i, sectorNumber); +- this.offsets.put(i, 0); ++ //this.offsets.put(i, 0); // Paper - we catch this, but need it in the header for the summary change + } else { +- this.usedSectors.force(sectorNumber, numSectors); ++ //this.usedSectors.force(sectorNumber, numSectors); // Paper - move this down so we can check if it fails to allocate ++ } ++ // Paper start - recalculate header on header corruption ++ if (sectorNumber < 2 || numSectors <= 0 || ((long)sectorNumber * 4096L) > size) { ++ if (this.canRecalcHeader) { ++ LOGGER.error("Detected invalid header for regionfile " + this.path.toAbsolutePath() + "! Recalculating header..."); ++ needsHeaderRecalc = true; ++ break; ++ } else { + // location = chunkX | (chunkZ << 5); + LOGGER.error("Detected invalid header for regionfile " + this.path.toAbsolutePath() + -+ "! Cannot recalculate, removing local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") from header"); ++ "! Cannot recalculate, removing local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") from header"); + if (!hasBackedUp) { + hasBackedUp = true; + this.backupRegionFile(); @@ -500,21 +483,38 @@ index 5e77906d77da82b23fbd6e8d16fbd0847c83f4da..e077797cefffcb9db627cab12c7d8824 + this.offsets.put(headerLocation, 0); // delete the entry from header + continue; + } -+ needsHeaderRecalc |= failedToAllocate; -+ // Paper end - recalculate header on header corruption ++ } ++ boolean failedToAllocate = !this.usedSectors.tryAllocate(sectorNumber, numSectors); ++ if (failedToAllocate) { ++ LOGGER.error("Overlapping allocation by local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") in regionfile " + this.path.toAbsolutePath()); } ++ if (failedToAllocate & !this.canRecalcHeader) { ++ // location = chunkX | (chunkZ << 5); ++ LOGGER.error("Detected invalid header for regionfile " + this.path.toAbsolutePath() + ++ "! Cannot recalculate, removing local chunk (" + (headerLocation & 31) + "," + (headerLocation >>> 5) + ") from header"); ++ if (!hasBackedUp) { ++ hasBackedUp = true; ++ this.backupRegionFile(); ++ } ++ this.timestamps.put(headerLocation, 0); // be consistent, delete the timestamp too ++ this.offsets.put(headerLocation, 0); // delete the entry from header ++ continue; ++ } ++ needsHeaderRecalc |= failedToAllocate; ++ // Paper end - recalculate header on header corruption } -+ // Paper start - recalculate header on header corruption -+ // we move the recalc here so comparison to old header is correct when logging to console -+ if (needsHeaderRecalc) { // true if header gave us overlapping allocations or had other issues -+ LOGGER.error("Recalculating regionfile " + this.path.toAbsolutePath() + ", header gave erroneous offsets & locations"); -+ this.recalculateHeader(); -+ } -+ // Paper end } ++ // Paper start - recalculate header on header corruption ++ // we move the recalc here so comparison to old header is correct when logging to console ++ if (needsHeaderRecalc) { // true if header gave us overlapping allocations or had other issues ++ LOGGER.error("Recalculating regionfile " + this.path.toAbsolutePath() + ", header gave erroneous offsets & locations"); ++ this.recalculateHeader(); ++ } ++ // Paper end } } -@@ -131,10 +535,34 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche + +@@ -130,10 +534,34 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche } private Path getExternalChunkPath(final ChunkPos pos) { @@ -550,77 +550,79 @@ index 5e77906d77da82b23fbd6e8d16fbd0847c83f4da..e077797cefffcb9db627cab12c7d8824 public synchronized @Nullable DataInputStream getChunkDataInputStream(final ChunkPos pos) throws IOException { int offset = this.getOffset(pos); if (offset == 0) { -@@ -155,30 +583,67 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche - buffer.flip(); - if (buffer.remaining() < 5) { - LOGGER.error("Chunk {} header is truncated: expected {} but read {}", pos, sectorsLength, buffer.remaining()); +@@ -155,6 +583,11 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche + buffer.flip(); + if (buffer.remaining() < 5) { + LOGGER.error("Chunk {} header is truncated: expected {} but read {}", pos, sectorsLength, buffer.remaining()); ++ // Paper start - recalculate header on regionfile corruption ++ if (this.canRecalcHeader && this.recalculateHeader()) { ++ return this.getChunkDataInputStream(pos); ++ } ++ // Paper end - recalculate header on regionfile corruption + return null; + } + +@@ -162,6 +595,11 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche + byte versionId = buffer.get(); + if (length == 0) { + LOGGER.warn("Chunk {} is allocated, but stream is missing", pos); ++ // Paper start - recalculate header on regionfile corruption ++ if (this.canRecalcHeader && this.recalculateHeader()) { ++ return this.getChunkDataInputStream(pos); ++ } ++ // Paper end - recalculate header on regionfile corruption + return null; + } + +@@ -169,18 +607,45 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche + if (isExternalStreamChunk(versionId)) { + if (streamLength != 0) { + LOGGER.warn("Chunk has both internal and external streams"); + // Paper start - recalculate header on regionfile corruption + if (this.canRecalcHeader && this.recalculateHeader()) { + return this.getChunkDataInputStream(pos); + } + // Paper end - recalculate header on regionfile corruption - return null; - } else { - int length = buffer.getInt(); - byte versionId = buffer.get(); - if (length == 0) { - LOGGER.warn("Chunk {} is allocated, but stream is missing", pos); -+ // Paper start - recalculate header on regionfile corruption -+ if (this.canRecalcHeader && this.recalculateHeader()) { -+ return this.getChunkDataInputStream(pos); -+ } -+ // Paper end - recalculate header on regionfile corruption - return null; - } else { - int streamLength = length - 1; - if (isExternalStreamChunk(versionId)) { - if (streamLength != 0) { - LOGGER.warn("Chunk has both internal and external streams"); -+ // Paper start - recalculate header on regionfile corruption -+ if (this.canRecalcHeader && this.recalculateHeader()) { -+ return this.getChunkDataInputStream(pos); -+ } -+ // Paper end - recalculate header on regionfile corruption - } - -- return this.createExternalChunkInputStream(pos, getExternalChunkVersion(versionId)); -+ // Paper start - recalculate header on regionfile corruption -+ final DataInputStream ret = this.createExternalChunkInputStream(pos, getExternalChunkVersion(versionId)); -+ if (ret == null && this.canRecalcHeader && this.recalculateHeader()) { -+ return this.getChunkDataInputStream(pos); -+ } -+ return ret; -+ // Paper end - recalculate header on regionfile corruption - } else if (streamLength > buffer.remaining()) { - LOGGER.error("Chunk {} stream is truncated: expected {} but read {}", pos, streamLength, buffer.remaining()); -+ // Paper start - recalculate header on regionfile corruption -+ if (this.canRecalcHeader && this.recalculateHeader()) { -+ return this.getChunkDataInputStream(pos); -+ } -+ // Paper end - recalculate header on regionfile corruption - return null; - } else if (streamLength < 0) { - LOGGER.error("Declared size {} of chunk {} is negative", length, pos); -+ // Paper start - recalculate header on regionfile corruption -+ if (this.canRecalcHeader && this.recalculateHeader()) { -+ return this.getChunkDataInputStream(pos); -+ } -+ // Paper end - recalculate header on regionfile corruption - return null; - } else { - JvmProfiler.INSTANCE.onRegionFileRead(this.info, pos, this.version, streamLength); -- return this.createChunkInputStream(pos, versionId, createStream(buffer, streamLength)); -+ // Paper start - recalculate header on regionfile corruption -+ final DataInputStream ret = this.createChunkInputStream(pos, versionId, createStream(buffer, streamLength)); -+ if (ret == null && this.canRecalcHeader && this.recalculateHeader()) { -+ return this.getChunkDataInputStream(pos); -+ } -+ return ret; -+ // Paper end - recalculate header on regionfile corruption - } - } } -@@ -358,9 +823,14 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche + +- return this.createExternalChunkInputStream(pos, getExternalChunkVersion(versionId)); ++ // Paper start - recalculate header on regionfile corruption ++ final DataInputStream ret = this.createExternalChunkInputStream(pos, getExternalChunkVersion(versionId)); ++ if (ret == null && this.canRecalcHeader && this.recalculateHeader()) { ++ return this.getChunkDataInputStream(pos); ++ } ++ return ret; ++ // Paper end - recalculate header on regionfile corruption + } else if (streamLength > buffer.remaining()) { + LOGGER.error("Chunk {} stream is truncated: expected {} but read {}", pos, streamLength, buffer.remaining()); ++ // Paper start - recalculate header on regionfile corruption ++ if (this.canRecalcHeader && this.recalculateHeader()) { ++ return this.getChunkDataInputStream(pos); ++ } ++ // Paper end - recalculate header on regionfile corruption + return null; + } else if (streamLength < 0) { + LOGGER.error("Declared size {} of chunk {} is negative", length, pos); ++ // Paper start - recalculate header on regionfile corruption ++ if (this.canRecalcHeader && this.recalculateHeader()) { ++ return this.getChunkDataInputStream(pos); ++ } ++ // Paper end - recalculate header on regionfile corruption + return null; + } else { + JvmProfiler.INSTANCE.onRegionFileRead(this.info, pos, this.version, streamLength); +- return this.createChunkInputStream(pos, versionId, createStream(buffer, streamLength)); ++ // Paper start - recalculate header on regionfile corruption ++ final DataInputStream ret = this.createChunkInputStream(pos, versionId, createStream(buffer, streamLength)); ++ if (ret == null && this.canRecalcHeader && this.recalculateHeader()) { ++ return this.getChunkDataInputStream(pos); ++ } ++ return ret; ++ // Paper end - recalculate header on regionfile corruption + } + } + +@@ -357,9 +822,14 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche } private ByteBuffer createExternalStub() { @@ -637,7 +639,7 @@ index 5e77906d77da82b23fbd6e8d16fbd0847c83f4da..e077797cefffcb9db627cab12c7d8824 return stub; } diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index 5fa64ff30b8252f139ca7f77c14352c384c8c0e5..eae4963b6d18c5f92871477b93f81c2c79331cd9 100644 +index 6875c3728544bd3b5172c9a3c3f01d033f158d50..9fd2fa679842ef851a15ea2bc48504757988619e 100644 --- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java @@ -24,6 +24,32 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise @@ -739,13 +741,19 @@ index 5fa64ff30b8252f139ca7f77c14352c384c8c0e5..eae4963b6d18c5f92871477b93f81c2c } @org.jetbrains.annotations.Contract("_, false -> !null") private @Nullable RegionFile getRegionFile(final ChunkPos pos, boolean existingOnly) throws IOException { // CraftBukkit -@@ -313,6 +365,19 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - } +@@ -307,7 +359,25 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise + // Paper end - var4 = NbtIo.read(regionChunkInputStream); + try (DataInputStream regionChunkInputStream = region.getChunkDataInputStream(pos)) { +- return regionChunkInputStream == null ? null : NbtIo.read(regionChunkInputStream); + // Paper start - recover from corrupt regionfile header ++ if (regionChunkInputStream == null) { ++ return null; ++ } ++ ++ final CompoundTag serialisedChunkData = NbtIo.read(regionChunkInputStream); + if (this.isChunkData) { -+ ChunkPos headerChunkPos = SerializableChunkData.getChunkCoordinate(var4); ++ ChunkPos headerChunkPos = SerializableChunkData.getChunkCoordinate(serialisedChunkData); + if (!headerChunkPos.equals(pos)) { + net.minecraft.server.MinecraftServer.LOGGER.error("Attempting to read chunk data at " + pos + " but got chunk data for " + headerChunkPos + " instead! Attempting regionfile recalculation for regionfile " + region.getPath().toAbsolutePath()); + if (region.recalculateHeader()) { @@ -755,10 +763,11 @@ index 5fa64ff30b8252f139ca7f77c14352c384c8c0e5..eae4963b6d18c5f92871477b93f81c2c + return null; + } + } ++ return serialisedChunkData; + // Paper end - recover from corrupt regionfile header } + } - return var4; diff --git a/net/minecraft/world/level/chunk/storage/RegionFileVersion.java b/net/minecraft/world/level/chunk/storage/RegionFileVersion.java index ea229f63f81c5638ded74c28e1e13d8948f2e5e0..d991fccfc3d2cc51611f802a6d40429024e21d9a 100644 --- a/net/minecraft/world/level/chunk/storage/RegionFileVersion.java @@ -791,7 +800,7 @@ index 590bd1ca60956e5c5be58481f97401e55f9e1aeb..4e0c9fa1eecfa9f21285b7911e25830b return new RegionStorageInfo(this.level, this.dimension, this.type + suffix); } diff --git a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java -index 1e0afa9590de7fe492cf29aded96be3db498c51e..df0bb06176ad5cce3ed8785d22d68b2dcbf5a8ca 100644 +index 2d326c3090a5d7621350347e131ee31d4715d3a7..98fb7a282a33f4391de124ed9be9bcf069178516 100644 --- a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java +++ b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java @@ -120,6 +120,18 @@ public record SerializableChunkData( @@ -813,7 +822,7 @@ index 1e0afa9590de7fe492cf29aded96be3db498c51e..df0bb06176ad5cce3ed8785d22d68b2d // Paper start - Do not let the server load chunks from newer versions private static final int CURRENT_DATA_VERSION = net.minecraft.SharedConstants.getCurrentVersion().dataVersion().version(); -@@ -544,7 +556,7 @@ public record SerializableChunkData( +@@ -542,7 +554,7 @@ public record SerializableChunkData( tag.putInt("xPos", this.chunkPos.x()); tag.putInt("yPos", this.minSectionY); tag.putInt("zPos", this.chunkPos.z()); @@ -823,7 +832,7 @@ index 1e0afa9590de7fe492cf29aded96be3db498c51e..df0bb06176ad5cce3ed8785d22d68b2d tag.putString("Status", BuiltInRegistries.CHUNK_STATUS.getKey(this.chunkStatus).toString()); tag.storeNullable("blending_data", BlendingData.Packed.CODEC, this.blendingData); diff --git a/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java b/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java -index 6e55cb304fd9a5a01bbe7666dddb882e684cdcf1..6d954064f409ddd2cb7cfd0d0c428ac186f5ca4d 100644 +index df4f03f3a346e0ab0074757b3a077b2407135ac3..0b0265c8d4cb70aef758c1b443d007ef8d6c282b 100644 --- a/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java +++ b/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java @@ -34,6 +34,7 @@ public class SimpleRegionStorage implements ca.spottedleaf.moonrise.patches.chun diff --git a/paper-server/patches/features/0020-Incremental-chunk-and-player-saving.patch b/paper-server/patches/features/0020-Incremental-chunk-and-player-saving.patch index 906d95d99e0b..25138bee13b5 100644 --- a/paper-server/patches/features/0020-Incremental-chunk-and-player-saving.patch +++ b/paper-server/patches/features/0020-Incremental-chunk-and-player-saving.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Incremental chunk and player saving diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 248a01f06ec822737a741873166aa4e502a7ba07..c4eb56fc227afd7e9631624537dd8e67ae3a8bea 100644 +index 49be7709026cd75cfcb31715550387f0ba954a16..f9da26656b18327e3bcc1537a5f51e84b32cc43a 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java -@@ -968,7 +968,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop= 15000L) { // use vanilla's 15000L between keep alive packets - if (this.keepAlivePending) { -- if (!this.processedDisconnect && elapsedTime >= KEEPALIVE_LIMIT) { // check keepalive limit, don't fire if already disconnected +- if (elapsedTime >= KEEPALIVE_LIMIT) { // check keepalive limit, don't fire if already disconnected - this.disconnect(TIMEOUT_DISCONNECTION_MESSAGE, io.papermc.paper.connection.DisconnectionReason.TIMEOUT); // Paper - kick event cause - } - // Paper end - give clients a longer time to respond to pings as per pre 1.12.2 timings @@ -230,7 +230,7 @@ index abeca4714053fd0a4fa489d496e2e0b844de40a8..7ed50fc00c58c7781c958df1d828a67a + if (oldest != null && (currTime - oldest.txTimeNS()) > java.util.concurrent.TimeUnit.MILLISECONDS.toNanos(KEEPALIVE_LIMIT)) { + LOGGER.info("{} was kicked due to keepalive timeout!", this.playerProfile().name()); + this.disconnect(TIMEOUT_DISCONNECTION_MESSAGE, io.papermc.paper.connection.DisconnectionReason.TIMEOUT); // Paper - kick event cause -+ // Paper end - improve keepalives ++ // Paper end - improve keepalives } } diff --git a/paper-server/patches/features/0025-Optimise-EntityScheduler-ticking.patch b/paper-server/patches/features/0025-Optimise-EntityScheduler-ticking.patch index c929667c8ef8..1e9b782ae115 100644 --- a/paper-server/patches/features/0025-Optimise-EntityScheduler-ticking.patch +++ b/paper-server/patches/features/0025-Optimise-EntityScheduler-ticking.patch @@ -20,11 +20,11 @@ index 2bc436cdf5180a7943c45fabb9fbbedae6f7db56..f312a7f5b1b2a777ab36b94ce7cbf387 @Override diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 8c4b40362f77cdea6e57315a6639006ac7ab27c7..a5217deb236ee922d020a7a6a03141a5f67acd77 100644 +index f9da26656b18327e3bcc1537a5f51e84b32cc43a..e69b540be1e0f0c699a57e07057cee74d4f8a771 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java -@@ -1794,32 +1794,22 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop collisionsBB = new java.util.ArrayList<>(); final List collisionsVoxel = new java.util.ArrayList<>(); @@ -62,10 +62,10 @@ index 06132bde0aed9dd9088c884ee31056b9176b6f90..08374da2d9b84e8ff13c670d7f45867f ); diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index fa3809be5c0488c5a1d2639579d68619b0a55de9..c332d48f5cac2f3be93201c66f4f7cdba916cbac 100644 +index 3d20ef3bc4e891e3e6e5f9f6f5efc6c0367369ea..62c8650462a866dcdb3f06f781c7a8c716b0d912 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java -@@ -1529,7 +1529,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -1528,7 +1528,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl if (entity instanceof net.minecraft.world.entity.decoration.ArmorStand && !entity.level().paperConfig().entities.armorStands.doCollisionEntityLookups) return false; // Paper start - optimise collisions diff --git a/paper-server/patches/features/0027-Optional-per-player-mob-spawns.patch b/paper-server/patches/features/0027-Optional-per-player-mob-spawns.patch index 16ec01667327..b14e4733d769 100644 --- a/paper-server/patches/features/0027-Optional-per-player-mob-spawns.patch +++ b/paper-server/patches/features/0027-Optional-per-player-mob-spawns.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Optional per player mob spawns diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java -index be28a41084d656c44b611cf3a01ba89de610d5b2..15d9c2d601a48d2288d5110f9991280129f43087 100644 +index 55cfe38c0daa3ca71a71bf8c7d88fd613fabd82d..2afc89ab4404cf04ba1da813f1c4a05baa4f44e3 100644 --- a/net/minecraft/server/level/ChunkMap.java +++ b/net/minecraft/server/level/ChunkMap.java @@ -238,11 +238,29 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP @@ -42,10 +42,10 @@ index be28a41084d656c44b611cf3a01ba89de610d5b2..15d9c2d601a48d2288d5110f99912801 protected ChunkGenerator generator() { return this.worldGenContext.generator(); diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index fcb23814c2539f4e31ed5191e03cc28f4e7f9c2d..0edfb9866ee2d0ff71394bc74f139fe3b4550c42 100644 +index a5685e0b50610cc8213f34c5db62b475bd54789b..a5023f6f7d912560f3488b1823ee22a1dc639203 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java -@@ -537,9 +537,18 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -535,9 +535,18 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon private void tickChunks(final ProfilerFiller profiler, final long timeDiff) { profiler.push("naturalSpawnCount"); int chunkCount = this.distanceManager.getNaturalSpawnChunkCount(); @@ -67,7 +67,7 @@ index fcb23814c2539f4e31ed5191e03cc28f4e7f9c2d..0edfb9866ee2d0ff71394bc74f139fe3 this.lastSpawnState = spawnCookie; boolean doMobSpawning = this.level.getGameRules().get(GameRules.SPAWN_MOBS) && !this.level.players().isEmpty(); // CraftBukkit int tickSpeed = this.level.getGameRules().get(GameRules.RANDOM_TICK_SPEED); -@@ -567,7 +576,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -565,7 +574,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon profiler.popPush("shuffleSpawningChunks"); // Paper start - chunk tick iteration optimisation this.shuffleRandom.setSeed(this.level.getRandom().nextLong()); @@ -77,10 +77,10 @@ index fcb23814c2539f4e31ed5191e03cc28f4e7f9c2d..0edfb9866ee2d0ff71394bc74f139fe3 profiler.popPush("tickSpawningChunks"); diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index 82e87270d1ad89ad7aa56e028ced6b998ea0eca5..558abe7248725a58b5aa1a36c7e372824c0fbe2e 100644 +index c8dd908ea52305d7ae1235ea430a26c88306f183..85d22ea2e0fb7c59c387df056ace9ef556f489a2 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java -@@ -430,6 +430,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc +@@ -411,6 +411,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc public boolean queueHealthUpdatePacket; public net.minecraft.network.protocol.game.@Nullable ClientboundSetHealthPacket queuedHealthUpdatePacket; // Paper end - cancellable death event @@ -92,7 +92,7 @@ index 82e87270d1ad89ad7aa56e028ced6b998ea0eca5..558abe7248725a58b5aa1a36c7e37282 public @Nullable String lastKnownName; // Better rename detection public String displayName; diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java -index 8ab7bdd487de7dbc5ea19d1f361ec52e367f8251..d9c1a04e53bec4a268ab58bfc8025c00bd3fa8ce 100644 +index c0a986932c25d056877e3147d09dd50d1264b13d..b1ecbc50ea908c6c11e9e1ae2f73d1eed669db08 100644 --- a/net/minecraft/world/level/NaturalSpawner.java +++ b/net/minecraft/world/level/NaturalSpawner.java @@ -70,6 +70,18 @@ public final class NaturalSpawner { diff --git a/paper-server/patches/features/0028-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch b/paper-server/patches/features/0028-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch index 115453902f6e..b3eb7c1ad2ce 100644 --- a/paper-server/patches/features/0028-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch +++ b/paper-server/patches/features/0028-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Improve cancelling PreCreatureSpawnEvent with per player mob diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java -index 15d9c2d601a48d2288d5110f9991280129f43087..01cbebd70223389c6d952be23e5d739579b96ead 100644 +index 2afc89ab4404cf04ba1da813f1c4a05baa4f44e3..42ec67c53c35189838ce4767c2be620e05108159 100644 --- a/net/minecraft/server/level/ChunkMap.java +++ b/net/minecraft/server/level/ChunkMap.java @@ -257,8 +257,25 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP @@ -37,10 +37,10 @@ index 15d9c2d601a48d2288d5110f9991280129f43087..01cbebd70223389c6d952be23e5d7395 // Paper end - Optional per player mob spawns diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index 0edfb9866ee2d0ff71394bc74f139fe3b4550c42..5a309dcf3c357f6b3a12d74aca2e9592f952318c 100644 +index a5023f6f7d912560f3488b1823ee22a1dc639203..0609c4e7ac7d027ed01684ab4fec2a7838f1f30f 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java -@@ -542,7 +542,17 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -540,7 +540,17 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon if ((this.spawnFriendlies || this.spawnEnemies) && this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { // don't count mobs when animals and monsters are disabled // re-set mob counts for (ServerPlayer player : this.level.players()) { @@ -60,10 +60,10 @@ index 0edfb9866ee2d0ff71394bc74f139fe3b4550c42..5a309dcf3c357f6b3a12d74aca2e9592 spawnCookie = NaturalSpawner.createState(chunkCount, this.level.getAllEntities(), this::getFullChunk, null, true); } else { diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index 558abe7248725a58b5aa1a36c7e372824c0fbe2e..06b938013f9dbee4fb3b86979d5a42f28a0ea33e 100644 +index 85d22ea2e0fb7c59c387df056ace9ef556f489a2..d354517cbfdcee0648daa8f3eb035b2024d5ce72 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java -@@ -434,6 +434,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc +@@ -415,6 +415,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc public static final int MOBCATEGORY_TOTAL_ENUMS = net.minecraft.world.entity.MobCategory.values().length; public final int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS]; // Paper end - Optional per player mob spawns @@ -72,7 +72,7 @@ index 558abe7248725a58b5aa1a36c7e372824c0fbe2e..06b938013f9dbee4fb3b86979d5a42f2 public @Nullable String lastKnownName; // Better rename detection public String displayName; diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java -index d9c1a04e53bec4a268ab58bfc8025c00bd3fa8ce..427573fc142c107d3fcc2be9000316221039ba4c 100644 +index b1ecbc50ea908c6c11e9e1ae2f73d1eed669db08..9764163a32b0389afa50ba093d0647de04d5119e 100644 --- a/net/minecraft/world/level/NaturalSpawner.java +++ b/net/minecraft/world/level/NaturalSpawner.java @@ -307,6 +307,11 @@ public final class NaturalSpawner { diff --git a/paper-server/patches/features/0029-Optimize-Hoppers.patch b/paper-server/patches/features/0029-Optimize-Hoppers.patch index 7b033ec6c836..ed6e4d516a27 100644 --- a/paper-server/patches/features/0029-Optimize-Hoppers.patch +++ b/paper-server/patches/features/0029-Optimize-Hoppers.patch @@ -48,10 +48,10 @@ index 0000000000000000000000000000000000000000..24a2090e068ad3c0d08705050944abdf + } +} diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index af1f5e83bd24e671399af2a9aadc8e11959ec5f4..b9efed1df74651c894a416f1d3db320d4ab20401 100644 +index e69b540be1e0f0c699a57e07057cee74d4f8a771..cc35c6271c98615a486422d0490145227626bd85 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java -@@ -1850,6 +1850,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Paper - BlockPhysicsEvent level.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent level.updateLagCompensationTick(); // Paper - lag compensation @@ -60,10 +60,10 @@ index af1f5e83bd24e671399af2a9aadc8e11959ec5f4..b9efed1df74651c894a416f1d3db320d profiler.push("tick"); diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java -index ee0fde839f06b6b900053b792617f3738b8000e8..54d67c847c1de9ee216cedb0527136f50223ea2d 100644 +index 95e0fb32457f2113de8d3e78fc18398bec83eccf..1d08ac66271a441811a157ed6619b14bf58c403f 100644 --- a/net/minecraft/world/item/ItemStack.java +++ b/net/minecraft/world/item/ItemStack.java -@@ -807,10 +807,16 @@ public final class ItemStack implements DataComponentHolder, ItemInstance { +@@ -807,11 +807,17 @@ public final class ItemStack implements DataComponentHolder, ItemInstance { } public ItemStack copy() { @@ -76,17 +76,18 @@ index ee0fde839f06b6b900053b792617f3738b8000e8..54d67c847c1de9ee216cedb0527136f5 + if (!originalItem && this.isEmpty()) { + // Paper end - Perf: Optimize Hoppers return EMPTY; - } else { -- ItemStack copy = new ItemStack(this.typeHolder(), this.count, this.components.copy()); -+ ItemStack copy = new ItemStack(originalItem ? this.item : this.typeHolder(), this.count, this.components.copy()); // Paper - Perf: Optimize Hoppers - copy.setPopTime(this.getPopTime()); - return copy; } + +- ItemStack copy = new ItemStack(this.typeHolder(), this.count, this.components.copy()); ++ ItemStack copy = new ItemStack(originalItem ? this.item : this.typeHolder(), this.count, this.components.copy()); // Paper - Perf: Optimize Hoppers + copy.setPopTime(this.getPopTime()); + return copy; + } diff --git a/net/minecraft/world/level/block/entity/BlockEntity.java b/net/minecraft/world/level/block/entity/BlockEntity.java -index 04cfd03f29b319225011b86d459626a6872a5e87..865f08c92946010a36947b7766b957f4c0517285 100644 +index 0e2b537ff5230e6bdb55e9e99d6b2202479b8fd2..2c9fb60cae8065b1cd70d6ec53122cec9cf7f2a7 100644 --- a/net/minecraft/world/level/block/entity/BlockEntity.java +++ b/net/minecraft/world/level/block/entity/BlockEntity.java -@@ -40,6 +40,7 @@ import org.jspecify.annotations.Nullable; +@@ -39,6 +39,7 @@ import org.jspecify.annotations.Nullable; import org.slf4j.Logger; public abstract class BlockEntity implements DebugValueSource, TypedInstance> { @@ -94,7 +95,7 @@ index 04cfd03f29b319225011b86d459626a6872a5e87..865f08c92946010a36947b7766b957f4 // CraftBukkit start - data containers private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry(); public final org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer persistentDataContainer; -@@ -229,6 +230,7 @@ public abstract class BlockEntity implements DebugValueSource, TypedInstance test) { + if (container instanceof WorldlyContainer) { + for (int slot : ((WorldlyContainer) container).getSlotsForFace(direction)) { @@ -362,78 +410,32 @@ index 0703e50ca36fbc084ed06811678efd0eb7d26455..085ed0eecc47cf9c0fa9fc26b3f7b852 + for (int slot = 0; slot < size; slot++) { + if (test.test(container.getItem(slot), slot)) { + return true; -+ } -+ } -+ } + } + } + } + return true; + } + private static final java.util.function.BiPredicate STACK_SIZE_TEST = (itemStack, i) -> itemStack.getCount() >= itemStack.getMaxStackSize(); + private static final java.util.function.BiPredicate IS_EMPTY_TEST = (itemStack, i) -> itemStack.isEmpty(); + // Paper end - Perf: Optimize Hoppers + +- return false; ++ private static boolean ejectItems(final Level level, final BlockPos blockPos, final HopperBlockEntity self) { ++ Container container = getAttachedContainer(level, blockPos, self); ++ if (container == null) { ++ return false; ++ } + - private static boolean ejectItems(final Level level, final BlockPos blockPos, final HopperBlockEntity self) { - Container container = getAttachedContainer(level, blockPos, self); - if (container == null) { -@@ -188,57 +426,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - if (isFullContainer(container, direction)) { - return false; - } else { -- for (int slot = 0; slot < self.getContainerSize(); slot++) { -- ItemStack itemStack = self.getItem(slot); -- if (!itemStack.isEmpty()) { -- int originalCount = itemStack.getCount(); -- // CraftBukkit start - Call event when pushing items into other inventories -- ItemStack original = itemStack.copy(); -- org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror( -- self.removeItem(slot, level.spigotConfig.hopperAmount) -- ); // Spigot -- -- org.bukkit.inventory.Inventory destinationInventory; -- // Have to special case large chests as they work oddly -- if (container instanceof final net.minecraft.world.CompoundContainer compoundContainer) { -- destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer); -- } else if (container.getOwner() != null) { -- destinationInventory = container.getOwner().getInventory(); -- } else { -- destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(container); -- } -- -- org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent( -- self.getOwner().getInventory(), -- oitemstack, -- destinationInventory, -- true -- ); -- if (!event.callEvent()) { -- self.setItem(slot, original); -- self.setCooldown(level.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot -- return false; -- } -- int origCount = event.getItem().getAmount(); // Spigot -- ItemStack result = HopperBlockEntity.addItem(self, container, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), direction); -- // CraftBukkit end -- -- if (result.isEmpty()) { -- container.setChanged(); -- return true; -- } -- -- itemStack.setCount(originalCount); -- // Spigot start -- itemStack.shrink(origCount - result.getCount()); -- if (originalCount <= level.spigotConfig.hopperAmount) { -- // Spigot end -- self.setItem(slot, itemStack); -- } -- } -- } -- -- return false; -+ return hopperPush(level, container, direction, self); // Paper - Perf: Optimize Hoppers - } - } ++ Direction direction = self.facing.getOpposite(); ++ if (isFullContainer(container, direction)) { ++ return false; ++ } ++ ++ return hopperPush(level, container, direction, self); // Paper - Perf: Optimize Hoppers } -@@ -293,6 +481,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen + + private static int[] getSlots(final Container container, final Direction direction) { +@@ -292,6 +481,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen Container container = getSourceContainer(level, hopper, blockPos, blockState); if (container != null) { Direction direction = Direction.DOWN; @@ -441,7 +443,7 @@ index 0703e50ca36fbc084ed06811678efd0eb7d26455..085ed0eecc47cf9c0fa9fc26b3f7b852 for (int slot : getSlots(container, direction)) { if (tryTakeInItemFromSlot(hopper, container, slot, direction, level)) { // Spigot -@@ -320,54 +509,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen +@@ -319,54 +509,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen private static boolean tryTakeInItemFromSlot(final Hopper hopper, final Container container, final int slot, final Direction direction, final Level level) { // Spigot ItemStack itemStack = container.getItem(slot); if (!itemStack.isEmpty() && canTakeItemFromContainer(hopper, container, itemStack, slot, direction)) { @@ -497,7 +499,7 @@ index 0703e50ca36fbc084ed06811678efd0eb7d26455..085ed0eecc47cf9c0fa9fc26b3f7b852 } return false; -@@ -376,13 +518,15 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen +@@ -375,13 +518,15 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen public static boolean addItem(final Container container, final ItemEntity entity) { boolean changed = false; // CraftBukkit start @@ -514,7 +516,7 @@ index 0703e50ca36fbc084ed06811678efd0eb7d26455..085ed0eecc47cf9c0fa9fc26b3f7b852 ItemStack copy = entity.getItem().copy(); ItemStack result = addItem(null, container, copy, null); if (result.isEmpty()) { -@@ -441,7 +585,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen +@@ -440,7 +585,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen itemStack = itemStack.split(container.getMaxStackSize()); } // Spigot end @@ -524,7 +526,7 @@ index 0703e50ca36fbc084ed06811678efd0eb7d26455..085ed0eecc47cf9c0fa9fc26b3f7b852 itemStack = leftover; // Paper - Make hoppers respect inventory max stack size success = true; } else if (canMergeItems(current, itemStack)) { -@@ -527,14 +673,22 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen +@@ -526,14 +673,22 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen } public static @Nullable Container getContainerAt(final Level level, final BlockPos pos) { @@ -549,7 +551,7 @@ index 0703e50ca36fbc084ed06811678efd0eb7d26455..085ed0eecc47cf9c0fa9fc26b3f7b852 result = getEntityContainer(level, x, y, z); } -@@ -558,14 +712,14 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen +@@ -559,14 +714,14 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen } private static @Nullable Container getEntityContainer(final Level level, final double x, final double y, final double z) { @@ -568,7 +570,7 @@ index 0703e50ca36fbc084ed06811678efd0eb7d26455..085ed0eecc47cf9c0fa9fc26b3f7b852 @Override diff --git a/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java b/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java -index 557ef92009f51b54e710f105254eb3e352c6057c..2270b5e5696ef65366c372b9606c5f03b6a11565 100644 +index 9ded208a6e3b86e24a36791f8bb74cec08cd6e9c..5019356f5f29be895d1b2ea8ee9a0e0f6f237a6a 100644 --- a/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java +++ b/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java @@ -52,7 +52,7 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc diff --git a/paper-server/patches/features/0030-Anti-Xray.patch b/paper-server/patches/features/0030-Anti-Xray.patch index 7ad1ed261c1d..a5a47c9de6c2 100644 --- a/paper-server/patches/features/0030-Anti-Xray.patch +++ b/paper-server/patches/features/0030-Anti-Xray.patch @@ -55,7 +55,7 @@ index cde895c776c3077292c1a8381461075b1fbc45c7..b817e30a23a0030f948ff6c12175767f if (buffer.writerIndex() != buffer.capacity()) { diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java -index 488d5654f5414c9950f19e86a791507366366e01..42bfd4b3b626ef66b0f2ef8438add5342b367800 100644 +index d7a1dde0452632d46fe594afa158cace71698de8..a52f93d0563f713b1d2b707cdb6ab74e4793a54d 100644 --- a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java +++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java @@ -41,13 +41,23 @@ public class ClientboundLevelChunkPacketData { @@ -155,7 +155,7 @@ index a94e6ca1d396b6b0781de5d550c4a804274ee003..a1018e9ca9dfb978d6e6633577abd7d5 private ClientboundLevelChunkWithLightPacket(final RegistryFriendlyByteBuf input) { diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 4ac7ef5a1ed1fac04a9fd246212f59919deb498c..e562aec4366d7724f915e3dd5ae440a77e0947c5 100644 +index ac3c00ccb3025cd45beb3c6b96f11dad38f78366..a9a00f9be49344b17b27f64834102df3a323f03b 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java @@ -631,7 +631,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet @@ -168,10 +168,10 @@ index 4ac7ef5a1ed1fac04a9fd246212f59919deb498c..e562aec4366d7724f915e3dd5ae440a7 this.weatherData.setLevel(this); this.typeKey = typeKey; diff --git a/net/minecraft/server/level/ServerPlayerGameMode.java b/net/minecraft/server/level/ServerPlayerGameMode.java -index f1faa0439bf5bce583e70ce37ade4b7e66daaaa4..f7390b91fe1866c6a11beb93711d0fcde4293164 100644 +index 837f8de90fddb5f458d44ee42ea11557463454c3..515dfa9c71333f68d6a42535f98977b5681eb407 100644 --- a/net/minecraft/server/level/ServerPlayerGameMode.java +++ b/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -321,6 +321,7 @@ public class ServerPlayerGameMode { +@@ -320,6 +320,7 @@ public class ServerPlayerGameMode { org.bukkit.craftbukkit.event.CraftEventFactory.callBlockDamageAbortEvent(this.player, pos, this.player.getInventory().getSelectedItem()); // CraftBukkit } } @@ -196,10 +196,10 @@ index ec40f02032f965f548b0c0a29aa9d9bbad6f439b..373da9d604cfb1614a0618d856aefd2b if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) { new io.papermc.paper.event.packet.PlayerChunkLoadEvent(new org.bukkit.craftbukkit.CraftChunk(chunk), connection.getPlayer().getBukkitEntity()).callEvent(); diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java -index 5e11abcfd681d86b1c0e282cf901108822766ce2..3020a3208b14bb483b08cf59a796fb83c2403d1c 100644 +index bab8c73be9537a1d531871b1b72bed87d2e0956e..02d19fc610e738f5ed12c23ab92bbdcbabaeced3 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java -@@ -331,7 +331,7 @@ public abstract class PlayerList { +@@ -330,7 +330,7 @@ public abstract class PlayerList { .getOrThrow(net.minecraft.world.level.biome.Biomes.PLAINS); player.connection.send(new net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket( new net.minecraft.world.level.chunk.EmptyLevelChunk(level, player.chunkPosition(), plains), @@ -209,7 +209,7 @@ index 5e11abcfd681d86b1c0e282cf901108822766ce2..3020a3208b14bb483b08cf59a796fb83 } // Paper end - Send empty chunk diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 829bb616e5d72b955248bbc150254c239176ce64..4b228b5c563e40b6f301df22b5c8a7f7988cb072 100644 +index 5a5f7cbc0217ab7aa034698802f634d149662da1..f4302e835fa9684d0fc7d6b65075ec3ec40f8f9f 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java @@ -145,6 +145,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl @@ -238,14 +238,14 @@ index 829bb616e5d72b955248bbc150254c239176ce64..4b228b5c563e40b6f301df22b5c8a7f7 } // Paper start - Cancel hit for vanished players -@@ -1085,6 +1088,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl - } - // CraftBukkit end - capture blockstates - BlockState oldState = chunk.setBlockState(pos, blockState, updateFlags); -+ this.chunkPacketBlockController.onBlockChange(this, pos, blockState, oldState, updateFlags, updateLimit); // Paper - Anti-Xray - if (oldState == null) { - // CraftBukkit start - remove blockstate if failed (or the same) - if (this.captureBlockStates && captured) { +@@ -1088,6 +1091,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + } + // CraftBukkit end - capture blockstates + BlockState oldState = chunk.setBlockState(pos, blockState, updateFlags); ++ this.chunkPacketBlockController.onBlockChange(this, pos, blockState, oldState, updateFlags, updateLimit); // Paper - Anti-Xray + if (oldState == null) { + // CraftBukkit start - remove blockstate if failed (or the same) + if (this.captureBlockStates && captured) { diff --git a/net/minecraft/world/level/chunk/ChunkAccess.java b/net/minecraft/world/level/chunk/ChunkAccess.java index c974b1c276d29610cb59566afaad19f5bcf0c602..c73b9871faa87493e081cb54e1bf1dce487359c6 100644 --- a/net/minecraft/world/level/chunk/ChunkAccess.java @@ -273,10 +273,10 @@ index c974b1c276d29610cb59566afaad19f5bcf0c602..c73b9871faa87493e081cb54e1bf1dce } } diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java -index b5b514b292f9fdbe410aba5facec1638682c9075..595e97d2772b504eb6a08e84e4f4a138eb7c5f37 100644 +index 536c24ec46bdf571637376728aee06755a6256ef..b381c4d5a8b981f34852d029bbe46374d24f7879 100644 --- a/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java -@@ -152,7 +152,7 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot +@@ -151,7 +151,7 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot final LevelChunk.@Nullable PostLoadProcessor postLoad, final @Nullable BlendingData blendingData ) { @@ -286,10 +286,10 @@ index b5b514b292f9fdbe410aba5facec1638682c9075..595e97d2772b504eb6a08e84e4f4a138 this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap<>(); diff --git a/net/minecraft/world/level/chunk/LevelChunkSection.java b/net/minecraft/world/level/chunk/LevelChunkSection.java -index 398018ad7037669a756f804403fd76cf333a06de..d274149a977ed828b6bd02d88d2850521ede6c60 100644 +index 0e7bb7db9e46b2cade771fa5e94469023d8b47b0..0f807317cc7fa113ee57ab31f91bb6b8df7c4ae0 100644 --- a/net/minecraft/world/level/chunk/LevelChunkSection.java +++ b/net/minecraft/world/level/chunk/LevelChunkSection.java -@@ -61,8 +61,14 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_ +@@ -60,8 +60,14 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_ this.recalcBlockCounts(); } @@ -305,7 +305,7 @@ index 398018ad7037669a756f804403fd76cf333a06de..d274149a977ed828b6bd02d88d285052 this.biomes = containerFactory.createForBiomes(); } -@@ -284,11 +290,17 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_ +@@ -283,11 +289,17 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_ this.biomes = biomes; } @@ -326,7 +326,7 @@ index 398018ad7037669a756f804403fd76cf333a06de..d274149a977ed828b6bd02d88d285052 public int getSerializedSize() { diff --git a/net/minecraft/world/level/chunk/PalettedContainer.java b/net/minecraft/world/level/chunk/PalettedContainer.java -index edf2990bfbe3d6b64eed85446eef207d2506efc5..09111c50cb34b643b7717f107a6f5bf6953bf0b2 100644 +index 4eeb920e4e71ab91cdb5a41f1eabdd47182c80fb..66a05adab494f8674f0636f8b34533f8ef640028 100644 --- a/net/minecraft/world/level/chunk/PalettedContainer.java +++ b/net/minecraft/world/level/chunk/PalettedContainer.java @@ -26,6 +26,7 @@ public class PalettedContainer implements PaletteResize, PalettedContainer @@ -421,7 +421,7 @@ index edf2990bfbe3d6b64eed85446eef207d2506efc5..09111c50cb34b643b7717f107a6f5bf6 this.data = this.createOrReuseData(null, 0); this.data.palette.idFor(initialValue, this); @@ -123,15 +169,39 @@ public class PalettedContainer implements PaletteResize, PalettedContainer - } + return new PalettedContainer.Data<>(dataConfiguration, storage, palette); } + // Paper start - Anti-Xray @@ -462,7 +462,7 @@ index edf2990bfbe3d6b64eed85446eef207d2506efc5..09111c50cb34b643b7717f107a6f5bf6 public synchronized T getAndSet(final int x, final int y, final int z, final T value) { // Paper - synchronize this.acquire(); -@@ -203,6 +273,7 @@ public class PalettedContainer implements PaletteResize, PalettedContainer +@@ -200,6 +270,7 @@ public class PalettedContainer implements PaletteResize, PalettedContainer newData.palette.read(buffer, this.strategy.globalMap()); buffer.readFixedSizeLongArray(newData.storage.getRaw()); this.data = newData; @@ -470,7 +470,7 @@ index edf2990bfbe3d6b64eed85446eef207d2506efc5..09111c50cb34b643b7717f107a6f5bf6 this.updateData(this.data); // Paper - optimise palette reads } finally { this.release(); -@@ -210,18 +281,31 @@ public class PalettedContainer implements PaletteResize, PalettedContainer +@@ -207,18 +278,31 @@ public class PalettedContainer implements PaletteResize, PalettedContainer } @Override @@ -504,16 +504,16 @@ index edf2990bfbe3d6b64eed85446eef207d2506efc5..09111c50cb34b643b7717f107a6f5bf6 List paletteEntries = discData.paletteEntries(); int entryCount = strategy.entryCount(); Configuration storedConfiguration = strategy.getConfigurationForPaletteSize(paletteEntries.size()); -@@ -259,7 +343,7 @@ public class PalettedContainer implements PaletteResize, PalettedContainer - } +@@ -257,7 +341,7 @@ public class PalettedContainer implements PaletteResize, PalettedContainer } - -- return DataResult.success(new PalettedContainer<>(strategy, storedConfiguration, storage, palette)); -+ return DataResult.success(new PalettedContainer<>(strategy, storedConfiguration, storage, palette, paletteEntries, defaultValue, presetValues)); // Paper - Anti-Xray - Add preset values } + +- return DataResult.success(new PalettedContainer<>(strategy, storedConfiguration, storage, palette)); ++ return DataResult.success(new PalettedContainer<>(strategy, storedConfiguration, storage, palette, paletteEntries, defaultValue, presetValues)); // Paper - Anti-Xray - Add preset values } -@@ -329,12 +413,12 @@ public class PalettedContainer implements PaletteResize, PalettedContainer + @Override +@@ -323,12 +407,12 @@ public class PalettedContainer implements PaletteResize, PalettedContainer @Override public PalettedContainer copy() { @@ -528,7 +528,7 @@ index edf2990bfbe3d6b64eed85446eef207d2506efc5..09111c50cb34b643b7717f107a6f5bf6 } @Override -@@ -404,9 +488,16 @@ public class PalettedContainer implements PaletteResize, PalettedContainer +@@ -398,9 +482,16 @@ public class PalettedContainer implements PaletteResize, PalettedContainer return 1 + this.palette.getSerializedSize(globalMap) + this.storage.getRaw().length * 8; } @@ -587,7 +587,7 @@ index 9977331d182cbc592f00006aabce23f0f69d2393..cd20a791b101548367ed53080f78e78b } } diff --git a/net/minecraft/world/level/chunk/PalettedContainerRO.java b/net/minecraft/world/level/chunk/PalettedContainerRO.java -index d2a2d435d0eda14a04f2c8582abffb8f98092a59..1498e9a760878f444debac9d4257d096731bb3ba 100644 +index 4607d2d7591a35d09d748d1ecf7582947bb86f39..f5f40aa2fd1b478045cb9a28b5ae11bc19f337f0 100644 --- a/net/minecraft/world/level/chunk/PalettedContainerRO.java +++ b/net/minecraft/world/level/chunk/PalettedContainerRO.java @@ -14,7 +14,11 @@ public interface PalettedContainerRO { @@ -603,7 +603,7 @@ index d2a2d435d0eda14a04f2c8582abffb8f98092a59..1498e9a760878f444debac9d4257d096 int getSerializedSize(); diff --git a/net/minecraft/world/level/chunk/Strategy.java b/net/minecraft/world/level/chunk/Strategy.java -index 45ff1447312f239154930f748637f413e2ea8f87..a0f8b23612f8315eef2aaf4c036c2ec759aafa66 100644 +index 5c518b6ec7da546460884c37e9af682b6ab9fc22..958be147cd940ac430576ca5b4ada70fa5d051e3 100644 --- a/net/minecraft/world/level/chunk/Strategy.java +++ b/net/minecraft/world/level/chunk/Strategy.java @@ -4,7 +4,7 @@ import net.minecraft.core.IdMap; @@ -616,7 +616,7 @@ index 45ff1447312f239154930f748637f413e2ea8f87..a0f8b23612f8315eef2aaf4c036c2ec7 private static final Palette.Factory HASHMAP_PALETTE_FACTORY = HashMapPalette::create; private static final Configuration ZERO_BITS = new Configuration.Simple(SINGLE_VALUE_PALETTE_FACTORY, 0); diff --git a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java -index df0bb06176ad5cce3ed8785d22d68b2dcbf5a8ca..9823f20186679d75444eff2b7a7b9cf8bb2ef575 100644 +index 98fb7a282a33f4391de124ed9be9bcf069178516..7d29fdc6548324d97ec34d476b5b48ec0bdba0d2 100644 --- a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java +++ b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java @@ -141,6 +141,7 @@ public record SerializableChunkData( @@ -626,17 +626,17 @@ index df0bb06176ad5cce3ed8785d22d68b2dcbf5a8ca..9823f20186679d75444eff2b7a7b9cf8 + net.minecraft.server.level.ServerLevel serverLevel = (net.minecraft.server.level.ServerLevel) levelHeight; // Paper - Anti-Xray This is is seemingly only called from ChunkMap, where, we have a server level. We'll fight this later if needed. if (chunkData.getString("Status").isEmpty()) { return null; - } else { -@@ -201,9 +202,11 @@ public record SerializableChunkData( - int y = sectionTag.getByteOr("Y", (byte)0); - LevelChunkSection section; - if (y >= levelHeight.getMinSectionY() && y <= levelHeight.getMaxSectionY()) { -+ final BlockState[] presetBlockStates = serverLevel.chunkPacketBlockController.getPresetBlockStates(serverLevel, chunkPos, y); // Paper - Anti-Xray - Add preset block states -+ final Codec> antiXrayBlockStateCodec = presetBlockStates == null ? blockStatesCodec : PalettedContainer.codecRW(BlockState.CODEC, containerFactory.blockStatesStrategy(), net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(), presetBlockStates); // Paper - Anti-Xray - PalettedContainer blocks = sectionTag.getCompound("block_states") - .map( -- container -> blockStatesCodec.parse(NbtOps.INSTANCE, container) -+ container -> antiXrayBlockStateCodec.parse(NbtOps.INSTANCE, container) // Paper - Anti-Xray - .promotePartial(msg -> logErrors(chunkPos, y, msg)) - .getOrThrow(SerializableChunkData.ChunkReadException::new) - ) + } +@@ -202,9 +203,11 @@ public record SerializableChunkData( + int y = sectionTag.getByteOr("Y", (byte)0); + LevelChunkSection section; + if (y >= levelHeight.getMinSectionY() && y <= levelHeight.getMaxSectionY()) { ++ final BlockState[] presetBlockStates = serverLevel.chunkPacketBlockController.getPresetBlockStates(serverLevel, chunkPos, y); // Paper - Anti-Xray - Add preset block states ++ final Codec> antiXrayBlockStateCodec = presetBlockStates == null ? blockStatesCodec : PalettedContainer.codecRW(BlockState.CODEC, containerFactory.blockStatesStrategy(), net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(), presetBlockStates); // Paper - Anti-Xray + PalettedContainer blocks = sectionTag.getCompound("block_states") + .map( +- container -> blockStatesCodec.parse(NbtOps.INSTANCE, container) ++ container -> antiXrayBlockStateCodec.parse(NbtOps.INSTANCE, container) // Paper - Anti-Xray + .promotePartial(msg -> logErrors(chunkPos, y, msg)) + .getOrThrow(SerializableChunkData.ChunkReadException::new) + ) diff --git a/paper-server/patches/features/0031-Delay-open-close-callbacks-for-chests.patch b/paper-server/patches/features/0031-Delay-open-close-callbacks-for-chests.patch index e65b1832872d..3b09bcfcc182 100644 --- a/paper-server/patches/features/0031-Delay-open-close-callbacks-for-chests.patch +++ b/paper-server/patches/features/0031-Delay-open-close-callbacks-for-chests.patch @@ -10,13 +10,13 @@ inside an entity status callback) or during shutdown (which has chunk loading restrictions due to the chunk system being halted). diff --git a/net/minecraft/world/level/block/entity/BarrelBlockEntity.java b/net/minecraft/world/level/block/entity/BarrelBlockEntity.java -index 9eb6cb86ff70f04863cae3def1006f82bcb4fa6b..da5fdf77dd26d97c8b92bac9a6af8d922c31eb9c 100644 +index b39b8176d6b1a1d3f7058387518bcbb71a3631bb..5ba46020b47edfc886ecd5c33483ebb0fa57e5dc 100644 --- a/net/minecraft/world/level/block/entity/BarrelBlockEntity.java +++ b/net/minecraft/world/level/block/entity/BarrelBlockEntity.java -@@ -66,6 +66,13 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity { - Objects.requireNonNull(BarrelBlockEntity.this); - } - +@@ -61,6 +61,13 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity { + private static final Component DEFAULT_NAME = Component.translatable("container.barrel"); + private NonNullList items = NonNullList.withSize(27, ItemStack.EMPTY); + public final ContainerOpenersCounter openersCounter = new ContainerOpenersCounter() { + // Paper start - delay open/close callbacks + @Override + public boolean delayCallbacks() { @@ -28,13 +28,14 @@ index 9eb6cb86ff70f04863cae3def1006f82bcb4fa6b..da5fdf77dd26d97c8b92bac9a6af8d92 protected void onOpen(final Level level, final BlockPos pos, final BlockState state) { BarrelBlockEntity.this.playSound(state, SoundEvents.BARREL_OPEN); diff --git a/net/minecraft/world/level/block/entity/ChestBlockEntity.java b/net/minecraft/world/level/block/entity/ChestBlockEntity.java -index 81a293cc13653a9a0336cb25d75273969fee4d16..8ebcce4c4971a11d367fb39e9c7fd280f63594e3 100644 +index 3635bd9e9b6292ff4389984eae1ae89ebca4be51..25c7e4dd69702ac89354040be9c471a8738c207c 100644 --- a/net/minecraft/world/level/block/entity/ChestBlockEntity.java +++ b/net/minecraft/world/level/block/entity/ChestBlockEntity.java -@@ -35,6 +35,13 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement - Objects.requireNonNull(ChestBlockEntity.this); - } - +@@ -30,6 +30,14 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement + public static final Component DEFAULT_NAME = Component.translatable("container.chest"); + private NonNullList items = NonNullList.withSize(27, ItemStack.EMPTY); + public final ContainerOpenersCounter openersCounter = new ContainerOpenersCounter() { ++ + // Paper start - delay open/close callbacks + @Override + public boolean delayCallbacks() { @@ -100,13 +101,14 @@ index baa8b5aba0500981a191626553d66650c7304b88..52737172ccfa0c7c977e4f2fe1db242e } } diff --git a/net/minecraft/world/level/block/entity/EnderChestBlockEntity.java b/net/minecraft/world/level/block/entity/EnderChestBlockEntity.java -index eeac644f60760570244380d3c454fd33e37b5a7f..751625124a87de63d933d9c7809e46361e3136a5 100644 +index 592d253921d8adb168840edcc1b24b64969e80f2..e0e72ff1a6c811ae843f2e1511628ab562530a0f 100644 --- a/net/minecraft/world/level/block/entity/EnderChestBlockEntity.java +++ b/net/minecraft/world/level/block/entity/EnderChestBlockEntity.java -@@ -18,6 +18,13 @@ public class EnderChestBlockEntity extends BlockEntity implements LidBlockEntity - Objects.requireNonNull(EnderChestBlockEntity.this); - } - +@@ -13,6 +13,14 @@ import net.minecraft.world.level.block.state.BlockState; + public class EnderChestBlockEntity extends BlockEntity implements LidBlockEntity { + private final ChestLidController chestLidController = new ChestLidController(); + public final ContainerOpenersCounter openersCounter = new ContainerOpenersCounter() { ++ + // Paper start - delay open/close callbacks + @Override + public boolean delayCallbacks() { diff --git a/paper-server/patches/features/0032-Improve-exact-choice-recipe-ingredients.patch b/paper-server/patches/features/0032-Improve-exact-choice-recipe-ingredients.patch index 60ecc236c6a2..ef902bd3347f 100644 --- a/paper-server/patches/features/0032-Improve-exact-choice-recipe-ingredients.patch +++ b/paper-server/patches/features/0032-Improve-exact-choice-recipe-ingredients.patch @@ -151,17 +151,17 @@ index 0000000000000000000000000000000000000000..f47c12e9dd6cfa857ca07a764edc22de + } +} diff --git a/net/minecraft/recipebook/ServerPlaceRecipe.java b/net/minecraft/recipebook/ServerPlaceRecipe.java -index 31f8aa58b48aeb64e57480490a449b6c46913880..b7ee9fe694ea37eeb58b5dded7967e7d0f338d0d 100644 +index da0380782a846dbb2657c58668e398f36f191c6e..d5ce83d5abd4de6f014a2827780170d3341eb927 100644 --- a/net/minecraft/recipebook/ServerPlaceRecipe.java +++ b/net/minecraft/recipebook/ServerPlaceRecipe.java -@@ -41,6 +41,7 @@ public class ServerPlaceRecipe> { - return RecipeBookMenu.PostPlaceAction.NOTHING; - } else { - StackedItemContents availableItems = new StackedItemContents(); -+ availableItems.initializeExtras(recipe.value(), null); // Paper - Improve exact choice recipe ingredients - inventory.fillStackedContents(availableItems); - menu.fillCraftSlotsStackedContents(availableItems); - return placer.tryPlaceRecipe(recipe, availableItems); +@@ -42,6 +42,7 @@ public class ServerPlaceRecipe> { + } + + StackedItemContents availableItems = new StackedItemContents(); ++ availableItems.initializeExtras(recipe.value(), null); // Paper - Improve exact choice recipe ingredients + inventory.fillStackedContents(availableItems); + menu.fillCraftSlotsStackedContents(availableItems); + return placer.tryPlaceRecipe(recipe, availableItems); @@ -100,7 +101,7 @@ public class ServerPlaceRecipe> { } @@ -195,7 +195,7 @@ index 31f8aa58b48aeb64e57480490a449b6c46913880..b7ee9fe694ea37eeb58b5dded7967e7d } return value; -@@ -165,7 +168,7 @@ public class ServerPlaceRecipe> { +@@ -167,7 +170,7 @@ public class ServerPlaceRecipe> { } } @@ -205,7 +205,7 @@ index 31f8aa58b48aeb64e57480490a449b6c46913880..b7ee9fe694ea37eeb58b5dded7967e7d int inventorySlotId = this.inventory.findSlotMatchingCraftingIngredient(itemInInventory, itemInTargetSlot); if (inventorySlotId == Inventory.NOT_FOUND_INDEX) { diff --git a/net/minecraft/world/entity/player/Inventory.java b/net/minecraft/world/entity/player/Inventory.java -index da8bab81e135a9b240fbeac0e9e1d2aa12c6212d..f004911c438e6f89d6e079437e3f4104d6cbacbd 100644 +index 5c083f2ec110c388be951014d8e5a6eb64ded371..cd7714dffcd7e7b6d96d18a97e65fd0914a739d1 100644 --- a/net/minecraft/world/entity/player/Inventory.java +++ b/net/minecraft/world/entity/player/Inventory.java @@ -252,12 +252,12 @@ public class Inventory implements Container, Nameable { @@ -225,10 +225,10 @@ index da8bab81e135a9b240fbeac0e9e1d2aa12c6212d..f004911c438e6f89d6e079437e3f4104 return i; } diff --git a/net/minecraft/world/entity/player/StackedContents.java b/net/minecraft/world/entity/player/StackedContents.java -index 889b8e6c3762203deccf657b505f6f29cc893526..6710653d033a48c4b3fc267496f93a2548b5c966 100644 +index 2a8527a2712de71f4c0d6a2e5af8dd3c01b8ff0a..5982b79f6b391ac9c01c452747fc235faf78369e 100644 --- a/net/minecraft/world/entity/player/StackedContents.java +++ b/net/minecraft/world/entity/player/StackedContents.java -@@ -14,7 +14,7 @@ import java.util.Objects; +@@ -13,7 +13,7 @@ import java.util.List; import org.jspecify.annotations.Nullable; public class StackedContents { @@ -237,7 +237,7 @@ index 889b8e6c3762203deccf657b505f6f29cc893526..6710653d033a48c4b3fc267496f93a25 private boolean hasAtLeast(final T item, final int count) { return this.amounts.getInt(item) >= count; -@@ -54,7 +54,7 @@ public class StackedContents { +@@ -53,7 +53,7 @@ public class StackedContents { private List getUniqueAvailableIngredientItems(final Iterable> ingredients) { List result = new ArrayList<>(); @@ -246,7 +246,7 @@ index 889b8e6c3762203deccf657b505f6f29cc893526..6710653d033a48c4b3fc267496f93a25 if (availableItem.getIntValue() > 0 && anyIngredientMatches(ingredients, availableItem.getKey())) { result.add(availableItem.getKey()); } -@@ -76,13 +76,13 @@ public class StackedContents { +@@ -75,13 +75,13 @@ public class StackedContents { @VisibleForTesting public int getResultUpperBound(final List> ingredients) { int min = Integer.MAX_VALUE; @@ -344,7 +344,7 @@ index ffaa8e450a11a01060b6847d1b66a76323f9d8ba..1ace17d8fc7e7b8b4722a1889d49233c } diff --git a/net/minecraft/world/item/crafting/Ingredient.java b/net/minecraft/world/item/crafting/Ingredient.java -index 3a8a07712a15167dabd12d4bfd258de11706ce93..1deeb3fd148c5d59250346147681b7e8f2147574 100644 +index 653fb104bb51fb738aa3ad22093c24f196f33df2..d4601c6a77f89d89ac9f042ee7b8c25461409523 100644 --- a/net/minecraft/world/item/crafting/Ingredient.java +++ b/net/minecraft/world/item/crafting/Ingredient.java @@ -22,7 +22,7 @@ import net.minecraft.world.item.Items; @@ -383,7 +383,7 @@ index 3a8a07712a15167dabd12d4bfd258de11706ce93..1deeb3fd148c5d59250346147681b7e8 return ingredient; } // CraftBukkit end -@@ -79,21 +83,22 @@ public final class Ingredient implements Predicate, StackedContents.I +@@ -81,21 +85,22 @@ public final class Ingredient implements Predicate, StackedContents.I public boolean test(final ItemStack input) { // CraftBukkit start if (this.isExact()) { @@ -415,7 +415,7 @@ index 3a8a07712a15167dabd12d4bfd258de11706ce93..1deeb3fd148c5d59250346147681b7e8 } @Override -@@ -118,6 +123,11 @@ public final class Ingredient implements Predicate, StackedContents.I +@@ -120,6 +125,11 @@ public final class Ingredient implements Predicate, StackedContents.I } public SlotDisplay display() { diff --git a/paper-server/patches/sources/com/mojang/math/OctahedralGroup.java.patch b/paper-server/patches/sources/com/mojang/math/OctahedralGroup.java.patch index 590b8b09adbb..78267026348b 100644 --- a/paper-server/patches/sources/com/mojang/math/OctahedralGroup.java.patch +++ b/paper-server/patches/sources/com/mojang/math/OctahedralGroup.java.patch @@ -1,16 +1,18 @@ --- a/com/mojang/math/OctahedralGroup.java +++ b/com/mojang/math/OctahedralGroup.java -@@ -99,6 +_,12 @@ +@@ -99,6 +_,14 @@ .map(f -> Arrays.stream(values()).filter(s -> f.compose(s) == IDENTITY).findAny().get()) .toArray(OctahedralGroup[]::new); ++ // Paper start - Avoid Lazy Initialization for Enum Fields + static { + for (OctahedralGroup octahedralGroup : values()) { -+ octahedralGroup.initializeRotationDirections(); // Paper - Avoid Lazy Initialization for Enum Fields ++ octahedralGroup.initializeRotationDirections(); + } + } ++ // Paper end - Avoid Lazy Initialization for Enum Fields + - private OctahedralGroup(final String name, final SymmetricGroup3 permutation, final boolean invertX, final boolean invertY, final boolean invertZ) { + OctahedralGroup(final String name, final SymmetricGroup3 permutation, final boolean invertX, final boolean invertY, final boolean invertZ) { this.name = name; this.invertX = invertX; @@ -139,7 +_,7 @@ diff --git a/paper-server/patches/sources/net/minecraft/CrashReport.java.patch b/paper-server/patches/sources/net/minecraft/CrashReport.java.patch index be129bb6bd26..cd847e191d32 100644 --- a/paper-server/patches/sources/net/minecraft/CrashReport.java.patch +++ b/paper-server/patches/sources/net/minecraft/CrashReport.java.patch @@ -8,7 +8,7 @@ } public String getTitle() { -@@ -217,7 +_,7 @@ +@@ -214,7 +_,7 @@ } public static void preload() { diff --git a/paper-server/patches/sources/net/minecraft/advancements/criterion/LocationPredicate.java.patch b/paper-server/patches/sources/net/minecraft/advancements/criterion/LocationPredicate.java.patch index 1f1c3031b202..17c5ea52bfc2 100644 --- a/paper-server/patches/sources/net/minecraft/advancements/criterion/LocationPredicate.java.patch +++ b/paper-server/patches/sources/net/minecraft/advancements/criterion/LocationPredicate.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/advancements/criterion/LocationPredicate.java +++ b/net/minecraft/advancements/criterion/LocationPredicate.java -@@ -44,7 +_,7 @@ - public boolean matches(final ServerLevel level, final double x, final double y, final double z) { - if (this.position.isPresent() && !this.position.get().matches(x, y, z)) { +@@ -46,7 +_,7 @@ return false; -- } else if (this.dimension.isPresent() && this.dimension.get() != level.dimension()) { -+ } else if (this.dimension.isPresent() && this.dimension.get() != (io.papermc.paper.configuration.GlobalConfiguration.get().misc.strictAdvancementDimensionCheck ? level.dimension() : org.bukkit.craftbukkit.util.CraftDimensionUtil.getMainDimensionKey(level))) { // Paper - Add option for strict advancement dimension checks + } + +- if (this.dimension.isPresent() && this.dimension.get() != level.dimension()) { ++ if (this.dimension.isPresent() && this.dimension.get() != (io.papermc.paper.configuration.GlobalConfiguration.get().misc.strictAdvancementDimensionCheck ? level.dimension() : org.bukkit.craftbukkit.util.CraftDimensionUtil.getMainDimensionKey(level))) { // Paper - Add option for strict advancement dimension checks return false; - } else { - BlockPos pos = BlockPos.containing(x, y, z); + } + diff --git a/paper-server/patches/sources/net/minecraft/commands/Commands.java.patch b/paper-server/patches/sources/net/minecraft/commands/Commands.java.patch index cfed6bb42dec..bd76d801d6ee 100644 --- a/paper-server/patches/sources/net/minecraft/commands/Commands.java.patch +++ b/paper-server/patches/sources/net/minecraft/commands/Commands.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/commands/Commands.java +++ b/net/minecraft/commands/Commands.java -@@ -157,6 +_,7 @@ +@@ -156,6 +_,7 @@ import org.slf4j.Logger; public class Commands { @@ -8,7 +8,7 @@ public static final String COMMAND_PREFIX = "/"; private static final ThreadLocal<@Nullable ExecutionContext> CURRENT_EXECUTION_CONTEXT = new ThreadLocal<>(); private static final Logger LOGGER = LogUtils.getLogger(); -@@ -181,6 +_,7 @@ +@@ -180,6 +_,7 @@ @Override public boolean isRestricted(final CommandNode node) { @@ -16,7 +16,7 @@ Predicate requirement = node.getRequirement(); return !requirement.test(this.noPermissionSource); } -@@ -188,6 +_,11 @@ +@@ -187,6 +_,11 @@ private final CommandDispatcher dispatcher = new CommandDispatcher<>(); public Commands(final Commands.CommandSelection commandSelection, final CommandBuildContext context) { @@ -28,7 +28,7 @@ AdvancementCommands.register(this.dispatcher); AttributeCommand.register(this.dispatcher, context); ExecuteCommand.register(this.dispatcher, context); -@@ -299,6 +_,42 @@ +@@ -298,6 +_,42 @@ PublishCommand.register(this.dispatcher); } @@ -71,7 +71,7 @@ this.dispatcher.setConsumer(ExecutionCommandSource.resultConsumer()); } -@@ -318,6 +_,13 @@ +@@ -317,6 +_,13 @@ } public void performCommand(final ParseResults command, final String commandString) { @@ -85,36 +85,36 @@ CommandSourceStack sender = command.getContext().getSource(); Profiler.get().push(() -> "/" + commandString); ContextChain commandChain = finishParsing(command, commandString, sender); -@@ -331,10 +_,12 @@ +@@ -330,10 +_,12 @@ ) ); } -- } catch (Exception var12) { +- } catch (Exception e) { + // Paper start -+ } catch (Throwable var12) { // always gracefully handle it, no matter how bad:tm: -+ if (throwCommandError) throw var12; // rethrow directly if requested - MutableComponent hover = Component.literal(var12.getMessage() == null ? var12.getClass().getName() : var12.getMessage()); ++ } catch (Throwable e) { // always gracefully handle it, no matter how bad:tm: ++ if (throwCommandError) throw e; // rethrow directly if requested + MutableComponent hover = Component.literal(e.getMessage() == null ? e.getClass().getName() : e.getMessage()); - if (LOGGER.isDebugEnabled()) { -- LOGGER.error("Command exception: /{}", commandString, var12); -+ LOGGER.error("Command exception: /{}", commandString, var12); // Paper - always show execution exception in console log +- LOGGER.error("Command exception: /{}", commandString, e); ++ LOGGER.error("Command exception: /{}", commandString, e); // Paper - always show execution exception in console log + if (sender.getServer().isDebugging() || LOGGER.isDebugEnabled()) { // Paper - Debugging - StackTraceElement[] stackTrace = var12.getStackTrace(); + StackTraceElement[] stackTrace = e.getStackTrace(); for (int i = 0; i < Math.min(stackTrace.length, 3); i++) { -@@ -365,7 +_,11 @@ +@@ -364,7 +_,11 @@ return ContextChain.tryFlatten(command.getContext().build(commandString)) .orElseThrow(() -> CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownCommand().createWithContext(command.getReader())); - } catch (CommandSyntaxException var7) { -- sender.sendFailure(ComponentUtils.fromMessage(var7.getRawMessage())); + } catch (CommandSyntaxException e) { +- sender.sendFailure(ComponentUtils.fromMessage(e.getRawMessage())); + // Paper start - Add UnknownCommandEvent + final net.kyori.adventure.text.TextComponent.Builder builder = net.kyori.adventure.text.Component.text(); + // sender.sendFailure(ComponentUtils.fromMessage(var7.getRawMessage())); -+ builder.color(net.kyori.adventure.text.format.NamedTextColor.RED).append(io.papermc.paper.command.brigadier.MessageComponentSerializer.message().deserialize(var7.getRawMessage())); ++ builder.color(net.kyori.adventure.text.format.NamedTextColor.RED).append(io.papermc.paper.command.brigadier.MessageComponentSerializer.message().deserialize(e.getRawMessage())); + // Paper end - Add UnknownCommandEvent - if (var7.getInput() != null && var7.getCursor() >= 0) { - int cursor = Math.min(var7.getInput().length(), var7.getCursor()); + if (e.getInput() != null && e.getCursor() >= 0) { + int cursor = Math.min(e.getInput().length(), e.getCursor()); MutableComponent context = Component.empty() -@@ -382,7 +_,17 @@ +@@ -381,7 +_,17 @@ } context.append(Component.translatable("command.context.here").withStyle(ChatFormatting.RED, ChatFormatting.ITALIC)); @@ -133,7 +133,7 @@ } return null; -@@ -410,19 +_,112 @@ +@@ -409,19 +_,112 @@ } public void sendCommands(final ServerPlayer player) { @@ -249,7 +249,7 @@ if (builder.getRedirect() != null) { builder.redirect(converted.get(builder.getRedirect())); } -@@ -431,7 +_,7 @@ +@@ -430,7 +_,7 @@ converted.put(child, node); target.addChild(node); if (!child.getChildren().isEmpty()) { diff --git a/paper-server/patches/sources/net/minecraft/commands/arguments/EntityArgument.java.patch b/paper-server/patches/sources/net/minecraft/commands/arguments/EntityArgument.java.patch index b6cb3432e751..686ffc34053d 100644 --- a/paper-server/patches/sources/net/minecraft/commands/arguments/EntityArgument.java.patch +++ b/paper-server/patches/sources/net/minecraft/commands/arguments/EntityArgument.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/commands/arguments/EntityArgument.java +++ b/net/minecraft/commands/arguments/EntityArgument.java -@@ -107,9 +_,14 @@ +@@ -106,9 +_,14 @@ } private EntitySelector parse(final StringReader reader, final boolean allowSelectors) throws CommandSyntaxException { @@ -16,7 +16,7 @@ if (selector.getMaxResults() > 1 && this.single) { if (this.playersOnly) { reader.setCursor(0); -@@ -131,7 +_,13 @@ +@@ -130,7 +_,13 @@ if (contextBuilder.getSource() instanceof SharedSuggestionProvider source) { StringReader reader = new StringReader(builder.getInput()); reader.setCursor(builder.getStart()); diff --git a/paper-server/patches/sources/net/minecraft/core/Direction.java.patch b/paper-server/patches/sources/net/minecraft/core/Direction.java.patch index 4d521d485ece..9d42e33e9aff 100644 --- a/paper-server/patches/sources/net/minecraft/core/Direction.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/Direction.java.patch @@ -10,7 +10,7 @@ + private final int adjZ; + // Paper end - Perf: Inline shift direction fields + - private Direction( + Direction( final int data3d, final int oppositeIndex, @@ -81,6 +_,11 @@ diff --git a/paper-server/patches/sources/net/minecraft/core/HolderLookup.java.patch b/paper-server/patches/sources/net/minecraft/core/HolderLookup.java.patch index fb7582690da5..1971a90b4cc6 100644 --- a/paper-server/patches/sources/net/minecraft/core/HolderLookup.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/HolderLookup.java.patch @@ -1,19 +1,18 @@ --- a/net/minecraft/core/HolderLookup.java +++ b/net/minecraft/core/HolderLookup.java -@@ -69,6 +_,9 @@ +@@ -68,6 +_,8 @@ } - public interface RegistryLookup extends HolderLookup, HolderOwner { -+ + interface RegistryLookup extends HolderLookup, HolderOwner { + Optional getValueForCopying(ResourceKey resourceKey); // Paper - add method to get the value for pre-filling builders in the reg mod API + ResourceKey> key(); Lifecycle registryLifecycle(); -@@ -83,6 +_,13 @@ - Objects.requireNonNull(RegistryLookup.this); - } +@@ -78,6 +_,13 @@ + default HolderLookup.RegistryLookup filterElements(final Predicate filter) { + return new HolderLookup.RegistryLookup.Delegate() { + // Paper start - add getValueForCopying + @Override + public Optional getValueForCopying(final ResourceKey resourceKey) { @@ -24,9 +23,9 @@ @Override public HolderLookup.RegistryLookup parent() { return RegistryLookup.this; -@@ -102,6 +_,13 @@ +@@ -97,6 +_,13 @@ - public interface Delegate extends HolderLookup.RegistryLookup { + interface Delegate extends HolderLookup.RegistryLookup { HolderLookup.RegistryLookup parent(); + + // Paper start - add getValueForCopying diff --git a/paper-server/patches/sources/net/minecraft/core/MappedRegistry.java.patch b/paper-server/patches/sources/net/minecraft/core/MappedRegistry.java.patch index 3ea652f70b8c..ab63e3224eb9 100644 --- a/paper-server/patches/sources/net/minecraft/core/MappedRegistry.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/MappedRegistry.java.patch @@ -31,23 +31,23 @@ @Override public Stream> listTags() { -@@ -114,6 +_,7 @@ - this.toId.put(value, newId); - this.registrationInfos.put(key, registrationInfo); - this.registryLifecycle = this.registryLifecycle.add(registrationInfo.lifecycle()); -+ this.temporaryUnfrozenMap.put(key.identifier(), value); // Paper - support pre-filling in registry mod API - return holder; - } +@@ -117,6 +_,7 @@ + this.toId.put(value, newId); + this.registrationInfos.put(key, registrationInfo); + this.registryLifecycle = this.registryLifecycle.add(registrationInfo.lifecycle()); ++ this.temporaryUnfrozenMap.put(key.identifier(), value); // Paper - support pre-filling in registry mod API + return holder; } -@@ -275,6 +_,7 @@ - return this; - } else { - this.frozen = true; -+ this.temporaryUnfrozenMap.clear(); // Paper - support pre-filling in registry mod API - this.byValue.forEach((value, holder) -> holder.bindValue((T)value)); - List unboundEntries = this.byKey - .entrySet() -@@ -522,4 +_,13 @@ + +@@ -278,6 +_,7 @@ + } + + this.frozen = true; ++ this.temporaryUnfrozenMap.clear(); // Paper - support pre-filling in registry mod API + this.byValue.forEach((value, holder) -> holder.bindValue((T)value)); + List unboundEntries = this.byKey + .entrySet() +@@ -512,4 +_,13 @@ Stream> getTags(); } diff --git a/paper-server/patches/sources/net/minecraft/core/RegistrySetBuilder.java.patch b/paper-server/patches/sources/net/minecraft/core/RegistrySetBuilder.java.patch index 3f34cbfa1e2b..f65cdf1d81ab 100644 --- a/paper-server/patches/sources/net/minecraft/core/RegistrySetBuilder.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/RegistrySetBuilder.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/core/RegistrySetBuilder.java +++ b/net/minecraft/core/RegistrySetBuilder.java -@@ -42,6 +_,13 @@ +@@ -41,6 +_,13 @@ final Map, Holder.Reference> entries ) { return new RegistrySetBuilder.EmptyTagRegistryLookup(owner) { @@ -14,7 +14,7 @@ @Override public ResourceKey> key() { return key; -@@ -128,6 +_,13 @@ +@@ -123,6 +_,13 @@ public Optional> lookup(final ResourceKey> registryKey) { return getEntry(registryKey).map(Entry::opsInfo); } diff --git a/paper-server/patches/sources/net/minecraft/core/Rotations.java.patch b/paper-server/patches/sources/net/minecraft/core/Rotations.java.patch index 1aeb50910287..97edf73d1f85 100644 --- a/paper-server/patches/sources/net/minecraft/core/Rotations.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/Rotations.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/core/Rotations.java +++ b/net/minecraft/core/Rotations.java -@@ -26,11 +_,22 @@ +@@ -26,10 +_,21 @@ output.writeFloat(value.z); } }; @@ -12,14 +12,13 @@ + SKIP_VALIDATION = false; + return rotations; + } -+ // Paper end - add internal method for skipping validation for plugins using userdev ++ // Paper end - add internal method for skipping validation for plugins using userdev - public Rotations(float x, float y, float z) { + public Rotations { + if (!SKIP_VALIDATION) { // Paper - add internal method for skipping validation for plugins using userdev x = !Float.isInfinite(x) && !Float.isNaN(x) ? x % 360.0F : 0.0F; y = !Float.isInfinite(y) && !Float.isNaN(y) ? y % 360.0F : 0.0F; z = !Float.isInfinite(z) && !Float.isNaN(z) ? z % 360.0F : 0.0F; + } // Paper - add internal method for skipping validation for plugins using userdev - this.x = x; - this.y = y; - this.z = z; + } + } diff --git a/paper-server/patches/sources/net/minecraft/core/cauldron/CauldronInteraction.java.patch b/paper-server/patches/sources/net/minecraft/core/cauldron/CauldronInteraction.java.patch index 70d5f3e67fab..b53444754aeb 100644 --- a/paper-server/patches/sources/net/minecraft/core/cauldron/CauldronInteraction.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/cauldron/CauldronInteraction.java.patch @@ -10,5 +10,5 @@ - InteractionResult interact(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack itemInHand); + InteractionResult interact(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, ItemStack itemInHand, net.minecraft.core.Direction hitDirection); // Paper - add hitDirection - public static class Dispatcher { + class Dispatcher { private final Map, CauldronInteraction> tags = new HashMap<>(); diff --git a/paper-server/patches/sources/net/minecraft/core/cauldron/CauldronInteractions.java.patch b/paper-server/patches/sources/net/minecraft/core/cauldron/CauldronInteractions.java.patch index 831d64efa7bb..0a1d9fb63129 100644 --- a/paper-server/patches/sources/net/minecraft/core/cauldron/CauldronInteractions.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/cauldron/CauldronInteractions.java.patch @@ -32,7 +32,7 @@ state, level, pos, -@@ -76,33 +_,43 @@ +@@ -76,23 +_,28 @@ itemInHand, new ItemStack(Items.WATER_BUCKET), s -> s.getValue(LayeredCauldronBlock.LEVEL) == 3, @@ -64,23 +64,24 @@ + WATER.put(Items.POTION, (state, level, pos, player, hand, itemInHand, hitDirection) -> { // Paper - add hitDirection if (state.getValue(LayeredCauldronBlock.LEVEL) == 3) { return InteractionResult.TRY_WITH_EMPTY_HAND; - } else { - PotionContents potion = itemInHand.get(DataComponents.POTION_CONTENTS); - if (potion != null && potion.is(Potions.WATER)) { - if (!level.isClientSide()) { -+ // CraftBukkit start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleCauldronLevelChangeEvent(level, pos, state.cycle(LayeredCauldronBlock.LEVEL), player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY)) { // Paper - Call CauldronLevelChangeEvent -+ return InteractionResult.SUCCESS; -+ } -+ // CraftBukkit end - player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, new ItemStack(Items.GLASS_BOTTLE))); - player.awardStat(Stats.USE_CAULDRON); - player.awardStat(Stats.ITEM_USED.get(itemInHand.getItem())); -- level.setBlockAndUpdate(pos, state.cycle(LayeredCauldronBlock.LEVEL)); -+ // level.setBlockAndUpdate(pos, state.cycle(LayeredCauldronBlock.LEVEL)); // CraftBukkit - level.playSound(null, pos, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F); - level.gameEvent(null, GameEvent.FLUID_PLACE, pos); - } + } +@@ -100,10 +_,15 @@ + PotionContents potion = itemInHand.get(DataComponents.POTION_CONTENTS); + if (potion != null && potion.is(Potions.WATER)) { + if (!level.isClientSide()) { ++ // CraftBukkit start ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleCauldronLevelChangeEvent(level, pos, state.cycle(LayeredCauldronBlock.LEVEL), player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY)) { // Paper - Call CauldronLevelChangeEvent ++ return InteractionResult.SUCCESS; ++ } ++ // CraftBukkit end + player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, new ItemStack(Items.GLASS_BOTTLE))); + player.awardStat(Stats.USE_CAULDRON); + player.awardStat(Stats.ITEM_USED.get(itemInHand.getItem())); +- level.setBlockAndUpdate(pos, state.cycle(LayeredCauldronBlock.LEVEL)); ++ // level.setBlockAndUpdate(pos, state.cycle(LayeredCauldronBlock.LEVEL)); // CraftBukkit + level.playSound(null, pos, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F); + level.gameEvent(null, GameEvent.FLUID_PLACE, pos); + } @@ -148,14 +_,14 @@ WATER.put(Items.YELLOW_SHULKER_BOX, CauldronInteractions::shulkerBoxInteraction); LAVA.put( @@ -108,7 +109,7 @@ ) ); addDefaultInteractions(POWDER_SNOW); -@@ -187,15 +_,46 @@ +@@ -187,16 +_,47 @@ final Predicate canFill, final SoundEvent soundEvent ) { @@ -131,31 +132,32 @@ + // Paper end - add hitDirection if (!canFill.test(state)) { return InteractionResult.TRY_WITH_EMPTY_HAND; - } else { - if (!level.isClientSide()) { -+ // Paper start - fire PlayerBucketFillEvent -+ if (hitDirection != null) { -+ org.bukkit.event.player.PlayerBucketEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent(level, player, pos, pos, hitDirection, itemInHand, newItem.getItem(), hand); -+ if (event.isCancelled()) { -+ return InteractionResult.PASS; -+ } -+ newItem = event.getItemStack() != null ? org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack()) : ItemStack.EMPTY; -+ } -+ // Paper end - fire PlayerBucketFillEvent -+ // CraftBukkit start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleCauldronLevelChangeEvent(level, pos, Blocks.CAULDRON.defaultBlockState(), player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BUCKET_FILL)) { // Paper - Call CauldronLevelChangeEvent -+ return InteractionResult.SUCCESS; + } + + if (!level.isClientSide()) { ++ // Paper start - fire PlayerBucketFillEvent ++ if (hitDirection != null) { ++ org.bukkit.event.player.PlayerBucketEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent(level, player, pos, pos, hitDirection, itemInHand, newItem.getItem(), hand); ++ if (event.isCancelled()) { ++ return InteractionResult.PASS; + } -+ // CraftBukkit end - Item itemUsed = itemInHand.getItem(); - player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, newItem)); - player.awardStat(Stats.USE_CAULDRON); - player.awardStat(Stats.ITEM_USED.get(itemUsed)); -- level.setBlockAndUpdate(pos, Blocks.CAULDRON.defaultBlockState()); -+ // level.setBlockAndUpdate(pos, Blocks.CAULDRON.defaultBlockState()); // CraftBukkit - level.playSound(null, pos, soundEvent, SoundSource.BLOCKS, 1.0F, 1.0F); - level.gameEvent(null, GameEvent.FLUID_PICKUP, pos); - } ++ newItem = event.getItemStack() != null ? org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack()) : ItemStack.EMPTY; ++ } ++ // Paper end - fire PlayerBucketFillEvent ++ // CraftBukkit start ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleCauldronLevelChangeEvent(level, pos, Blocks.CAULDRON.defaultBlockState(), player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BUCKET_FILL)) { // Paper - Call CauldronLevelChangeEvent ++ return InteractionResult.SUCCESS; ++ } ++ // CraftBukkit end + Item itemUsed = itemInHand.getItem(); + player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, newItem)); + player.awardStat(Stats.USE_CAULDRON); + player.awardStat(Stats.ITEM_USED.get(itemUsed)); +- level.setBlockAndUpdate(pos, Blocks.CAULDRON.defaultBlockState()); ++ // level.setBlockAndUpdate(pos, Blocks.CAULDRON.defaultBlockState()); // CraftBukkit + level.playSound(null, pos, soundEvent, SoundSource.BLOCKS, 1.0F, 1.0F); + level.gameEvent(null, GameEvent.FLUID_PICKUP, pos); + } @@ -213,12 +_,42 @@ final BlockState newState, final SoundEvent soundEvent @@ -218,25 +220,25 @@ - final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final ItemStack itemInHand + final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final ItemStack itemInHand, final net.minecraft.core.Direction hitDirection // Paper - add hitDirection ) { - return (InteractionResult)(isUnderWater(level, pos) + return isUnderWater(level, pos) ? InteractionResult.CONSUME -- : emptyBucket(level, pos, player, hand, itemInHand, Blocks.LAVA_CAULDRON.defaultBlockState(), SoundEvents.BUCKET_EMPTY_LAVA)); -+ : emptyBucket(level, pos, player, hand, itemInHand, Blocks.LAVA_CAULDRON.defaultBlockState(), SoundEvents.BUCKET_EMPTY_LAVA, hitDirection)); // Paper - add hitDirection +- : emptyBucket(level, pos, player, hand, itemInHand, Blocks.LAVA_CAULDRON.defaultBlockState(), SoundEvents.BUCKET_EMPTY_LAVA); ++ : emptyBucket(level, pos, player, hand, itemInHand, Blocks.LAVA_CAULDRON.defaultBlockState(), SoundEvents.BUCKET_EMPTY_LAVA, hitDirection); // Paper - add hitDirection } private static InteractionResult fillPowderSnowInteraction( - final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final ItemStack itemInHand + final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final ItemStack itemInHand, final net.minecraft.core.Direction hitDirection // Paper - add hitDirection ) { - return (InteractionResult)(isUnderWater(level, pos) + return isUnderWater(level, pos) ? InteractionResult.CONSUME -@@ -254,22 +_,27 @@ +@@ -254,12 +_,12 @@ hand, itemInHand, Blocks.POWDER_SNOW_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3), - SoundEvents.BUCKET_EMPTY_POWDER_SNOW + SoundEvents.BUCKET_EMPTY_POWDER_SNOW, hitDirection // Paper - add hitDirection - )); + ); } private static InteractionResult shulkerBoxInteraction( @@ -245,23 +247,23 @@ ) { Block block = Block.byItem(itemInHand.getItem()); if (!(block instanceof ShulkerBoxBlock)) { - return InteractionResult.TRY_WITH_EMPTY_HAND; - } else { - if (!level.isClientSide()) { -+ // CraftBukkit start -+ if (!LayeredCauldronBlock.lowerFillLevel(state, level, pos, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.SHULKER_WASH)) { -+ return InteractionResult.SUCCESS; -+ } -+ // CraftBukkit end - ItemStack cleanedShulkerBox = itemInHand.transmuteCopy(Blocks.SHULKER_BOX, 1); - player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, cleanedShulkerBox, false)); - player.awardStat(Stats.CLEAN_SHULKER_BOX); -- LayeredCauldronBlock.lowerFillLevel(state, level, pos); -+ // LayeredCauldronBlock.lowerFillLevel(state, level, pos); // CraftBukkit - } +@@ -267,17 +_,22 @@ + } - return InteractionResult.SUCCESS; -@@ -277,18 +_,23 @@ + if (!level.isClientSide()) { ++ // CraftBukkit start ++ if (!LayeredCauldronBlock.lowerFillLevel(state, level, pos, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.SHULKER_WASH)) { ++ return InteractionResult.SUCCESS; ++ } ++ // CraftBukkit end + ItemStack cleanedShulkerBox = itemInHand.transmuteCopy(Blocks.SHULKER_BOX, 1); + player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, cleanedShulkerBox, false)); + player.awardStat(Stats.CLEAN_SHULKER_BOX); +- LayeredCauldronBlock.lowerFillLevel(state, level, pos); ++ // LayeredCauldronBlock.lowerFillLevel(state, level, pos); // CraftBukkit + } + + return InteractionResult.SUCCESS; } private static InteractionResult bannerInteraction( @@ -270,24 +272,24 @@ ) { BannerPatternLayers patterns = itemInHand.getOrDefault(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY); if (patterns.layers().isEmpty()) { - return InteractionResult.TRY_WITH_EMPTY_HAND; - } else { - if (!level.isClientSide()) { -+ // CraftBukkit start -+ if (!LayeredCauldronBlock.lowerFillLevel(state, level, pos, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BANNER_WASH)) { -+ return InteractionResult.SUCCESS; -+ } -+ // CraftBukkit end - ItemStack cleanedBanner = itemInHand.copyWithCount(1); - cleanedBanner.set(DataComponents.BANNER_PATTERNS, patterns.removeLast()); - player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, cleanedBanner, false)); - player.awardStat(Stats.CLEAN_BANNER); -- LayeredCauldronBlock.lowerFillLevel(state, level, pos); -+ // LayeredCauldronBlock.lowerFillLevel(state, level, pos); // CraftBukkit - } +@@ -285,27 +_,37 @@ + } - return InteractionResult.SUCCESS; -@@ -296,15 +_,20 @@ + if (!level.isClientSide()) { ++ // CraftBukkit start ++ if (!LayeredCauldronBlock.lowerFillLevel(state, level, pos, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.BANNER_WASH)) { ++ return InteractionResult.SUCCESS; ++ } ++ // CraftBukkit end + ItemStack cleanedBanner = itemInHand.copyWithCount(1); + cleanedBanner.set(DataComponents.BANNER_PATTERNS, patterns.removeLast()); + player.setItemInHand(hand, ItemUtils.createFilledResult(itemInHand, player, cleanedBanner, false)); + player.awardStat(Stats.CLEAN_BANNER); +- LayeredCauldronBlock.lowerFillLevel(state, level, pos); ++ // LayeredCauldronBlock.lowerFillLevel(state, level, pos); // CraftBukkit + } + + return InteractionResult.SUCCESS; } private static InteractionResult dyedItemIteration( @@ -296,17 +298,18 @@ ) { if (!itemInHand.has(DataComponents.DYED_COLOR)) { return InteractionResult.TRY_WITH_EMPTY_HAND; - } else { - if (!level.isClientSide()) { -+ // CraftBukkit start -+ if (!LayeredCauldronBlock.lowerFillLevel(state, level, pos, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.ARMOR_WASH)) { -+ return InteractionResult.SUCCESS; -+ } -+ // CraftBukkit end - itemInHand.remove(DataComponents.DYED_COLOR); - player.awardStat(Stats.CLEAN_ARMOR); -- LayeredCauldronBlock.lowerFillLevel(state, level, pos); -+ // LayeredCauldronBlock.lowerFillLevel(state, level, pos); // CraftBukkit - } + } - return InteractionResult.SUCCESS; + if (!level.isClientSide()) { ++ // CraftBukkit start ++ if (!LayeredCauldronBlock.lowerFillLevel(state, level, pos, player, org.bukkit.event.block.CauldronLevelChangeEvent.ChangeReason.ARMOR_WASH)) { ++ return InteractionResult.SUCCESS; ++ } ++ // CraftBukkit end + itemInHand.remove(DataComponents.DYED_COLOR); + player.awardStat(Stats.CLEAN_ARMOR); +- LayeredCauldronBlock.lowerFillLevel(state, level, pos); ++ // LayeredCauldronBlock.lowerFillLevel(state, level, pos); // CraftBukkit + } + + return InteractionResult.SUCCESS; diff --git a/paper-server/patches/sources/net/minecraft/core/component/DataComponentPatch.java.patch b/paper-server/patches/sources/net/minecraft/core/component/DataComponentPatch.java.patch index 1de1c463cb95..bf66928dede9 100644 --- a/paper-server/patches/sources/net/minecraft/core/component/DataComponentPatch.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/component/DataComponentPatch.java.patch @@ -24,10 +24,10 @@ @@ -126,6 +_,7 @@ patch.map )) { - Optional value = entryx.getValue(); -+ value = io.papermc.paper.util.sanitizer.ItemComponentSanitizer.override(itemObfuscationSession, entryx.getKey(), entryx.getValue()); // Paper - data sanitization for items + Optional value = entry.getValue(); ++ value = io.papermc.paper.util.sanitizer.ItemComponentSanitizer.override(itemObfuscationSession, entry.getKey(), entry.getValue()); // Paper - data sanitization for items if (value.isPresent()) { - DataComponentType type = entryx.getKey(); + DataComponentType type = entry.getKey(); DataComponentType.STREAM_CODEC.encode(output, type); @@ -145,7 +_,13 @@ } diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch index de3f5d8968e0..0d7e83b21326 100644 --- a/paper-server/patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/DispenseItemBehavior.java.patch @@ -124,7 +124,7 @@ return this.consumeWithRemainder(source, dispensed, new ItemStack(Items.BUCKET)); } else { return this.defaultDispenseItemBehavior.dispense(source, dispensed); -@@ -174,12 +_,19 @@ +@@ -174,13 +_,20 @@ BlockPos target = source.pos().relative(source.state().getValue(DispenserBlock.FACING)); BlockState blockState = level.getBlockState(target); if (blockState.getBlock() instanceof BucketPickup bucket) { @@ -132,19 +132,20 @@ + ItemStack pickup = bucket.pickupBlock(null, org.bukkit.craftbukkit.util.DummyLevelAccessor.INSTANCE, target, blockState); // CraftBukkit if (pickup.isEmpty()) { return super.execute(source, dispensed); - } else { - level.gameEvent(null, GameEvent.FLUID_PICKUP, target); - Item targetType = pickup.getItem(); -+ // Paper start - Call BlockDispenseEvent -+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this); -+ if (result != null) { -+ return result; -+ } -+ // Paper end - Call BlockDispenseEvent -+ pickup = bucket.pickupBlock(null, level, target, blockState); // CraftBukkit - from above - return this.consumeWithRemainder(source, dispensed, new ItemStack(targetType)); } + + level.gameEvent(null, GameEvent.FLUID_PICKUP, target); + Item targetType = pickup.getItem(); ++ // Paper start - Call BlockDispenseEvent ++ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this); ++ if (result != null) { ++ return result; ++ } ++ // Paper end - Call BlockDispenseEvent ++ pickup = bucket.pickupBlock(null, level, target, blockState); // CraftBukkit - from above + return this.consumeWithRemainder(source, dispensed, new ItemStack(targetType)); } else { + return super.execute(source, dispensed); @@ -194,15 +_,26 @@ this.setSuccess(true); Direction facing = source.state().getValue(DispenserBlock.FACING); @@ -333,35 +334,35 @@ RespawnAnchorBlock.charge(null, level, pos, blockState); dispensed.shrink(1); } else { -@@ -383,6 +_,28 @@ - this.setSuccess(false); +@@ -384,6 +_,28 @@ return dispensed; - } else { -+ // CraftBukkit start -+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, source.pos()); -+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(dispensed); // Paper - ignore stack size on damageable items + } + ++ // CraftBukkit start ++ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, source.pos()); ++ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(dispensed); // Paper - ignore stack size on damageable items + -+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), armadillos.get(0).getBukkitLivingEntity()); -+ level.getCraftServer().getPluginManager().callEvent(event); ++ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), armadillos.get(0).getBukkitLivingEntity()); ++ level.getCraftServer().getPluginManager().callEvent(event); + -+ if (event.isCancelled()) { -+ this.setSuccess(false); -+ return dispensed; -+ } ++ if (event.isCancelled()) { ++ this.setSuccess(false); ++ return dispensed; ++ } + -+ if (!event.getItem().equals(craftItem)) { -+ // Chain to handler for new item -+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); -+ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack); -+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) { -+ dispenseBehavior.dispense(source, eventStack); -+ return dispensed; -+ } ++ if (!event.getItem().equals(craftItem)) { ++ // Chain to handler for new item ++ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); ++ DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack); ++ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) { ++ dispenseBehavior.dispense(source, eventStack); ++ return dispensed; + } -+ // CraftBukkit end - for (Armadillo armadillo : armadillos) { - if (armadillo.brushOffScute(null, dispensed)) { - dispensed.hurtAndBreak(16, level, null, item -> {}); ++ } ++ // CraftBukkit end + for (Armadillo armadillo : armadillos) { + if (armadillo.brushOffScute(null, dispensed)) { + dispensed.hurtAndBreak(16, level, null, item -> {}); @@ -403,6 +_,13 @@ BlockState blockState = level.getBlockState(pos); Optional maybeWaxed = HoneycombItem.getWaxed(blockState); @@ -376,16 +377,16 @@ level.setBlockAndUpdate(pos, maybeWaxed.get()); level.levelEvent(LevelEvent.PARTICLES_AND_SOUND_WAX_ON, pos, 0); dispensed.shrink(1); -@@ -430,6 +_,12 @@ - if (!level.getBlockState(target).is(BlockTags.CONVERTABLE_TO_MUD)) { - return this.defaultDispenseItemBehavior.dispense(source, dispensed); - } else { -+ // Paper start - Call BlockDispenseEvent -+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this); -+ if (result != null) { -+ return result; -+ } -+ // Paper end - Call BlockDispenseEvent - if (!level.isClientSide()) { - RandomSource random = level.getRandom(); +@@ -432,6 +_,12 @@ + return this.defaultDispenseItemBehavior.dispense(source, dispensed); + } + ++ // Paper start - Call BlockDispenseEvent ++ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(source, target, dispensed, this); ++ if (result != null) { ++ return result; ++ } ++ // Paper end - Call BlockDispenseEvent + if (!level.isClientSide()) { + RandomSource random = level.getRandom(); diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java.patch index fd59898eb292..98198f8de5fc 100644 --- a/paper-server/patches/sources/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java.patch @@ -19,45 +19,45 @@ BlockPos pos = source.pos().relative(source.state().getValue(DispenserBlock.FACING)); List entities = source.level().getEntitiesOfClass(LivingEntity.class, new AABB(pos), entity -> entity.canEquipWithDispenser(dispensed)); if (entities.isEmpty()) { -@@ -25,13 +_,39 @@ - } else { - LivingEntity target = entities.getFirst(); - EquipmentSlot slot = target.getEquipmentSlotForItem(dispensed); -- ItemStack equip = dispensed.split(1); -- target.setItemSlot(slot, equip); -+ ItemStack equip = dispensed.copyWithCount(1); // Paper - shrink below and single item in event -+ // CraftBukkit start -+ net.minecraft.world.level.Level world = source.level(); -+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, source.pos()); -+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(equip); +@@ -26,13 +_,39 @@ + + LivingEntity target = entities.getFirst(); + EquipmentSlot slot = target.getEquipmentSlotForItem(dispensed); +- ItemStack equip = dispensed.split(1); +- target.setItemSlot(slot, equip); ++ ItemStack equip = dispensed.copyWithCount(1); // Paper - shrink below and single item in event ++ // CraftBukkit start ++ net.minecraft.world.level.Level world = source.level(); ++ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, source.pos()); ++ org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(equip); + -+ org.bukkit.event.block.BlockDispenseArmorEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) target.getBukkitEntity()); -+ world.getCraftServer().getPluginManager().callEvent(event); ++ org.bukkit.event.block.BlockDispenseArmorEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) target.getBukkitEntity()); ++ world.getCraftServer().getPluginManager().callEvent(event); + -+ if (event.isCancelled()) { -+ return false; -+ } ++ if (event.isCancelled()) { ++ return false; ++ } + -+ boolean shrink = true; -+ if (!event.getItem().equals(craftItem)) { -+ shrink = false; -+ // Chain to handler for new item -+ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); -+ DispenseItemBehavior dispenseItemBehavior = DispenserBlock.getDispenseBehavior(source, eventStack); -+ if (dispenseItemBehavior != DispenseItemBehavior.NOOP && (currentBehavior == null || dispenseItemBehavior != currentBehavior)) { -+ dispenseItemBehavior.dispense(source, eventStack); -+ return true; -+ } ++ boolean shrink = true; ++ if (!event.getItem().equals(craftItem)) { ++ shrink = false; ++ // Chain to handler for new item ++ ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()); ++ DispenseItemBehavior dispenseItemBehavior = DispenserBlock.getDispenseBehavior(source, eventStack); ++ if (dispenseItemBehavior != DispenseItemBehavior.NOOP && (currentBehavior == null || dispenseItemBehavior != currentBehavior)) { ++ dispenseItemBehavior.dispense(source, eventStack); ++ return true; + } ++ } + -+ target.setItemSlot(slot, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem())); -+ // CraftBukkit end - if (target instanceof Mob targetMob) { - targetMob.setGuaranteedDrop(slot); - targetMob.setPersistenceRequired(); - } - -+ if (shrink) dispensed.shrink(1); // Paper - shrink here - return true; ++ target.setItemSlot(slot, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem())); ++ // CraftBukkit end + if (target instanceof Mob targetMob) { + targetMob.setGuaranteedDrop(slot); + targetMob.setPersistenceRequired(); } + ++ if (shrink) dispensed.shrink(1); // Paper - shrink here + return true; } + } diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java.patch index acc9e4c90c27..633393b05579 100644 --- a/paper-server/patches/sources/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java.patch @@ -35,6 +35,6 @@ + dispensed.shrink(1); // vanilla shrink is in the place function above, manually handle it here + } + // Paper end - track changed items in the dispense event - } catch (Exception var8) { - LOGGER.error("Error trying to place shulker box at {}", relativePos, var8); + } catch (Exception e) { + LOGGER.error("Error trying to place shulker box at {}", relativePos, e); } diff --git a/paper-server/patches/sources/net/minecraft/core/dispenser/SpawnEggItemBehavior.java.patch b/paper-server/patches/sources/net/minecraft/core/dispenser/SpawnEggItemBehavior.java.patch index 026114b948d0..99e409f5b601 100644 --- a/paper-server/patches/sources/net/minecraft/core/dispenser/SpawnEggItemBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/dispenser/SpawnEggItemBehavior.java.patch @@ -1,42 +1,42 @@ --- a/net/minecraft/core/dispenser/SpawnEggItemBehavior.java +++ b/net/minecraft/core/dispenser/SpawnEggItemBehavior.java -@@ -18,14 +_,37 @@ - if (type == null) { +@@ -19,14 +_,37 @@ return dispensed; - } else { -+ // Paper start - block dispense event -+ ItemStack singleDispensed = dispensed.copyWithCount(1); -+ final org.bukkit.craftbukkit.inventory.CraftItemStack eventItemCopy = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleDispensed); -+ final org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent( -+ org.bukkit.craftbukkit.block.CraftBlock.at(source.level(), source.pos()), -+ eventItemCopy, -+ new org.bukkit.util.Vector(0, 0, 0) -+ ); -+ if (!event.callEvent()) return dispensed; -+ -+ final boolean shrink = event.getItem().equals(eventItemCopy); -+ if (!shrink) { -+ final ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getItem()); -+ final DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack); -+ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) { -+ dispenseBehavior.dispense(source, eventStack); -+ return dispensed; -+ } + } + ++ // Paper start - block dispense event ++ ItemStack singleDispensed = dispensed.copyWithCount(1); ++ final org.bukkit.craftbukkit.inventory.CraftItemStack eventItemCopy = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleDispensed); ++ final org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent( ++ org.bukkit.craftbukkit.block.CraftBlock.at(source.level(), source.pos()), ++ eventItemCopy, ++ new org.bukkit.util.Vector(0, 0, 0) ++ ); ++ if (!event.callEvent()) return dispensed; + -+ type = SpawnEggItem.getType(eventStack); -+ singleDispensed = eventStack; ++ final boolean shrink = event.getItem().equals(eventItemCopy); ++ if (!shrink) { ++ final ItemStack eventStack = org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getItem()); ++ final DispenseItemBehavior dispenseBehavior = DispenserBlock.getDispenseBehavior(source, eventStack); ++ if (dispenseBehavior != DispenseItemBehavior.NOOP && dispenseBehavior != this) { ++ dispenseBehavior.dispense(source, eventStack); ++ return dispensed; + } -+ // Paper end - block dispense event - try { -- type.spawn(source.level(), dispensed, null, source.pos().relative(direction), EntitySpawnReason.DISPENSER, direction != Direction.UP, false); -+ type.spawn(source.level(), singleDispensed, null, source.pos().relative(direction), EntitySpawnReason.DISPENSER, direction != Direction.UP, false); // Paper - block dispense event - update used item stack - } catch (Exception var6) { - LOGGER.error("Error while dispensing spawn egg from dispenser at {}", source.pos(), var6); - return ItemStack.EMPTY; - } - -- dispensed.shrink(1); -+ if (shrink) dispensed.shrink(1); // Paper - block dispense event - only shrink if above logic requires it. - source.level().gameEvent(null, GameEvent.ENTITY_PLACE, source.pos()); - return dispensed; ++ ++ type = SpawnEggItem.getType(eventStack); ++ singleDispensed = eventStack; ++ } ++ // Paper end - block dispense event + try { +- type.spawn(source.level(), dispensed, null, source.pos().relative(direction), EntitySpawnReason.DISPENSER, direction != Direction.UP, false); ++ type.spawn(source.level(), singleDispensed, null, source.pos().relative(direction), EntitySpawnReason.DISPENSER, direction != Direction.UP, false); // Paper - block dispense event - update used item stack + } catch (Exception e) { + LOGGER.error("Error while dispensing spawn egg from dispenser at {}", source.pos(), e); + return ItemStack.EMPTY; } + +- dispensed.shrink(1); ++ if (shrink) dispensed.shrink(1); // Paper - block dispense event - only shrink if above logic requires it. + source.level().gameEvent(null, GameEvent.ENTITY_PLACE, source.pos()); + return dispensed; + } diff --git a/paper-server/patches/sources/net/minecraft/gametest/framework/GameTestServer.java.patch b/paper-server/patches/sources/net/minecraft/gametest/framework/GameTestServer.java.patch index 3cd39b15ac0a..d4acbfb1c257 100644 --- a/paper-server/patches/sources/net/minecraft/gametest/framework/GameTestServer.java.patch +++ b/paper-server/patches/sources/net/minecraft/gametest/framework/GameTestServer.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/gametest/framework/GameTestServer.java +++ b/net/minecraft/gametest/framework/GameTestServer.java -@@ -155,6 +_,8 @@ +@@ -154,6 +_,8 @@ final int repeatCount ) { super( @@ -9,21 +9,18 @@ serverThread, levelStorageSource, packRepository, -@@ -173,13 +_,21 @@ +@@ -172,9 +_,17 @@ @Override protected boolean initServer() { +- this.setPlayerList(new PlayerList(this, this.registries(), this.playerDataStorage, new EmptyNotificationService()) {}); + // Paper start - this.setPlayerList(new PlayerList(this, this.registries(), this.playerDataStorage, new EmptyNotificationService()) { - { - Objects.requireNonNull(GameTestServer.this); - } -+ ++ this.setPlayerList(new PlayerList(this, this.registries(), this.playerDataStorage, new EmptyNotificationService()) { + @Override + public void loadAndSaveFiles() { + throw new UnsupportedOperationException("Should not be called in a GameTestServer"); + } - }); ++ }); + this.initPostWorld(); Gizmos.withCollector(GizmoCollector.NOOP); - this.loadLevel(); @@ -32,7 +29,7 @@ ServerLevel level = this.overworld(); this.testBatches = this.evaluateTestsToRun(level); LOGGER.info("Started game test server"); -@@ -385,6 +_,13 @@ +@@ -380,6 +_,13 @@ return false; } @@ -46,7 +43,7 @@ @Override public boolean isSingleplayerOwner(final NameAndId nameAndId) { return false; -@@ -432,5 +_,16 @@ +@@ -427,5 +_,16 @@ @Override public void save() { } diff --git a/paper-server/patches/sources/net/minecraft/nbt/CompoundTag.java.patch b/paper-server/patches/sources/net/minecraft/nbt/CompoundTag.java.patch index 651d45dd8b23..5e6262f04cb4 100644 --- a/paper-server/patches/sources/net/minecraft/nbt/CompoundTag.java.patch +++ b/paper-server/patches/sources/net/minecraft/nbt/CompoundTag.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/nbt/CompoundTag.java +++ b/net/minecraft/nbt/CompoundTag.java -@@ -54,7 +_,7 @@ +@@ -51,7 +_,7 @@ private static CompoundTag loadCompound(final DataInput input, final NbtAccounter accounter) throws IOException { accounter.accountBytes(48L); @@ -9,7 +9,7 @@ byte tagType; while ((tagType = input.readByte()) != 0) { -@@ -171,7 +_,7 @@ +@@ -165,7 +_,7 @@ } public CompoundTag() { @@ -18,7 +18,7 @@ } @Override -@@ -400,9 +_,16 @@ +@@ -394,9 +_,16 @@ @Override public CompoundTag copy() { @@ -38,7 +38,7 @@ } @Override -@@ -523,22 +_,47 @@ +@@ -517,22 +_,47 @@ this.merge((CompoundTag)codec.encoder().encodeStart(ops, value).getOrThrow()); } diff --git a/paper-server/patches/sources/net/minecraft/nbt/NbtAccounter.java.patch b/paper-server/patches/sources/net/minecraft/nbt/NbtAccounter.java.patch index b0f9bc4d69ca..48cfa9296ed5 100644 --- a/paper-server/patches/sources/net/minecraft/nbt/NbtAccounter.java.patch +++ b/paper-server/patches/sources/net/minecraft/nbt/NbtAccounter.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/nbt/NbtAccounter.java +++ b/net/minecraft/nbt/NbtAccounter.java -@@ -48,6 +_,16 @@ - } +@@ -50,6 +_,16 @@ + this.usage += size; } + // Paper start - Track codec depth diff --git a/paper-server/patches/sources/net/minecraft/nbt/NbtIo.java.patch b/paper-server/patches/sources/net/minecraft/nbt/NbtIo.java.patch index e94e7511736f..153bf5a8bd81 100644 --- a/paper-server/patches/sources/net/minecraft/nbt/NbtIo.java.patch +++ b/paper-server/patches/sources/net/minecraft/nbt/NbtIo.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/nbt/NbtIo.java +++ b/net/minecraft/nbt/NbtIo.java -@@ -117,7 +_,12 @@ +@@ -108,7 +_,12 @@ return read(input, NbtAccounter.unlimitedHeap()); } diff --git a/paper-server/patches/sources/net/minecraft/network/Connection.java.patch b/paper-server/patches/sources/net/minecraft/network/Connection.java.patch index a2aae515dd33..dfb10ac330e0 100644 --- a/paper-server/patches/sources/net/minecraft/network/Connection.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/Connection.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/network/Connection.java +++ b/net/minecraft/network/Connection.java -@@ -68,6 +_,11 @@ +@@ -67,6 +_,11 @@ private final Queue> pendingActions = Queues.newConcurrentLinkedQueue(); public Channel channel; public SocketAddress address; @@ -12,7 +12,7 @@ private volatile @Nullable PacketListener disconnectListener; private volatile @Nullable PacketListener packetListener; private @Nullable DisconnectionDetails disconnectionDetails; -@@ -81,6 +_,44 @@ +@@ -80,6 +_,44 @@ private boolean handlingFault; private volatile @Nullable DisconnectionDetails delayedDisconnect; private @Nullable BandwidthDebugMonitor bandwidthDebugMonitor; @@ -57,7 +57,7 @@ public Connection(final PacketFlow receiving) { this.receiving = receiving; -@@ -91,6 +_,7 @@ +@@ -90,6 +_,7 @@ super.channelActive(ctx); this.channel = ctx.channel(); this.address = this.channel.remoteAddress(); @@ -65,7 +65,7 @@ if (this.delayedDisconnect != null) { this.disconnect(this.delayedDisconnect); } -@@ -102,15 +_,32 @@ +@@ -101,15 +_,32 @@ } @Override @@ -99,7 +99,7 @@ this.disconnect(Component.translatable("disconnect.timeout")); } else { Component reason = Component.translatable("disconnect.genericReason", "Internal Exception: " + cause); -@@ -122,9 +_,11 @@ +@@ -121,9 +_,11 @@ details = new DisconnectionDetails(reason); } @@ -109,10 +109,10 @@ - if (this.getSending() == PacketFlow.CLIENTBOUND) { + boolean doesDisconnectExist = this.packetListener.protocol() != ConnectionProtocol.STATUS && this.packetListener.protocol() != ConnectionProtocol.HANDSHAKING; // Paper + if (this.getSending() == PacketFlow.CLIENTBOUND && doesDisconnectExist) { // Paper - Packet packet = (Packet)(this.sendLoginDisconnect + Packet packet = this.sendLoginDisconnect ? new ClientboundLoginDisconnectPacket(reason) - : new ClientboundDisconnectPacket(reason)); -@@ -141,6 +_,7 @@ + : new ClientboundDisconnectPacket(reason); +@@ -140,6 +_,7 @@ } } } @@ -120,68 +120,69 @@ } @Override -@@ -150,10 +_,60 @@ +@@ -149,11 +_,60 @@ if (packetListener == null) { throw new IllegalStateException("Received a packet before the packet listener was initialized"); - } else { -+ // Paper start - packet limiter -+ if (this.stopReadingPackets) { -+ return; -+ } -+ if (this.allPacketCounts != null || -+ io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.overrides.containsKey(packet.getClass())) { -+ long time = System.nanoTime(); -+ synchronized (PACKET_LIMIT_LOCK) { -+ if (this.allPacketCounts != null) { -+ this.allPacketCounts.updateAndAdd(1, time); -+ if (this.allPacketCounts.getRate() >= io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.maxPacketRate()) { -+ this.killForPacketSpam(); -+ return; -+ } + } +- ++ // Paper start - packet limiter ++ if (this.stopReadingPackets) { ++ return; ++ } ++ if (this.allPacketCounts != null || ++ io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.overrides.containsKey(packet.getClass())) { ++ long time = System.nanoTime(); ++ synchronized (PACKET_LIMIT_LOCK) { ++ if (this.allPacketCounts != null) { ++ this.allPacketCounts.updateAndAdd(1, time); ++ if (this.allPacketCounts.getRate() >= io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.maxPacketRate()) { ++ this.killForPacketSpam(); ++ return; + } ++ } + -+ for (Class check = packet.getClass(); check != Object.class; check = check.getSuperclass()) { -+ io.papermc.paper.configuration.GlobalConfiguration.PacketLimiter.PacketLimit packetSpecificLimit = -+ io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.overrides.get(check); -+ if (packetSpecificLimit == null || !packetSpecificLimit.isEnabled()) { -+ continue; -+ } -+ io.papermc.paper.util.IntervalledCounter counter = this.packetSpecificLimits.computeIfAbsent((Class)check, (clazz) -> { -+ return new io.papermc.paper.util.IntervalledCounter((long)(packetSpecificLimit.interval() * 1.0e9)); -+ }); -+ counter.updateAndAdd(1, time); -+ if (counter.getRate() >= packetSpecificLimit.maxPacketRate()) { -+ switch (packetSpecificLimit.action()) { -+ case DROP: -+ return; -+ case KICK: -+ String deobfedPacketName = check.getName(); ++ for (Class check = packet.getClass(); check != Object.class; check = check.getSuperclass()) { ++ io.papermc.paper.configuration.GlobalConfiguration.PacketLimiter.PacketLimit packetSpecificLimit = ++ io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.overrides.get(check); ++ if (packetSpecificLimit == null || !packetSpecificLimit.isEnabled()) { ++ continue; ++ } ++ io.papermc.paper.util.IntervalledCounter counter = this.packetSpecificLimits.computeIfAbsent((Class)check, (clazz) -> { ++ return new io.papermc.paper.util.IntervalledCounter((long)(packetSpecificLimit.interval() * 1.0e9)); ++ }); ++ counter.updateAndAdd(1, time); ++ if (counter.getRate() >= packetSpecificLimit.maxPacketRate()) { ++ switch (packetSpecificLimit.action()) { ++ case DROP: ++ return; ++ case KICK: ++ String deobfedPacketName = check.getName(); + -+ String playerName; -+ if (this.packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl impl) { -+ playerName = impl.getOwner().name(); -+ } else { -+ playerName = this.getLoggableAddress(net.minecraft.server.MinecraftServer.getServer().logIPs()); -+ } ++ String playerName; ++ if (this.packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl impl) { ++ playerName = impl.getOwner().name(); ++ } else { ++ playerName = this.getLoggableAddress(net.minecraft.server.MinecraftServer.getServer().logIPs()); ++ } + -+ Connection.LOGGER.warn("{} kicked for packet spamming: {}", playerName, deobfedPacketName.substring(deobfedPacketName.lastIndexOf(".") + 1)); -+ this.killForPacketSpam(); -+ return; -+ } ++ Connection.LOGGER.warn("{} kicked for packet spamming: {}", playerName, deobfedPacketName.substring(deobfedPacketName.lastIndexOf(".") + 1)); ++ this.killForPacketSpam(); ++ return; + } + } + } + } -+ // Paper end - packet limiter - if (packetListener.shouldHandleMessage(packet)) { - try { - genericsFtw(packet, packetListener); - } catch (RunningOnDifferentThreadException var5) { -+ } catch (io.papermc.paper.util.ServerStopRejectedExecutionException ignored) { // Paper - do not prematurely disconnect players on stop - } catch (RejectedExecutionException var6) { - this.disconnect(Component.translatable("multiplayer.disconnect.server_shutdown")); - } catch (ClassCastException var7) { -@@ -344,10 +_,30 @@ ++ } ++ // Paper end - packet limiter + if (packetListener.shouldHandleMessage(packet)) { + try { + genericsFtw(packet, packetListener); + } catch (RunningOnDifferentThreadException var5) { ++ } catch (io.papermc.paper.util.ServerStopRejectedExecutionException ignored) { // Paper - do not prematurely disconnect players on stop + } catch (RejectedExecutionException ignored) { + this.disconnect(Component.translatable("multiplayer.disconnect.server_shutdown")); + } catch (ClassCastException exception) { +@@ -343,10 +_,30 @@ } } @@ -212,7 +213,7 @@ } if (!this.isConnected() && !this.disconnectionHandled) { -@@ -355,7 +_,7 @@ +@@ -354,7 +_,7 @@ } if (this.channel != null) { @@ -221,7 +222,7 @@ } if (this.tickCount++ % 20 == 0) { -@@ -391,6 +_,7 @@ +@@ -390,6 +_,7 @@ } public void disconnect(final DisconnectionDetails details) { @@ -229,7 +230,7 @@ if (this.channel == null) { this.delayedDisconnect = details; } -@@ -543,6 +_,14 @@ +@@ -534,6 +_,14 @@ } } @@ -244,7 +245,7 @@ public void setupCompression(final int threshold, final boolean validateDecompressed) { if (threshold >= 0) { if (this.channel.pipeline().get(HandlerNames.DECOMPRESS) instanceof CompressionDecoder compressionDecoder) { -@@ -556,6 +_,7 @@ +@@ -547,6 +_,7 @@ } else { this.channel.pipeline().addAfter(HandlerNames.PREPENDER, HandlerNames.COMPRESS, new CompressionEncoder(threshold)); } @@ -252,7 +253,7 @@ } else { if (this.channel.pipeline().get(HandlerNames.DECOMPRESS) instanceof CompressionDecoder) { this.channel.pipeline().remove(HandlerNames.DECOMPRESS); -@@ -564,6 +_,7 @@ +@@ -555,6 +_,7 @@ if (this.channel.pipeline().get(HandlerNames.COMPRESS) instanceof CompressionEncoder) { this.channel.pipeline().remove(HandlerNames.COMPRESS); } @@ -260,7 +261,7 @@ } } -@@ -581,6 +_,26 @@ +@@ -572,6 +_,26 @@ ); disconnectListener.onDisconnect(details); } diff --git a/paper-server/patches/sources/net/minecraft/network/FriendlyByteBuf.java.patch b/paper-server/patches/sources/net/minecraft/network/FriendlyByteBuf.java.patch index d477f5aab15b..fe3cf91b56ef 100644 --- a/paper-server/patches/sources/net/minecraft/network/FriendlyByteBuf.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/FriendlyByteBuf.java.patch @@ -40,8 +40,8 @@ try { NbtIo.writeAnyTag(tag, new ByteBufOutputStream(output)); -- } catch (IOException var3) { -+ } catch (Exception var3) { // CraftBukkit - IOException -> Exception - throw new EncoderException(var3); +- } catch (IOException e) { ++ } catch (Exception e) { // CraftBukkit - IOException -> Exception + throw new EncoderException(e); } } diff --git a/paper-server/patches/sources/net/minecraft/network/PacketEncoder.java.patch b/paper-server/patches/sources/net/minecraft/network/PacketEncoder.java.patch index ad66db91b916..aeff0a1f1538 100644 --- a/paper-server/patches/sources/net/minecraft/network/PacketEncoder.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/PacketEncoder.java.patch @@ -16,7 +16,7 @@ if (LOGGER.isDebugEnabled()) { @@ -44,7 +_,33 @@ - throw var9; + throw t; } finally { + // Paper start - Handle large packets disconnecting client + int packetLength = output.readableBytes(); diff --git a/paper-server/patches/sources/net/minecraft/network/PacketProcessor.java.patch b/paper-server/patches/sources/net/minecraft/network/PacketProcessor.java.patch index 03a36be3541b..5b07c1540e5a 100644 --- a/paper-server/patches/sources/net/minecraft/network/PacketProcessor.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/PacketProcessor.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/network/PacketProcessor.java +++ b/net/minecraft/network/PacketProcessor.java -@@ -19,15 +_,42 @@ +@@ -19,16 +_,42 @@ this.runningThread = runningThread; } @@ -27,24 +27,26 @@ public void scheduleIfPossible(final T listener, final Packet packet) { if (this.closed) { - throw new RejectedExecutionException("Server already shutting down"); +- } +- +- this.packetsToBeHandled.add(new PacketProcessor.ListenerAndPacket<>(listener, packet)); + throw new io.papermc.paper.util.ServerStopRejectedExecutionException("Server already shutting down"); // Paper - do not prematurely disconnect players on stop - } else { -- this.packetsToBeHandled.add(new PacketProcessor.ListenerAndPacket<>(listener, packet)); -+ // Paper start - improve tick loop -+ // wake up main thread inbetween ticks to process packets -+ final boolean isEmpty = this.packetsToBeHandled.isEmpty(); -+ final ListenerAndPacket toAdd = new PacketProcessor.ListenerAndPacket<>(listener, packet); -+ this.packetsToBeHandled.add(toAdd); -+ if (isEmpty || this.packetsToBeHandled.peek() == toAdd) { -+ // only unpark if we are the first packet OR are at the head of the queue -+ // we unpark if we are at the head in case the main thread emptied the queue -+ // immediately before we added but after checking isEmpty -+ java.util.concurrent.locks.LockSupport.unpark(this.runningThread); -+ } -+ // Paper end - improve tick loop - } ++ } ++ // Paper start - improve tick loop ++ // wake up main thread inbetween ticks to process packets ++ final boolean isEmpty = this.packetsToBeHandled.isEmpty(); ++ final ListenerAndPacket toAdd = new PacketProcessor.ListenerAndPacket<>(listener, packet); ++ this.packetsToBeHandled.add(toAdd); ++ if (isEmpty || this.packetsToBeHandled.peek() == toAdd) { ++ // only unpark if we are the first packet OR are at the head of the queue ++ // we unpark if we are at the head in case the main thread emptied the queue ++ // immediately before we added but after checking isEmpty ++ java.util.concurrent.locks.LockSupport.unpark(this.runningThread); ++ } ++ // Paper end - improve tick loop } + public void processQueuedPackets() { @@ -44,8 +_,28 @@ this.closed = true; } diff --git a/paper-server/patches/sources/net/minecraft/network/chat/OutgoingChatMessage.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/OutgoingChatMessage.java.patch index 1c01a7e3c5f9..31495aad7995 100644 --- a/paper-server/patches/sources/net/minecraft/network/chat/OutgoingChatMessage.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/chat/OutgoingChatMessage.java.patch @@ -11,10 +11,10 @@ + // Paper end + static OutgoingChatMessage create(final PlayerChatMessage message) { - return (OutgoingChatMessage)(message.isSystem() - ? new OutgoingChatMessage.Disguised(message.decoratedContent()) -@@ -16,7 +_,13 @@ - public record Disguised(@Override Component content) implements OutgoingChatMessage { + return message.isSystem() ? new OutgoingChatMessage.Disguised(message.decoratedContent()) : new OutgoingChatMessage.Player(message); + } +@@ -14,7 +_,13 @@ + record Disguised(@Override Component content) implements OutgoingChatMessage { @Override public void sendToPlayer(final ServerPlayer player, final boolean filtered, final ChatType.Bound chatType) { - player.connection.sendDisguisedChatMessage(this.content, chatType); @@ -28,7 +28,7 @@ } } -@@ -28,7 +_,14 @@ +@@ -26,7 +_,14 @@ @Override public void sendToPlayer(final ServerPlayer player, final boolean filtered, final ChatType.Bound chatType) { diff --git a/paper-server/patches/sources/net/minecraft/network/chat/SignedMessageChain.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/SignedMessageChain.java.patch index bd43bcbeab6e..3bb5db8b395e 100644 --- a/paper-server/patches/sources/net/minecraft/network/chat/SignedMessageChain.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/chat/SignedMessageChain.java.patch @@ -1,23 +1,24 @@ --- a/net/minecraft/network/chat/SignedMessageChain.java +++ b/net/minecraft/network/chat/SignedMessageChain.java -@@ -44,14 +_,14 @@ - if (signature == null) { - throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.MISSING_PROFILE_KEY); - } else if (profilePublicKey.data().hasExpired()) { +@@ -41,7 +_,7 @@ + } + + if (profilePublicKey.data().hasExpired()) { - throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.EXPIRED_PROFILE_KEY); + throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.EXPIRED_PROFILE_KEY, org.bukkit.event.player.PlayerKickEvent.Cause.EXPIRED_PROFILE_PUBLIC_KEY); // Paper - kick event causes - } else { - SignedMessageLink link = SignedMessageChain.this.nextLink; - if (link == null) { - throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.CHAIN_BROKEN); - } else if (body.timeStamp().isBefore(SignedMessageChain.this.lastTimeStamp)) { - this.setChainBroken(); -- throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.OUT_OF_ORDER_CHAT); -+ throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.OUT_OF_ORDER_CHAT, org.bukkit.event.player.PlayerKickEvent.Cause.OUT_OF_ORDER_CHAT); // Paper - kick event causes - } else { - SignedMessageChain.this.lastTimeStamp = body.timeStamp(); - PlayerChatMessage unpacked = new PlayerChatMessage(link, signature, body, null, FilterMask.PASS_THROUGH); -@@ -84,8 +_,15 @@ + } + + SignedMessageLink link = SignedMessageChain.this.nextLink; +@@ -51,7 +_,7 @@ + + if (body.timeStamp().isBefore(SignedMessageChain.this.lastTimeStamp)) { + this.setChainBroken(); +- throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.OUT_OF_ORDER_CHAT); ++ throw new SignedMessageChain.DecodeException(SignedMessageChain.DecodeException.OUT_OF_ORDER_CHAT, org.bukkit.event.player.PlayerKickEvent.Cause.OUT_OF_ORDER_CHAT); // Paper - kick event causes + } + + SignedMessageChain.this.lastTimeStamp = body.timeStamp(); +@@ -83,8 +_,15 @@ private static final Component INVALID_SIGNATURE = Component.translatable("chat.disabled.invalid_signature"); private static final Component OUT_OF_ORDER_CHAT = Component.translatable("chat.disabled.out_of_order_chat"); diff --git a/paper-server/patches/sources/net/minecraft/network/chat/contents/SelectorContents.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/contents/SelectorContents.java.patch index d7fd00d307ee..f2cb018f102d 100644 --- a/paper-server/patches/sources/net/minecraft/network/chat/contents/SelectorContents.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/chat/contents/SelectorContents.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/network/chat/contents/SelectorContents.java +++ b/net/minecraft/network/chat/contents/SelectorContents.java -@@ -37,7 +_,7 @@ - if (source == null) { +@@ -38,7 +_,7 @@ return Component.empty(); - } else { -- Optional resolvedSeparator = ComponentUtils.resolve(context, this.separator, recursionDepth); -+ Optional resolvedSeparator = ComponentUtils.resolveSeparator(context, this.separator, recursionDepth); // Paper - validate separator - return ComponentUtils.formatList(this.selector.compiled().findEntities(source), resolvedSeparator, Entity::getDisplayName); } + +- Optional resolvedSeparator = ComponentUtils.resolve(context, this.separator, recursionDepth); ++ Optional resolvedSeparator = ComponentUtils.resolveSeparator(context, this.separator, recursionDepth); // Paper - validate separator + return ComponentUtils.formatList(this.selector.compiled().findEntities(source), resolvedSeparator, Entity::getDisplayName); } + diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/handshake/ClientIntentionPacket.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/handshake/ClientIntentionPacket.java.patch index 200a4d0c8260..aeb5a6b6d50b 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/handshake/ClientIntentionPacket.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/handshake/ClientIntentionPacket.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/network/protocol/handshake/ClientIntentionPacket.java +++ b/net/minecraft/network/protocol/handshake/ClientIntentionPacket.java -@@ -20,7 +_,7 @@ +@@ -16,7 +_,7 @@ } private ClientIntentionPacket(final FriendlyByteBuf input) { diff --git a/paper-server/patches/sources/net/minecraft/network/syncher/SynchedEntityData.java.patch b/paper-server/patches/sources/net/minecraft/network/syncher/SynchedEntityData.java.patch index 33c19095a735..74bbabef15c6 100644 --- a/paper-server/patches/sources/net/minecraft/network/syncher/SynchedEntityData.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/syncher/SynchedEntityData.java.patch @@ -14,7 +14,7 @@ public boolean isDirty() { return this.isDirty; } -@@ -167,6 +_,19 @@ +@@ -171,6 +_,19 @@ return new SynchedEntityData(this.entity, this.itemsById); } } diff --git a/paper-server/patches/sources/net/minecraft/resources/Identifier.java.patch b/paper-server/patches/sources/net/minecraft/resources/Identifier.java.patch index 9e5183c80408..0313fcd319a9 100644 --- a/paper-server/patches/sources/net/minecraft/resources/Identifier.java.patch +++ b/paper-server/patches/sources/net/minecraft/resources/Identifier.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/resources/Identifier.java +++ b/net/minecraft/resources/Identifier.java -@@ -22,6 +_,7 @@ +@@ -22,12 +_,20 @@ public static final String DEFAULT_NAMESPACE = "minecraft"; public static final String REALMS_NAMESPACE = "realms"; public static final String ALLOWED_NAMESPACE_CHARACTERS = "[a-z0-9_.-]"; @@ -8,10 +8,9 @@ private final String namespace; private final String path; -@@ -30,6 +_,13 @@ - + private Identifier(final String namespace, final String path) { + assert isValidNamespace(namespace); assert isValidPath(path); - + // Paper start - Validate Identifier + // Check for the max network string length (capped at Short.MAX_VALUE) as well as the max bytes of a StringTag (length written as an unsigned short) + final int length = namespace.length() + path.length() + 1; @@ -22,7 +21,7 @@ this.namespace = namespace; this.path = path; } -@@ -242,7 +_,7 @@ +@@ -240,7 +_,7 @@ private static String assertValidNamespace(final String namespace, final String path) { if (!isValidNamespace(namespace)) { @@ -31,7 +30,7 @@ } else { return namespace; } -@@ -258,7 +_,7 @@ +@@ -256,7 +_,7 @@ private static String assertValidPath(final String namespace, final String path) { if (!isValidPath(path)) { diff --git a/paper-server/patches/sources/net/minecraft/resources/NetworkRegistryLoadTask.java.patch b/paper-server/patches/sources/net/minecraft/resources/NetworkRegistryLoadTask.java.patch index 2f7996f97cc3..1ca69e52a7a0 100644 --- a/paper-server/patches/sources/net/minecraft/resources/NetworkRegistryLoadTask.java.patch +++ b/paper-server/patches/sources/net/minecraft/resources/NetworkRegistryLoadTask.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/resources/NetworkRegistryLoadTask.java +++ b/net/minecraft/resources/NetworkRegistryLoadTask.java -@@ -79,7 +_,7 @@ - } +@@ -80,7 +_,7 @@ + } - return Util.sequence(elements).thenAcceptAsync(pendingRegistrations -> { -- this.registerElements(pendingRegistrations.stream()); -+ this.registerElements(pendingRegistrations.stream(), null); // Paper - this code is only used on the client - Map, List>> pendingTags = TagLoader.loadTagsFromNetwork(registryEntries.tags(), this.readOnlyRegistry()); - this.registerTags(pendingTags); - }, executor); + return Util.sequence(elements).thenAcceptAsync(pendingRegistrations -> { +- this.registerElements(pendingRegistrations.stream()); ++ this.registerElements(pendingRegistrations.stream(), null); // Paper - this code is only used on the client + Map, List>> pendingTags = TagLoader.loadTagsFromNetwork(registryEntries.tags(), this.readOnlyRegistry()); + this.registerTags(pendingTags); + }, executor); diff --git a/paper-server/patches/sources/net/minecraft/server/Bootstrap.java.patch b/paper-server/patches/sources/net/minecraft/server/Bootstrap.java.patch index 89768f069023..3ca47e862d0e 100644 --- a/paper-server/patches/sources/net/minecraft/server/Bootstrap.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/Bootstrap.java.patch @@ -7,91 +7,90 @@ + io.papermc.paper.plugin.entrypoint.LaunchEntryPointHandler.enterBootstrappers(); // Paper - Entrypoint for bootstrapping if (BuiltInRegistries.REGISTRY.keySet().isEmpty()) { throw new IllegalStateException("Unable to load registries"); - } else { -@@ -54,11 +_,85 @@ - EntitySelectorOptions.bootStrap(); - DispenseItemBehavior.bootStrap(); - CauldronInteractions.bootStrap(); -- BuiltInRegistries.bootStrap(); -+ // Paper start -+ BuiltInRegistries.bootStrap(() -> { -+ io.papermc.paper.world.worldgen.OptionallyFlatBedrockConditionSource.bootstrap(); // Paper - Flat bedrock generator settings -+ }); -+ // Paper end - CreativeModeTabs.validate(); - wrapStreams(); - bootstrapDuration.set(Duration.between(start, Instant.now()).toMillis()); - } -+ // CraftBukkit start -+ // TODO Check what of this is needed, maybe report it to Mojira. if deemed relevant, move to the respective classes -+ // Used in CraftLegacy -+ for (int i = 0; i <= 15; i++) { -+ net.minecraft.util.datafix.fixes.BlockStateData.register( -+ 1008 + i, -+ new com.mojang.serialization.Dynamic<>(com.mojang.serialization.JavaOps.INSTANCE, java.util.Map.of( -+ "Name", "minecraft:oak_sign", -+ "Properties", java.util.Map.of("rotation", String.valueOf(i)) -+ )).convert(net.minecraft.nbt.NbtOps.INSTANCE), -+ new com.mojang.serialization.Dynamic<>(com.mojang.serialization.JavaOps.INSTANCE, java.util.Map.of( -+ "Name", "minecraft:standing_sign", -+ "Properties", java.util.Map.of("rotation", String.valueOf(i)) -+ )).convert(net.minecraft.nbt.NbtOps.INSTANCE) -+ ); -+ } -+ -+ net.minecraft.util.datafix.fixes.BlockStateData.register(1440, + } +@@ -56,10 +_,84 @@ + EntitySelectorOptions.bootStrap(); + DispenseItemBehavior.bootStrap(); + CauldronInteractions.bootStrap(); +- BuiltInRegistries.bootStrap(); ++ // Paper start ++ BuiltInRegistries.bootStrap(() -> { ++ io.papermc.paper.world.worldgen.OptionallyFlatBedrockConditionSource.bootstrap(); // Paper - Flat bedrock generator settings ++ }); ++ // Paper end + CreativeModeTabs.validate(); + wrapStreams(); + bootstrapDuration.set(Duration.between(start, Instant.now()).toMillis()); ++ // CraftBukkit start ++ // TODO Check what of this is needed, maybe report it to Mojira. if deemed relevant, move to the respective classes ++ // Used in CraftLegacy ++ for (int i = 0; i <= 15; i++) { ++ net.minecraft.util.datafix.fixes.BlockStateData.register( ++ 1008 + i, + new com.mojang.serialization.Dynamic<>(com.mojang.serialization.JavaOps.INSTANCE, java.util.Map.of( -+ "Name", "minecraft:portal", -+ "Properties", java.util.Map.of("axis", "x") ++ "Name", "minecraft:oak_sign", ++ "Properties", java.util.Map.of("rotation", String.valueOf(i)) + )).convert(net.minecraft.nbt.NbtOps.INSTANCE), + new com.mojang.serialization.Dynamic<>(com.mojang.serialization.JavaOps.INSTANCE, java.util.Map.of( -+ "Name", "minecraft:portal", -+ "Properties", java.util.Map.of("axis", "x") ++ "Name", "minecraft:standing_sign", ++ "Properties", java.util.Map.of("rotation", String.valueOf(i)) + )).convert(net.minecraft.nbt.NbtOps.INSTANCE) + ); ++ } + -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(409, "minecraft:prismarine_shard"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(410, "minecraft:prismarine_crystals"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(411, "minecraft:rabbit"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(412, "minecraft:cooked_rabbit"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(413, "minecraft:rabbit_stew"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(414, "minecraft:rabbit_foot"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(415, "minecraft:rabbit_hide"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(416, "minecraft:armor_stand"); ++ net.minecraft.util.datafix.fixes.BlockStateData.register(1440, ++ new com.mojang.serialization.Dynamic<>(com.mojang.serialization.JavaOps.INSTANCE, java.util.Map.of( ++ "Name", "minecraft:portal", ++ "Properties", java.util.Map.of("axis", "x") ++ )).convert(net.minecraft.nbt.NbtOps.INSTANCE), ++ new com.mojang.serialization.Dynamic<>(com.mojang.serialization.JavaOps.INSTANCE, java.util.Map.of( ++ "Name", "minecraft:portal", ++ "Properties", java.util.Map.of("axis", "x") ++ )).convert(net.minecraft.nbt.NbtOps.INSTANCE) ++ ); + -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(423, "minecraft:mutton"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(424, "minecraft:cooked_mutton"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(425, "minecraft:banner"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(426, "minecraft:end_crystal"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(427, "minecraft:spruce_door"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(428, "minecraft:birch_door"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(429, "minecraft:jungle_door"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(430, "minecraft:acacia_door"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(431, "minecraft:dark_oak_door"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(432, "minecraft:chorus_fruit"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(433, "minecraft:chorus_fruit_popped"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(434, "minecraft:beetroot"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(435, "minecraft:beetroot_seeds"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(436, "minecraft:beetroot_soup"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(437, "minecraft:dragon_breath"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(438, "minecraft:splash_potion"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(439, "minecraft:spectral_arrow"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(440, "minecraft:tipped_arrow"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(441, "minecraft:lingering_potion"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(442, "minecraft:shield"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(443, "minecraft:elytra"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(444, "minecraft:spruce_boat"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(445, "minecraft:birch_boat"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(446, "minecraft:jungle_boat"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(447, "minecraft:acacia_boat"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(448, "minecraft:dark_oak_boat"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(449, "minecraft:totem_of_undying"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(450, "minecraft:shulker_shell"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(452, "minecraft:iron_nugget"); -+ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(453, "minecraft:knowledge_book"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(409, "minecraft:prismarine_shard"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(410, "minecraft:prismarine_crystals"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(411, "minecraft:rabbit"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(412, "minecraft:cooked_rabbit"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(413, "minecraft:rabbit_stew"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(414, "minecraft:rabbit_foot"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(415, "minecraft:rabbit_hide"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(416, "minecraft:armor_stand"); + -+ net.minecraft.util.datafix.fixes.ItemSpawnEggFix.ID_TO_ENTITY[23] = "Arrow"; -+ // CraftBukkit end - } ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(423, "minecraft:mutton"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(424, "minecraft:cooked_mutton"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(425, "minecraft:banner"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(426, "minecraft:end_crystal"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(427, "minecraft:spruce_door"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(428, "minecraft:birch_door"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(429, "minecraft:jungle_door"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(430, "minecraft:acacia_door"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(431, "minecraft:dark_oak_door"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(432, "minecraft:chorus_fruit"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(433, "minecraft:chorus_fruit_popped"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(434, "minecraft:beetroot"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(435, "minecraft:beetroot_seeds"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(436, "minecraft:beetroot_soup"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(437, "minecraft:dragon_breath"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(438, "minecraft:splash_potion"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(439, "minecraft:spectral_arrow"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(440, "minecraft:tipped_arrow"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(441, "minecraft:lingering_potion"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(442, "minecraft:shield"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(443, "minecraft:elytra"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(444, "minecraft:spruce_boat"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(445, "minecraft:birch_boat"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(446, "minecraft:jungle_boat"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(447, "minecraft:acacia_boat"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(448, "minecraft:dark_oak_boat"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(449, "minecraft:totem_of_undying"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(450, "minecraft:shulker_shell"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(452, "minecraft:iron_nugget"); ++ net.minecraft.util.datafix.fixes.ItemIdFix.ITEM_NAMES.put(453, "minecraft:knowledge_book"); ++ ++ net.minecraft.util.datafix.fixes.ItemSpawnEggFix.ID_TO_ENTITY[23] = "Arrow"; ++ // CraftBukkit end } } + diff --git a/paper-server/patches/sources/net/minecraft/server/Main.java.patch b/paper-server/patches/sources/net/minecraft/server/Main.java.patch index c55839fbe739..31e6c418b7de 100644 --- a/paper-server/patches/sources/net/minecraft/server/Main.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/Main.java.patch @@ -190,7 +190,7 @@ } }, WorldStem::new, -@@ -191,6 +_,7 @@ +@@ -190,6 +_,7 @@ return; } @@ -198,7 +198,7 @@ RegistryAccess.Frozen registryHolder = worldStem.registries().compositeAccess(); WorldData data = worldStem.worldDataAndGenSettings().data(); boolean recreateRegionFilesValue = options.has(recreateRegionFiles); -@@ -199,22 +_,51 @@ +@@ -198,22 +_,51 @@ } access.saveDataTag(data); @@ -253,13 +253,13 @@ Thread shutdownThread = new Thread("Server Shutdown Thread") { @Override public void run() { -@@ -223,12 +_,13 @@ +@@ -222,12 +_,13 @@ }; shutdownThread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(LOGGER)); Runtime.getRuntime().addShutdownHook(shutdownThread); + */ // CraftBukkit end - } catch (Throwable var40) { - LOGGER.error(LogUtils.FATAL_MARKER, "Failed to start the minecraft server", var40); + } catch (Throwable t) { + LOGGER.error(LogUtils.FATAL_MARKER, "Failed to start the minecraft server", t); } } @@ -268,7 +268,7 @@ final DedicatedServerSettings settings, final WorldLoader.DataLoadContext context, final Registry datapackDimensions, -@@ -299,7 +_,11 @@ +@@ -298,7 +_,11 @@ final RegistryAccess registryAccess, final boolean recreateRegionFiles ) { @@ -281,7 +281,7 @@ try (WorldUpgrader upgrader = new WorldUpgrader(storageSource, fixerUpper, registryAccess, eraseCache, recreateRegionFiles)) { Component lastStatus = null; -@@ -327,5 +_,6 @@ +@@ -326,5 +_,6 @@ } } } diff --git a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch index 73dcdaec0643..287219cd7f3b 100644 --- a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch @@ -200,7 +200,7 @@ final Thread serverThread, final LevelStorageSource.LevelStorageAccess storageSource, final PackRepository packRepository, -@@ -322,27 +_,27 @@ +@@ -322,28 +_,28 @@ final boolean propagatesCrashes ) { super("Server", propagatesCrashes); @@ -209,41 +209,40 @@ - if (!this.registries.compositeAccess().lookupOrThrow(Registries.LEVEL_STEM).containsKey(LevelStem.OVERWORLD)) { + if (false && !this.registries.compositeAccess().lookupOrThrow(Registries.LEVEL_STEM).containsKey(LevelStem.OVERWORLD)) { // CraftBukkit - initialised later throw new IllegalStateException("Missing Overworld dimension data"); - } else { -- this.savedDataStorage = new SavedDataStorage(storageSource.getLevelPath(LevelResource.DATA), fixerUpper, this.registries.compositeAccess()); -+ this.savedDataStorage = new SavedDataStorage(storageSource.getLevelPath(LevelResource.ROOT).resolve(LevelResource.DATA.id()), fixerUpper, this.registries.compositeAccess()); - this.worldData = worldStem.worldDataAndGenSettings().data(); - this.worldGenSettings = worldStem.worldDataAndGenSettings().genSettings(); -- this.savedDataStorage.set(WorldGenSettings.TYPE, this.worldGenSettings); -+ // this.savedDataStorage.set(WorldGenSettings.TYPE, this.worldGenSettings); // Paper - save in level storage - this.proxy = proxy; - this.packRepository = packRepository; - this.resources = new MinecraftServer.ReloadableResources(worldStem.resourceManager(), worldStem.dataPackResources()); - this.services = services; -- this.connection = new ServerConnectionListener(this); -+ // this.connection = new ServerConnectionListener(this); // Spigot - this.tickRateManager = new ServerTickRateManager(this); -- this.levelLoadListener = levelLoadListener; -+ // Paper - per-level load listener - move LevelLoadListener to ServerLevel - this.storageSource = storageSource; - this.playerDataStorage = storageSource.createPlayerStorage(); - this.randomSequences = this.savedDataStorage.computeIfAbsent(RandomSequences.TYPE); -- this.weatherData = this.getDataStorage().computeIfAbsent(WeatherData.TYPE); -- this.gameRules = new GameRules(this.worldData.enabledFeatures(), this.savedDataStorage.computeIfAbsent(GameRuleMap.TYPE)); -- gameRules.ifPresent(g -> this.gameRules.setAll(g, null)); -+ // Paper - per-level WeatherData -+ // Paper - per-level GameRules - this.fixerUpper = fixerUpper; - this.functionManager = new ServerFunctionManager(this, this.resources.managers.getFunctionLibrary()); - HolderGetter blockLookup = this.registries -@@ -362,8 +_,40 @@ - this.clockManager = this.getDataStorage().computeIfAbsent(ServerClockManager.TYPE); - this.clockManager.init(this); - this.customBossEvents = this.savedDataStorage.computeIfAbsent(CustomBossEvents.TYPE); -- this.scheduledEvents = this.savedDataStorage.computeIfAbsent(TimerQueue.TYPE); -- } -+ // Paper - per-level scheduledEvents -+ } + } + +- this.savedDataStorage = new SavedDataStorage(storageSource.getLevelPath(LevelResource.DATA), fixerUpper, this.registries.compositeAccess()); ++ this.savedDataStorage = new SavedDataStorage(storageSource.getLevelPath(LevelResource.ROOT).resolve(LevelResource.DATA.id()), fixerUpper, this.registries.compositeAccess()); // Paper - save in level storage + this.worldData = worldStem.worldDataAndGenSettings().data(); + this.worldGenSettings = worldStem.worldDataAndGenSettings().genSettings(); +- this.savedDataStorage.set(WorldGenSettings.TYPE, this.worldGenSettings); ++ // this.savedDataStorage.set(WorldGenSettings.TYPE, this.worldGenSettings); // Paper - save in level storage + this.proxy = proxy; + this.packRepository = packRepository; + this.resources = new MinecraftServer.ReloadableResources(worldStem.resourceManager(), worldStem.dataPackResources()); + this.services = services; +- this.connection = new ServerConnectionListener(this); ++ // this.connection = new ServerConnectionListener(this); // Spigot + this.tickRateManager = new ServerTickRateManager(this); +- this.levelLoadListener = levelLoadListener; ++ // Paper - per-level load listener - move LevelLoadListener to ServerLevel + this.storageSource = storageSource; + this.playerDataStorage = storageSource.createPlayerStorage(); + this.randomSequences = this.savedDataStorage.computeIfAbsent(RandomSequences.TYPE); +- this.weatherData = this.getDataStorage().computeIfAbsent(WeatherData.TYPE); +- this.gameRules = new GameRules(this.worldData.enabledFeatures(), this.savedDataStorage.computeIfAbsent(GameRuleMap.TYPE)); +- gameRules.ifPresent(g -> this.gameRules.setAll(g, null)); ++ // Paper - per-level WeatherData ++ // Paper - per-level GameRules + this.fixerUpper = fixerUpper; + this.functionManager = new ServerFunctionManager(this, this.resources.managers.getFunctionLibrary()); + HolderGetter blockLookup = this.registries.compositeAccess().lookupOrThrow(Registries.BLOCK).filterFeatures(this.worldData.enabledFeatures()); +@@ -360,7 +_,39 @@ + this.clockManager = this.getDataStorage().computeIfAbsent(ServerClockManager.TYPE); + this.clockManager.init(this); + this.customBossEvents = this.savedDataStorage.computeIfAbsent(CustomBossEvents.TYPE); +- this.scheduledEvents = this.savedDataStorage.computeIfAbsent(TimerQueue.TYPE); ++ // Paper - per-level scheduledEvents + // CraftBukkit start + this.options = options; + this.worldLoaderContext = worldLoaderContext; @@ -279,7 +278,7 @@ } protected abstract boolean initServer() throws IOException; -@@ -400,15 +_,15 @@ +@@ -393,15 +_,15 @@ }; } @@ -300,7 +299,7 @@ if (profiledDuration != null) { profiledDuration.finish(true); } -@@ -422,33 +_,150 @@ +@@ -415,33 +_,150 @@ } } @@ -463,9 +462,9 @@ - this.setupDebugLevel(this.worldData); + this.setupDebugLevel(this.worldData, overworld); // Paper - per-level GameRules } - } catch (Throwable var20) { - CrashReport report = CrashReport.forThrowable(var20, "Exception initializing level"); -@@ -465,25 +_,7 @@ + } catch (Throwable t) { + CrashReport report = CrashReport.forThrowable(t, "Exception initializing level"); +@@ -458,25 +_,7 @@ } GlobalPos focusPos = this.selectLevelLoadFocusPos(); @@ -492,7 +491,7 @@ } private static void setInitialSpawn( -@@ -499,6 +_,28 @@ +@@ -492,6 +_,28 @@ levelData.setSpawn(LevelData.RespawnData.of(level.dimension(), BlockPos.ZERO.above(80), 0.0F, 0.0F)); } else { ServerChunkCache chunkSource = level.getChunkSource(); @@ -506,7 +505,7 @@ + throw new IllegalStateException("Cannot set spawn point for " + levelData.getLevelName() + " to be in another world (" + spawn.getWorld().key().asString() + ")"); + } else { + levelData.setSpawn( -+ net.minecraft.world.level.storage.LevelData.RespawnData.of( ++ LevelData.RespawnData.of( + level.dimension(), + org.bukkit.craftbukkit.util.CraftLocation.toBlockPos(spawn), + spawn.getYaw(), @@ -521,7 +520,7 @@ ChunkPos spawnChunk = ChunkPos.containing(chunkSource.randomState().sampler().findSpawnPosition()); levelLoadListener.start(LevelLoadListener.Stage.PREPARE_GLOBAL_SPAWN, 0); levelLoadListener.updateFocus(level.dimension(), spawnChunk); -@@ -544,19 +_,22 @@ +@@ -537,19 +_,22 @@ } } @@ -548,7 +547,7 @@ chunkLoadCounter.track(level, () -> { TicketStorage savedTickets = level.getDataStorage().get(TicketStorage.TYPE); if (savedTickets != null) { -@@ -565,17 +_,19 @@ +@@ -558,17 +_,19 @@ }); } @@ -574,7 +573,7 @@ } protected GlobalPos selectLevelLoadFocusPos() { -@@ -649,19 +_,49 @@ +@@ -639,19 +_,49 @@ this.stopServer(); } @@ -625,15 +624,15 @@ } LOGGER.info("Saving worlds"); -@@ -704,6 +_,20 @@ - } catch (IOException var4) { - LOGGER.error("Failed to unlock level {}", this.storageSource.getLevelId(), var4); +@@ -694,6 +_,20 @@ + } catch (IOException e) { + LOGGER.error("Failed to unlock level {}", this.storageSource.getLevelId(), e); } + // Spigot start + io.papermc.paper.util.MCUtil.ASYNC_EXECUTOR.shutdown(); // Paper + try { + io.papermc.paper.util.MCUtil.ASYNC_EXECUTOR.awaitTermination(30, java.util.concurrent.TimeUnit.SECONDS); // Paper -+ } catch (java.lang.InterruptedException ignored) {} // Paper ++ } catch (InterruptedException _) {} // Paper + if (org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) { + LOGGER.info("Saving usercache.json"); + this.services().nameToIdCache().save(false); // Paper - Perf: Async GameProfileCache saving @@ -646,7 +645,7 @@ } public String getLocalIp() { -@@ -719,6 +_,14 @@ +@@ -709,6 +_,14 @@ } public void halt(final boolean wait) { @@ -661,7 +660,7 @@ this.running = false; if (wait) { try { -@@ -729,6 +_,122 @@ +@@ -719,6 +_,122 @@ } } @@ -784,7 +783,7 @@ protected void runServer() { try { if (!this.initServer()) { -@@ -736,30 +_,73 @@ +@@ -726,30 +_,73 @@ } this.nextTickTimeNanos = Util.getNanos(); @@ -872,7 +871,7 @@ boolean sprinting = thisTickNanos == 0L; if (this.debugCommandProfilerDelayStart) { -@@ -767,7 +_,7 @@ +@@ -757,7 +_,7 @@ this.debugCommandProfiler = new MinecraftServer.TimeProfiler(Util.getNanos(), this.tickCount); } @@ -881,7 +880,7 @@ try (Profiler.Scope ignored = Profiler.use(this.createProfiler())) { this.processPacketsAndTick(sprinting); -@@ -776,7 +_,7 @@ +@@ -766,7 +_,7 @@ this.mayHaveDelayedTasks = true; this.delayedTasksMaxNextTickTimeNanos = Math.max(Util.getNanos() + thisTickNanos, this.nextTickTimeNanos); this.startMeasuringTaskExecutionTime(); @@ -890,16 +889,16 @@ this.finishMeasuringTaskExecutionTime(); if (sprinting) { this.tickRateManager.endTickWork(); -@@ -810,7 +_,7 @@ - } catch (Throwable var64) { - LOGGER.error("Exception stopping the server", var64); +@@ -800,7 +_,7 @@ + } catch (Throwable t) { + LOGGER.error("Exception stopping the server", t); } finally { - this.onServerExit(); + //this.onServerExit(); // Paper - Improved watchdog support; moved into stop } } } -@@ -862,7 +_,14 @@ +@@ -852,7 +_,14 @@ } private boolean haveTime() { @@ -915,7 +914,7 @@ } public NotificationManager notificationManager() { -@@ -870,11 +_,11 @@ +@@ -860,11 +_,11 @@ } protected void waitUntilNextTick() { @@ -929,7 +928,7 @@ } finally { this.waitingForNextTick = false; } -@@ -892,18 +_,38 @@ +@@ -882,18 +_,38 @@ } @Override @@ -972,26 +971,26 @@ this.mayHaveDelayedTasks = mayHaveMoreTasks; return mayHaveMoreTasks; } -@@ -912,15 +_,16 @@ - if (super.pollTask()) { +@@ -903,15 +_,16 @@ return true; - } else { -+ boolean ret = false; // Paper - force execution of all worlds, do not just bias the first - if (this.tickRateManager.isSprinting() || this.shouldRunAllTasks() || this.haveTime()) { - for (ServerLevel level : this.getAllLevels()) { - if (level.getChunkSource().pollTask()) { -- return true; -+ ret = true; // Paper - force execution of all worlds, do not just bias the first - } + } + ++ boolean ret = false; // Paper - force execution of all worlds, do not just bias the first + if (this.tickRateManager.isSprinting() || this.shouldRunAllTasks() || this.haveTime()) { + for (ServerLevel level : this.getAllLevels()) { + if (level.getChunkSource().pollTask()) { +- return true; ++ ret = true; // Paper - force execution of all worlds, do not just bias the first } } - -- return false; -+ return ret; // Paper - force execution of all worlds, do not just bias the first } + +- return false; ++ return ret; // Paper - force execution of all worlds, do not just bias the first } -@@ -973,26 +_,44 @@ + @Override +@@ -963,26 +_,44 @@ } protected void tickServer(final BooleanSupplier haveTime) { @@ -1037,7 +1036,7 @@ this.tickCount++; this.tickRateManager.tick(); this.tickChildren(haveTime); -@@ -1002,11 +_,18 @@ +@@ -992,11 +_,18 @@ } this.ticksUntilAutosave--; @@ -1057,7 +1056,7 @@ profiler.push("tallying"); long tickTime = Util.getNanos() - nano; int tickIndex = this.tickCount % 100; -@@ -1022,16 +_,16 @@ +@@ -1012,16 +_,16 @@ ProfilerFiller profiler = Profiler.get(); profiler.push("tick"); this.tickFrame.start(); @@ -1078,7 +1077,7 @@ LOGGER.debug("Autosave started"); ProfilerFiller profiler = Profiler.get(); profiler.push("save"); -@@ -1073,7 +_,7 @@ +@@ -1063,7 +_,7 @@ private ServerStatus buildServerStatus() { ServerStatus.Players players = this.buildPlayerStatus(); return new ServerStatus( @@ -1087,16 +1086,16 @@ Optional.of(players), Optional.of(ServerStatus.Version.current()), Optional.ofNullable(this.statusIcon), -@@ -1087,7 +_,7 @@ - if (this.hidesOnlinePlayers()) { +@@ -1078,7 +_,7 @@ return new ServerStatus.Players(maxPlayers, players.size(), List.of()); - } else { -- int sampleSize = Math.min(players.size(), 12); -+ int sampleSize = Math.min(players.size(), org.spigotmc.SpigotConfig.playerSample); // Paper - PaperServerListPingEvent - ObjectArrayList sample = new ObjectArrayList<>(sampleSize); - int offset = Mth.nextInt(this.random, 0, players.size() - sampleSize); + } + +- int sampleSize = Math.min(players.size(), 12); ++ int sampleSize = Math.min(players.size(), org.spigotmc.SpigotConfig.playerSample); // Paper - PaperServerListPingEvent + ObjectArrayList sample = new ObjectArrayList<>(sampleSize); + int offset = Mth.nextInt(this.random, 0, players.size() - sampleSize); -@@ -1104,12 +_,46 @@ +@@ -1094,12 +_,46 @@ protected void tickChildren(final BooleanSupplier haveTime) { ProfilerFiller profiler = Profiler.get(); this.getPlayerList().getPlayers().forEach(playerx -> playerx.connection.suspendFlushing()); @@ -1144,7 +1143,7 @@ profiler.pop(); } -@@ -1119,10 +_,20 @@ +@@ -1109,10 +_,20 @@ profiler.pop(); } @@ -1165,7 +1164,7 @@ profiler.push(() -> level + " " + level.dimension().identifier()); profiler.push("tick"); -@@ -1136,7 +_,9 @@ +@@ -1126,7 +_,9 @@ profiler.pop(); profiler.pop(); @@ -1175,7 +1174,7 @@ profiler.popPush("connection"); this.tickConnection(); -@@ -1166,9 +_,12 @@ +@@ -1156,9 +_,12 @@ this.serverActivityMonitor.tick(); } @@ -1190,7 +1189,7 @@ this.effectiveRespawnData = respawnLevel.getWorldBorderAdjustedRespawnData(respawnData); } -@@ -1179,7 +_,11 @@ +@@ -1169,7 +_,11 @@ public void forceGameTimeSynchronization() { ProfilerFiller profiler = Profiler.get(); profiler.push("timeSync"); @@ -1203,7 +1202,7 @@ profiler.pop(); } -@@ -1207,6 +_,22 @@ +@@ -1197,6 +_,22 @@ return this.levels.get(dimension); } @@ -1226,7 +1225,7 @@ public Set> levelKeys() { return this.levels.keySet(); } -@@ -1230,7 +_,7 @@ +@@ -1220,7 +_,7 @@ } public String getServerModName() { @@ -1235,7 +1234,7 @@ } public ServerClockManager clockManager() { -@@ -1269,7 +_,7 @@ +@@ -1259,7 +_,7 @@ @Override public void sendSystemMessage(final Component message) { @@ -1244,7 +1243,7 @@ } public KeyPair getKeyPair() { -@@ -1306,11 +_,17 @@ +@@ -1296,11 +_,17 @@ } } @@ -1267,7 +1266,7 @@ } } -@@ -1326,6 +_,11 @@ +@@ -1316,6 +_,11 @@ public void setDifficultyLocked(final boolean locked) { this.worldData.setDifficultyLocked(locked); @@ -1279,7 +1278,7 @@ this.getPlayerList().getPlayers().forEach(this::sendDifficultyUpdate); } -@@ -1382,10 +_,20 @@ +@@ -1372,10 +_,20 @@ @Override public String getMotd() { @@ -1301,23 +1300,22 @@ this.motd = motd; } -@@ -1414,17 +_,20 @@ - int count = 0; +@@ -1405,16 +_,20 @@ + int count = 0; - for (ServerPlayer player : this.getPlayerList().getPlayers()) { -- if (player.setGameMode(gameType)) { -- count++; -+ // Paper start - Expand PlayerGameModeChangeEvent -+ org.bukkit.event.player.PlayerGameModeChangeEvent event = player.setGameMode(gameType, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, null); -+ if (event == null || event.isCancelled()) { -+ continue; - } -+ count++; -+ // Paper end - Expand PlayerGameModeChangeEvent + for (ServerPlayer player : this.getPlayerList().getPlayers()) { +- if (player.setGameMode(gameType)) { +- count++; ++ // Paper start - Expand PlayerGameModeChangeEvent ++ org.bukkit.event.player.PlayerGameModeChangeEvent event = player.setGameMode(gameType, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, null); ++ if (event == null || event.isCancelled()) { ++ continue; } -- - return count; ++ count++; ++ // Paper end - Expand PlayerGameModeChangeEvent } + + return count; } public ServerConnectionListener getConnection() { @@ -1326,16 +1324,16 @@ } public boolean isReady() { -@@ -1487,7 +_,7 @@ +@@ -1477,7 +_,7 @@ @Override public void executeIfPossible(final Runnable command) { if (this.isStopped()) { - throw new RejectedExecutionException("Server already shutting down"); + throw new io.papermc.paper.util.ServerStopRejectedExecutionException("Server already shutting down"); // Paper - do not prematurely disconnect players on stop - } else { - super.executeIfPossible(command); } -@@ -1522,7 +_,16 @@ + + super.executeIfPossible(command); +@@ -1512,7 +_,16 @@ return this.functionManager; } @@ -1352,7 +1350,7 @@ CompletableFuture result = CompletableFuture.supplyAsync( () -> packsToEnable.stream() .map(this.packRepository::getPack) -@@ -1534,7 +_,7 @@ +@@ -1524,7 +_,7 @@ .thenCompose( packsToLoad -> { CloseableResourceManager resources = new MultiPackResourceManager(PackType.SERVER_DATA, packsToLoad); @@ -1361,7 +1359,7 @@ return ReloadableServerResources.loadResources( resources, this.registries, -@@ -1554,18 +_,37 @@ +@@ -1544,18 +_,37 @@ } ) .thenAcceptAsync(newResources -> { @@ -1401,7 +1399,7 @@ }, this); if (this.isSameThread()) { this.managedBlock(result::isDone); -@@ -1580,7 +_,7 @@ +@@ -1570,7 +_,7 @@ DataPackConfig dataPackConfig = initialDataConfig.dataPacks(); FeatureFlagSet forcedFeatures = initMode ? FeatureFlagSet.of() : initialDataConfig.enabledFeatures(); FeatureFlagSet allowedFeatures = initMode ? FeatureFlags.REGISTRY.allFlags() : initialDataConfig.enabledFeatures(); @@ -1409,8 +1407,8 @@ + packRepository.reload(true); // Paper - will load resource packs if (safeMode) { return configureRepositoryWithSelection(packRepository, List.of("vanilla"), forcedFeatures, false); - } else { -@@ -1635,7 +_,7 @@ + } +@@ -1625,7 +_,7 @@ private static WorldDataConfiguration configureRepositoryWithSelection( final PackRepository packRepository, final Collection selected, final FeatureFlagSet forcedFeatures, final boolean disableInactive ) { @@ -1419,7 +1417,7 @@ enableForcedFeaturePacks(packRepository, forcedFeatures); DataPackConfig packConfig = getSelectedPacks(packRepository, disableInactive); FeatureFlagSet packRequestedFeatures = packRepository.getRequestedFeatureFlags().join(forcedFeatures); -@@ -1667,7 +_,7 @@ +@@ -1657,7 +_,7 @@ } } @@ -1428,7 +1426,7 @@ } } -@@ -1684,8 +_,8 @@ +@@ -1674,8 +_,8 @@ UserWhiteList whiteList = playerList.getWhiteList(); for (ServerPlayer player : Lists.newArrayList(playerList.getPlayers())) { @@ -1439,7 +1437,7 @@ } } } -@@ -1715,12 +_,12 @@ +@@ -1705,12 +_,12 @@ } public ServerLevel findRespawnDimension() { @@ -1454,7 +1452,7 @@ public void setRespawnData(final LevelData.RespawnData respawnData) { ServerLevelData levelData = this.worldData.overworldData(); LevelData.RespawnData oldRespawnData = levelData.getRespawnData(); -@@ -1788,17 +_,20 @@ +@@ -1778,17 +_,20 @@ return this.randomSequences; } @@ -1480,16 +1478,16 @@ } public boolean isEnforceWhitelist() { -@@ -1889,7 +_,7 @@ +@@ -1879,7 +_,7 @@ private void dumpGameRules(final Path path) throws IOException { try (Writer output = Files.newBufferedWriter(path)) { final List entries = Lists.newArrayList(); - final GameRules gameRules = this.getGameRules(); + final GameRules gameRules = this.overworld().getGameRules(); // Paper - per-level GameRules gameRules.visitGameRuleTypes(new GameRuleTypeVisitor() { - { - Objects.requireNonNull(MinecraftServer.this); -@@ -1951,6 +_,17 @@ + @Override + public void visit(final GameRule gameRule) { +@@ -1937,6 +_,17 @@ } } @@ -1507,7 +1505,7 @@ private ProfilerFiller createProfiler() { if (this.willStartRecordingMetrics) { this.metricsRecorder = ActiveMetricsRecorder.createStarted( -@@ -2071,16 +_,22 @@ +@@ -2057,16 +_,22 @@ } public void logChatMessage(final Component message, final ChatType.Bound chatType, final @Nullable String tag) { @@ -1534,7 +1532,7 @@ } public boolean logIPs() { -@@ -2091,8 +_,9 @@ +@@ -2077,8 +_,9 @@ LOGGER.debug("Received custom click action {} with payload {}", id, payload.orElse(null)); } @@ -1545,7 +1543,7 @@ } public boolean setAutoSave(final boolean enable) { -@@ -2118,12 +_,14 @@ +@@ -2104,12 +_,14 @@ return false; } @@ -1563,7 +1561,7 @@ player.connection.send(new ClientboundEntityEventPacket(player, event)); } } else if (rule == GameRules.LIMITED_CRAFTING || rule == GameRules.IMMEDIATE_RESPAWN) { -@@ -2131,20 +_,21 @@ +@@ -2117,20 +_,21 @@ ? ClientboundGameEventPacket.LIMITED_CRAFTING : ClientboundGameEventPacket.IMMEDIATE_RESPAWN; ClientboundGameEventPacket packet = new ClientboundGameEventPacket(eventType, (Boolean)value ? 1.0F : 0.0F); @@ -1590,7 +1588,7 @@ } } -@@ -2157,12 +_,14 @@ +@@ -2143,12 +_,14 @@ return this.savedDataStorage; } @@ -1607,7 +1605,7 @@ } public boolean acceptsTransfers() { -@@ -2312,4 +_,53 @@ +@@ -2294,4 +_,53 @@ }; } } diff --git a/paper-server/patches/sources/net/minecraft/server/commands/BanIpCommands.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/BanIpCommands.java.patch index e1adcc14f76f..cd0718c09501 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/BanIpCommands.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/BanIpCommands.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/server/commands/BanIpCommands.java +++ b/net/minecraft/server/commands/BanIpCommands.java -@@ -62,7 +_,7 @@ - } +@@ -63,7 +_,7 @@ + } - for (ServerPlayer player : players) { -- player.connection.disconnect(Component.translatable("multiplayer.disconnect.ip_banned")); -+ player.connection.disconnect(Component.translatable("multiplayer.disconnect.ip_banned"), org.bukkit.event.player.PlayerKickEvent.Cause.IP_BANNED); // Paper - kick event cause - } + for (ServerPlayer player : players) { +- player.connection.disconnect(Component.translatable("multiplayer.disconnect.ip_banned")); ++ player.connection.disconnect(Component.translatable("multiplayer.disconnect.ip_banned"), org.bukkit.event.player.PlayerKickEvent.Cause.IP_BANNED); // Paper - kick event cause + } - return players.size(); + return players.size(); diff --git a/paper-server/patches/sources/net/minecraft/server/commands/DebugCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/DebugCommand.java.patch index c6335f8a1965..3716c968149e 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/DebugCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/DebugCommand.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/commands/DebugCommand.java +++ b/net/minecraft/server/commands/DebugCommand.java -@@ -277,6 +_,13 @@ +@@ -273,6 +_,13 @@ return true; } @@ -13,4 +13,4 @@ + @Override public void close() { - IOUtils.closeQuietly((Writer)this.output); + IOUtils.closeQuietly(this.output); diff --git a/paper-server/patches/sources/net/minecraft/server/commands/DifficultyCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/DifficultyCommand.java.patch index 940dc6091475..fb0f2487c318 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/DifficultyCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/DifficultyCommand.java.patch @@ -1,15 +1,16 @@ --- a/net/minecraft/server/commands/DifficultyCommand.java +++ b/net/minecraft/server/commands/DifficultyCommand.java -@@ -31,10 +_,10 @@ +@@ -31,11 +_,11 @@ public static int setDifficulty(final CommandSourceStack source, final Difficulty difficulty) throws CommandSyntaxException { MinecraftServer server = source.getServer(); - if (server.getWorldData().getDifficulty() == difficulty) { + if (source.getLevel().getDifficulty() == difficulty) { // CraftBukkit throw ERROR_ALREADY_SAME_DIFFICULTY.create(difficulty.getSerializedName()); - } else { -- server.setDifficulty(difficulty, true); -+ server.setDifficulty(source.getLevel(), difficulty, source, true); // Paper - per level difficulty; don't skip other difficulty-changing logic (fix upstream's fix); WorldDifficultyChangeEvent - source.sendSuccess(() -> Component.translatable("commands.difficulty.success", difficulty.getDisplayName()), true); - return 0; } + +- server.setDifficulty(difficulty, true); ++ server.setDifficulty(source.getLevel(), difficulty, source, true); // Paper - per level difficulty; don't skip other difficulty-changing logic (fix upstream's fix); WorldDifficultyChangeEvent + source.sendSuccess(() -> Component.translatable("commands.difficulty.success", difficulty.getDisplayName()), true); + return 0; + } diff --git a/paper-server/patches/sources/net/minecraft/server/commands/GiveCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/GiveCommand.java.patch index 341dc8af2e35..b8cd001ae92b 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/GiveCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/GiveCommand.java.patch @@ -1,29 +1,29 @@ --- a/net/minecraft/server/commands/GiveCommand.java +++ b/net/minecraft/server/commands/GiveCommand.java -@@ -62,7 +_,7 @@ - ItemStack copyToDrop = prototypeItemStack.copyWithCount(size); - boolean added = player.getInventory().add(copyToDrop); - if (added && copyToDrop.isEmpty()) { -- ItemEntity drop = player.drop(prototypeItemStack.copy(), false); -+ ItemEntity drop = player.drop(prototypeItemStack.copy(), false, false, false, null); // Paper - do not fire PlayerDropItemEvent for /give command - if (drop != null) { - drop.makeFakeItem(); - } -@@ -80,7 +_,7 @@ - ); - player.containerMenu.broadcastChanges(); - } else { -- ItemEntity drop = player.drop(copyToDrop, false); -+ ItemEntity drop = player.drop(copyToDrop, false, false, false, null); // Paper - do not fire PlayerDropItemEvent for /give command - if (drop != null) { - drop.setNoPickUpDelay(); - drop.setTarget(player.getUUID()); +@@ -63,7 +_,7 @@ + ItemStack copyToDrop = prototypeItemStack.copyWithCount(size); + boolean added = player.getInventory().add(copyToDrop); + if (added && copyToDrop.isEmpty()) { +- ItemEntity drop = player.drop(prototypeItemStack.copy(), false); ++ ItemEntity drop = player.drop(prototypeItemStack.copy(), false, false, false, null); // Paper - do not fire PlayerDropItemEvent for /give command + if (drop != null) { + drop.makeFakeItem(); + } +@@ -81,7 +_,7 @@ + ); + player.containerMenu.broadcastChanges(); + } else { +- ItemEntity drop = player.drop(copyToDrop, false); ++ ItemEntity drop = player.drop(copyToDrop, false, false, false, null); // Paper - do not fire PlayerDropItemEvent for /give command + if (drop != null) { + drop.setNoPickUpDelay(); + drop.setTarget(player.getUUID()); @@ -98,7 +_,7 @@ - ); - } else { - source.sendSuccess( -- () -> Component.translatable("commands.give.success.single", count, prototypeItemStack.getDisplayName(), players.size()), true -+ () -> Component.translatable("commands.give.success.multiple", count, prototypeItemStack.getDisplayName(), players.size()), true // Paper - MC-151857 - correct translation key - ); - } + true + ); + } else { +- source.sendSuccess(() -> Component.translatable("commands.give.success.single", count, prototypeItemStack.getDisplayName(), players.size()), true); ++ source.sendSuccess(() -> Component.translatable("commands.give.success.multiple", count, prototypeItemStack.getDisplayName(), players.size()), true); // Paper - MC-151857 - correct translation key + } + return players.size(); diff --git a/paper-server/patches/sources/net/minecraft/server/commands/KickCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/KickCommand.java.patch index 6427c3df646f..5ea8e5eccc39 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/KickCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/KickCommand.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/server/commands/KickCommand.java +++ b/net/minecraft/server/commands/KickCommand.java -@@ -42,7 +_,7 @@ +@@ -43,7 +_,7 @@ - for (ServerPlayer player : players) { - if (!source.getServer().isSingleplayerOwner(player.nameAndId())) { -- player.connection.disconnect(reason); -+ player.connection.disconnect(reason, org.bukkit.event.player.PlayerKickEvent.Cause.KICK_COMMAND); // Paper - kick event cause - source.sendSuccess(() -> Component.translatable("commands.kick.success", player.getDisplayName(), reason), true); - count++; - } + for (ServerPlayer player : players) { + if (!source.getServer().isSingleplayerOwner(player.nameAndId())) { +- player.connection.disconnect(reason); ++ player.connection.disconnect(reason, org.bukkit.event.player.PlayerKickEvent.Cause.KICK_COMMAND); // Paper - kick event cause + source.sendSuccess(() -> Component.translatable("commands.kick.success", player.getDisplayName(), reason), true); + count++; + } diff --git a/paper-server/patches/sources/net/minecraft/server/commands/PlaceCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/PlaceCommand.java.patch index e8f8b0c9f58f..dfbc359450bc 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/PlaceCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/PlaceCommand.java.patch @@ -1,10 +1,10 @@ --- a/net/minecraft/server/commands/PlaceCommand.java +++ b/net/minecraft/server/commands/PlaceCommand.java -@@ -298,6 +_,7 @@ - if (!start.isValid()) { +@@ -299,6 +_,7 @@ throw ERROR_STRUCTURE_FAILED.create(); - } else { -+ start.generationEventCause = org.bukkit.event.world.AsyncStructureGenerateEvent.Cause.COMMAND; // CraftBukkit - set AsyncStructureGenerateEvent.Cause.COMMAND as generation cause - BoundingBox boundingBox = start.getBoundingBox(); - ChunkPos chunkMin = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.minX()), SectionPos.blockToSectionCoord(boundingBox.minZ())); - ChunkPos chunkMax = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.maxX()), SectionPos.blockToSectionCoord(boundingBox.maxZ())); + } + ++ start.generationEventCause = org.bukkit.event.world.AsyncStructureGenerateEvent.Cause.COMMAND; // CraftBukkit - set AsyncStructureGenerateEvent.Cause.COMMAND as generation cause + BoundingBox boundingBox = start.getBoundingBox(); + ChunkPos chunkMin = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.minX()), SectionPos.blockToSectionCoord(boundingBox.minZ())); + ChunkPos chunkMax = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.maxX()), SectionPos.blockToSectionCoord(boundingBox.maxZ())); diff --git a/paper-server/patches/sources/net/minecraft/server/commands/RideCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/RideCommand.java.patch index 75ea71d04e42..f68ef1494ca4 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/RideCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/RideCommand.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/server/commands/RideCommand.java +++ b/net/minecraft/server/commands/RideCommand.java -@@ -54,7 +_,7 @@ - Entity currentVehicle = target.getVehicle(); - if (currentVehicle != null) { +@@ -56,7 +_,7 @@ throw ERROR_ALREADY_RIDING.create(target.getDisplayName(), currentVehicle.getDisplayName()); -- } else if (vehicle.is(EntityType.PLAYER)) { -+ } else if (vehicle.is(EntityType.PLAYER) && !io.papermc.paper.configuration.GlobalConfiguration.get().commands.rideCommandAllowPlayerAsVehicle) { // Paper - allow player as vehicle + } + +- if (vehicle.is(EntityType.PLAYER)) { ++ if (vehicle.is(EntityType.PLAYER) && !io.papermc.paper.configuration.GlobalConfiguration.get().commands.rideCommandAllowPlayerAsVehicle) { // Paper - allow player as vehicle throw ERROR_MOUNTING_PLAYER.create(); - } else if (target.getSelfAndPassengers().anyMatch(e -> e == vehicle)) { - throw ERROR_MOUNTING_LOOP.create(); + } + diff --git a/paper-server/patches/sources/net/minecraft/server/commands/ScheduleCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/ScheduleCommand.java.patch index ea60bef179a9..61e46dfd9391 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/ScheduleCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/ScheduleCommand.java.patch @@ -9,16 +9,16 @@ ); public static void register(final CommandDispatcher dispatcher) { -@@ -101,7 +_,7 @@ - } else { - long tickTime = source.getLevel().getGameTime() + time; - Identifier callbackId = callback.getFirst(); -- TimerQueue queue = source.getServer().getScheduledEvents(); -+ TimerQueue queue = source.getLevel().scheduledEvents; // CraftBukkit - SPIGOT-6667: Use world specific function timer - Optional> function = callback.getSecond().left(); - if (function.isPresent()) { - if (function.get() instanceof MacroFunction) { -@@ -132,7 +_,7 @@ +@@ -102,7 +_,7 @@ + + long tickTime = source.getLevel().getGameTime() + time; + Identifier callbackId = callback.getFirst(); +- TimerQueue queue = source.getServer().getScheduledEvents(); ++ TimerQueue queue = source.getLevel().scheduledEvents; // CraftBukkit - SPIGOT-6667: Use world specific function timer + Optional> function = callback.getSecond().left(); + if (function.isPresent()) { + if (function.get() instanceof MacroFunction) { +@@ -130,7 +_,7 @@ } private static int remove(final CommandSourceStack source, final String id) throws CommandSyntaxException { @@ -26,4 +26,4 @@ + int count = source.getLevel().scheduledEvents.remove(id); // Paper - Make schedule command per-world if (count == 0) { throw ERROR_CANT_REMOVE.create(id); - } else { + } diff --git a/paper-server/patches/sources/net/minecraft/server/commands/SummonCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/SummonCommand.java.patch index 3c6f91342b94..864b687049c4 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/SummonCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/SummonCommand.java.patch @@ -1,28 +1,28 @@ --- a/net/minecraft/server/commands/SummonCommand.java +++ b/net/minecraft/server/commands/SummonCommand.java -@@ -78,7 +_,7 @@ - BlockPos blockPos = BlockPos.containing(pos); - if (!Level.isInSpawnableBounds(blockPos)) { +@@ -80,7 +_,7 @@ throw INVALID_POSITION.create(); -- } else if (source.getLevel().getDifficulty() == Difficulty.PEACEFUL && !type.value().isAllowedInPeaceful()) { -+ } else if (source.getLevel().getDifficulty() == Difficulty.PEACEFUL && !type.value().isAllowedInPeaceful(nbt)) { // Paper - check peaceful override + } + +- if (source.getLevel().getDifficulty() == Difficulty.PEACEFUL && !type.value().isAllowedInPeaceful()) { ++ if (source.getLevel().getDifficulty() == Difficulty.PEACEFUL && !type.value().isAllowedInPeaceful(nbt)) { // Paper - check peaceful override throw ERROR_FAILED_PEACEFUL.create(); - } else { - CompoundTag entityTag = nbt.copy(); -@@ -86,6 +_,7 @@ - ServerLevel level = source.getLevel(); - Entity entity = EntityType.loadEntityRecursive(entityTag, level, EntitySpawnReason.COMMAND, e -> { - e.snapTo(pos.x, pos.y, pos.z, e.getYRot(), e.getXRot()); -+ e.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.COMMAND; // Paper - Entity#getEntitySpawnReason - return e; - }); - if (entity == null) { -@@ -95,7 +_,7 @@ - mob.finalizeSpawn(source.getLevel(), source.getLevel().getCurrentDifficultyAt(entity.blockPosition()), EntitySpawnReason.COMMAND, null); - } + } -- if (!level.tryAddFreshEntityWithPassengers(entity)) { -+ if (!level.tryAddFreshEntityWithPassengers(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.COMMAND)) { // CraftBukkit - pass a spawn reason of "COMMAND" - throw ERROR_DUPLICATE_UUID.create(); - } else { - return entity; +@@ -89,6 +_,7 @@ + ServerLevel level = source.getLevel(); + Entity entity = EntityType.loadEntityRecursive(entityTag, level, EntitySpawnReason.COMMAND, e -> { + e.snapTo(pos.x, pos.y, pos.z, e.getYRot(), e.getXRot()); ++ e.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.COMMAND; // Paper - Entity#getEntitySpawnReason + return e; + }); + if (entity == null) { +@@ -99,7 +_,7 @@ + mob.finalizeSpawn(source.getLevel(), source.getLevel().getCurrentDifficultyAt(entity.blockPosition()), EntitySpawnReason.COMMAND, null); + } + +- if (!level.tryAddFreshEntityWithPassengers(entity)) { ++ if (!level.tryAddFreshEntityWithPassengers(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.COMMAND)) { // CraftBukkit - pass a spawn reason of "COMMAND" + throw ERROR_DUPLICATE_UUID.create(); + } else { + return entity; diff --git a/paper-server/patches/sources/net/minecraft/server/commands/TeleportCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/TeleportCommand.java.patch index 448fd552bf7f..232050da4cc9 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/TeleportCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/TeleportCommand.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/server/commands/TeleportCommand.java +++ b/net/minecraft/server/commands/TeleportCommand.java -@@ -255,7 +_,7 @@ - float relativeOrAbsoluteXRot = relatives.contains(Relative.X_ROT) ? xRot - victim.getXRot() : xRot; - float newYRot = Mth.wrapDegrees(relativeOrAbsoluteYRot); - float newXRot = Mth.wrapDegrees(relativeOrAbsoluteXRot); -- if (victim.teleportTo(level, relativeOrAbsoluteX, relativeOrAbsoluteY, relativeOrAbsoluteZ, relatives, newYRot, newXRot, true)) { -+ if (victim.teleportTo(level, relativeOrAbsoluteX, relativeOrAbsoluteY, relativeOrAbsoluteZ, relatives, newYRot, newXRot, true, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.COMMAND)) { // Paper - teleport cause - if (lookAt != null) { - lookAt.perform(source, victim); - } +@@ -256,7 +_,7 @@ + float relativeOrAbsoluteXRot = relatives.contains(Relative.X_ROT) ? xRot - victim.getXRot() : xRot; + float newYRot = Mth.wrapDegrees(relativeOrAbsoluteYRot); + float newXRot = Mth.wrapDegrees(relativeOrAbsoluteXRot); +- if (victim.teleportTo(level, relativeOrAbsoluteX, relativeOrAbsoluteY, relativeOrAbsoluteZ, relatives, newYRot, newXRot, true)) { ++ if (victim.teleportTo(level, relativeOrAbsoluteX, relativeOrAbsoluteY, relativeOrAbsoluteZ, relatives, newYRot, newXRot, true, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.COMMAND)) { // Paper - teleport cause + if (lookAt != null) { + lookAt.perform(source, victim); + } diff --git a/paper-server/patches/sources/net/minecraft/server/commands/TimeCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/TimeCommand.java.patch index 49cecb5c7c9c..12632227b8c6 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/TimeCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/TimeCommand.java.patch @@ -18,25 +18,24 @@ long totalTicks = clockManager.getTotalTicks(clock); source.sendSuccess(() -> Component.translatable("commands.time.query.absolute", clock.getRegisteredName(), totalTicks), false); return wrapTime(totalTicks); -@@ -151,7 +_,7 @@ - if (!clock.equals(timeline.value().clock())) { +@@ -152,7 +_,7 @@ throw ERROR_WRONG_TIMELINE_FOR_CLOCK.create(clock.getRegisteredName(), timeline.getRegisteredName()); - } else { -- ServerClockManager clockManager = source.getServer().clockManager(); -+ ServerClockManager clockManager = source.getLevel().clockManager(); // Paper - per-world time - long currentTicks = timeline.value().getCurrentTicks(clockManager); - source.sendSuccess(() -> Component.translatable("commands.time.query.timeline", timeline.getRegisteredName(), currentTicks), false); - return wrapTime(currentTicks); -@@ -162,33 +_,53 @@ - if (!clock.equals(timeline.value().clock())) { + } + +- ServerClockManager clockManager = source.getServer().clockManager(); ++ ServerClockManager clockManager = source.getLevel().clockManager(); // Paper - per-world time + long currentTicks = timeline.value().getCurrentTicks(clockManager); + source.sendSuccess(() -> Component.translatable("commands.time.query.timeline", timeline.getRegisteredName(), currentTicks), false); + return wrapTime(currentTicks); +@@ -163,45 +_,67 @@ throw ERROR_WRONG_TIMELINE_FOR_CLOCK.create(clock.getRegisteredName(), timeline.getRegisteredName()); - } else { -- ServerClockManager clockManager = source.getServer().clockManager(); -+ ServerClockManager clockManager = source.getLevel().clockManager(); // Paper - per-world time - long repetitions = timeline.value().getPeriodCount(clockManager); - source.sendSuccess(() -> Component.translatable("commands.time.query.timeline.repetitions", timeline.getRegisteredName(), repetitions), false); - return wrapTime(repetitions); } + +- ServerClockManager clockManager = source.getServer().clockManager(); ++ ServerClockManager clockManager = source.getLevel().clockManager(); // Paper - per-world time + long repetitions = timeline.value().getPeriodCount(clockManager); + source.sendSuccess(() -> Component.translatable("commands.time.query.timeline.repetitions", timeline.getRegisteredName(), repetitions), false); + return wrapTime(repetitions); } + // Paper start - per-world time @@ -79,18 +78,19 @@ + ServerClockManager clockManager = source.getLevel().clockManager(); + java.util.OptionalLong targetTime = clockManager.getTotalTicksToTimeMarker(clock, timeMarkerId); + if (targetTime.isEmpty()) { - throw ERROR_NO_TIME_MARKER_FOUND.create(clock.getRegisteredName(), timeMarkerId); - } else { -+ final long currentTime = clockManager.getTotalTicks(clock); -+ final org.bukkit.event.world.ClockTimeSkipEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.createTimeSkipEvent(source, targetTime.getAsLong() - currentTime); -+ if (event.callEvent()) { -+ clockManager.setTotalTicks(clock, currentTime + event.getSkipAmount()); -+ } + // Paper end - per-world time - source.sendSuccess( - () -> Component.translatable("commands.time.set.time_marker", clock.getRegisteredName(), timeMarkerId.identifier().toString()), true - ); -@@ -197,13 +_,13 @@ + throw ERROR_NO_TIME_MARKER_FOUND.create(clock.getRegisteredName(), timeMarkerId); + } + ++ // Paper start - per-world time ++ final long currentTime = clockManager.getTotalTicks(clock); ++ final org.bukkit.event.world.ClockTimeSkipEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.createTimeSkipEvent(source, targetTime.getAsLong() - currentTime); ++ if (event.callEvent()) { ++ clockManager.setTotalTicks(clock, currentTime + event.getSkipAmount()); ++ } ++ // Paper end - per-world time + source.sendSuccess(() -> Component.translatable("commands.time.set.time_marker", clock.getRegisteredName(), timeMarkerId.identifier().toString()), true); + return wrapTime(clockManager.getTotalTicks(clock)); } private static int setPaused(final CommandSourceStack source, final Holder clock, final boolean paused) { diff --git a/paper-server/patches/sources/net/minecraft/server/commands/WaypointCommand.java.patch b/paper-server/patches/sources/net/minecraft/server/commands/WaypointCommand.java.patch index a88eca96a9e1..65d885fc3451 100644 --- a/paper-server/patches/sources/net/minecraft/server/commands/WaypointCommand.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/commands/WaypointCommand.java.patch @@ -5,7 +5,7 @@ private static void mutateIcon(final CommandSourceStack source, final WaypointTransmitter waypoint, final Consumer iconConsumer) { - ServerLevel level = source.getLevel(); -+ ServerLevel level = (waypoint instanceof LivingEntity livingEntity) ? (net.minecraft.server.level.ServerLevel) livingEntity.level() : source.getLevel(); // Paper - MC-300685 use level of waypoint if it's a living entity for broadcast ++ ServerLevel level = (waypoint instanceof LivingEntity livingEntity) ? (ServerLevel) livingEntity.level() : source.getLevel(); // Paper - MC-300685 use level of waypoint if it's a living entity for broadcast level.getWaypointManager().untrackWaypoint(waypoint); iconConsumer.accept(waypoint.waypointIcon()); level.getWaypointManager().trackWaypoint(waypoint); diff --git a/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch b/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch index c19fea33bc86..7e43d28d3f0c 100644 --- a/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -84,9 +_,9 @@ +@@ -83,9 +_,9 @@ private static final Logger LOGGER = LogUtils.getLogger(); private static final int CONVERSION_RETRY_DELAY_MS = 5000; private static final int CONVERSION_RETRIES = 2; @@ -12,7 +12,7 @@ private @Nullable RconThread rconThread; public DedicatedServerSettings settings; private @Nullable MinecraftServerGui gui; -@@ -99,6 +_,7 @@ +@@ -98,6 +_,7 @@ private long lastHeartbeat; public DedicatedServer( @@ -20,7 +20,7 @@ final Thread serverThread, final LevelStorageSource.LevelStorageAccess levelStorageSource, final PackRepository packRepository, -@@ -109,6 +_,7 @@ +@@ -108,6 +_,7 @@ final Services services ) { super( @@ -28,7 +28,7 @@ serverThread, levelStorageSource, packRepository, -@@ -121,7 +_,8 @@ +@@ -120,7 +_,8 @@ true ); this.settings = settings; @@ -38,8 +38,8 @@ this.serverTextFilter = ServerTextFilter.createFromConfig(settings.getProperties()); this.serverLinks = createServerLinks(settings); if (settings.getProperties().codeOfConduct) { -@@ -211,6 +_,10 @@ - +@@ -206,6 +_,10 @@ + Thread consoleThread = new Thread("Server console handler") { @Override public void run() { + if (!org.bukkit.craftbukkit.Main.useConsole) return; // CraftBukkit @@ -49,9 +49,9 @@ BufferedReader reader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8)); String line; -@@ -221,16 +_,41 @@ - } catch (IOException var4) { - DedicatedServer.LOGGER.error("Exception handling console input", (Throwable)var4); +@@ -216,16 +_,41 @@ + } catch (IOException e) { + DedicatedServer.LOGGER.error("Exception handling console input", e); } + */ + // Paper end - Use TerminalConsoleAppender @@ -92,7 +92,7 @@ LOGGER.info("Loading properties"); DedicatedServerProperties properties = this.settings.getProperties(); if (this.isSingleplayer()) { -@@ -241,8 +_,45 @@ +@@ -236,8 +_,45 @@ this.setLocalIp(properties.serverIp); } @@ -139,7 +139,7 @@ InetAddress localAddress = null; if (!this.getLocalIp().isEmpty()) { localAddress = InetAddress.getByName(this.getLocalIp()); -@@ -251,46 +_,72 @@ +@@ -246,47 +_,73 @@ if (this.getPort() < 0) { this.setPort(properties.serverPort); } @@ -153,11 +153,11 @@ try { - this.getConnection().startTcpServerListener(localAddress, this.getPort()); + this.getConnection().startTcpServerListener(bindAddress); // Paper - Unix domain socket support - } catch (IOException var11) { + } catch (IOException e) { LOGGER.warn("**** FAILED TO BIND TO PORT!"); - LOGGER.warn("The exception was: {}", var11.toString()); + LOGGER.warn("The exception was: {}", e.toString()); LOGGER.warn("Perhaps a server is already running on that port?"); -+ if (true) throw new IllegalStateException("Failed to bind to port", var11); // Paper - Propagate failed to bind to port error ++ if (true) throw new IllegalStateException("Failed to bind to port", e); // Paper - Propagate failed to bind to port error return false; } @@ -200,37 +200,38 @@ if (!OldUsersConverter.areOldUserlistsRemoved()) { return false; - } else { -- this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage)); -+ // this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage)); // CraftBukkit - moved up - this.tickTimeLogger = new RemoteSampleLogger(TpsDebugDimensions.values().length, this.debugSubscribers(), RemoteDebugSampleType.TICK_TIME); - long levelNanoTime = Util.getNanos(); - this.services.nameToIdCache().resolveOfflineUsers(!this.usesAuthentication()); - LOGGER.info("Preparing level \"{}\"", this.getLevelIdName()); -- this.loadLevel(); -+ this.loadLevel(this.storageSource.getLevelId()); // CraftBukkit - long elapsed = Util.getNanos() - levelNanoTime; - String time = String.format(Locale.ROOT, "%.3fs", elapsed / 1.0E9); -- LOGGER.info("Done ({})! For help, type \"help\"", time); -+ LOGGER.info("Done preparing level \"{}\" ({})", this.getLevelIdName(), time); // Paper - Improve startup message, add total time -+ this.initPostWorld(); // Paper - don't include plugins in world preparation time - if (properties.announcePlayerAchievements != null) { -- this.getGameRules().set(GameRules.SHOW_ADVANCEMENT_MESSAGES, properties.announcePlayerAchievements, this); -+ this.getAllLevels().forEach(l -> l.getGameRules().set(GameRules.SHOW_ADVANCEMENT_MESSAGES, properties.announcePlayerAchievements, this.overworld())); // Paper - per-world game rules - } + } - if (properties.enableQuery) { -@@ -303,7 +_,7 @@ - this.rconThread = RconThread.create(this); - } +- this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage)); ++ // this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage)); // CraftBukkit - moved up + this.tickTimeLogger = new RemoteSampleLogger(TpsDebugDimensions.values().length, this.debugSubscribers(), RemoteDebugSampleType.TICK_TIME); + long levelNanoTime = Util.getNanos(); + this.services.nameToIdCache().resolveOfflineUsers(!this.usesAuthentication()); + LOGGER.info("Preparing level \"{}\"", this.getLevelIdName()); +- this.loadLevel(); ++ this.loadLevel(this.storageSource.getLevelId()); // CraftBukkit + long elapsed = Util.getNanos() - levelNanoTime; + String time = String.format(Locale.ROOT, "%.3fs", elapsed / 1.0E9); +- LOGGER.info("Done ({})! For help, type \"help\"", time); ++ LOGGER.info("Done preparing level \"{}\" ({})", this.getLevelIdName(), time); // Paper - Improve startup message, add total time ++ this.initPostWorld(); // Paper - don't include plugins in world preparation time + if (properties.announcePlayerAchievements != null) { +- this.getGameRules().set(GameRules.SHOW_ADVANCEMENT_MESSAGES, properties.announcePlayerAchievements, this); ++ this.getAllLevels().forEach(l -> l.getGameRules().set(GameRules.SHOW_ADVANCEMENT_MESSAGES, properties.announcePlayerAchievements, this.overworld())); // Paper - per-world game rules + } -- if (this.getMaxTickLength() > 0L) { -+ if (false && this.getMaxTickLength() > 0L) { // Spigot - disable - Thread watchdog = new Thread(new ServerWatchdog(this)); - watchdog.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandlerWithName(LOGGER)); - watchdog.setName("Server Watchdog"); -@@ -322,6 +_,12 @@ + if (properties.enableQuery) { +@@ -299,7 +_,7 @@ + this.rconThread = RconThread.create(this); } + +- if (this.getMaxTickLength() > 0L) { ++ if (false && this.getMaxTickLength() > 0L) { // Spigot - disable + Thread watchdog = new Thread(new ServerWatchdog(this)); + watchdog.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandlerWithName(LOGGER)); + watchdog.setName("Server Watchdog"); +@@ -317,6 +_,12 @@ + return true; } + // Paper start @@ -242,7 +243,7 @@ @Override public boolean isEnforceWhitelist() { return this.settings.getProperties().enforceWhitelist.get(); -@@ -339,6 +_,7 @@ +@@ -334,6 +_,7 @@ @Override public void setUsingWhitelist(final boolean usingWhitelist) { @@ -250,7 +251,7 @@ this.settings.update(p -> p.whiteList.update(this.registryAccess(), usingWhitelist)); } -@@ -400,7 +_,7 @@ +@@ -395,7 +_,7 @@ @Override protected void forceDifficulty() { @@ -259,7 +260,7 @@ } public int viewDistance() { -@@ -456,11 +_,11 @@ +@@ -451,11 +_,11 @@ } if (this.rconThread != null) { @@ -273,8 +274,8 @@ } if (this.jsonRpcServer != null) { -@@ -470,6 +_,9 @@ - LOGGER.error("Interrupted while stopping the management server", (Throwable)var2); +@@ -465,6 +_,9 @@ + LOGGER.error("Interrupted while stopping the management server", e); } } + @@ -283,7 +284,7 @@ } @Override -@@ -479,12 +_,20 @@ +@@ -474,12 +_,20 @@ } public void handleConsoleInput(final String msg, final CommandSourceStack source) { @@ -307,7 +308,7 @@ this.getCommands().performPrefixedCommand(input.source, input.msg); } } -@@ -624,12 +_,15 @@ +@@ -625,12 +_,15 @@ @Override public String getMotd() { @@ -325,7 +326,7 @@ } @Override -@@ -655,7 +_,11 @@ +@@ -656,7 +_,11 @@ @Override public boolean enforceSecureProfile() { DedicatedServerProperties properties = this.getProperties(); @@ -338,7 +339,7 @@ } @Override -@@ -740,21 +_,60 @@ +@@ -741,21 +_,60 @@ @Override public String getPluginNames() { @@ -404,7 +405,7 @@ } @Override -@@ -882,4 +_,15 @@ +@@ -883,4 +_,15 @@ public Map getCodeOfConducts() { return this.codeOfConductTexts; } diff --git a/paper-server/patches/sources/net/minecraft/server/dedicated/ServerWatchdog.java.patch b/paper-server/patches/sources/net/minecraft/server/dedicated/ServerWatchdog.java.patch index d0a306f98961..6979890a62db 100644 --- a/paper-server/patches/sources/net/minecraft/server/dedicated/ServerWatchdog.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/dedicated/ServerWatchdog.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/dedicated/ServerWatchdog.java +++ b/net/minecraft/server/dedicated/ServerWatchdog.java -@@ -49,7 +_,7 @@ +@@ -48,7 +_,7 @@ CrashReport report = createWatchdogCrashReport("Watching Server", this.server.getRunningThread().threadId()); this.server.fillSystemReport(report.getSystemReport()); CrashReportCategory serverStats = report.addCategory("Performance stats"); diff --git a/paper-server/patches/sources/net/minecraft/server/dedicated/Settings.java.patch b/paper-server/patches/sources/net/minecraft/server/dedicated/Settings.java.patch index 9b7f098a142d..9bf3449060fc 100644 --- a/paper-server/patches/sources/net/minecraft/server/dedicated/Settings.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/dedicated/Settings.java.patch @@ -26,9 +26,9 @@ public static Properties loadFromFile(final Path file) { + if (!Files.exists(file)) return new Properties(); // CraftBukkit - SPIGOT-7465, MC-264979: Don't load if file doesn't exist try { - try { - Properties var13; -@@ -65,7 +_,53 @@ + try (InputStream is = Files.newInputStream(file)) { + CharsetDecoder reportingUtf8Decoder = StandardCharsets.UTF_8 +@@ -57,7 +_,53 @@ } public void store(final Path output) { @@ -81,9 +81,9 @@ + java.io.BufferedWriter os = new java.io.BufferedWriter(new java.io.OutputStreamWriter(bufferedOutputStream, java.nio.charset.StandardCharsets.UTF_8.newEncoder())); + // Paper end - allow skipping server.properties comments this.properties.store(os, "Minecraft server properties"); - } catch (IOException var7) { + } catch (IOException e) { LOGGER.error("Failed to store properties to file: {}", output); -@@ -95,7 +_,7 @@ +@@ -87,7 +_,7 @@ } public @Nullable String getStringRaw(final String key) { @@ -92,7 +92,7 @@ } protected @Nullable V getLegacy(final String key, final Function deserializer) { -@@ -109,6 +_,16 @@ +@@ -101,6 +_,16 @@ } protected V get(final String key, final Function deserializer, final Function serializer, final V defaultValue) { @@ -109,7 +109,7 @@ String value = this.getStringRaw(key); V result = MoreObjects.firstNonNull(value != null ? deserializer.apply(value) : null, defaultValue); this.properties.put(key, serializer.apply(result)); -@@ -191,7 +_,7 @@ +@@ -183,7 +_,7 @@ return result; } @@ -118,7 +118,7 @@ public class MutableValue implements Supplier { private final String key; -@@ -214,7 +_,7 @@ +@@ -204,7 +_,7 @@ public T update(final RegistryAccess registryAccess, final V value) { Properties properties = Settings.this.cloneProperties(); properties.put(this.key, this.serializer.apply(value)); diff --git a/paper-server/patches/sources/net/minecraft/server/gui/MinecraftServerGui.java.patch b/paper-server/patches/sources/net/minecraft/server/gui/MinecraftServerGui.java.patch index 53a34b4876cc..7d1652db9cb0 100644 --- a/paper-server/patches/sources/net/minecraft/server/gui/MinecraftServerGui.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/gui/MinecraftServerGui.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/gui/MinecraftServerGui.java +++ b/net/minecraft/server/gui/MinecraftServerGui.java -@@ -54,6 +_,13 @@ +@@ -53,6 +_,13 @@ frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); @@ -14,15 +14,15 @@ frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(final WindowEvent event) { -@@ -75,6 +_,7 @@ +@@ -74,6 +_,7 @@ this.setLayout(new BorderLayout()); try { + this.add(this.buildOnboardingPanel(), "North"); // Paper - Add onboarding message for initial server start this.add(this.buildChatPanel(), "Center"); this.add(this.buildInfoPanel(), "West"); - } catch (Exception var3) { -@@ -88,7 +_,7 @@ + } catch (Exception e) { +@@ -87,7 +_,7 @@ private JComponent buildInfoPanel() { JPanel panel = new JPanel(new BorderLayout()); @@ -31,7 +31,7 @@ this.finalizers.add(comp::close); panel.add(comp, "North"); panel.add(this.buildPlayerPanel(), "Center"); -@@ -155,6 +_,7 @@ +@@ -150,6 +_,7 @@ this.finalizers.forEach(Runnable::run); } @@ -39,7 +39,7 @@ public void print(final JTextArea console, final JScrollPane scrollPane, final String line) { if (!SwingUtilities.isEventDispatchThread()) { SwingUtilities.invokeLater(() -> this.print(console, scrollPane, line)); -@@ -167,7 +_,7 @@ +@@ -162,7 +_,7 @@ } try { @@ -48,7 +48,7 @@ } catch (BadLocationException var8) { } -@@ -176,4 +_,37 @@ +@@ -171,4 +_,37 @@ } } } diff --git a/paper-server/patches/sources/net/minecraft/server/level/ChunkHolder.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ChunkHolder.java.patch index 40e8aed5c903..52808dc0fd74 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ChunkHolder.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ChunkHolder.java.patch @@ -41,14 +41,14 @@ return this.getTickingChunkFuture().getNow(UNLOADED_LEVEL_CHUNK).orElse(null); } -@@ -127,6 +_,7 @@ - } else { - boolean hadChangedSections = this.hasChangedSections; - int sectionIndex = this.levelHeightAccessor.getSectionIndex(pos.getY()); -+ if (sectionIndex < 0 || sectionIndex >= this.changedBlocksPerSection.length) return false; // CraftBukkit - SPIGOT-6086, SPIGOT-6296 - ShortSet changedBlocksInSection = this.changedBlocksPerSection[sectionIndex]; - if (changedBlocksInSection == null) { - this.hasChangedSections = true; +@@ -128,6 +_,7 @@ + + boolean hadChangedSections = this.hasChangedSections; + int sectionIndex = this.levelHeightAccessor.getSectionIndex(pos.getY()); ++ if (sectionIndex < 0 || sectionIndex >= this.changedBlocksPerSection.length) return false; // CraftBukkit - SPIGOT-6086, SPIGOT-6296 + ShortSet changedBlocksInSection = this.changedBlocksPerSection[sectionIndex]; + if (changedBlocksInSection == null) { + this.hasChangedSections = true; @@ -270,6 +_,38 @@ scheduler.onFullChunkStatusChange(this.pos, status); } diff --git a/paper-server/patches/sources/net/minecraft/server/level/ChunkMap.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ChunkMap.java.patch index 922dc8e44673..c2584b6efe61 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ChunkMap.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ChunkMap.java.patch @@ -81,14 +81,14 @@ CrashReport report = CrashReport.forThrowable(exception, "Chunk loading"); CrashReportCategory category = report.addCategory("Chunk loading"); category.setDetail("Details", details); -@@ -385,6 +_,7 @@ - chunk.setTicketLevel(level); - } else { - chunk = new ChunkHolder(ChunkPos.unpack(node), level, this.level, this.lightEngine, this::onLevelChange, this); -+ ca.spottedleaf.moonrise.common.PlatformHooks.get().onChunkHolderCreate(this.level, chunk); // Paper - } +@@ -386,6 +_,7 @@ + chunk.setTicketLevel(level); + } else { + chunk = new ChunkHolder(ChunkPos.unpack(node), level, this.level, this.lightEngine, this::onLevelChange, this); ++ ca.spottedleaf.moonrise.common.PlatformHooks.get().onChunkHolderCreate(this.level, chunk); // Paper + } - this.updatingChunkMap.put(node, chunk); + this.updatingChunkMap.put(node, chunk); @@ -413,8 +_,8 @@ protected void saveAllChunks(final boolean flushStorage) { @@ -141,7 +141,7 @@ } }, this.unloadQueue::add).whenComplete((ignored, throwable) -> { if (throwable != null) { -@@ -841,7 +_,7 @@ +@@ -843,7 +_,7 @@ } public int size() { @@ -150,7 +150,7 @@ } public net.minecraft.server.level.DistanceManager getDistanceManager() { -@@ -868,10 +_,10 @@ +@@ -870,10 +_,10 @@ .addColumn("fluid_ticks") .build(output); @@ -165,7 +165,7 @@ Optional chunk = Optional.ofNullable(holder.getLatestChunk()); Optional fullChunk = chunk.flatMap( chunkAccess -> chunkAccess instanceof LevelChunk ? Optional.of((LevelChunk)chunkAccess) : Optional.empty() -@@ -920,14 +_,14 @@ +@@ -922,14 +_,14 @@ return this.upgradeChunkTag( tag, -1, @@ -183,7 +183,7 @@ generatorIdentifier.ifPresent(identifier -> contextTag.putString("generator", identifier.toString())); return contextTag; } -@@ -939,7 +_,7 @@ +@@ -941,7 +_,7 @@ ChunkHolder holder = this.visibleChunkMap.get(spawnCandidateChunks.nextLong()); if (holder != null) { LevelChunk chunk = holder.getTickingChunk(); @@ -192,7 +192,7 @@ output.add(chunk); } } -@@ -959,8 +_,14 @@ +@@ -961,8 +_,14 @@ } public boolean anyPlayerCloseEnoughForSpawning(final ChunkPos pos) { @@ -208,7 +208,7 @@ } boolean anyPlayerCloseEnoughTo(final BlockPos pos, final int maxDistance) { -@@ -976,8 +_,24 @@ +@@ -978,8 +_,24 @@ } private boolean anyPlayerCloseEnoughForSpawningInternal(final ChunkPos pos) { @@ -234,31 +234,32 @@ return true; } } -@@ -993,7 +_,7 @@ - Builder builder = ImmutableList.builder(); +@@ -996,7 +_,7 @@ + Builder builder = ImmutableList.builder(); - for (ServerPlayer player : this.playerMap.getAllPlayers()) { -- if (this.playerIsCloseEnoughForSpawning(player, pos)) { -+ if (this.playerIsCloseEnoughForSpawning(player, pos, 16384.0)) { // Spigot - builder.add(player); - } + for (ServerPlayer player : this.playerMap.getAllPlayers()) { +- if (this.playerIsCloseEnoughForSpawning(player, pos)) { ++ if (this.playerIsCloseEnoughForSpawning(player, pos, 16384.0)) { // Spigot + builder.add(player); } -@@ -1002,12 +_,12 @@ } +@@ -1004,13 +_,13 @@ + return builder.build(); } - private boolean playerIsCloseEnoughForSpawning(final ServerPlayer player, final ChunkPos pos) { + private boolean playerIsCloseEnoughForSpawning(final ServerPlayer player, final ChunkPos pos, final double range) { // Spigot if (player.isSpectator()) { return false; - } else { - double distanceToChunk = euclideanDistanceSquared(pos, player.position()); -- return distanceToChunk < 16384.0; -+ return distanceToChunk < range; // Spigot } + + double distanceToChunk = euclideanDistanceSquared(pos, player.position()); +- return distanceToChunk < 16384.0; ++ return distanceToChunk < range; // Spigot } -@@ -1136,9 +_,19 @@ + private boolean playerIsCloseEnoughTo(final ServerPlayer player, final Vec3 pos, final int maxDistance) { +@@ -1138,9 +_,19 @@ } public void addEntity(final Entity entity) { @@ -278,7 +279,7 @@ if (range != 0) { int updateInterval = type.updateInterval(); if (this.entityMap.containsKey(entity.getId())) { -@@ -1162,6 +_,7 @@ +@@ -1164,6 +_,7 @@ } protected void removeEntity(final Entity entity) { @@ -286,18 +287,20 @@ if (entity instanceof ServerPlayer player) { this.updatePlayerStatus(player, false); -@@ -1329,8 +_,8 @@ +@@ -1325,10 +_,10 @@ + private final Entity entity; + private final int range; + private SectionPos lastSectionPos; +- public final Set seenBy = Sets.newIdentityHashSet(); ++ public final Set seenBy = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl + public TrackedEntity(final Entity entity, final int range, final int updateInterval, final boolean trackDelta) { - Objects.requireNonNull(ChunkMap.this); - super(); -- this.seenBy = Sets.newIdentityHashSet(); - this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, updateInterval, trackDelta, this); -+ this.seenBy = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl + this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, updateInterval, trackDelta, this, this.seenBy); // Paper this.entity = entity; this.range = range; this.lastSectionPos = SectionPos.of(entity); -@@ -1377,6 +_,7 @@ +@@ -1375,6 +_,7 @@ } public void removePlayer(final ServerPlayer player) { @@ -305,7 +308,7 @@ if (this.seenBy.remove(player.connection)) { this.serverEntity.removePairing(player); if (this.seenBy.isEmpty()) { -@@ -1386,23 +_,47 @@ +@@ -1384,23 +_,47 @@ } public void updatePlayer(final ServerPlayer player) { @@ -356,7 +359,7 @@ } } else { this.removePlayer(player); -@@ -1419,6 +_,7 @@ +@@ -1417,6 +_,7 @@ for (Entity passenger : this.entity.getIndirectPassengers()) { int passengerRange = passenger.getType().clientTrackingRange() * 16; diff --git a/paper-server/patches/sources/net/minecraft/server/level/DistanceManager.java.patch b/paper-server/patches/sources/net/minecraft/server/level/DistanceManager.java.patch index 0b09c2876f86..fc6279bfda6a 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/DistanceManager.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/DistanceManager.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/level/DistanceManager.java +++ b/net/minecraft/server/level/DistanceManager.java -@@ -73,6 +_,12 @@ +@@ -72,6 +_,12 @@ } if (!this.chunksToUpdateFutures.isEmpty()) { @@ -13,7 +13,7 @@ for (ChunkHolder chunksToUpdateFuture : this.chunksToUpdateFutures) { chunksToUpdateFuture.updateHighestAllowedStatus(scheduler); } -@@ -120,8 +_,10 @@ +@@ -119,8 +_,10 @@ ChunkPos chunk = pos.chunk(); long chunkPos = chunk.pack(); ObjectSet chunkPlayers = this.playersPerChunk.get(chunkPos); diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerChunkCache.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerChunkCache.java.patch index 429613b7c742..6c6d0782b322 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerChunkCache.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerChunkCache.java.patch @@ -31,7 +31,7 @@ this.level = level; this.mainThreadProcessor = new ServerChunkCache.MainThreadExecutor(level); @@ -99,7 +_,7 @@ - LOGGER.error("Failed to create dimension data storage directory", (Throwable)var14); + LOGGER.error("Failed to create dimension data storage directory", e); } - this.savedDataStorage = new SavedDataStorage(dataFolder, fixerUpper, level.registryAccess()); @@ -104,23 +104,15 @@ @Override public ThreadedLevelLightEngine getLightEngine() { return this.lightEngine; -@@ -155,7 +_,7 @@ - for (int i = 0; i < 4; i++) { - if (pos == this.lastChunkPos[i] && targetStatus == this.lastChunkStatus[i]) { - ChunkAccess chunkAccess = this.lastChunk[i]; -- if (chunkAccess != null || !loadOrGenerate) { -+ if (chunkAccess != null) { // CraftBukkit - the chunk can become accessible in the meantime TODO for non-null chunks it might also make sense to check that the chunk's state hasn't changed in the meantime - return chunkAccess; - } +@@ -156,7 +_,7 @@ + for (int i = 0; i < 4; i++) { + if (pos == this.lastChunkPos[i] && targetStatus == this.lastChunkStatus[i]) { + ChunkAccess chunkAccess = this.lastChunk[i]; +- if (chunkAccess != null || !loadOrGenerate) { ++ if (chunkAccess != null) { // CraftBukkit - the chunk can become accessible in the meantime TODO for non-null chunks it might also make sense to check that the chunk's state hasn't changed in the meantime + return chunkAccess; } -@@ -164,6 +_,7 @@ - profiler.incrementCounter("getChunkCacheMiss"); - CompletableFuture> serverFuture = this.getChunkFutureMainThread(x, z, targetStatus, loadOrGenerate); - this.mainThreadProcessor.managedBlock(serverFuture::isDone); -+ // com.destroystokyo.paper.io.SyncLoadFinder.logSyncLoad(this.level, x, z); // Paper - Add debug for sync chunk loads - ChunkResult chunkResult = serverFuture.join(); - ChunkAccess chunk = chunkResult.orElse(null); - if (chunk == null && loadOrGenerate) { + } @@ -236,7 +_,15 @@ long key = pos.pack(); int targetTicketLevel = ChunkLevel.byStatus(targetStatus); @@ -223,7 +215,7 @@ } else { spawningCategories = List.of(); } -@@ -556,7 +_,13 @@ +@@ -558,7 +_,13 @@ @Override public void setSpawnSettings(final boolean spawnEnemies) { @@ -237,17 +229,17 @@ } public String getChunkDebugData(final ChunkPos pos) { -@@ -624,12 +_,18 @@ +@@ -625,12 +_,18 @@ @Override protected boolean pollTask() { + try { // CraftBukkit - process pending Chunk loadCallback() and unloadCallback() after each run task if (ServerChunkCache.this.runDistanceManagerUpdates()) { return true; - } else { - ServerChunkCache.this.lightEngine.tryScheduleUpdate(); - return super.pollTask(); } + + ServerChunkCache.this.lightEngine.tryScheduleUpdate(); + return super.pollTask(); + // CraftBukkit start - process pending Chunk loadCallback() and unloadCallback() after each run task + } finally { + ServerChunkCache.this.chunkMap.callbackExecutor.run(); diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch index 0ecdec0eace2..c71e11b9d093 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch @@ -417,7 +417,7 @@ } } -@@ -611,16 +_,24 @@ +@@ -611,6 +_,13 @@ } protected BlockPos findLightningTargetAround(final BlockPos pos) { @@ -431,18 +431,20 @@ BlockPos center = this.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, pos); Optional lightningRodTarget = this.findLightningRod(center); if (lightningRodTarget.isPresent()) { - return lightningRodTarget.get(); - } else { - AABB search = AABB.encapsulatingFullBlocks(center, center.atY(this.getMaxY() + 1)).inflate(3.0); -- List entities = this.getEntitiesOfClass(LivingEntity.class, search, input -> input.isAlive() && this.canSeeSky(input.blockPosition())); -+ List entities = this.getEntitiesOfClass(LivingEntity.class, search, input -> input.isAlive() && this.canSeeSky(input.blockPosition()) && !input.isSpectator()); // Paper - Fix lightning being able to hit spectators (MC-262422) - if (!entities.isEmpty()) { - return entities.get(this.random.nextInt(entities.size())).blockPosition(); - } else { -+ if (returnNullWhenNoTarget) return null; // Paper - Add methods to find targets for lightning strikes - if (center.getY() == this.getMinY() - 1) { - center = center.above(2); - } +@@ -618,11 +_,12 @@ + } + + AABB search = AABB.encapsulatingFullBlocks(center, center.atY(this.getMaxY() + 1)).inflate(3.0); +- List entities = this.getEntitiesOfClass(LivingEntity.class, search, input -> input.isAlive() && this.canSeeSky(input.blockPosition())); ++ List entities = this.getEntitiesOfClass(LivingEntity.class, search, input -> input.isAlive() && this.canSeeSky(input.blockPosition()) && !input.isSpectator()); // Paper - Fix lightning being able to hit spectators (MC-262422) + if (!entities.isEmpty()) { + return entities.get(this.random.nextInt(entities.size())).blockPosition(); + } + ++ if (returnNullWhenNoTarget) return null; // Paper - Add methods to find targets for lightning strikes + if (center.getY() == this.getMinY() - 1) { + center = center.above(2); + } @@ -739,8 +_,8 @@ weatherData.setThunderTime(thunderTime); weatherData.setRainTime(rainTime); @@ -682,11 +684,11 @@ + // CraftBukkit end if (entity.getSelfAndPassengers().map(Entity::getUUID).anyMatch(this.entityManager::isLoaded)) { return false; - } else { -- this.addFreshEntityWithPassengers(entity); -+ this.addFreshEntityWithPassengers(entity, reason); // CraftBukkit - return true; } + +- this.addFreshEntityWithPassengers(entity); ++ this.addFreshEntityWithPassengers(entity, reason); // CraftBukkit + return true; } public void unload(final LevelChunk levelChunk) { @@ -976,8 +978,8 @@ - if (!this.server.getWorldGenSettings().options().generateStructures()) { + if (!this.worldGenSettings.options().generateStructures()) { // CraftBukkit return null; - } else { - Optional> tag = this.registryAccess().lookupOrThrow(Registries.STRUCTURE).get(structureTag); + } + @@ -1479,10 +_,36 @@ @Override @@ -1115,7 +1117,7 @@ @Override public CrashReportCategory fillReportDetails(final CrashReport report) { -@@ -1905,6 +_,7 @@ +@@ -1900,6 +_,7 @@ if (entity instanceof WaypointTransmitter waypoint && waypoint.isTransmittingWaypoint()) { ServerLevel.this.getWaypointManager().trackWaypoint(waypoint); } @@ -1123,7 +1125,7 @@ } @Override -@@ -1918,17 +_,24 @@ +@@ -1913,17 +_,24 @@ @Override public void onTickingStart(final Entity entity) { @@ -1149,7 +1151,7 @@ if (entity instanceof ServerPlayer player) { ServerLevel.this.players.add(player); if (player.isReceivingWaypoints()) { -@@ -1943,7 +_,7 @@ +@@ -1938,7 +_,7 @@ } if (entity instanceof Mob mob) { @@ -1158,7 +1160,7 @@ String message = "onTrackingStart called during navigation iteration"; Util.logAndPauseIfInIde( "onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration") -@@ -1960,10 +_,52 @@ +@@ -1955,10 +_,52 @@ } entity.updateDynamicGameEventListener(DynamicGameEventListener::add); @@ -1211,7 +1213,7 @@ ServerLevel.this.getChunkSource().removeEntity(entity); if (entity instanceof ServerPlayer player) { ServerLevel.this.players.remove(player); -@@ -1972,7 +_,7 @@ +@@ -1967,7 +_,7 @@ } if (entity instanceof Mob mob) { @@ -1220,7 +1222,7 @@ String message = "onTrackingStart called during navigation iteration"; Util.logAndPauseIfInIde( "onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration") -@@ -1990,6 +_,15 @@ +@@ -1985,6 +_,15 @@ entity.updateDynamicGameEventListener(DynamicGameEventListener::remove); ServerLevel.this.debugSynchronizers.dropEntity(entity); @@ -1236,7 +1238,7 @@ } @Override -@@ -1997,4 +_,24 @@ +@@ -1992,4 +_,24 @@ entity.updateDynamicGameEventListener(DynamicGameEventListener::move); } } diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch index 353b83ed6014..36e80c0dc5b1 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java -@@ -253,7 +_,8 @@ +@@ -252,7 +_,8 @@ private int levitationStartTime; private boolean disconnected; private int requestedViewDistance = 2; @@ -10,7 +10,7 @@ private @Nullable Vec3 startingToFallPosition; private @Nullable Vec3 enteredNetherPosition; private @Nullable Vec3 enteredLavaOnVehiclePosition; -@@ -308,6 +_,13 @@ +@@ -297,6 +_,13 @@ } } @@ -24,7 +24,7 @@ @Override public void sendSlotChange(final AbstractContainerMenu container, final int slotIndex, final ItemStack itemStack) { ServerPlayer.this.connection.send(new ClientboundContainerSetSlotPacket(container.containerId, container.incrementStateId(), slotIndex, itemStack)); -@@ -347,6 +_,32 @@ +@@ -332,6 +_,32 @@ } } @@ -57,7 +57,7 @@ @Override public void dataChanged(final AbstractContainerMenu container, final int id, final int value) { } -@@ -377,10 +_,43 @@ +@@ -358,10 +_,43 @@ public void sendSystemMessage(final Component message) { ServerPlayer.this.sendSystemMessage(message); } @@ -101,7 +101,7 @@ public ServerPlayer(final MinecraftServer server, final ServerLevel level, final GameProfile gameProfile, final ClientInformation clientInformation) { super(level, gameProfile); -@@ -391,8 +_,14 @@ +@@ -372,8 +_,14 @@ this.recipeBook = new ServerRecipeBook((id, output) -> server.getRecipeManager().listDisplaysForRecipe(id, output)); this.stats = server.getPlayerList().getPlayerStats(this); this.advancements = server.getPlayerList().getPlayerAdvancements(this); @@ -117,7 +117,7 @@ } @Override -@@ -410,6 +_,7 @@ +@@ -391,6 +_,7 @@ this.seenCredits = input.getBooleanOr("seenCredits", false); input.read("recipeBook", ServerRecipeBook.Packed.CODEC) .ifPresent(p -> this.recipeBook.loadUntrusted(p, id -> this.server.getRecipeManager().byKey(id).isPresent())); @@ -125,7 +125,7 @@ if (this.isSleeping()) { this.stopSleeping(); } -@@ -417,6 +_,19 @@ +@@ -398,6 +_,19 @@ this.respawnConfig = input.read("respawn", ServerPlayer.RespawnConfig.CODEC).orElse(null); this.spawnExtraParticlesOnFall = input.getBooleanOr("spawn_extra_particles_on_fall", false); this.raidOmenPosition = input.read("raid_omen_position", BlockPos.CODEC).orElse(null); @@ -145,7 +145,7 @@ this.gameMode .setGameModeForPlayer(this.calculateGameModeForNewPlayer(readPlayerMode(input, "playerGameType")), readPlayerMode(input, "previousPlayerGameType")); this.setShoulderEntityLeft(input.read("ShoulderEntityLeft", CompoundTag.CODEC).orElseGet(CompoundTag::new)); -@@ -444,12 +_,24 @@ +@@ -425,12 +_,24 @@ if (!this.getShoulderEntityRight().isEmpty()) { output.store("ShoulderEntityRight", CompoundTag.CODEC, this.getShoulderEntityRight()); } @@ -171,7 +171,7 @@ ValueOutput vehicleWrapper = playerOutput.child("RootVehicle"); vehicleWrapper.store("Attach", UUIDUtil.CODEC, vehicle.getUUID()); rootVehicle.save(vehicleWrapper.child("Entity")); -@@ -461,7 +_,7 @@ +@@ -442,7 +_,7 @@ if (!rootTag.isEmpty()) { ServerLevel serverLevel = this.level(); Entity vehicle = EntityType.loadEntityRecursive( @@ -180,20 +180,20 @@ ); if (vehicle != null) { UUID attachTo = rootTag.get().read("Attach", UUIDUtil.CODEC).orElse(null); -@@ -478,10 +_,10 @@ +@@ -459,10 +_,10 @@ if (!this.isPassenger()) { LOGGER.warn("Couldn't reattach entity to player"); - vehicle.discard(); + vehicle.discard(null); // CraftBukkit - add Bukkit remove cause - for (Entity entityx : vehicle.getIndirectPassengers()) { -- entityx.discard(); -+ entityx.discard(null); // CraftBukkit - add Bukkit remove cause + for (Entity entity : vehicle.getIndirectPassengers()) { +- entity.discard(); ++ entity.discard(null); // CraftBukkit - add Bukkit remove cause } } } -@@ -493,6 +_,7 @@ +@@ -474,6 +_,7 @@ ValueOutput.ValueOutputList pearlsOutput = playerOutput.childrenList("ender_pearls"); for (ThrownEnderpearl enderPearl : this.enderPearls) { @@ -201,7 +201,7 @@ if (enderPearl.isRemoved()) { LOGGER.warn("Trying to save removed ender pearl, skipping"); } else { -@@ -527,6 +_,16 @@ +@@ -508,6 +_,16 @@ } } @@ -218,7 +218,7 @@ public void setExperiencePoints(final int amount) { float limit = this.getXpNeededForNextLevel(); float max = (limit - 1.0F) / limit; -@@ -591,6 +_,11 @@ +@@ -572,6 +_,11 @@ @Override public void tick() { @@ -230,7 +230,7 @@ this.connection.tickClientLoadTimeout(); this.gameMode.tick(); this.wardenSpawnTracker.tick(); -@@ -598,9 +_,18 @@ +@@ -579,9 +_,18 @@ this.invulnerableTime--; } @@ -252,7 +252,7 @@ this.containerMenu = this.inventoryMenu; } -@@ -659,10 +_,10 @@ +@@ -640,10 +_,10 @@ public void doTick() { try { @@ -265,7 +265,7 @@ this.containerMenu = this.inventoryMenu; } -@@ -692,7 +_,7 @@ +@@ -673,7 +_,7 @@ if (this.getHealth() != this.lastSentHealth || this.lastSentFood != this.foodData.getFoodLevel() || this.foodData.getSaturationLevel() == 0.0F != this.lastFoodSaturationZero) { @@ -274,8 +274,8 @@ this.lastSentHealth = this.getHealth(); this.lastSentFood = this.foodData.getFoodLevel(); this.lastFoodSaturationZero = this.foodData.getSaturationLevel() == 0.0F; -@@ -723,6 +_,12 @@ - this.updateScoreForCriteria(ObjectiveCriteria.EXPERIENCE, Mth.ceil((float)this.lastRecordedExperience)); +@@ -704,6 +_,12 @@ + this.updateScoreForCriteria(ObjectiveCriteria.EXPERIENCE, Mth.ceil(this.lastRecordedExperience)); } + // CraftBukkit start - Force max health updates @@ -286,12 +286,11 @@ + if (this.experienceLevel != this.lastRecordedLevel) { this.lastRecordedLevel = this.experienceLevel; - this.updateScoreForCriteria(ObjectiveCriteria.LEVEL, Mth.ceil((float)this.lastRecordedLevel)); -@@ -736,6 +_,21 @@ + this.updateScoreForCriteria(ObjectiveCriteria.LEVEL, Mth.ceil(this.lastRecordedLevel)); +@@ -717,6 +_,20 @@ if (this.tickCount % 20 == 0) { CriteriaTriggers.LOCATION.trigger(this); } -+ + // CraftBukkit start - initialize oldLevel, fire PlayerLevelChangeEvent, and tick client-sided world border + if (this.oldLevel == -1) { + this.oldLevel = this.experienceLevel; @@ -306,10 +305,10 @@ + ((org.bukkit.craftbukkit.CraftWorldBorder) this.getBukkitEntity().getWorldBorder()).getHandle().tick(); + } + // CraftBukkit end - } catch (Throwable var4) { - CrashReport report = CrashReport.forThrowable(var4, "Ticking player"); + } catch (Throwable t) { + CrashReport report = CrashReport.forThrowable(t, "Ticking player"); CrashReportCategory category = report.addCategory("Player being ticked"); -@@ -760,7 +_,7 @@ +@@ -741,7 +_,7 @@ if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.level().getGameRules().get(GameRules.NATURAL_HEALTH_REGENERATION)) { if (this.tickCount % 20 == 0) { if (this.getHealth() < this.getMaxHealth()) { @@ -318,7 +317,7 @@ } float saturation = this.foodData.getSaturationLevel(); -@@ -780,6 +_,7 @@ +@@ -761,6 +_,7 @@ this.playShoulderEntityAmbientSound(this.getShoulderEntityLeft()); this.playShoulderEntityAmbientSound(this.getShoulderEntityRight()); if (this.fallDistance > 0.5 || this.isInWater() || this.getAbilities().flying || this.isSleeping() || this.isInPowderSnow) { @@ -326,7 +325,7 @@ this.removeEntitiesOnShoulder(); } } -@@ -824,33 +_,62 @@ +@@ -805,29 +_,58 @@ @Override public void removeEntitiesOnShoulder() { if (this.timeEntitySatOnShoulder + 20L < this.level().getGameTime()) { @@ -369,34 +368,30 @@ + @Nullable + private Entity respawnEntityOnShoulder0(final CompoundTag tag) { // CraftBukkit void->boolean + // Paper end - release entity api - return entity - overload - ServerLevel reporter = this.level(); - if (reporter instanceof ServerLevel) { - ServerLevel serverLevel = reporter; - if (!tag.isEmpty()) { - try (ProblemReporter.ScopedCollector reporterx = new ProblemReporter.ScopedCollector(this.problemPath(), LOGGER)) { -- EntityType.create( -+ return EntityType.create( // Paper - release entity api - TagValueInput.create(reporterx.forChild(() -> ".shoulder"), serverLevel.registryAccess(), tag), serverLevel, EntitySpawnReason.LOAD - ) -- .ifPresent(entity -> { -+ .map(entity -> { // Paper - release entity api - if (entity instanceof TamableAnimal tamed) { - tamed.setOwner(this); - } - - entity.setPos(this.getX(), this.getY() + 0.7F, this.getZ()); -- serverLevel.addWithUUID(entity); -- }); -+ return serverLevel.addWithUUID(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SHOULDER_ENTITY) ? entity : null; // Paper - spawn reason -+ }).orElse(null); // Paper - release entity api - return entity - } + if (this.level() instanceof ServerLevel serverLevel && !tag.isEmpty()) { + try (ProblemReporter.ScopedCollector reporter = new ProblemReporter.ScopedCollector(this.problemPath(), LOGGER)) { +- EntityType.create( ++ return EntityType.create( // Paper - release entity api + TagValueInput.create(reporter.forChild(() -> ".shoulder"), serverLevel.registryAccess(), tag), serverLevel, EntitySpawnReason.LOAD + ) +- .ifPresent(entity -> { ++ .map(entity -> { // Paper - release entity api + if (entity instanceof TamableAnimal tamed) { + tamed.setOwner(this); + } + + entity.setPos(this.getX(), this.getY() + 0.7F, this.getZ()); +- serverLevel.addWithUUID(entity); +- }); ++ return serverLevel.addWithUUID(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SHOULDER_ENTITY) ? entity : null; // Paper - spawn reason ++ }).orElse(null); // Paper - release entity api - return entity } } + return null; // Paper - return null } @Override -@@ -887,15 +_,36 @@ +@@ -864,15 +_,36 @@ } private void updateScoreForCriteria(final ObjectiveCriteria criteria, final int value) { @@ -442,7 +437,7 @@ this.connection .send( new ClientboundPlayerCombatKillPacket(this.getId(), deathMessage), -@@ -912,6 +_,64 @@ +@@ -889,6 +_,64 @@ } ) ); @@ -507,7 +502,7 @@ Team team = this.getTeam(); if (team == null || team.getDeathMessageVisibility() == Team.Visibility.ALWAYS) { this.server.getPlayerList().broadcastSystemMessage(deathMessage, false); -@@ -921,7 +_,7 @@ +@@ -898,7 +_,7 @@ this.server.getPlayerList().broadcastSystemToAllExceptTeam(this, deathMessage); } } else { @@ -516,7 +511,7 @@ } this.removeEntitiesOnShoulder(); -@@ -929,11 +_,35 @@ +@@ -906,11 +_,35 @@ this.tellNeutralMobsThatIDied(); } @@ -555,7 +550,7 @@ LivingEntity killer = this.getKillCredit(); if (killer != null) { this.awardStat(Stats.ENTITY_KILLED_BY.get(killer.getType())); -@@ -967,10 +_,10 @@ +@@ -944,10 +_,10 @@ if (victim != this) { super.awardKillScore(victim, killingBlow); Scoreboard scoreboard = this.level().getScoreboard(); @@ -568,7 +563,7 @@ } else { this.awardStat(Stats.MOB_KILLS); } -@@ -983,11 +_,11 @@ +@@ -960,11 +_,11 @@ private void handleTeamKill(final ScoreHolder source, final ScoreHolder target, final ObjectiveCriteria[] criteriaByTeam) { Scoreboard scoreboard = this.level().getScoreboard(); @@ -582,31 +577,31 @@ } } } -@@ -998,9 +_,20 @@ - return false; - } else { - Entity entity = source.getEntity(); -- return !(entity instanceof Player playerx && !this.canHarmPlayer(playerx)) -- && !(entity instanceof AbstractArrow arrow && arrow.getOwner() instanceof Player player && !this.canHarmPlayer(player)) -- && super.hurtServer(level, source, damage); -+ if (!( // Paper - split the if statement. If below statement is false, hurtServer would not have been evaluated. Return false. -+ !(entity instanceof Player playerx && !this.canHarmPlayer(playerx)) -+ && !(entity instanceof AbstractArrow arrow && arrow.getOwner() instanceof Player player && !this.canHarmPlayer(player)) -+ )) return false; // Paper - split the if statement. If below statement is false, hurtServer would not have been evaluated. Return false. -+ // Paper start - cancellable death events -+ this.queueHealthUpdatePacket = true; -+ boolean damaged = super.hurtServer(level, source, damage); -+ this.queueHealthUpdatePacket = false; -+ if (this.queuedHealthUpdatePacket != null) { -+ this.connection.send(this.queuedHealthUpdatePacket); -+ this.queuedHealthUpdatePacket = null; -+ } -+ return damaged; -+ // Paper end - cancellable death events +@@ -976,9 +_,20 @@ } + + Entity entity = source.getEntity(); +- return !(entity instanceof Player player && !this.canHarmPlayer(player)) +- && !(entity instanceof AbstractArrow arrow && arrow.getOwner() instanceof Player owner && !this.canHarmPlayer(owner)) +- && super.hurtServer(level, source, damage); ++ if (!( // Paper - split the if statement. If below statement is false, hurtServer would not have been evaluated. Return false. ++ !(entity instanceof Player player && !this.canHarmPlayer(player)) ++ && !(entity instanceof AbstractArrow arrow && arrow.getOwner() instanceof Player owner && !this.canHarmPlayer(owner)) ++ )) return false; // Paper - split the if statement. If below statement is false, hurtServer would not have been evaluated. Return false. ++ // Paper start - cancellable death events ++ this.queueHealthUpdatePacket = true; ++ boolean damaged = super.hurtServer(level, source, damage); ++ this.queueHealthUpdatePacket = false; ++ if (this.queuedHealthUpdatePacket != null) { ++ this.connection.send(this.queuedHealthUpdatePacket); ++ this.queuedHealthUpdatePacket = null; ++ } ++ return damaged; ++ // Paper end - cancellable death events } -@@ -1013,24 +_,98 @@ + @Override +@@ -990,24 +_,98 @@ return this.level().isPvpAllowed(); } @@ -712,7 +707,7 @@ } public boolean isReceivingWaypoints() { -@@ -1064,15 +_,17 @@ +@@ -1041,16 +_,18 @@ if (block instanceof RespawnAnchorBlock && (forced || blockState.getValue(RespawnAnchorBlock.CHARGE) > 0) && RespawnAnchorBlock.canSetSpawn(level, pos) ) { @@ -726,14 +721,15 @@ - return standUpPosition.map(p -> ServerPlayer.RespawnPosAngle.of(p, pos, 0.0F)); + return standUpPosition.map(p -> ServerPlayer.RespawnPosAngle.of(p, pos, 0.0F, false, true, finalConsumeAnchorCharge)); // Paper - Fix SPIGOT-5989 (don't use charge until after respawn event) - } else if (block instanceof BedBlock && level.environmentAttributes().getValue(EnvironmentAttributes.BED_RULE, pos).canSetSpawn(level)) { - return BedBlock.findStandUpPosition(EntityType.PLAYER, level, pos, blockState.getValue(BedBlock.FACING), yaw) -- .map(p -> ServerPlayer.RespawnPosAngle.of(p, pos, 0.0F)); -+ .map(p -> ServerPlayer.RespawnPosAngle.of(p, pos, 0.0F, true, false, null)); // Paper - Fix SPIGOT-5989 - } else if (!forced) { - return Optional.empty(); } else { -@@ -1080,7 +_,7 @@ + if (block instanceof BedBlock && level.environmentAttributes().getValue(EnvironmentAttributes.BED_RULE, pos).canSetSpawn(level)) { + return BedBlock.findStandUpPosition(EntityType.PLAYER, level, pos, blockState.getValue(BedBlock.FACING), yaw) +- .map(p -> ServerPlayer.RespawnPosAngle.of(p, pos, 0.0F)); ++ .map(p -> ServerPlayer.RespawnPosAngle.of(p, pos, 0.0F, true, false, null)); // Paper - Fix SPIGOT-5989 + } + + if (!forced) { +@@ -1061,7 +_,7 @@ BlockState topState = level.getBlockState(pos.above()); boolean freeTop = topState.getBlock().isPossibleToRespawnInThis(topState); return freeBottom && freeTop @@ -742,7 +738,7 @@ : Optional.empty(); } } -@@ -1096,7 +_,8 @@ +@@ -1077,7 +_,8 @@ } @Override @@ -751,94 +747,94 @@ + if (this.isSleeping()) return null; // CraftBukkit - SPIGOT-3154 if (this.isRemoved()) { return null; - } else { -@@ -1107,12 +_,46 @@ - ServerLevel newLevel = transition.newLevel(); - ServerLevel oldLevel = this.level(); - ResourceKey lastDimension = oldLevel.dimension(); -+ // CraftBukkit start -+ ResourceKey oldLevelTypeKey = oldLevel.getTypeKey(); -+ -+ org.bukkit.Location enter = this.getBukkitEntity().getLocation(); -+ PositionMoveRotation absolutePosition = PositionMoveRotation.calculateAbsolute(PositionMoveRotation.of(this), PositionMoveRotation.of(transition), transition.relatives()); -+ org.bukkit.Location exit = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(absolutePosition.position(), newLevel, absolutePosition.yRot(), absolutePosition.xRot()); -+ final org.bukkit.event.player.PlayerTeleportEvent tpEvent; -+ // Paper start - gateway-specific teleport event -+ if (this.portalProcess != null && this.portalProcess.isSamePortal(((net.minecraft.world.level.block.EndGatewayBlock) net.minecraft.world.level.block.Blocks.END_GATEWAY)) && this.level().getBlockEntity(this.portalProcess.getEntryPosition()) instanceof net.minecraft.world.level.block.entity.TheEndGatewayBlockEntity theEndGatewayBlockEntity) { -+ tpEvent = new com.destroystokyo.paper.event.player.PlayerTeleportEndGatewayEvent(this.getBukkitEntity(), enter, exit.clone(), new org.bukkit.craftbukkit.block.CraftEndGateway(this.level().getWorld(), theEndGatewayBlockEntity)); -+ } else { -+ tpEvent = new org.bukkit.event.player.PlayerTeleportEvent(this.getBukkitEntity(), enter, exit.clone(), transition.cause()); -+ } -+ // Paper end - gateway-specific teleport event -+ org.bukkit.Bukkit.getServer().getPluginManager().callEvent(tpEvent); -+ org.bukkit.Location newExit = tpEvent.getTo(); -+ if (tpEvent.isCancelled()) { -+ return null; -+ } -+ if (!newExit.equals(exit)) { -+ newLevel = ((org.bukkit.craftbukkit.CraftWorld) newExit.getWorld()).getHandle(); -+ transition = new TeleportTransition( -+ newLevel, -+ org.bukkit.craftbukkit.util.CraftLocation.toVec3(newExit), -+ Vec3.ZERO, -+ newExit.getYaw(), -+ newExit.getPitch(), -+ transition.missingRespawnBlock(), -+ transition.asPassenger(), -+ Set.of(), -+ transition.postTeleportTransition(), -+ transition.cause()); -+ } -+ // CraftBukkit end - if (!transition.asPassenger()) { - this.removeVehicle(); - } - - if (newLevel.dimension() == lastDimension) { -- this.connection.teleport(PositionMoveRotation.of(transition), transition.relatives()); -+ this.connection.internalTeleport(PositionMoveRotation.of(transition), transition.relatives()); // CraftBukkit - this.connection.resetPosition(); - transition.postTeleportTransition().onTransition(this); - return this; -@@ -1123,18 +_,19 @@ - this.connection.send(new ClientboundChangeDifficultyPacket(levelData.getDifficulty(), levelData.isDifficultyLocked())); - PlayerList playerList = this.server.getPlayerList(); - playerList.sendPlayerPermissionLevel(this); -+ this.portalProcess = null; // SPIGOT-7785: there is no need to carry this over as it contains the old world/location and we might run into trouble if there is a portal in the same spot in both worlds - oldLevel.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION); - this.unsetRemoved(); - ProfilerFiller profiler = Profiler.get(); - profiler.push("moving"); -- if (lastDimension == Level.OVERWORLD && newLevel.dimension() == Level.NETHER) { -+ if (oldLevelTypeKey == net.minecraft.world.level.dimension.LevelStem.OVERWORLD && newLevel.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER) { // CraftBukkit - empty to fall through to null to event - this.enteredNetherPosition = this.position(); - } + } +@@ -1089,12 +_,46 @@ + ServerLevel newLevel = transition.newLevel(); + ServerLevel oldLevel = this.level(); + ResourceKey lastDimension = oldLevel.dimension(); ++ // CraftBukkit start ++ ResourceKey oldLevelTypeKey = oldLevel.getTypeKey(); ++ ++ org.bukkit.Location enter = this.getBukkitEntity().getLocation(); ++ PositionMoveRotation absolutePosition = PositionMoveRotation.calculateAbsolute(PositionMoveRotation.of(this), PositionMoveRotation.of(transition), transition.relatives()); ++ org.bukkit.Location exit = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(absolutePosition.position(), newLevel, absolutePosition.yRot(), absolutePosition.xRot()); ++ final org.bukkit.event.player.PlayerTeleportEvent tpEvent; ++ // Paper start - gateway-specific teleport event ++ if (this.portalProcess != null && this.portalProcess.isSamePortal(((net.minecraft.world.level.block.EndGatewayBlock) net.minecraft.world.level.block.Blocks.END_GATEWAY)) && this.level().getBlockEntity(this.portalProcess.getEntryPosition()) instanceof net.minecraft.world.level.block.entity.TheEndGatewayBlockEntity theEndGatewayBlockEntity) { ++ tpEvent = new com.destroystokyo.paper.event.player.PlayerTeleportEndGatewayEvent(this.getBukkitEntity(), enter, exit.clone(), new org.bukkit.craftbukkit.block.CraftEndGateway(this.level().getWorld(), theEndGatewayBlockEntity)); ++ } else { ++ tpEvent = new org.bukkit.event.player.PlayerTeleportEvent(this.getBukkitEntity(), enter, exit.clone(), transition.cause()); ++ } ++ // Paper end - gateway-specific teleport event ++ org.bukkit.Bukkit.getServer().getPluginManager().callEvent(tpEvent); ++ org.bukkit.Location newExit = tpEvent.getTo(); ++ if (tpEvent.isCancelled()) { ++ return null; ++ } ++ if (!newExit.equals(exit)) { ++ newLevel = ((org.bukkit.craftbukkit.CraftWorld) newExit.getWorld()).getHandle(); ++ transition = new TeleportTransition( ++ newLevel, ++ org.bukkit.craftbukkit.util.CraftLocation.toVec3(newExit), ++ Vec3.ZERO, ++ newExit.getYaw(), ++ newExit.getPitch(), ++ transition.missingRespawnBlock(), ++ transition.asPassenger(), ++ Set.of(), ++ transition.postTeleportTransition(), ++ transition.cause()); ++ } ++ // CraftBukkit end + if (!transition.asPassenger()) { + this.removeVehicle(); + } - profiler.pop(); - profiler.push("placing"); - this.setServerLevel(newLevel); -- this.connection.teleport(PositionMoveRotation.of(transition), transition.relatives()); -+ this.connection.internalTeleport(PositionMoveRotation.of(transition), transition.relatives()); // CraftBukkit - use internal teleport without event - this.connection.resetPosition(); - newLevel.addDuringTeleport(this); - profiler.pop(); -@@ -1149,6 +_,15 @@ - this.lastSentHealth = -1.0F; - this.lastSentFood = -1; - this.teleportSpectators(transition, oldLevel); -+ // CraftBukkit start -+ org.bukkit.event.player.PlayerChangedWorldEvent changeEvent = new org.bukkit.event.player.PlayerChangedWorldEvent(this.getBukkitEntity(), oldLevel.getWorld()); -+ this.level().getCraftServer().getPluginManager().callEvent(changeEvent); -+ // CraftBukkit end -+ // Paper start - Reset shield blocking on dimension change -+ if (this.isBlocking()) { -+ this.stopUsingItem(); -+ } -+ // Paper end - Reset shield blocking on dimension change - return this; - } + if (newLevel.dimension() == lastDimension) { +- this.connection.teleport(PositionMoveRotation.of(transition), transition.relatives()); ++ this.connection.internalTeleport(PositionMoveRotation.of(transition), transition.relatives()); // CraftBukkit + this.connection.resetPosition(); + transition.postTeleportTransition().onTransition(this); + return this; +@@ -1106,18 +_,19 @@ + this.connection.send(new ClientboundChangeDifficultyPacket(levelData.getDifficulty(), levelData.isDifficultyLocked())); + PlayerList playerList = this.server.getPlayerList(); + playerList.sendPlayerPermissionLevel(this); ++ this.portalProcess = null; // SPIGOT-7785: there is no need to carry this over as it contains the old world/location and we might run into trouble if there is a portal in the same spot in both worlds + oldLevel.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION); + this.unsetRemoved(); + ProfilerFiller profiler = Profiler.get(); + profiler.push("moving"); +- if (lastDimension == Level.OVERWORLD && newLevel.dimension() == Level.NETHER) { ++ if (oldLevelTypeKey == net.minecraft.world.level.dimension.LevelStem.OVERWORLD && newLevel.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER) { // CraftBukkit - empty to fall through to null to event + this.enteredNetherPosition = this.position(); } -@@ -1163,12 +_,26 @@ + + profiler.pop(); + profiler.push("placing"); + this.setServerLevel(newLevel); +- this.connection.teleport(PositionMoveRotation.of(transition), transition.relatives()); ++ this.connection.internalTeleport(PositionMoveRotation.of(transition), transition.relatives()); // CraftBukkit - use internal teleport without event + this.connection.resetPosition(); + newLevel.addDuringTeleport(this); + profiler.pop(); +@@ -1132,6 +_,15 @@ + this.lastSentHealth = -1.0F; + this.lastSentFood = -1; + this.teleportSpectators(transition, oldLevel); ++ // CraftBukkit start ++ org.bukkit.event.player.PlayerChangedWorldEvent changeEvent = new org.bukkit.event.player.PlayerChangedWorldEvent(this.getBukkitEntity(), oldLevel.getWorld()); ++ this.level().getCraftServer().getPluginManager().callEvent(changeEvent); ++ // CraftBukkit end ++ // Paper start - Reset shield blocking on dimension change ++ if (this.isBlocking()) { ++ this.stopUsingItem(); ++ } ++ // Paper end - Reset shield blocking on dimension change + return this; + } + +@@ -1144,12 +_,26 @@ public void triggerDimensionChangeTriggers(final ServerLevel oldLevel) { ResourceKey oldKey = oldLevel.dimension(); ResourceKey newKey = this.level().dimension(); @@ -868,41 +864,36 @@ this.enteredNetherPosition = null; } } -@@ -1184,10 +_,12 @@ +@@ -1165,9 +_,10 @@ this.containerMenu.broadcastChanges(); } - @Override - public Either startSleepInBed(final BlockPos pos) { - Direction direction = this.level().getBlockState(pos).getValue(HorizontalDirectionalBlock.FACING); -- if (!this.isSleeping() && this.isAlive()) { + // CraftBukkit start - moved bed result checks from below into separate method + private Either getBedResult(final BlockPos pos, final Direction direction) { + BedRule bedRule = this.level().environmentAttributes().getValue(EnvironmentAttributes.BED_RULE, pos); -+ if (bedRule.explodes()) { -+ return Either.left(Player.BedSleepingProblem.EXPLOSION); -+ } else if (!this.isSleeping() && this.isAlive()) { ++ if (bedRule.explodes()) return Either.left(Player.BedSleepingProblem.EXPLOSION); + if (!this.isSleeping() && this.isAlive()) { BedRule rule = this.level().environmentAttributes().getValue(EnvironmentAttributes.BED_RULE, pos); boolean canSleep = rule.canSleep(this.level()); - boolean canSetSpawn = rule.canSetSpawn(this.level()); -@@ -1200,7 +_,7 @@ - } else { - if (canSetSpawn) { - this.setRespawnPosition( -- new ServerPlayer.RespawnConfig(LevelData.RespawnData.of(this.level().dimension(), pos, this.getYRot(), this.getXRot()), false), true -+ new ServerPlayer.RespawnConfig(LevelData.RespawnData.of(this.level().dimension(), pos, this.getYRot(), this.getXRot()), false), true, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.BED // Paper - Add PlayerSetSpawnEvent - ); - } +@@ -1186,7 +_,7 @@ -@@ -1229,7 +_,37 @@ - } - } + if (canSetSpawn) { + this.setRespawnPosition( +- new ServerPlayer.RespawnConfig(LevelData.RespawnData.of(this.level().dimension(), pos, this.getYRot(), this.getXRot()), false), true ++ new ServerPlayer.RespawnConfig(LevelData.RespawnData.of(this.level().dimension(), pos, this.getYRot(), this.getXRot()), false), true, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.BED // Paper - Add PlayerSetSpawnEvent + ); + } -- Either result = super.startSleepInBed(pos).ifRight(unit -> { -+ // CraftBukkit start -+ return Either.right(Unit.INSTANCE); -+ } -+ } +@@ -1209,7 +_,33 @@ + } + } + +- Either result = super.startSleepInBed(pos).ifRight(unit -> { ++ // CraftBukkit start ++ return Either.right(Unit.INSTANCE); + } else { + return Either.left(Player.BedSleepingProblem.OTHER_PROBLEM); + } @@ -925,26 +916,22 @@ + if (bedResult.left().isPresent()) { + return bedResult; + } -+ + { -+ { -+ Either result = super.startSleepInBed(pos, force).ifRight(unit -> { -+ // CraftBukkit end - this.awardStat(Stats.SLEEP_IN_BED); - CriteriaTriggers.SLEPT_IN_BED.trigger(this); - }); -@@ -1239,10 +_,7 @@ - - this.level().updateSleepingPlayerList(); - return result; -- } - } ++ Either result = super.startSleepInBed(pos, force).ifRight(unit -> { ++ // CraftBukkit end + this.awardStat(Stats.SLEEP_IN_BED); + CriteriaTriggers.SLEPT_IN_BED.trigger(this); + }); +@@ -1219,8 +_,6 @@ + + this.level().updateSleepingPlayerList(); + return result; - } else { - return Either.left(Player.BedSleepingProblem.OTHER_PROBLEM); } } -@@ -1270,19 +_,30 @@ +@@ -1248,19 +_,30 @@ @Override public void stopSleepInBed(final boolean forcefulWakeUp, final boolean updateLevelList) { @@ -977,7 +964,7 @@ } @Override -@@ -1330,8 +_,9 @@ +@@ -1308,8 +_,9 @@ this.connection.send(new ClientboundShowDialogPacket(dialog)); } @@ -988,64 +975,65 @@ } @Override -@@ -1339,12 +_,39 @@ - if (provider == null) { +@@ -1318,12 +_,39 @@ return OptionalInt.empty(); - } else { -- if (this.containerMenu != this.inventoryMenu) { -+ if (false && this.containerMenu != this.inventoryMenu) { // CraftBukkit - SPIGOT-6552: Handle inventory closing in CraftEventFactory#callInventoryOpenEventWithTitle(...) - this.closeContainer(); - } + } - this.nextContainerCounter(); - AbstractContainerMenu menu = provider.createMenu(this.containerCounter, this.getInventory(), this); -+ Component title = null; // Paper - Add titleOverride to InventoryOpenEvent -+ // CraftBukkit start - Inventory open hook -+ if (menu != null) { -+ menu.setTitle(provider.getDisplayName()); -+ -+ boolean cancelled = false; -+ // Paper start - Add titleOverride to InventoryOpenEvent -+ final com.mojang.datafixers.util.Pair result = org.bukkit.craftbukkit.event.CraftEventFactory.callInventoryOpenEventWithTitle(this, menu, cancelled); -+ menu = result.getSecond(); -+ title = io.papermc.paper.adventure.PaperAdventure.asVanilla(result.getFirst()); -+ // Paper end - Add titleOverride to InventoryOpenEvent -+ if (menu == null && !cancelled) { // Let pre-cancelled events fall through -+ // SPIGOT-5263 - close chest if cancelled -+ if (provider instanceof Container container) { -+ container.stopOpen(this); -+ } else if (provider instanceof org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest.Provider doubleChestProvider) { -+ // SPIGOT-5355 - double chests too :( -+ doubleChestProvider.container.stopOpen(this); -+ // Paper start - Fix InventoryOpenEvent cancellation -+ } else if (!this.enderChestInventory.isActiveChest(null)) { -+ this.enderChestInventory.stopOpen(this); -+ // Paper end - Fix InventoryOpenEvent cancellation -+ } -+ return OptionalInt.empty(); +- if (this.containerMenu != this.inventoryMenu) { ++ if (false && this.containerMenu != this.inventoryMenu) { // CraftBukkit - SPIGOT-6552: Handle inventory closing in CraftEventFactory#callInventoryOpenEventWithTitle(...) + this.closeContainer(); + } + + this.nextContainerCounter(); + AbstractContainerMenu menu = provider.createMenu(this.containerCounter, this.getInventory(), this); ++ Component title = null; // Paper - Add titleOverride to InventoryOpenEvent ++ // CraftBukkit start - Inventory open hook ++ if (menu != null) { ++ menu.setTitle(provider.getDisplayName()); ++ ++ boolean cancelled = false; ++ // Paper start - Add titleOverride to InventoryOpenEvent ++ final com.mojang.datafixers.util.Pair result = org.bukkit.craftbukkit.event.CraftEventFactory.callInventoryOpenEventWithTitle(this, menu, cancelled); ++ menu = result.getSecond(); ++ title = io.papermc.paper.adventure.PaperAdventure.asVanilla(result.getFirst()); ++ // Paper end - Add titleOverride to InventoryOpenEvent ++ if (menu == null && !cancelled) { // Let pre-cancelled events fall through ++ // SPIGOT-5263 - close chest if cancelled ++ if (provider instanceof Container container) { ++ container.stopOpen(this); ++ } else if (provider instanceof org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest.Provider doubleChestProvider) { ++ // SPIGOT-5355 - double chests too :( ++ doubleChestProvider.container.stopOpen(this); ++ // Paper start - Fix InventoryOpenEvent cancellation ++ } else if (!this.enderChestInventory.isActiveChest(null)) { ++ this.enderChestInventory.stopOpen(this); ++ // Paper end - Fix InventoryOpenEvent cancellation + } ++ return OptionalInt.empty(); + } -+ // CraftBukkit end - if (menu == null) { - if (this.isSpectator()) { - this.sendOverlayMessage(Component.translatable("container.spectatorCantOpen").withStyle(ChatFormatting.RED)); -@@ -1352,9 +_,13 @@ ++ } ++ // CraftBukkit end + if (menu == null) { + if (this.isSpectator()) { + this.sendOverlayMessage(Component.translatable("container.spectatorCantOpen").withStyle(ChatFormatting.RED)); +@@ -1331,9 +_,14 @@ - return OptionalInt.empty(); - } else { -- this.connection.send(new ClientboundOpenScreenPacket(menu.containerId, menu.getType(), provider.getDisplayName())); -+ // CraftBukkit start -+ this.containerMenu = menu; // Moved up -+ if (!this.isImmobile()) -+ this.connection.send(new net.minecraft.network.protocol.game.ClientboundOpenScreenPacket(menu.containerId, menu.getType(), java.util.Objects.requireNonNullElseGet(title, menu::getTitle))); // Paper - Add titleOverride to InventoryOpenEven -+ // CraftBukkit end - this.initMenu(menu); -- this.containerMenu = menu; -+ // CraftBukkit - moved up - return OptionalInt.of(this.containerCounter); - } + return OptionalInt.empty(); + } else { +- this.connection.send(new ClientboundOpenScreenPacket(menu.containerId, menu.getType(), provider.getDisplayName())); ++ // CraftBukkit start ++ this.containerMenu = menu; // Moved up ++ if (!this.isImmobile()) { ++ this.connection.send(new ClientboundOpenScreenPacket(menu.containerId, menu.getType(), java.util.Objects.requireNonNullElseGet(title, menu::getTitle))); // Paper - Add titleOverride to InventoryOpenEven ++ } ++ // CraftBukkit end + this.initMenu(menu); +- this.containerMenu = menu; ++ // CraftBukkit - moved up + return OptionalInt.of(this.containerCounter); } -@@ -1374,27 +_,49 @@ + } +@@ -1352,27 +_,49 @@ @Override public void openHorseInventory(final AbstractHorse horse, final Container container) { @@ -1100,7 +1088,7 @@ this.initMenu(this.containerMenu); } -@@ -1416,10 +_,30 @@ +@@ -1394,10 +_,30 @@ @Override public void closeContainer() { @@ -1131,7 +1119,7 @@ @Override public void doCloseContainer() { this.containerMenu.removed(this); -@@ -1442,19 +_,19 @@ +@@ -1420,19 +_,19 @@ int distance = Math.round((float)Math.sqrt(dx * dx + dy * dy + dz * dz) * 100.0F); if (distance > 0) { this.awardStat(Stats.SWIM_ONE_CM, distance); @@ -1154,7 +1142,7 @@ } } else if (this.onClimbable()) { if (dy > 0.0) { -@@ -1465,13 +_,13 @@ +@@ -1443,13 +_,13 @@ if (horizontalDistance > 0) { if (this.isSprinting()) { this.awardStat(Stats.SPRINT_ONE_CM, horizontalDistance); @@ -1171,7 +1159,7 @@ } } } else if (this.isFallFlying()) { -@@ -1515,13 +_,13 @@ +@@ -1493,13 +_,13 @@ @Override public void awardStat(final Stat stat, final int count) { this.stats.increment(this, stat, count); @@ -1187,7 +1175,7 @@ } @Override -@@ -1552,9 +_,9 @@ +@@ -1530,9 +_,9 @@ super.jumpFromGround(); this.awardStat(Stats.JUMP); if (this.isSprinting()) { @@ -1199,7 +1187,7 @@ } } -@@ -1569,6 +_,13 @@ +@@ -1547,6 +_,13 @@ public void disconnect() { this.disconnected = true; this.ejectPassengers(); @@ -1213,7 +1201,7 @@ if (this.isSleeping()) { this.stopSleepInBed(true, false); } -@@ -1580,6 +_,7 @@ +@@ -1558,6 +_,7 @@ public void resetSentInfo() { this.lastSentHealth = -1.0E8F; @@ -1221,7 +1209,7 @@ } @Override -@@ -1609,18 +_,18 @@ +@@ -1587,18 +_,18 @@ this.onUpdateAbilities(); this.getAttributes().assignBaseValues(oldPlayer.getAttributes()); if (restoreAll) { @@ -1243,7 +1231,7 @@ if (this.level().getGameRules().get(GameRules.KEEP_INVENTORY) || oldPlayer.isSpectator()) { this.transferInventoryXpAndScore(oldPlayer); } -@@ -1632,7 +_,7 @@ +@@ -1610,7 +_,7 @@ this.lastSentExp = -1; this.lastSentHealth = -1.0F; this.lastSentFood = -1; @@ -1252,7 +1240,7 @@ this.seenCredits = oldPlayer.seenCredits; this.enteredNetherPosition = oldPlayer.enteredNetherPosition; this.chunkTrackingView = oldPlayer.chunkTrackingView; -@@ -1684,9 +_,22 @@ +@@ -1662,9 +_,22 @@ CriteriaTriggers.EFFECTS_CHANGED.trigger(this, null); } @@ -1276,7 +1264,7 @@ } @Override -@@ -1704,6 +_,7 @@ +@@ -1682,6 +_,7 @@ final float newYRot, final float newXRot, final boolean resetCamera @@ -1284,7 +1272,7 @@ ) { if (this.isSleeping()) { this.stopSleepInBed(true, true); -@@ -1713,7 +_,7 @@ +@@ -1691,7 +_,7 @@ this.setCamera(this); } @@ -1293,7 +1281,7 @@ if (success) { this.setYHeadRot(relatives.contains(Relative.Y_ROT) ? this.getYHeadRot() + newYRot : newYRot); this.connection.resetFlyingTicks(); -@@ -1752,9 +_,18 @@ +@@ -1730,11 +_,16 @@ } public boolean setGameMode(final GameType mode) { @@ -1305,25 +1293,25 @@ boolean wasSpectator = this.isSpectator(); - if (!this.gameMode.changeGameModeForPlayer(mode)) { - return false; +- } +- + org.bukkit.event.player.PlayerGameModeChangeEvent event = this.gameMode.changeGameModeForPlayer(mode, cause, message); -+ if (event == null) { -+ return null; -+ } else if (event.isCancelled()) { -+ return event; // need to return the event for the cancel message -+ // Paper end - Expand PlayerGameModeChangeEvent - } else { - this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.CHANGE_GAME_MODE, mode.getId())); - if (mode == GameType.SPECTATOR) { -@@ -1771,7 +_,7 @@ - - this.onUpdateAbilities(); - this.updateEffectVisibility(); -- return true; -+ return event; // Paper - Expand PlayerGameModeChangeEvent - } ++ if (event == null) return null; ++ if (event.isCancelled()) return event; // need to return the event for the cancel message ++ // Paper end - Expand PlayerGameModeChangeEvent + this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.CHANGE_GAME_MODE, mode.getId())); + if (mode == GameType.SPECTATOR) { + this.removeEntitiesOnShoulder(); +@@ -1750,7 +_,7 @@ + + this.onUpdateAbilities(); + this.updateEffectVisibility(); +- return true; ++ return event; // Paper - Expand PlayerGameModeChangeEvent } -@@ -1840,8 +_,13 @@ + @Override +@@ -1818,8 +_,13 @@ } public void sendChatMessage(final OutgoingChatMessage message, final boolean filtered, final ChatType.Bound chatType) { @@ -1338,7 +1326,7 @@ } } -@@ -1852,7 +_,42 @@ +@@ -1830,7 +_,42 @@ } public void updateOptions(final ClientInformation information) { @@ -1381,9 +1369,9 @@ this.requestedViewDistance = information.viewDistance(); this.chatVisibility = information.chatVisibility(); this.canChatColor = information.chatColors(); -@@ -1937,8 +_,23 @@ +@@ -1915,8 +_,23 @@ Entity oldCamera = this.getCamera(); - this.camera = (Entity)(newCamera == null ? this : newCamera); + this.camera = newCamera == null ? this : newCamera; if (oldCamera != this.camera) { + // Paper start - Add PlayerStartSpectatingEntityEvent and PlayerStopSpectatingEntity + if (this.camera == this) { @@ -1406,7 +1394,7 @@ } if (newCamera != null) { -@@ -1962,11 +_,11 @@ +@@ -1940,11 +_,11 @@ } public @Nullable Component getTabListDisplayName() { @@ -1420,7 +1408,7 @@ } @Override -@@ -1996,11 +_,60 @@ +@@ -1974,11 +_,60 @@ } public void setRespawnPosition(final ServerPlayer.@Nullable RespawnConfig respawnConfig, final boolean showMessage) { @@ -1464,7 +1452,7 @@ + + if (event.getLocation() != null) { + respawnConfig = new ServerPlayer.RespawnConfig( -+ net.minecraft.world.level.storage.LevelData.RespawnData.of( ++ LevelData.RespawnData.of( + ((org.bukkit.craftbukkit.CraftWorld) event.getLocation().getWorld()).getHandle().dimension(), + org.bukkit.craftbukkit.util.CraftLocation.toBlockPos(event.getLocation()), + event.getLocation().getYaw(), @@ -1483,7 +1471,7 @@ } public SectionPos getLastSectionPos() { -@@ -2020,16 +_,23 @@ +@@ -1998,16 +_,23 @@ } @Override @@ -1512,7 +1500,7 @@ return entity; } -@@ -2081,7 +_,7 @@ +@@ -2059,7 +_,7 @@ super.updateUsingItem(useItem); } @@ -1521,7 +1509,7 @@ Inventory inventory = this.getInventory(); ItemStack removed = inventory.removeFromSelected(all); this.containerMenu -@@ -2091,7 +_,7 @@ +@@ -2069,7 +_,7 @@ this.stopUsingItem(); } @@ -1530,7 +1518,7 @@ } @Override -@@ -2154,9 +_,9 @@ +@@ -2132,9 +_,9 @@ } @Override @@ -1542,7 +1530,7 @@ if (oldVehicle instanceof LivingEntity livingEntity) { for (MobEffectInstance effect : livingEntity.getActiveEffects()) { this.connection.send(new ClientboundRemoveMobEffectPacket(oldVehicle.getId(), effect.getEffect())); -@@ -2278,7 +_,7 @@ +@@ -2256,7 +_,7 @@ } public static long placeEnderPearlTicket(final ServerLevel level, final ChunkPos chunk) { @@ -1551,7 +1539,7 @@ return TicketType.ENDER_PEARL.timeout(); } -@@ -2308,9 +_,11 @@ +@@ -2286,9 +_,11 @@ } } @@ -1566,7 +1554,7 @@ } private static float calculateLookAtYaw(final Vec3 position, final BlockPos lookAtBlockPos) { -@@ -2330,4 +_,135 @@ +@@ -2308,4 +_,135 @@ ); public static final ServerPlayer.SavedPosition EMPTY = new ServerPlayer.SavedPosition(Optional.empty(), Optional.empty(), Optional.empty()); } diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch index e05a0ec589bb..00980a49a7e5 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/level/ServerPlayerGameMode.java +++ b/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -46,16 +_,37 @@ +@@ -46,17 +_,37 @@ private BlockPos delayedDestroyPos = BlockPos.ZERO; private int delayedTickStart; private int lastSentState = -1; @@ -23,38 +23,40 @@ + // Paper end - Expand PlayerGameModeChangeEvent if (gameModeForPlayer == this.gameModeForPlayer) { - return false; +- } +- + return null; // Paper - Expand PlayerGameModeChangeEvent - } else { -+ // CraftBukkit start -+ org.bukkit.event.player.PlayerGameModeChangeEvent event = new org.bukkit.event.player.PlayerGameModeChangeEvent( -+ this.player.getBukkitEntity(), -+ org.bukkit.GameMode.getByValue(gameModeForPlayer.getId()), -+ playerGameModeChangeCause, // Paper -+ cancelMessage -+ ); -+ if (!event.callEvent()) { -+ return event; // Paper - Expand PlayerGameModeChangeEvent -+ } -+ // CraftBukkit end - Abilities abilities = this.player.getAbilities(); - this.setGameModeForPlayer(gameModeForPlayer, this.gameModeForPlayer); - if (abilities.flying && gameModeForPlayer != GameType.SPECTATOR && this.isInRangeOfGround()) { -@@ -66,13 +_,13 @@ - this.level - .getServer() - .getPlayerList() -- .broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, this.player)); -+ .broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, this.player), this.player); // CraftBukkit - this.level.updateSleepingPlayerList(); - if (gameModeForPlayer == GameType.CREATIVE) { - this.player.resetCurrentImpulseContext(); - } - -- return true; ++ } ++ // CraftBukkit start ++ org.bukkit.event.player.PlayerGameModeChangeEvent event = new org.bukkit.event.player.PlayerGameModeChangeEvent( ++ this.player.getBukkitEntity(), ++ org.bukkit.GameMode.getByValue(gameModeForPlayer.getId()), ++ playerGameModeChangeCause, ++ cancelMessage ++ ); ++ if (!event.callEvent()) { + return event; // Paper - Expand PlayerGameModeChangeEvent ++ } ++ // CraftBukkit end + Abilities abilities = this.player.getAbilities(); + this.setGameModeForPlayer(gameModeForPlayer, this.gameModeForPlayer); + if (abilities.flying && gameModeForPlayer != GameType.SPECTATOR && this.isInRangeOfGround()) { +@@ -67,13 +_,13 @@ + this.level + .getServer() + .getPlayerList() +- .broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, this.player)); ++ .broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, this.player), this.player); // CraftBukkit + this.level.updateSleepingPlayerList(); + if (gameModeForPlayer == GameType.CREATIVE) { + this.player.resetCurrentImpulseContext(); } + +- return true; ++ return event; // Paper - Expand PlayerGameModeChangeEvent } + protected void setGameModeForPlayer(final GameType gameModeForPlayer, final @Nullable GameType previousGameModeForPlayer) { @@ -105,10 +_,11 @@ } @@ -189,7 +191,7 @@ } } } -@@ -261,17 +_,62 @@ +@@ -261,13 +_,53 @@ public boolean destroyBlock(final BlockPos pos) { BlockState state = this.level.getBlockState(pos); @@ -235,103 +237,94 @@ + + if (false && !this.player.getMainHandItem().canDestroyBlock(state, this.level, pos, this.player)) { // CraftBukkit - false return false; - } else { -+ state = this.level.getBlockState(pos); // CraftBukkit - update state from plugins -+ if (state.isAir()) return false; // CraftBukkit - A plugin set block to air without cancelling - BlockEntity blockEntity = this.level.getBlockEntity(pos); - Block block = state.getBlock(); -- if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks()) { -+ if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks() && !(block instanceof net.minecraft.world.level.block.CommandBlock && (this.player.isCreative() && this.player.getBukkitEntity().hasPermission("minecraft.commandblock")))) { // Paper - command block permission - this.level.sendBlockUpdated(pos, state, state, Block.UPDATE_ALL); - return false; - } else if (this.player.blockActionRestricted(this.level, pos, this.gameModeForPlayer)) { - return false; - } else { -+ // CraftBukkit start -+ org.bukkit.block.BlockState bState = bblock.getState(); -+ this.level.captureDrops = new java.util.ArrayList<>(); -+ // CraftBukkit end - BlockState adjustedState = block.playerWillDestroy(this.level, pos, state, this.player); - boolean changed = this.level.removeBlock(pos, false); - if (SharedConstants.DEBUG_BLOCK_BREAK) { -@@ -282,19 +_,44 @@ - block.destroy(this.level, pos, adjustedState); - } - -+ ItemStack mainHandStack = null; // Paper - Trigger bee_nest_destroyed trigger in the correct place -+ boolean isCorrectTool = false; // Paper - Trigger bee_nest_destroyed trigger in the correct place - if (this.player.preventsBlockDrops()) { -- return true; -+ // return true; // CraftBukkit - } else { - ItemStack itemStack = this.player.getMainHandItem(); - ItemStack destroyedWith = itemStack.copy(); - boolean canDestroy = this.player.hasCorrectToolForDrops(adjustedState); -+ mainHandStack = destroyedWith; // Paper - Trigger bee_nest_destroyed trigger in the correct place -+ isCorrectTool = canDestroy; // Paper - Trigger bee_nest_destroyed trigger in the correct place - itemStack.mineBlock(this.level, adjustedState, pos, this.player); -- if (changed && canDestroy) { -- block.playerDestroy(this.level, this.player, pos, adjustedState, blockEntity, destroyedWith); -- } + } - -- return true; -- } -+ if (changed && canDestroy) { // CraftBukkit - Check if block should drop items // Paper - fix drops not preventing stats/food exhaustion -+ block.playerDestroy(this.level, this.player, pos, adjustedState, blockEntity, destroyedWith, event.isDropItems(), false); // Paper - fix drops not preventing stats/food exhaustion -+ } -+ -+ // return true; // CraftBukkit -+ } -+ // CraftBukkit start -+ java.util.List itemsToDrop = this.level.captureDrops; // Paper - capture all item additions to the world -+ this.level.captureDrops = null; // Paper - capture all item additions to the world; Remove this earlier so that we can actually drop stuff -+ if (event.isDropItems()) { -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDropItemEvent(bblock, bState, this.player, itemsToDrop); // Paper - capture all item additions to the world -+ } ++ state = this.level.getBlockState(pos); // CraftBukkit - update state from plugins ++ if (state.isAir()) return false; // CraftBukkit - A plugin set block to air without cancelling + BlockEntity blockEntity = this.level.getBlockEntity(pos); + Block block = state.getBlock(); +- if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks()) { ++ if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks() && !(block instanceof net.minecraft.world.level.block.CommandBlock && (this.player.isCreative() && this.player.getBukkitEntity().hasPermission("minecraft.commandblock")))) { // Paper - command block permission + this.level.sendBlockUpdated(pos, state, state, Block.UPDATE_ALL); + return false; + } +@@ -276,6 +_,10 @@ + return false; + } + ++ // CraftBukkit start ++ org.bukkit.block.BlockState bState = bblock.getState(); ++ this.level.captureDrops = new java.util.ArrayList<>(); ++ // CraftBukkit end + BlockState adjustedState = block.playerWillDestroy(this.level, pos, state, this.player); + boolean changed = this.level.removeBlock(pos, false); + if (SharedConstants.DEBUG_BLOCK_BREAK) { +@@ -286,17 +_,38 @@ + block.destroy(this.level, pos, adjustedState); + } + +- if (this.player.preventsBlockDrops()) { ++ if (false && this.player.preventsBlockDrops()) { // CraftBukkit + return true; + } + + ItemStack itemStack = this.player.getMainHandItem(); + ItemStack destroyedWith = itemStack.copy(); + boolean canDestroy = this.player.hasCorrectToolForDrops(adjustedState); ++ ItemStack mainHandStack = destroyedWith; // Paper - Trigger bee_nest_destroyed trigger in the correct place + itemStack.mineBlock(this.level, adjustedState, pos, this.player); + if (changed && canDestroy) { +- block.playerDestroy(this.level, this.player, pos, adjustedState, blockEntity, destroyedWith); +- } ++ block.playerDestroy(this.level, this.player, pos, adjustedState, blockEntity, destroyedWith, event.isDropItems(), false); // Paper - fix drops not preventing stats/food exhaustion ++ } + -+ // Drop event experience -+ if (changed) { -+ state.getBlock().popExperience(this.level, pos, event.getExpToDrop(), this.player); // Paper -+ } -+ // Paper start - Trigger bee_nest_destroyed trigger in the correct place (check impls of block#playerDestroy) -+ if (mainHandStack != null) { -+ if (changed && isCorrectTool && event.isDropItems() && block instanceof net.minecraft.world.level.block.BeehiveBlock && blockEntity instanceof net.minecraft.world.level.block.entity.BeehiveBlockEntity beehiveBlockEntity) { // simulates the guard on block#playerDestroy above -+ CriteriaTriggers.BEE_NEST_DESTROYED.trigger(player, state, mainHandStack, beehiveBlockEntity.getOccupantCount()); -+ } -+ } -+ // Paper end - Trigger bee_nest_destroyed trigger in the correct place ++ // CraftBukkit start ++ java.util.List itemsToDrop = this.level.captureDrops; // Paper - capture all item additions to the world ++ this.level.captureDrops = null; // Paper - capture all item additions to the world; Remove this earlier so that we can actually drop stuff ++ if (event.isDropItems()) { ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDropItemEvent(bblock, bState, this.player, itemsToDrop); // Paper - capture all item additions to the world ++ } + -+ return true; -+ // CraftBukkit end - } - } ++ // Drop event experience ++ if (changed) { ++ state.getBlock().popExperience(this.level, pos, event.getExpToDrop(), this.player); // Paper ++ } ++ // Paper start - Trigger bee_nest_destroyed trigger in the correct place (check impls of block#playerDestroy) ++ if (mainHandStack != null) { ++ if (changed && canDestroy && event.isDropItems() && block instanceof net.minecraft.world.level.block.BeehiveBlock && blockEntity instanceof net.minecraft.world.level.block.entity.BeehiveBlockEntity beehiveBlockEntity) { // simulates the guard on block#playerDestroy above ++ CriteriaTriggers.BEE_NEST_DESTROYED.trigger(this.player, state, mainHandStack, beehiveBlockEntity.getOccupantCount()); ++ } ++ } ++ // Paper end - Trigger bee_nest_destroyed trigger in the correct place ++ // CraftBukkit end + + return true; } -@@ -307,6 +_,7 @@ - } else { - int oldCount = itemStack.getCount(); - int oldDamage = itemStack.getDamageValue(); -+ final ItemStack stackBeforeUse = itemStack.copy(); // Paper - Store stack before use for interact prediction check - InteractionResult result = itemStack.use(level, player, hand); - ItemStack resultStack; - if (result instanceof InteractionResult.Success success) { -@@ -332,7 +_,14 @@ - } +@@ -312,6 +_,7 @@ - if (!player.isUsingItem()) { -- player.inventoryMenu.sendAllDataToRemote(); -+ // Paper start - Optimize sendAllDataToRemote calls -+ // This is a weird one where the Vanilla behavior is from an ancient version, but also isn't calling startUsingItem on certain instant-use items -+ // TODO Check up on this proper, possibly remove all and move into more specific places -+ if (io.papermc.paper.util.MCUtil.clientPredictsInteraction(player, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(), stackBeforeUse)) { -+ player.inventoryMenu.forceHeldSlot(hand); -+ } -+ player.inventoryMenu.broadcastChanges(); -+ // Paper end - Optimize sendAllDataToRemote calls - } + int oldCount = itemStack.getCount(); + int oldDamage = itemStack.getDamageValue(); ++ final ItemStack stackBeforeUse = itemStack.copy(); // Paper - Store stack before use for interact prediction check + InteractionResult result = itemStack.use(level, player, hand); + ItemStack resultStack; + if (result instanceof InteractionResult.Success success) { +@@ -340,25 +_,70 @@ + } - return result; -@@ -340,17 +_,55 @@ + if (!player.isUsingItem()) { +- player.inventoryMenu.sendAllDataToRemote(); ++ // Paper start - Optimize sendAllDataToRemote calls ++ // This is a weird one where the Vanilla behavior is from an ancient version, but also isn't calling startUsingItem on certain instant-use items ++ // TODO Check up on this proper, possibly remove all and move into more specific places ++ if (io.papermc.paper.util.MCUtil.clientPredictsInteraction(player, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(), stackBeforeUse)) { ++ player.inventoryMenu.forceHeldSlot(hand); ++ } ++ player.inventoryMenu.broadcastChanges(); ++ // Paper end - Optimize sendAllDataToRemote calls } + + return result; } + // CraftBukkit start - whole method @@ -349,7 +342,9 @@ + boolean cancelledItem = false; // Paper - correctly handle items on cooldown if (!state.getBlock().isEnabled(level.enabledFeatures())) { return InteractionResult.FAIL; - } else if (this.gameModeForPlayer == GameType.SPECTATOR) { + } + + if (this.gameModeForPlayer == GameType.SPECTATOR) { MenuProvider menuProvider = state.getMenuProvider(level, pos); - if (menuProvider != null) { - player.openMenu(menuProvider); @@ -388,7 +383,7 @@ return InteractionResult.CONSUME; } else { return InteractionResult.PASS; -@@ -375,7 +_,7 @@ +@@ -383,7 +_,7 @@ } } @@ -397,7 +392,7 @@ UseOnContext context = new UseOnContext(player, hand, hitResult); InteractionResult success; if (player.hasInfiniteMaterials()) { -@@ -392,6 +_,11 @@ +@@ -400,6 +_,11 @@ return success; } else { diff --git a/paper-server/patches/sources/net/minecraft/server/level/WorldGenRegion.java.patch b/paper-server/patches/sources/net/minecraft/server/level/WorldGenRegion.java.patch index 97ed6a25d732..2afc9c8017cd 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/WorldGenRegion.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/WorldGenRegion.java.patch @@ -30,7 +30,7 @@ public BlockState getBlockState(final BlockPos pos) { return this.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())).getBlockState(pos); @@ -221,6 +_,7 @@ - } + return null; } + private boolean hasSetFarWarned = false; // Paper - Buffer OOB setBlock calls @@ -59,24 +59,24 @@ return false; } } -@@ -273,6 +_,17 @@ - chunk.removeBlockEntity(pos); - } - } else { -+ // Paper start - Clear block entity before setting up a DUMMY block entity -+ // The concept of removing a block entity when the block itself changes is generally lifted -+ // from LevelChunk#setBlockState. -+ // It is however to note that this may only run if the block actually changes. -+ // Otherwise a chest block entity generated by a structure template that is later "updated" to -+ // be waterlogged would remove its existing block entity (see PaperMC/Paper#10750) -+ // This logic is *also* found in LevelChunk#setBlockState. -+ if (oldState != null && !java.util.Objects.equals(oldState.getBlock(), blockState.getBlock())) { -+ chunk.removeBlockEntity(pos); -+ } -+ // Paper end - Clear block entity before setting up a DUMMY block entity - CompoundTag tag = new CompoundTag(); - tag.putInt("x", pos.getX()); - tag.putInt("y", pos.getY()); +@@ -274,6 +_,17 @@ + chunk.removeBlockEntity(pos); + } + } else { ++ // Paper start - Clear block entity before setting up a DUMMY block entity ++ // The concept of removing a block entity when the block itself changes is generally lifted ++ // from LevelChunk#setBlockState. ++ // It is however to note that this may only run if the block actually changes. ++ // Otherwise a chest block entity generated by a structure template that is later "updated" to ++ // be waterlogged would remove its existing block entity (see PaperMC/Paper#10750) ++ // This logic is *also* found in LevelChunk#setBlockState. ++ if (oldState != null && !java.util.Objects.equals(oldState.getBlock(), blockState.getBlock())) { ++ chunk.removeBlockEntity(pos); ++ } ++ // Paper end - Clear block entity before setting up a DUMMY block entity + CompoundTag tag = new CompoundTag(); + tag.putInt("x", pos.getX()); + tag.putInt("y", pos.getY()); @@ -301,6 +_,13 @@ @Override diff --git a/paper-server/patches/sources/net/minecraft/server/network/LegacyQueryHandler.java.patch b/paper-server/patches/sources/net/minecraft/server/network/LegacyQueryHandler.java.patch index ab3151fb49dd..2decedf75c72 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/LegacyQueryHandler.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/LegacyQueryHandler.java.patch @@ -53,15 +53,22 @@ if (in.isReadable()) { - if (!readCustomPayloadPacket(in)) { +- return; + // Paper start - Replace below + if (in.readUnsignedByte() != LegacyProtocolUtils.CUSTOM_PAYLOAD_PACKET_ID) { + body = this.readLegacy1_6(ctx, in); + if (body == null) { + return; + } -+ } + } +- +- LOGGER.debug("Ping: (1.6) from {}", socket); + // Paper end - Replace below -+ } else { + } else { +- LOGGER.debug("Ping: (1.4-1.5.x) from {}", socket); +- } +- +- String body = createVersion1Response(this.server); + LOGGER.debug("Ping: (1.4-1.5.x) from {}", net.minecraft.server.MinecraftServer.getServer().logIPs() ? socket : ""); // Paper - Respect logIPs option + } + @@ -72,12 +79,9 @@ + ctx.close(); + in.release(); + connectNormally = false; - return; - } - -- LOGGER.debug("Ping: (1.6) from {}", socket); -- } else { -- LOGGER.debug("Ping: (1.4-1.5.x) from {}", socket); ++ return; ++ } ++ + // See createVersion1Response + body = String.format( + Locale.ROOT, @@ -87,10 +91,8 @@ + event.getNumPlayers(), + event.getMaxPlayers() + ); -+ // Paper end - Call PaperServerListPingEvent and use results - } -- -- String body = createVersion1Response(this.server); ++ } ++ // Paper end - Call PaperServerListPingEvent and use results sendFlushAndClose(ctx, createLegacyDisconnectPacket(ctx.alloc(), body)); } diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch index cd0231da8081..19e75f568090 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch @@ -188,7 +188,7 @@ + if (!this.isSingleplayerOwner() && elapsedTime >= 15000L) { // use vanilla's 15000L between keep alive packets if (this.keepAlivePending) { - this.disconnect(TIMEOUT_DISCONNECTION_MESSAGE); -+ if (!this.processedDisconnect && elapsedTime >= KEEPALIVE_LIMIT) { // check keepalive limit, don't fire if already disconnected ++ if (elapsedTime >= KEEPALIVE_LIMIT) { // check keepalive limit, don't fire if already disconnected + this.disconnect(TIMEOUT_DISCONNECTION_MESSAGE, io.papermc.paper.connection.DisconnectionReason.TIMEOUT); // Paper - kick event cause + } + // Paper end - give clients a longer time to respond to pings as per pre 1.12.2 timings diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch index 9d6515de84a2..cd94a1842b79 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch @@ -96,9 +96,9 @@ if (loginError != null) { this.disconnect(loginError); return; -@@ -229,4 +_,29 @@ - this.startNextTask(); - } +@@ -231,4 +_,29 @@ + this.currentTask = null; + this.startNextTask(); } + + // Paper start diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerConnectionListener.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerConnectionListener.java.patch index 401e8689924f..77ce3cb40925 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerConnectionListener.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerConnectionListener.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/network/ServerConnectionListener.java +++ b/net/minecraft/server/network/ServerConnectionListener.java -@@ -50,9 +_,31 @@ +@@ -49,9 +_,31 @@ this.running = true; } @@ -33,10 +33,10 @@ this.channels .add( new ServerBootstrap() -@@ -80,22 +_,64 @@ - Connection connection = (Connection)(rateLimitPacketsPerSecond > 0 +@@ -75,22 +_,64 @@ + Connection connection = rateLimitPacketsPerSecond > 0 ? new RateKickingConnection(rateLimitPacketsPerSecond) - : new Connection(PacketFlow.SERVERBOUND)); + : new Connection(PacketFlow.SERVERBOUND); - ServerConnectionListener.this.connections.add(connection); + // Paper start - Add support for Proxy Protocol + if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.proxyProtocol) { @@ -100,7 +100,7 @@ public SocketAddress startMemoryChannel() { ChannelFuture newChannel; synchronized (this.channels) { -@@ -151,12 +_,26 @@ +@@ -142,12 +_,26 @@ public void tick() { synchronized (this.connections) { @@ -126,8 +126,8 @@ + // Paper end - Force kill connection ticking try { connection.tick(); - } catch (Exception var7) { -@@ -170,6 +_,7 @@ + } catch (Exception e) { +@@ -161,6 +_,7 @@ connection.setReadOnly(); } } else { diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch index 535ad83014bf..8a9fec619627 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -977,7 +977,7 @@ this.player .doCheckFallDamage( this.player.getX() - startX, this.player.getY() - startY, this.player.getZ() - startZ, packet.isOnGround() -@@ -1223,6 +_,7 @@ +@@ -1225,6 +_,7 @@ this.player.getXRot() ); } @@ -985,7 +985,7 @@ return true; } else { -@@ -1248,10 +_,77 @@ +@@ -1250,10 +_,77 @@ } public void teleport(final double x, final double y, final double z, final float yRot, final float xRot) { @@ -1064,7 +1064,7 @@ this.awaitingTeleportTime = this.tickCount; if (++this.awaitingTeleport == Integer.MAX_VALUE) { this.awaitingTeleport = 0; -@@ -1259,12 +_,20 @@ +@@ -1261,12 +_,20 @@ this.player.teleportSetPosition(destination, relatives); this.awaitingPositionFromClient = this.player.position(); @@ -1085,7 +1085,7 @@ if (this.hasClientLoaded()) { BlockPos pos = packet.getPos(); this.player.resetLastActionTime(); -@@ -1289,32 +_,95 @@ +@@ -1291,32 +_,95 @@ case SWAP_ITEM_WITH_OFFHAND: if (!this.player.isSpectator()) { ItemStack swap = this.player.getItemInHand(InteractionHand.OFF_HAND); @@ -1183,8 +1183,8 @@ return; default: throw new IllegalArgumentException("Invalid player action"); -@@ -1332,9 +_,36 @@ - } +@@ -1334,9 +_,36 @@ + && !player.getCooldowns().isOnCooldown(itemStack); } + // Paper start - limit place/interactions @@ -1220,7 +1220,7 @@ if (this.hasClientLoaded()) { this.ackBlockChangesUpTo(packet.getSequence()); ServerLevel level = this.player.level(); -@@ -1343,6 +_,11 @@ +@@ -1345,6 +_,11 @@ if (itemStack.isItemEnabled(level.enabledFeatures())) { BlockHitResult blockHit = packet.getHitResult(); Vec3 location = blockHit.getLocation(); @@ -1232,7 +1232,7 @@ BlockPos pos = blockHit.getBlockPos(); if (this.player.isWithinBlockInteractionRange(pos, 1.0)) { Vec3 distance = location.subtract(Vec3.atCenterOf(pos)); -@@ -1357,9 +_,13 @@ +@@ -1359,9 +_,13 @@ } else if (pos.getY() < minY) { this.player.sendBuildLimitMessage(false, minY); } else { @@ -1248,7 +1248,7 @@ InteractionResult interactionResult = this.player.gameMode.useItemOn(this.player, level, itemStack, hand, blockHit); if (interactionResult.consumesAction()) { CriteriaTriggers.ANY_BLOCK_USE.trigger(this.player, blockHit.getBlockPos(), itemStack); -@@ -1371,7 +_,7 @@ +@@ -1373,7 +_,7 @@ && wasBlockPlacementAttempt(this.player, itemStack)) { this.player.sendBuildLimitMessage(true, maxY); } else if (interactionResult instanceof InteractionResult.Success success @@ -1257,7 +1257,7 @@ this.player.swing(hand, true); } -@@ -1385,6 +_,15 @@ +@@ -1387,6 +_,15 @@ && success.swingSource() == InteractionResult.SwingSource.SERVER) { this.player.swing(hand, true); } @@ -1273,7 +1273,7 @@ } else { this.player.sendBuildLimitMessage(true, maxY); } -@@ -1392,13 +_,8 @@ +@@ -1394,13 +_,8 @@ this.send(new ClientboundBlockUpdatePacket(level, pos)); this.send(new ClientboundBlockUpdatePacket(level, pos.relative(direction))); } @@ -1289,7 +1289,7 @@ } } } -@@ -1408,6 +_,8 @@ +@@ -1410,6 +_,8 @@ @Override public void handleUseItem(final ServerboundUseItemPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); @@ -1298,7 +1298,7 @@ if (this.hasClientLoaded()) { this.ackBlockChangesUpTo(packet.getSequence()); ServerLevel level = this.player.level(); -@@ -1421,6 +_,44 @@ +@@ -1423,6 +_,44 @@ this.player.absSnapRotationTo(targetYRot, targetXRot); } @@ -1343,7 +1343,7 @@ if (this.player.gameMode.useItem(this.player, level, itemStack, hand) instanceof InteractionResult.Success success && success.swingSource() == InteractionResult.SwingSource.SERVER) { this.player.swing(hand, true); -@@ -1436,7 +_,7 @@ +@@ -1438,7 +_,7 @@ for (ServerLevel level : this.server.getAllLevels()) { Entity entity = packet.getEntity(level); if (entity != null) { @@ -1352,7 +1352,7 @@ return; } } -@@ -1454,23 +_,42 @@ +@@ -1456,23 +_,42 @@ @Override public void onDisconnect(final DisconnectionDetails details) { LOGGER.info("{} lost connection: {}", this.player.getPlainTextName(), details.reason().getString()); @@ -1395,9 +1395,9 @@ if (packetSequenceNr < 0) { + this.disconnect(Component.literal("Expected packet sequence nr >= 0"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - Treat sequence violations like they should be throw new IllegalArgumentException("Expected packet sequence nr >= 0"); - } else { - this.ackBlockChangesUpTo = Math.max(packetSequenceNr, this.ackBlockChangesUpTo); -@@ -1480,20 +_,38 @@ + } + +@@ -1482,20 +_,38 @@ @Override public void handleSetCarriedItem(final ServerboundSetCarriedItemPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); @@ -1436,7 +1436,7 @@ Optional unpackedLastSeen = this.unpackAndApplyLastSeen(packet.lastSeenMessages()); if (!unpackedLastSeen.isEmpty()) { this.tryHandleChat(packet.message(), false, () -> { -@@ -1505,25 +_,45 @@ +@@ -1507,25 +_,45 @@ return; } @@ -1490,7 +1490,7 @@ ParseResults parsed = this.parseCommand(command); if (this.server.enforceSecureProfile() && SignableCommand.hasSignableArguments(parsed)) { LOGGER.error( -@@ -1540,26 +_,55 @@ +@@ -1542,26 +_,55 @@ Optional unpackedLastSeen = this.unpackAndApplyLastSeen(packet.lastSeenMessages()); if (!unpackedLastSeen.isEmpty()) { this.tryHandleChat(packet.command(), true, () -> { @@ -1524,8 +1524,8 @@ try { + // Paper - Always parse the original command to add to the chat chain signedArguments = this.collectSignedArguments(packet, SignableCommand.of(command), lastSeenMessages); - } catch (SignedMessageChain.DecodeException var6) { - this.handleMessageDecodeFailure(var6); + } catch (SignedMessageChain.DecodeException e) { + this.handleMessageDecodeFailure(e); return; } @@ -1549,7 +1549,7 @@ } private void handleMessageDecodeFailure(final SignedMessageChain.DecodeException e) { -@@ -1623,14 +_,20 @@ +@@ -1625,14 +_,20 @@ return commands.parse(command, this.player.createCommandSourceStack()); } @@ -1574,16 +1574,16 @@ } } -@@ -1642,7 +_,7 @@ +@@ -1644,7 +_,7 @@ var10000 = Optional.of(result); - } catch (LastSeenMessagesValidator.ValidationException var5) { - LOGGER.error("Failed to validate message acknowledgements from {}: {}", this.player.getPlainTextName(), var5.getMessage()); + } catch (LastSeenMessagesValidator.ValidationException e) { + LOGGER.error("Failed to validate message acknowledgements from {}: {}", this.player.getPlainTextName(), e.getMessage()); - this.disconnect(CHAT_VALIDATION_FAILED); + this.disconnectAsync(CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes & add proper async disconnect return Optional.empty(); } -@@ -1660,22 +_,81 @@ +@@ -1662,22 +_,81 @@ return false; } @@ -1671,16 +1671,16 @@ } } -@@ -1686,7 +_,7 @@ +@@ -1688,7 +_,7 @@ this.lastSeenMessages.applyOffset(packet.offset()); - } catch (LastSeenMessagesValidator.ValidationException var5) { - LOGGER.error("Failed to validate message acknowledgement offset from {}: {}", this.player.getPlainTextName(), var5.getMessage()); + } catch (LastSeenMessagesValidator.ValidationException e) { + LOGGER.error("Failed to validate message acknowledgement offset from {}: {}", this.player.getPlainTextName(), e.getMessage()); - this.disconnect(CHAT_VALIDATION_FAILED); + this.disconnectAsync(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes & add proper async disconnect } } } -@@ -1694,7 +_,34 @@ +@@ -1696,7 +_,34 @@ @Override public void handleAnimate(final ServerboundSwingPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); @@ -1715,7 +1715,7 @@ this.player.swing(packet.getHand()); } -@@ -1702,6 +_,21 @@ +@@ -1704,6 +_,21 @@ public void handlePlayerCommand(final ServerboundPlayerCommandPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); if (this.hasClientLoaded()) { @@ -1737,7 +1737,7 @@ this.player.resetLastActionTime(); switch (packet.getAction()) { case START_SPRINTING: -@@ -1746,6 +_,14 @@ +@@ -1748,6 +_,14 @@ } public void sendPlayerChatMessage(final PlayerChatMessage message, final ChatType.Bound chatType) { @@ -1752,7 +1752,7 @@ this.send( new ClientboundPlayerChatPacket( this.nextChatIndex++, -@@ -1768,9 +_,11 @@ +@@ -1770,9 +_,11 @@ } if (trackedCount > 4096) { @@ -1765,7 +1765,7 @@ } public void sendDisguisedChatMessage(final Component content, final ChatType.Bound chatType) { -@@ -1781,6 +_,17 @@ +@@ -1783,6 +_,17 @@ return this.connection.getRemoteAddress(); } @@ -1783,7 +1783,7 @@ public void switchToConfig() { this.waitingForSwitchToConfig = true; this.removePlayerFromWorld(); -@@ -1796,20 +_,27 @@ +@@ -1798,20 +_,27 @@ @Override public void handleAttack(final ServerboundAttackPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); @@ -1813,7 +1813,7 @@ LOGGER.warn("Player {} tried to attack an invalid entity", this.player.getPlainTextName()); } else if (mainHandItem.isItemEnabled(level.enabledFeatures())) { if (!this.player.cannotAttackWithItem(mainHandItem, 5)) { -@@ -1819,25 +_,88 @@ +@@ -1821,25 +_,88 @@ } } } @@ -1903,7 +1903,7 @@ if (this.player.interactOn(target, hand, location) instanceof InteractionResult.Success success) { ItemStack awardedForStack = success.wasItemInteraction() ? usedItemStack : ItemStack.EMPTY; CriteriaTriggers.PLAYER_INTERACTED_WITH_ENTITY.trigger(this.player, awardedForStack, target); -@@ -1848,6 +_,12 @@ +@@ -1850,6 +_,12 @@ } } } @@ -1916,7 +1916,7 @@ } } -@@ -1859,7 +_,7 @@ +@@ -1861,7 +_,7 @@ ServerLevel level = this.player.level(); Entity target = level.getEntityOrPart(packet.entityId()); if (target != null && level.getWorldBorder().isWithinBounds(target.blockPosition())) { @@ -1925,7 +1925,7 @@ if (target.isPickable()) { this.player.setCamera(target); } -@@ -1877,7 +_,7 @@ +@@ -1879,7 +_,7 @@ case PERFORM_RESPAWN: if (this.player.wonGame) { this.player.wonGame = false; @@ -1934,7 +1934,7 @@ this.resetPosition(); this.restartClientLoadTimerAfterRespawn(); CriteriaTriggers.CHANGED_DIMENSION.trigger(this.player, Level.END, Level.OVERWORLD); -@@ -1886,12 +_,12 @@ +@@ -1888,12 +_,12 @@ return; } @@ -1950,7 +1950,7 @@ } } break; -@@ -1904,7 +_,7 @@ +@@ -1906,7 +_,7 @@ } private void sendGameRuleValues() { @@ -1959,7 +1959,7 @@ LOGGER.warn("Player {} tried to request game rule values without required permissions", this.player.getGameProfile().name()); } else { GameRules gameRules = this.player.level().getGameRules(); -@@ -1920,16 +_,27 @@ +@@ -1922,16 +_,27 @@ @Override public void handleContainerClose(final ServerboundContainerClosePacket packet) { @@ -1989,7 +1989,7 @@ this.player.containerMenu.sendAllDataToRemote(); } else if (!this.player.containerMenu.stillValid(this.player)) { LOGGER.debug("Player {} interacted with invalid menu {}", this.player, this.player.containerMenu); -@@ -1945,7 +_,298 @@ +@@ -1947,7 +_,298 @@ } else { boolean fullResyncNeeded = packet.stateId() != this.player.containerMenu.getStateId(); this.player.containerMenu.suppressRemoteUpdates(); @@ -2289,7 +2289,7 @@ for (Entry e : Int2ObjectMaps.fastIterable(packet.changedSlots())) { this.player.containerMenu.setRemoteSlotUnsafe(e.getIntKey(), e.getValue()); -@@ -1958,6 +_,8 @@ +@@ -1960,6 +_,8 @@ } else { this.player.containerMenu.broadcastChanges(); } @@ -2298,7 +2298,7 @@ } } } -@@ -1965,6 +_,14 @@ +@@ -1967,6 +_,14 @@ @Override public void handlePlaceRecipe(final ServerboundPlaceRecipePacket packet) { @@ -2313,7 +2313,7 @@ PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); this.player.resetLastActionTime(); if (!this.player.isSpectator() && this.player.containerMenu.containerId == packet.containerId()) { -@@ -1981,9 +_,44 @@ +@@ -1983,9 +_,44 @@ return; } @@ -2359,7 +2359,7 @@ if (postPlaceAction == RecipeBookMenu.PostPlaceAction.PLACE_GHOST_RECIPE) { this.send(new ClientboundPlaceGhostRecipePacket(this.player.containerMenu.containerId, displayInfo.display().display())); } -@@ -1997,6 +_,7 @@ +@@ -1999,6 +_,7 @@ @Override public void handleContainerButtonClick(final ServerboundContainerButtonClickPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); @@ -2367,7 +2367,7 @@ this.player.resetLastActionTime(); if (this.player.containerMenu.containerId == packet.containerId() && !this.player.isSpectator()) { if (!this.player.containerMenu.stillValid(this.player)) { -@@ -2006,6 +_,7 @@ +@@ -2008,6 +_,7 @@ if (clickAccepted) { this.player.containerMenu.broadcastChanges(); } @@ -2375,7 +2375,7 @@ } } } -@@ -2022,10 +_,48 @@ +@@ -2024,10 +_,48 @@ boolean validSlot = packet.slotNum() >= 1 && packet.slotNum() <= 45; boolean validData = itemStack.isEmpty() || itemStack.getCount() <= itemStack.getMaxStackSize(); @@ -2424,7 +2424,7 @@ } else if (drop && validData) { if (this.dropSpamThrottler.isUnderThreshold()) { this.dropSpamThrottler.increment(); -@@ -2039,15 +_,38 @@ +@@ -2041,15 +_,38 @@ @Override public void handleSignUpdate(final ServerboundSignUpdatePacket packet) { @@ -2464,7 +2464,7 @@ if (!(level.getBlockEntity(pos) instanceof SignBlockEntity sign)) { return; } -@@ -2059,14 +_,32 @@ +@@ -2061,14 +_,32 @@ @Override public void handlePlayerAbilities(final ServerboundPlayerAbilitiesPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); @@ -2498,7 +2498,7 @@ if (this.player.isModelPartShown(PlayerModelPart.HAT) != wasHatShown) { this.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_HAT, this.player)); } -@@ -2082,21 +_,21 @@ +@@ -2084,21 +_,21 @@ packet.difficulty().getDisplayName() ); } else { @@ -2523,7 +2523,7 @@ } } -@@ -2116,7 +_,7 @@ +@@ -2118,7 +_,7 @@ ProfilePublicKey.Data newProfileKey = newChatSession.profilePublicKey(); if (!Objects.equals(oldProfileKey, newProfileKey)) { if (oldProfileKey != null && newProfileKey.expiresAt().isBefore(oldProfileKey.expiresAt())) { @@ -2532,33 +2532,33 @@ } else { try { SignatureValidator profileKeySignatureValidator = this.server.services().profileKeySignatureValidator(); -@@ -2127,8 +_,8 @@ +@@ -2129,8 +_,8 @@ this.resetPlayerChatState(newChatSession.validate(this.player.getGameProfile(), profileKeySignatureValidator)); - } catch (ProfilePublicKey.ValidationException var6) { -- LOGGER.error("Failed to validate profile key: {}", var6.getMessage()); -- this.disconnect(var6.getComponent()); -+ // LOGGER.error("Failed to validate profile key: {}", var6.getMessage()); // Paper - Improve logging and errors -+ this.disconnect(var6.getComponent(), var6.kickCause); // Paper - kick event causes + } catch (ProfilePublicKey.ValidationException e) { +- LOGGER.error("Failed to validate profile key: {}", e.getMessage()); +- this.disconnect(e.getComponent()); ++ // LOGGER.error("Failed to validate profile key: {}", e.getMessage()); // Paper - Improve logging and errors ++ this.disconnect(e.getComponent(), e.kickCause); // Paper - kick event causes } } } -@@ -2139,11 +_,13 @@ - if (!this.waitingForSwitchToConfig) { +@@ -2142,11 +_,13 @@ throw new IllegalStateException("Client acknowledged config, but none was requested"); - } else { -+ final ServerConfigurationPacketListenerImpl listener = new ServerConfigurationPacketListenerImpl(this.server, this.connection, this.createCookie(this.player.clientInformation())); // Paper - this.connection - .setupInboundProtocol( - ConfigurationProtocols.SERVERBOUND, -- new ServerConfigurationPacketListenerImpl(this.server, this.connection, this.createCookie(this.player.clientInformation())) -+ listener // Paper - ); -+ new io.papermc.paper.event.connection.configuration.PlayerConnectionReconfigureEvent(listener.paperConnection).callEvent(); // Paper } + ++ final ServerConfigurationPacketListenerImpl listener = new ServerConfigurationPacketListenerImpl(this.server, this.connection, this.createCookie(this.player.clientInformation())); // Paper + this.connection + .setupInboundProtocol( + ConfigurationProtocols.SERVERBOUND, +- new ServerConfigurationPacketListenerImpl(this.server, this.connection, this.createCookie(this.player.clientInformation())) ++ listener // Paper + ); ++ new io.papermc.paper.event.connection.configuration.PlayerConnectionReconfigureEvent(listener.paperConnection).callEvent(); // Paper } -@@ -2161,27 +_,32 @@ + @Override +@@ -2163,27 +_,32 @@ private void resetPlayerChatState(final RemoteChatSession chatSession) { this.chatSession = chatSession; @@ -2592,7 +2592,7 @@ if (!this.receivedMovementThisTick) { this.player.setKnownMovement(Vec3.ZERO); } -@@ -2213,12 +_,23 @@ +@@ -2215,12 +_,23 @@ } public void tickClientLoadTimeout() { @@ -2618,7 +2618,7 @@ this.clientLoadedTimeoutTimer = 0; } -@@ -2230,4 +_,80 @@ +@@ -2232,4 +_,80 @@ this.waitingForRespawn = false; this.clientLoadedTimeoutTimer = 60; } diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch index 7bf327394d3b..760d2c14f7ef 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch @@ -173,16 +173,16 @@ @Override @@ -186,7 +_,8 @@ - throw new IllegalStateException("Protocol error", var7); + throw new IllegalStateException("Protocol error", e); } - Thread thread = new Thread("User Authenticator #" + UNIQUE_THREAD_ID.incrementAndGet()) { + // Paper start - Virtual authenticator threads + authenticatorPool.execute(new Runnable() { - { - Objects.requireNonNull(ServerLoginPacketListenerImpl.this); - } -@@ -202,12 +_,18 @@ + @Override + public void run() { + String name = Objects.requireNonNull(ServerLoginPacketListenerImpl.this.requestedUsername, "Player name not initialized"); +@@ -198,12 +_,18 @@ .hasJoinedServer(name, digest, this.getAddress()); if (result != null) { GameProfile profile = result.profile(); @@ -202,8 +202,8 @@ } else { ServerLoginPacketListenerImpl.this.disconnect(Component.translatable("multiplayer.disconnect.unverified_username")); ServerLoginPacketListenerImpl.LOGGER.error("Username '{}' tried to join with an invalid session", name); -@@ -215,11 +_,16 @@ - } catch (AuthenticationUnavailableException var4) { +@@ -211,11 +_,16 @@ + } catch (AuthenticationUnavailableException ignored) { if (ServerLoginPacketListenerImpl.this.server.isSingleplayer()) { ServerLoginPacketListenerImpl.LOGGER.warn("Authentication servers are down but will let them in anyway!"); - ServerLoginPacketListenerImpl.this.startClientVerification(UUIDUtil.createOfflineProfile(name)); @@ -221,7 +221,7 @@ } } -@@ -229,18 +_,123 @@ +@@ -225,18 +_,123 @@ ? ((InetSocketAddress)remoteAddress).getAddress() : null; } @@ -349,7 +349,7 @@ Validate.validState(this.state == ServerLoginPacketListenerImpl.State.PROTOCOL_SWITCHING, "Unexpected login acknowledgement packet"); this.connection.setupOutboundProtocol(ConfigurationProtocols.CLIENTBOUND); CommonListenerCookie cookie = CommonListenerCookie.createInitial(Objects.requireNonNull(this.authenticatedProfile), this.transferred); -@@ -257,8 +_,31 @@ +@@ -253,8 +_,31 @@ @Override public void handleCookieResponse(final ServerboundCookieResponsePacket packet) { @@ -379,5 +379,5 @@ + } + // Spigot end - public static enum State { + public enum State { HELLO, diff --git a/paper-server/patches/sources/net/minecraft/server/network/config/PrepareSpawnTask.java.patch b/paper-server/patches/sources/net/minecraft/server/network/config/PrepareSpawnTask.java.patch index 7f726f2395ab..b9b280a6aeab 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/config/PrepareSpawnTask.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/config/PrepareSpawnTask.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/network/config/PrepareSpawnTask.java +++ b/net/minecraft/server/network/config/PrepareSpawnTask.java -@@ -37,10 +_,18 @@ +@@ -36,10 +_,18 @@ private final LevelLoadListener loadListener; private PrepareSpawnTask.@Nullable State state; @@ -22,7 +22,7 @@ } @Override -@@ -50,16 +_,58 @@ +@@ -49,16 +_,58 @@ .getPlayerList() .loadPlayerData(this.nameAndId) .map(tag -> TagValueInput.create(reporter, this.server.registryAccess(), tag)); @@ -86,7 +86,7 @@ Vec2 spawnAngle = loadedPosition.rotation().orElse(new Vec2(respawnData.yaw(), respawnData.pitch())); this.state = new PrepareSpawnTask.Preparing(spawnLevel, spawnPosition, spawnAngle); } -@@ -111,10 +_,11 @@ +@@ -110,10 +_,11 @@ } private final class Preparing implements PrepareSpawnTask.State { @@ -98,65 +98,65 @@ + private Vec2 spawnAngle; // Paper - remove final private @Nullable CompletableFuture chunkLoadFuture; + private @Nullable CompletableFuture eventFuture; // Paper - private final ChunkLoadCounter chunkLoadCounter; + private final ChunkLoadCounter chunkLoadCounter = new ChunkLoadCounter(); private Preparing(final ServerLevel spawnLevel, final CompletableFuture spawnPosition, final Vec2 spawnAngle) { -@@ -136,6 +_,54 @@ - } else { - Vec3 spawnPosition = this.spawnPosition.join(); - if (this.chunkLoadFuture == null) { -+ // Paper start - PlayerSpawnLocationEvent -+ if (this.eventFuture == null && org.spigotmc.event.player.PlayerSpawnLocationEvent.getHandlerList().getRegisteredListeners().length != 0) { -+ ServerPlayer player; -+ if (PrepareSpawnTask.this.listener.connection.savedPlayerForLegacyEvents != null) { -+ player = PrepareSpawnTask.this.listener.connection.savedPlayerForLegacyEvents; -+ } else { -+ player = new ServerPlayer( -+ PrepareSpawnTask.this.server, -+ PrepareSpawnTask.this.server.overworld(), -+ PrepareSpawnTask.this.profile, -+ net.minecraft.server.level.ClientInformation.createDefault() -+ ); -+ PrepareSpawnTask.this.listener.connection.savedPlayerForLegacyEvents = player; -+ } -+ org.spigotmc.event.player.PlayerSpawnLocationEvent ev = new org.spigotmc.event.player.PlayerSpawnLocationEvent( -+ player.getBukkitEntity(), -+ org.bukkit.craftbukkit.util.CraftLocation.toBukkit(spawnPosition, this.spawnLevel, this.spawnAngle.x, this.spawnAngle.y) +@@ -133,6 +_,54 @@ + + Vec3 spawnPosition = this.spawnPosition.join(); + if (this.chunkLoadFuture == null) { ++ // Paper start - PlayerSpawnLocationEvent ++ if (this.eventFuture == null && org.spigotmc.event.player.PlayerSpawnLocationEvent.getHandlerList().getRegisteredListeners().length != 0) { ++ ServerPlayer player; ++ if (PrepareSpawnTask.this.listener.connection.savedPlayerForLegacyEvents != null) { ++ player = PrepareSpawnTask.this.listener.connection.savedPlayerForLegacyEvents; ++ } else { ++ player = new ServerPlayer( ++ PrepareSpawnTask.this.server, ++ PrepareSpawnTask.this.server.overworld(), ++ PrepareSpawnTask.this.profile, ++ net.minecraft.server.level.ClientInformation.createDefault() + ); -+ ev.callEvent(); -+ spawnPosition = io.papermc.paper.util.MCUtil.toVec3(ev.getSpawnLocation()); -+ if (ev.getSpawnLocation().getWorld() != null) this.spawnLevel = ((org.bukkit.craftbukkit.CraftWorld) ev.getSpawnLocation().getWorld()).getHandle(); -+ this.spawnPosition = CompletableFuture.completedFuture(spawnPosition); -+ this.spawnAngle = new Vec2(ev.getSpawnLocation().getYaw(), ev.getSpawnLocation().getPitch()); ++ PrepareSpawnTask.this.listener.connection.savedPlayerForLegacyEvents = player; + } ++ org.spigotmc.event.player.PlayerSpawnLocationEvent ev = new org.spigotmc.event.player.PlayerSpawnLocationEvent( ++ player.getBukkitEntity(), ++ org.bukkit.craftbukkit.util.CraftLocation.toBukkit(spawnPosition, this.spawnLevel, this.spawnAngle.x, this.spawnAngle.y) ++ ); ++ ev.callEvent(); ++ spawnPosition = io.papermc.paper.util.MCUtil.toVec3(ev.getSpawnLocation()); ++ if (ev.getSpawnLocation().getWorld() != null) this.spawnLevel = ((org.bukkit.craftbukkit.CraftWorld) ev.getSpawnLocation().getWorld()).getHandle(); ++ this.spawnPosition = CompletableFuture.completedFuture(spawnPosition); ++ this.spawnAngle = new Vec2(ev.getSpawnLocation().getYaw(), ev.getSpawnLocation().getPitch()); ++ } + -+ if (this.eventFuture == null && io.papermc.paper.event.player.AsyncPlayerSpawnLocationEvent.getHandlerList().getRegisteredListeners().length != 0) { -+ final Vec3 spawnPositionFinal = spawnPosition; -+ this.eventFuture = CompletableFuture.supplyAsync(() -> { -+ io.papermc.paper.event.player.AsyncPlayerSpawnLocationEvent ev = new io.papermc.paper.event.player.AsyncPlayerSpawnLocationEvent( -+ PrepareSpawnTask.this.listener.paperConnection, -+ org.bukkit.craftbukkit.util.CraftLocation.toBukkit(spawnPositionFinal, this.spawnLevel, this.spawnAngle.x, this.spawnAngle.y), -+ PrepareSpawnTask.this.newPlayer -+ ); -+ ev.callEvent(); -+ return ev.getSpawnLocation(); -+ }, io.papermc.paper.connection.PaperConfigurationTask.CONFIGURATION_POOL); -+ } -+ if (this.eventFuture != null) { -+ if (!this.eventFuture.isDone()) { -+ return null; -+ } -+ org.bukkit.Location location = this.eventFuture.join(); -+ spawnPosition = io.papermc.paper.util.MCUtil.toVec3(location); -+ this.spawnLevel = ((org.bukkit.craftbukkit.CraftWorld) location.getWorld()).getHandle(); -+ this.spawnPosition = CompletableFuture.completedFuture(spawnPosition); -+ this.spawnAngle = new Vec2(location.getYaw(), location.getPitch()); ++ if (this.eventFuture == null && io.papermc.paper.event.player.AsyncPlayerSpawnLocationEvent.getHandlerList().getRegisteredListeners().length != 0) { ++ final Vec3 spawnPositionFinal = spawnPosition; ++ this.eventFuture = CompletableFuture.supplyAsync(() -> { ++ io.papermc.paper.event.player.AsyncPlayerSpawnLocationEvent ev = new io.papermc.paper.event.player.AsyncPlayerSpawnLocationEvent( ++ PrepareSpawnTask.this.listener.paperConnection, ++ org.bukkit.craftbukkit.util.CraftLocation.toBukkit(spawnPositionFinal, this.spawnLevel, this.spawnAngle.x, this.spawnAngle.y), ++ PrepareSpawnTask.this.newPlayer ++ ); ++ ev.callEvent(); ++ return ev.getSpawnLocation(); ++ }, io.papermc.paper.connection.PaperConfigurationTask.CONFIGURATION_POOL); ++ } ++ if (this.eventFuture != null) { ++ if (!this.eventFuture.isDone()) { ++ return null; + } -+ // Paper end - PlayerSpawnLocationEvent - ChunkPos spawnChunk = ChunkPos.containing(BlockPos.containing(spawnPosition)); - this.chunkLoadCounter - .track( -@@ -178,15 +_,48 @@ ++ org.bukkit.Location location = this.eventFuture.join(); ++ spawnPosition = io.papermc.paper.util.MCUtil.toVec3(location); ++ this.spawnLevel = ((org.bukkit.craftbukkit.CraftWorld) location.getWorld()).getHandle(); ++ this.spawnPosition = CompletableFuture.completedFuture(spawnPosition); ++ this.spawnAngle = new Vec2(location.getYaw(), location.getPitch()); ++ } ++ // Paper end - PlayerSpawnLocationEvent + ChunkPos spawnChunk = ChunkPos.containing(BlockPos.containing(spawnPosition)); + this.chunkLoadCounter + .track( +@@ -172,14 +_,47 @@ public ServerPlayer spawn(final Connection connection, final CommonListenerCookie cookie) { ChunkPos spawnChunk = ChunkPos.containing(BlockPos.containing(this.spawnPosition)); this.spawnLevel.waitForEntities(spawnChunk, 3); @@ -175,7 +175,6 @@ + } + // Paper end - configuration api - possibly use legacy saved server player instance - ServerPlayer var7; try (ProblemReporter.ScopedCollector reporter = new ProblemReporter.ScopedCollector(player.problemPath(), PrepareSpawnTask.LOGGER)) { Optional input = PrepareSpawnTask.this.server .getPlayerList() diff --git a/paper-server/patches/sources/net/minecraft/server/players/CachedUserNameToIdResolver.java.patch b/paper-server/patches/sources/net/minecraft/server/players/CachedUserNameToIdResolver.java.patch index 8da762b0a07c..7a11cc56148c 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/CachedUserNameToIdResolver.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/CachedUserNameToIdResolver.java.patch @@ -11,7 +11,7 @@ public CachedUserNameToIdResolver(final GameProfileRepository profileRepository, final File file) { this.profileRepository = profileRepository; -@@ -54,23 +_,27 @@ +@@ -54,10 +_,12 @@ } private void safeAdd(final CachedUserNameToIdResolver.GameProfileInfo profileInfo) { @@ -24,15 +24,15 @@ } private Optional lookupGameProfile(final GameProfileRepository profileRepository, final String name) { - if (!StringUtil.isValidPlayerName(name)) { +@@ -65,12 +_,14 @@ return this.createUnknownProfile(name); - } else { -- Optional profile = profileRepository.findProfileByName(name).map(NameAndId::new); -+ final boolean shouldLookup = !org.apache.commons.lang3.StringUtils.isBlank(name) // Paper - Don't lookup a profile with a blank name -+ && io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode(); // Paper - Add setting for proxy online mode status -+ Optional profile = shouldLookup ? profileRepository.findProfileByName(name).map(NameAndId::new) : Optional.empty(); // Paper - Don't lookup a profile with a blank name - return profile.isEmpty() ? this.createUnknownProfile(name) : profile; } + +- Optional profile = profileRepository.findProfileByName(name).map(NameAndId::new); ++ final boolean shouldLookup = !org.apache.commons.lang3.StringUtils.isBlank(name) // Paper - Don't lookup a profile with a blank name ++ && io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode(); // Paper - Add setting for proxy online mode status ++ Optional profile = shouldLookup ? profileRepository.findProfileByName(name).map(NameAndId::new) : Optional.empty(); // Paper - Don't lookup a profile with a blank name + return profile.isEmpty() ? this.createUnknownProfile(name) : profile; } private Optional createUnknownProfile(final String name) { @@ -111,26 +111,26 @@ if (profileInfo == null) { return Optional.empty(); @@ -140,6 +_,7 @@ - profileInfo.setLastAccess(this.getNextOperation()); - return Optional.of(profileInfo.nameAndId()); - } + + profileInfo.setLastAccess(this.getNextOperation()); + return Optional.of(profileInfo.nameAndId()); + } finally { this.stateLock.unlock(); } // Paper - Fix GameProfileCache concurrency } private static DateFormat createDateFormat() { -@@ -164,6 +_,11 @@ - - return (List)var9; +@@ -158,6 +_,11 @@ + DateFormat dateFormat = createDateFormat(); + entryList.forEach(element -> readGameProfile(element, dateFormat).ifPresent(result::add)); } catch (FileNotFoundException var7) { + // Spigot start -+ } catch (com.google.gson.JsonSyntaxException | NullPointerException ex) { ++ } catch (com.google.gson.JsonSyntaxException | NullPointerException e) { + LOGGER.warn("Usercache.json is corrupted or has bad formatting. Deleting it to prevent further issues."); + this.file.delete(); + // Spigot end - } catch (JsonParseException | IOException var8) { - LOGGER.warn("Failed to load profile cache {}", this.file, var8); + } catch (IOException | JsonParseException e) { + LOGGER.warn("Failed to load profile cache {}", this.file, e); } -@@ -173,23 +_,51 @@ +@@ -167,23 +_,51 @@ @Override public void save() { @@ -145,7 +145,7 @@ DateFormat dateFormat = createDateFormat(); - this.getTopMRUProfiles(1000).forEach(entry -> entryList.add(writeGameProfile(entry, dateFormat))); + this.listTopMRUProfiles(org.spigotmc.SpigotConfig.userCacheCap).forEach(entry -> entryList.add(writeGameProfile(entry, dateFormat))); // Spigot // Paper - Fix GameProfileCache concurrency - String toSave = this.gson.toJson((JsonElement)entryList); + String toSave = this.gson.toJson(entryList); + Runnable save = () -> { // Paper - Perf: Async GameProfileCache saving try (Writer writer = Files.newWriter(this.file, StandardCharsets.UTF_8)) { diff --git a/paper-server/patches/sources/net/minecraft/server/players/OldUsersConverter.java.patch b/paper-server/patches/sources/net/minecraft/server/players/OldUsersConverter.java.patch index 02d4bec2ed83..f9eb3fd9e170 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/OldUsersConverter.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/OldUsersConverter.java.patch @@ -13,8 +13,8 @@ @@ -66,7 +_,7 @@ try { bans.load(); - } catch (IOException var6) { -- LOGGER.warn("Could not load existing file {}", bans.getFile().getName(), var6); + } catch (IOException e) { +- LOGGER.warn("Could not load existing file {}", bans.getFile().getName(), e); + LOGGER.warn("Could not load existing file {}", bans.getFile().getName()); // CraftBukkit - don't print stacktrace } } @@ -22,8 +22,8 @@ @@ -122,7 +_,7 @@ try { ipBans.load(); - } catch (IOException var11) { -- LOGGER.warn("Could not load existing file {}", ipBans.getFile().getName(), var11); + } catch (IOException e) { +- LOGGER.warn("Could not load existing file {}", ipBans.getFile().getName(), e); + LOGGER.warn("Could not load existing file {}", ipBans.getFile().getName()); // CraftBukkit - don't print stacktrace } } @@ -31,8 +31,8 @@ @@ -158,7 +_,7 @@ try { opsList.load(); - } catch (IOException var6) { -- LOGGER.warn("Could not load existing file {}", opsList.getFile().getName(), var6); + } catch (IOException e) { +- LOGGER.warn("Could not load existing file {}", opsList.getFile().getName(), e); + LOGGER.warn("Could not load existing file {}", opsList.getFile().getName()); // CraftBukkit - don't print stacktrace } } @@ -40,8 +40,8 @@ @@ -203,7 +_,7 @@ try { whitelist.load(); - } catch (IOException var6) { -- LOGGER.warn("Could not load existing file {}", whitelist.getFile().getName(), var6); + } catch (IOException e) { +- LOGGER.warn("Could not load existing file {}", whitelist.getFile().getName(), e); + LOGGER.warn("Could not load existing file {}", whitelist.getFile().getName()); // CraftBukkit - don't print stacktrace } } diff --git a/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch b/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch index b6c7894d187b..cc1ff3d76cab 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java -@@ -114,14 +_,16 @@ +@@ -113,14 +_,16 @@ private static final int SEND_PLAYER_INFO_INTERVAL = 600; private static final SimpleDateFormat BAN_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z", Locale.ROOT); private final MinecraftServer server; @@ -20,7 +20,7 @@ public final PlayerDataStorage playerIo; private final LayeredRegistryAccess registries; private int viewDistance; -@@ -129,12 +_,20 @@ +@@ -128,12 +_,20 @@ private boolean allowCommandsForAllPlayers; private int sendAllPlayerInfoIn; @@ -41,7 +41,7 @@ this.server = server; this.registries = registries; this.playerIo = playerIo; -@@ -144,23 +_,19 @@ +@@ -143,23 +_,19 @@ this.ipBans = new IpBanList(IPBANLIST_FILE, notificationService); } @@ -70,7 +70,7 @@ LevelData levelData = level.getLevelData(); ServerGamePacketListenerImpl playerConnection = new ServerGamePacketListenerImpl(this.server, connection, player, cookie); connection.setupInboundProtocol( -@@ -177,8 +_,8 @@ +@@ -176,8 +_,8 @@ levelData.isHardcore(), this.server.levelKeys(), this.getMaxPlayers(), @@ -81,7 +81,7 @@ reducedDebugInfo, !immediateRespawn, doLimitedCrafting, -@@ -186,6 +_,7 @@ +@@ -185,6 +_,7 @@ this.server.enforceSecureProfile() ) ); @@ -89,7 +89,7 @@ playerConnection.send(new ClientboundChangeDifficultyPacket(levelData.getDifficulty(), levelData.isDifficultyLocked())); playerConnection.send(new ClientboundPlayerAbilitiesPacket(player.getAbilities())); playerConnection.send(new ClientboundSetHeldSlotPacket(player.getInventory().getSelectedSlot())); -@@ -205,24 +_,129 @@ +@@ -204,24 +_,129 @@ component = Component.translatable("multiplayer.player.joined.renamed", player.getDisplayName(), oldName); } @@ -223,7 +223,7 @@ } public void updateEntireScoreboard(final ServerScoreboard scoreboard, final ServerPlayer player) { -@@ -244,6 +_,15 @@ +@@ -243,31 +_,40 @@ } } @@ -238,9 +238,6 @@ + // Paper end - virtual world border API public void addWorldborderListener(final ServerLevel level) { level.getWorldBorder().addListener(new BorderChangeListener() { - { -@@ -252,27 +_,27 @@ - @Override public void onSetSize(final WorldBorder border, final double newSize) { - PlayerList.this.broadcastAll(new ClientboundSetBorderSizePacket(border), level.dimension()); @@ -272,7 +269,7 @@ } @Override -@@ -296,64 +_,147 @@ +@@ -291,65 +_,146 @@ } protected void save(final ServerPlayer player) { @@ -426,27 +423,27 @@ } - return reason; -- } else if (!this.isWhiteListed(nameAndId)) { -- return Component.translatable("multiplayer.disconnect.not_whitelisted"); + return new LoginResult(reason, org.bukkit.event.player.PlayerLoginEvent.Result.KICK_BANNED); // Paper - PlayerLoginEvent -+ // Paper start - whitelist event -+ } else if ((whitelistEventResult = this.isWhiteListedLogin(nameAndId)).result == org.bukkit.event.player.PlayerLoginEvent.Result.KICK_WHITELIST) { -+ return whitelistEventResult; -+ // Paper end - } else if (this.ipBans.isBanned(address)) { - IpBanListEntry ban = this.ipBans.get(address); - MutableComponent reason = Component.translatable("multiplayer.disconnect.banned_ip.reason", ban.getReasonMessage()); -@@ -361,19 +_,18 @@ - reason.append(Component.translatable("multiplayer.disconnect.banned_ip.expiration", BAN_DATE_FORMAT.format(ban.getExpires()))); + } else { +- if (!this.isWhiteListed(nameAndId)) { +- return Component.translatable("multiplayer.disconnect.not_whitelisted"); ++ if ((whitelistEventResult = this.isWhiteListedLogin(nameAndId)).result == org.bukkit.event.player.PlayerLoginEvent.Result.KICK_WHITELIST) { // Paper - whitelist event ++ return whitelistEventResult; // Paper - whitelist event } -- return reason; -+ return new LoginResult(reason, org.bukkit.event.player.PlayerLoginEvent.Result.KICK_BANNED); // Paper - PlayerLoginEvent - } else { -- return this.players.size() >= this.getMaxPlayers() && !this.canBypassPlayerLimit(nameAndId) -- ? Component.translatable("multiplayer.disconnect.server_full") -- : null; -+ return this.canBypassFullServerLogin(nameAndId, new LoginResult(Component.translatable("multiplayer.disconnect.server_full"), org.bukkit.event.player.PlayerLoginEvent.Result.KICK_FULL)); // Paper - PlayerServerFullCheckEvent + if (this.ipBans.isBanned(address)) { +@@ -359,20 +_,19 @@ + reason.append(Component.translatable("multiplayer.disconnect.banned_ip.expiration", BAN_DATE_FORMAT.format(ban.getExpires()))); + } + +- return reason; ++ return new LoginResult(reason, org.bukkit.event.player.PlayerLoginEvent.Result.KICK_BANNED); // Paper - PlayerLoginEvent + } else { +- return this.players.size() >= this.getMaxPlayers() && !this.canBypassPlayerLimit(nameAndId) +- ? Component.translatable("multiplayer.disconnect.server_full") +- : null; ++ return this.canBypassFullServerLogin(nameAndId, new LoginResult(Component.translatable("multiplayer.disconnect.server_full"), org.bukkit.event.player.PlayerLoginEvent.Result.KICK_FULL)); // Paper - PlayerServerFullCheckEvent + } } } @@ -461,12 +458,12 @@ dupes.add(player); } } -@@ -384,23 +_,31 @@ +@@ -383,23 +_,31 @@ } - for (ServerPlayer playerx : dupes) { -- playerx.connection.disconnect(DUPLICATE_LOGIN_DISCONNECT_MESSAGE); -+ playerx.connection.disconnect(DUPLICATE_LOGIN_DISCONNECT_MESSAGE, io.papermc.paper.connection.DisconnectionReason.DUPLICATE_LOGIN_MESSAGE); // Paper - disconnect API + for (ServerPlayer player : dupes) { +- player.connection.disconnect(DUPLICATE_LOGIN_DISCONNECT_MESSAGE); ++ player.connection.disconnect(DUPLICATE_LOGIN_DISCONNECT_MESSAGE, io.papermc.paper.connection.DisconnectionReason.DUPLICATE_LOGIN_MESSAGE); // Paper - disconnect API } return !dupes.isEmpty(); @@ -498,7 +495,7 @@ player.copyRespawnPosition(serverPlayer); } -@@ -408,17 +_,26 @@ +@@ -407,17 +_,26 @@ player.addTag(tag); } @@ -526,7 +523,7 @@ player.connection.send(new ClientboundSetDefaultSpawnPositionPacket(level.getRespawnData())); player.connection.send(new ClientboundChangeDifficultyPacket(levelData.getDifficulty(), levelData.isDifficultyLocked())); player.connection.send(new ClientboundSetExperiencePacket(player.experienceProgress, player.totalExperience, player.experienceLevel)); -@@ -427,9 +_,15 @@ +@@ -426,9 +_,15 @@ this.sendPlayerPermissionLevel(player); level.addRespawnedPlayer(player); this.players.add(player); @@ -542,7 +539,7 @@ ServerPlayer.RespawnConfig respawnConfig = player.getRespawnConfig(); if (!keepAllPlayerData && respawnConfig != null) { LevelData.RespawnData respawnData = respawnConfig.respawnData(); -@@ -455,6 +_,29 @@ +@@ -454,6 +_,29 @@ } } @@ -572,7 +569,7 @@ return player; } -@@ -463,23 +_,58 @@ +@@ -462,23 +_,58 @@ } public void sendActiveEffects(final LivingEntity livingEntity, final ServerGamePacketListenerImpl connection) { @@ -634,7 +631,7 @@ public void broadcastAll(final Packet packet) { for (ServerPlayer player : this.players) { player.connection.send(packet); -@@ -565,6 +_,12 @@ +@@ -564,6 +_,12 @@ } private void sendPlayerPermissionLevel(final ServerPlayer player, final LevelBasedPermissionSet permissions) { @@ -647,7 +644,7 @@ if (player.connection != null) { byte eventId = switch (permissions.level()) { case ALL -> EntityEvent.PERMISSION_LEVEL_ALL; -@@ -576,9 +_,48 @@ +@@ -575,9 +_,48 @@ player.connection.send(new ClientboundEntityEventPacket(player, eventId)); } @@ -698,7 +695,7 @@ public boolean isWhiteListed(final NameAndId nameAndId) { return !this.isUsingWhitelist() || this.ops.contains(nameAndId) || this.whitelist.contains(nameAndId); } -@@ -590,16 +_,7 @@ +@@ -589,16 +_,7 @@ } public @Nullable ServerPlayer getPlayerByName(final String name) { @@ -716,7 +713,7 @@ } public void broadcast( -@@ -613,6 +_,11 @@ +@@ -612,6 +_,11 @@ ) { for (int i = 0; i < this.players.size(); i++) { ServerPlayer player = this.players.get(i); @@ -728,7 +725,7 @@ if (player != except && player.level().dimension() == dimension) { double xd = x - player.getX(); double yd = y - player.getY(); -@@ -625,9 +_,11 @@ +@@ -624,9 +_,11 @@ } public void saveAll() { @@ -740,7 +737,7 @@ } public UserWhiteList getWhiteList() { -@@ -652,12 +_,20 @@ +@@ -651,12 +_,20 @@ public void sendLevelInfo(final ServerPlayer player, final ServerLevel level) { WorldBorder worldBorder = level.getWorldBorder(); player.connection.send(new ClientboundInitializeBorderPacket(worldBorder)); @@ -765,7 +762,7 @@ } player.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.LEVEL_CHUNKS_LOAD_START, 0.0F)); -@@ -666,8 +_,21 @@ +@@ -665,8 +_,21 @@ public void sendAllPlayerInfo(final ServerPlayer player) { player.inventoryMenu.sendAllDataToRemote(); @@ -788,7 +785,7 @@ } public int getPlayerCount() { -@@ -711,9 +_,26 @@ +@@ -710,9 +_,26 @@ } public void removeAll() { @@ -818,7 +815,7 @@ } public void broadcastSystemMessage(final Component message, final boolean overlay) { -@@ -736,20 +_,39 @@ +@@ -735,20 +_,39 @@ } public void broadcastChatMessage(final PlayerChatMessage message, final ServerPlayer sender, final ChatType.Bound chatType) { @@ -861,7 +858,7 @@ wasFullyFiltered |= filtered && message.isFullyFiltered(); } -@@ -762,13 +_,21 @@ +@@ -761,13 +_,21 @@ return message.hasSignature() && !message.hasExpiredServer(Instant.now()); } @@ -886,7 +883,7 @@ private Path locateStatsFile(final GameProfile gameProfile) { Path statFolder = this.server.getWorldPath(LevelResource.PLAYER_STATS_DIR); -@@ -795,11 +_,11 @@ +@@ -794,11 +_,11 @@ public PlayerAdvancements getPlayerAdvancements(final ServerPlayer player) { UUID uuid = player.getUUID(); @@ -900,7 +897,7 @@ } result.setPlayer(player); -@@ -847,11 +_,34 @@ +@@ -846,11 +_,34 @@ } public void reloadResources() { diff --git a/paper-server/patches/sources/net/minecraft/server/players/ProfileResolver.java.patch b/paper-server/patches/sources/net/minecraft/server/players/ProfileResolver.java.patch index 0ea61aa2ca67..e9aa7334268d 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/ProfileResolver.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/ProfileResolver.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/players/ProfileResolver.java +++ b/net/minecraft/server/players/ProfileResolver.java -@@ -26,7 +_,7 @@ +@@ -25,7 +_,7 @@ private final LoadingCache> profileCacheByName; private final LoadingCache> profileCacheById; @@ -9,7 +9,7 @@ this.profileCacheById = CacheBuilder.newBuilder() .expireAfterAccess(Duration.ofMinutes(10L)) .maximumSize(256L) -@@ -38,7 +_,13 @@ +@@ -33,7 +_,13 @@ @Override public Optional load(final UUID profileId) { ProfileResult result = sessionService.fetchProfile(profileId, true); diff --git a/paper-server/patches/sources/net/minecraft/server/players/UserBanListEntry.java.patch b/paper-server/patches/sources/net/minecraft/server/players/UserBanListEntry.java.patch index ff61eda61ae4..de30853b7873 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/UserBanListEntry.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/UserBanListEntry.java.patch @@ -11,7 +11,7 @@ @Override @@ -39,4 +_,31 @@ NameAndId user = this.getUser(); - return (Component)(user != null ? Component.literal(user.name()) : MESSAGE_UNKNOWN_USER); + return user != null ? Component.literal(user.name()) : MESSAGE_UNKNOWN_USER; } + + // Spigot start diff --git a/paper-server/patches/sources/net/minecraft/server/rcon/thread/QueryThreadGs4.java.patch b/paper-server/patches/sources/net/minecraft/server/rcon/thread/QueryThreadGs4.java.patch index 35ae01a2673f..363a23cc964d 100644 --- a/paper-server/patches/sources/net/minecraft/server/rcon/thread/QueryThreadGs4.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/rcon/thread/QueryThreadGs4.java.patch @@ -39,89 +39,89 @@ this.sendTo(dos.toByteArray(), packet); LOGGER.debug("Status [{}]", socketAddress); } -@@ -146,31 +_,76 @@ - this.rulesResponse.writeString("splitnum"); - this.rulesResponse.write(128); - this.rulesResponse.write(0); -+ // Paper start -+ // Pack plugins -+ java.util.List plugins = java.util.Collections.emptyList(); -+ org.bukkit.plugin.Plugin[] bukkitPlugins; -+ if (((net.minecraft.server.dedicated.DedicatedServer) this.serverInterface).server.getQueryPlugins() && (bukkitPlugins = org.bukkit.Bukkit.getPluginManager().getPlugins()).length > 0) { -+ plugins = java.util.stream.Stream.of(bukkitPlugins) -+ .map(plugin -> com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation.of(plugin.getName(), plugin.getDescription().getVersion())) -+ .collect(java.util.stream.Collectors.toList()); -+ } +@@ -147,31 +_,76 @@ + this.rulesResponse.writeString("splitnum"); + this.rulesResponse.write(128); + this.rulesResponse.write(0); ++ // Paper start ++ // Pack plugins ++ java.util.List plugins = java.util.Collections.emptyList(); ++ org.bukkit.plugin.Plugin[] bukkitPlugins; ++ if (((net.minecraft.server.dedicated.DedicatedServer) this.serverInterface).server.getQueryPlugins() && (bukkitPlugins = org.bukkit.Bukkit.getPluginManager().getPlugins()).length > 0) { ++ plugins = java.util.stream.Stream.of(bukkitPlugins) ++ .map(plugin -> com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation.of(plugin.getName(), plugin.getDescription().getVersion())) ++ .collect(java.util.stream.Collectors.toList()); ++ } + -+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse queryResponse = com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.builder() -+ .motd(this.serverName) -+ .map(this.worldName) -+ .currentPlayers(this.serverInterface.getPlayerCount()) -+ .maxPlayers(this.maxPlayers) -+ .port(this.serverPort) -+ .hostname(this.hostIp) -+ .plugins(plugins) -+ .players(this.serverInterface.getPlayerNames()) -+ .gameVersion(this.serverInterface.getServerVersion()) -+ .serverVersion(org.bukkit.Bukkit.getServer().getName() + " on " + org.bukkit.Bukkit.getServer().getBukkitVersion()) -+ .build(); -+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType queryType = -+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType.FULL; -+ com.destroystokyo.paper.event.server.GS4QueryEvent queryEvent = -+ new com.destroystokyo.paper.event.server.GS4QueryEvent(queryType, packet.getAddress(), queryResponse); -+ queryEvent.callEvent(); -+ queryResponse = queryEvent.getResponse(); - this.rulesResponse.writeString("hostname"); -- this.rulesResponse.writeString(this.serverName); -+ this.rulesResponse.writeString(queryResponse.getMotd()); - this.rulesResponse.writeString("gametype"); - this.rulesResponse.writeString("SMP"); - this.rulesResponse.writeString("game_id"); - this.rulesResponse.writeString("MINECRAFT"); - this.rulesResponse.writeString("version"); -- this.rulesResponse.writeString(this.serverInterface.getServerVersion()); -+ this.rulesResponse.writeString(queryResponse.getGameVersion()); - this.rulesResponse.writeString("plugins"); -- this.rulesResponse.writeString(this.serverInterface.getPluginNames()); -+ java.lang.StringBuilder pluginsString = new java.lang.StringBuilder(); -+ pluginsString.append(queryResponse.getServerVersion()); -+ if (!queryResponse.getPlugins().isEmpty()) { -+ pluginsString.append(": "); -+ java.util.Iterator iter = queryResponse.getPlugins().iterator(); -+ while (iter.hasNext()) { -+ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation info = iter.next(); -+ pluginsString.append(info.getName()); -+ if (info.getVersion() != null) { -+ pluginsString.append(' ').append(info.getVersion().replace(";", ",")); -+ } -+ if (iter.hasNext()) { -+ pluginsString.append(';').append(' '); -+ } ++ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse queryResponse = com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.builder() ++ .motd(this.serverName) ++ .map(this.worldName) ++ .currentPlayers(this.serverInterface.getPlayerCount()) ++ .maxPlayers(this.maxPlayers) ++ .port(this.serverPort) ++ .hostname(this.hostIp) ++ .plugins(plugins) ++ .players(this.serverInterface.getPlayerNames()) ++ .gameVersion(this.serverInterface.getServerVersion()) ++ .serverVersion(org.bukkit.Bukkit.getServer().getName() + " on " + org.bukkit.Bukkit.getServer().getBukkitVersion()) ++ .build(); ++ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType queryType = ++ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType.FULL; ++ com.destroystokyo.paper.event.server.GS4QueryEvent queryEvent = ++ new com.destroystokyo.paper.event.server.GS4QueryEvent(queryType, packet.getAddress(), queryResponse); ++ queryEvent.callEvent(); ++ queryResponse = queryEvent.getResponse(); + this.rulesResponse.writeString("hostname"); +- this.rulesResponse.writeString(this.serverName); ++ this.rulesResponse.writeString(queryResponse.getMotd()); + this.rulesResponse.writeString("gametype"); + this.rulesResponse.writeString("SMP"); + this.rulesResponse.writeString("game_id"); + this.rulesResponse.writeString("MINECRAFT"); + this.rulesResponse.writeString("version"); +- this.rulesResponse.writeString(this.serverInterface.getServerVersion()); ++ this.rulesResponse.writeString(queryResponse.getGameVersion()); + this.rulesResponse.writeString("plugins"); +- this.rulesResponse.writeString(this.serverInterface.getPluginNames()); ++ StringBuilder pluginsString = new StringBuilder(); ++ pluginsString.append(queryResponse.getServerVersion()); ++ if (!queryResponse.getPlugins().isEmpty()) { ++ pluginsString.append(": "); ++ java.util.Iterator iter = queryResponse.getPlugins().iterator(); ++ while (iter.hasNext()) { ++ com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation info = iter.next(); ++ pluginsString.append(info.getName()); ++ if (info.getVersion() != null) { ++ pluginsString.append(' ').append(info.getVersion().replace(";", ",")); ++ } ++ if (iter.hasNext()) { ++ pluginsString.append(';').append(' '); + } + } -+ this.rulesResponse.writeString(pluginsString.toString()); - this.rulesResponse.writeString("map"); -- this.rulesResponse.writeString(this.worldName); -+ this.rulesResponse.writeString(queryResponse.getMap()); - this.rulesResponse.writeString("numplayers"); -- this.rulesResponse.writeString(this.serverInterface.getPlayerCount() + ""); -+ this.rulesResponse.writeString(Integer.toString(queryResponse.getCurrentPlayers())); - this.rulesResponse.writeString("maxplayers"); -- this.rulesResponse.writeString(this.maxPlayers + ""); -+ this.rulesResponse.writeString(Integer.toString(queryResponse.getMaxPlayers())); - this.rulesResponse.writeString("hostport"); -- this.rulesResponse.writeString(this.serverPort + ""); -+ this.rulesResponse.writeString(Integer.toString(queryResponse.getPort())); - this.rulesResponse.writeString("hostip"); -- this.rulesResponse.writeString(this.hostIp); -+ this.rulesResponse.writeString(queryResponse.getHostname()); - this.rulesResponse.write(0); - this.rulesResponse.write(1); - this.rulesResponse.writeString("player_"); - this.rulesResponse.write(0); -- String[] players = this.serverInterface.getPlayerNames(); -+ String[] players = queryResponse.getPlayers().toArray(String[]::new); -+ // Paper end ++ } ++ this.rulesResponse.writeString(pluginsString.toString()); + this.rulesResponse.writeString("map"); +- this.rulesResponse.writeString(this.worldName); ++ this.rulesResponse.writeString(queryResponse.getMap()); + this.rulesResponse.writeString("numplayers"); +- this.rulesResponse.writeString(this.serverInterface.getPlayerCount() + ""); ++ this.rulesResponse.writeString(Integer.toString(queryResponse.getCurrentPlayers())); + this.rulesResponse.writeString("maxplayers"); +- this.rulesResponse.writeString(this.maxPlayers + ""); ++ this.rulesResponse.writeString(Integer.toString(queryResponse.getMaxPlayers())); + this.rulesResponse.writeString("hostport"); +- this.rulesResponse.writeString(this.serverPort + ""); ++ this.rulesResponse.writeString(Integer.toString(queryResponse.getPort())); + this.rulesResponse.writeString("hostip"); +- this.rulesResponse.writeString(this.hostIp); ++ this.rulesResponse.writeString(queryResponse.getHostname()); + this.rulesResponse.write(0); + this.rulesResponse.write(1); + this.rulesResponse.writeString("player_"); + this.rulesResponse.write(0); +- String[] players = this.serverInterface.getPlayerNames(); ++ String[] players = queryResponse.getPlayers().toArray(String[]::new); ++ // Paper end - for (String player : players) { - this.rulesResponse.writeString(player); + for (String player : players) { + this.rulesResponse.writeString(player); diff --git a/paper-server/patches/sources/net/minecraft/server/rcon/thread/RconClient.java.patch b/paper-server/patches/sources/net/minecraft/server/rcon/thread/RconClient.java.patch index 65e879ba64fc..71a3892df1cd 100644 --- a/paper-server/patches/sources/net/minecraft/server/rcon/thread/RconClient.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/rcon/thread/RconClient.java.patch @@ -31,6 +31,6 @@ try { - this.sendCmdResponse(requestid, this.serverInterface.runCommand(command)); + this.sendCmdResponse(requestid, this.serverInterface.runCommand(this.rconConsoleSource, command)); // CraftBukkit - } catch (Exception var15) { - this.sendCmdResponse(requestid, "Error executing: " + command + " (" + var15.getMessage() + ")"); + } catch (Exception e) { + this.sendCmdResponse(requestid, "Error executing: " + command + " (" + e.getMessage() + ")"); } diff --git a/paper-server/patches/sources/net/minecraft/server/waypoints/ServerWaypointManager.java.patch b/paper-server/patches/sources/net/minecraft/server/waypoints/ServerWaypointManager.java.patch index dc552adc08ca..978ae5743a5c 100644 --- a/paper-server/patches/sources/net/minecraft/server/waypoints/ServerWaypointManager.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/waypoints/ServerWaypointManager.java.patch @@ -39,7 +39,7 @@ + } // Paper - optimize ServerWaypointManager with locator bar disabled if (player.isTransmittingWaypoint()) { - this.trackWaypoint((WaypointTransmitter)player); + this.trackWaypoint(player); @@ -65,6 +_,7 @@ } diff --git a/paper-server/patches/sources/net/minecraft/stats/ServerStatsCounter.java.patch b/paper-server/patches/sources/net/minecraft/stats/ServerStatsCounter.java.patch index a095b44e2e5a..d93c2ca8aa6a 100644 --- a/paper-server/patches/sources/net/minecraft/stats/ServerStatsCounter.java.patch +++ b/paper-server/patches/sources/net/minecraft/stats/ServerStatsCounter.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/stats/ServerStatsCounter.java +++ b/net/minecraft/stats/ServerStatsCounter.java @@ -75,9 +_,21 @@ - LOGGER.error("Couldn't parse statistics file {}", file, var9); + LOGGER.error("Couldn't parse statistics file {}", file, e); } } + // Paper start - Moved after stat fetching for player state file diff --git a/paper-server/patches/sources/net/minecraft/tags/TagLoader.java.patch b/paper-server/patches/sources/net/minecraft/tags/TagLoader.java.patch index 09f37b6e02ff..30caf439d8c8 100644 --- a/paper-server/patches/sources/net/minecraft/tags/TagLoader.java.patch +++ b/paper-server/patches/sources/net/minecraft/tags/TagLoader.java.patch @@ -11,8 +11,8 @@ + // Paper end final Map> newTags = new HashMap<>(); TagEntry.Lookup lookup = new TagEntry.Lookup() { - { -@@ -116,7 +_,7 @@ + @Override +@@ -112,7 +_,7 @@ ) .ifRight(tag -> newTags.put(id, (List)tag)) ); @@ -21,7 +21,7 @@ } public static Map, List>> loadTagsFromNetwork(final TagNetworkSerialization.NetworkPayload tags, final Registry registry) { -@@ -124,18 +_,39 @@ +@@ -120,18 +_,39 @@ } public static List> loadTagsForExistingRegistries(final ResourceManager manager, final RegistryAccess layer) { @@ -64,7 +64,7 @@ } private static Map, List>> wrapTags( -@@ -144,12 +_,12 @@ +@@ -140,12 +_,12 @@ return tags.entrySet().stream().collect(Collectors.toUnmodifiableMap(e -> TagKey.create(registryKey, e.getKey()), Entry::getValue)); } diff --git a/paper-server/patches/sources/net/minecraft/util/PlaceholderLookupProvider.java.patch b/paper-server/patches/sources/net/minecraft/util/PlaceholderLookupProvider.java.patch index fd298fb998c3..8b6037975a17 100644 --- a/paper-server/patches/sources/net/minecraft/util/PlaceholderLookupProvider.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/PlaceholderLookupProvider.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/util/PlaceholderLookupProvider.java +++ b/net/minecraft/util/PlaceholderLookupProvider.java -@@ -57,6 +_,13 @@ +@@ -52,6 +_,13 @@ ) ); } diff --git a/paper-server/patches/sources/net/minecraft/util/SimpleBitStorage.java.patch b/paper-server/patches/sources/net/minecraft/util/SimpleBitStorage.java.patch index 8de07f4f8ce7..a65553b73845 100644 --- a/paper-server/patches/sources/net/minecraft/util/SimpleBitStorage.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/SimpleBitStorage.java.patch @@ -34,8 +34,8 @@ @Override - public int getAndSet(final int index, final int value) { -- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); -- Validate.inclusiveBetween(0L, this.mask, (long)value); +- Validate.inclusiveBetween(0L, this.size - 1, index); +- Validate.inclusiveBetween(0L, this.mask, value); + public final int getAndSet(final int index, final int value) { // Paper - Perf: Optimize SimpleBitStorage int cellIndex = this.cellIndex(index); long cellValue = this.data[cellIndex]; @@ -45,8 +45,8 @@ @Override - public void set(final int index, final int value) { -- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); -- Validate.inclusiveBetween(0L, this.mask, (long)value); +- Validate.inclusiveBetween(0L, this.size - 1, index); +- Validate.inclusiveBetween(0L, this.mask, value); + public final void set(final int index, final int value) { // Paper - Perf: Optimize SimpleBitStorage int cellIndex = this.cellIndex(index); long cellValue = this.data[cellIndex]; @@ -56,7 +56,7 @@ @Override - public int get(final int index) { -- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); +- Validate.inclusiveBetween(0L, this.size - 1, index); + public final int get(final int index) { // Paper - Perf: Optimize SimpleBitStorage int cellIndex = this.cellIndex(index); long cellValue = this.data[cellIndex]; diff --git a/paper-server/patches/sources/net/minecraft/util/ZeroBitStorage.java.patch b/paper-server/patches/sources/net/minecraft/util/ZeroBitStorage.java.patch index de6cbf1fea52..e6aba154593b 100644 --- a/paper-server/patches/sources/net/minecraft/util/ZeroBitStorage.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/ZeroBitStorage.java.patch @@ -5,28 +5,28 @@ @Override - public int getAndSet(final int index, final int value) { -- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); -- Validate.inclusiveBetween(0L, 0L, (long)value); +- Validate.inclusiveBetween(0L, this.size - 1, index); +- Validate.inclusiveBetween(0L, 0L, value); + public final int getAndSet(final int index, final int value) { // Paper - Perf: Optimize SimpleBitStorage -+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage -+ //Validate.inclusiveBetween(0L, 0L, (long)value); // Paper - Perf: Optimize SimpleBitStorage ++ //Validate.inclusiveBetween(0L, this.size - 1, index); // Paper - Perf: Optimize SimpleBitStorage ++ //Validate.inclusiveBetween(0L, 0L, value); // Paper - Perf: Optimize SimpleBitStorage return 0; } @Override - public void set(final int index, final int value) { -- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); -- Validate.inclusiveBetween(0L, 0L, (long)value); +- Validate.inclusiveBetween(0L, this.size - 1, index); +- Validate.inclusiveBetween(0L, 0L, value); + public final void set(final int index, final int value) { // Paper - Perf: Optimize SimpleBitStorage -+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage -+ //Validate.inclusiveBetween(0L, 0L, (long)value); // Paper - Perf: Optimize SimpleBitStorage ++ //Validate.inclusiveBetween(0L, this.size - 1, index); // Paper - Perf: Optimize SimpleBitStorage ++ //Validate.inclusiveBetween(0L, 0L, value); // Paper - Perf: Optimize SimpleBitStorage } @Override - public int get(final int index) { -- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); +- Validate.inclusiveBetween(0L, this.size - 1, index); + public final int get(final int index) { // Paper - Perf: Optimize SimpleBitStorage -+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage ++ //Validate.inclusiveBetween(0L, this.size - 1, index); // Paper - Perf: Optimize SimpleBitStorage return 0; } diff --git a/paper-server/patches/sources/net/minecraft/util/datafix/DataFixTypes.java.patch b/paper-server/patches/sources/net/minecraft/util/datafix/DataFixTypes.java.patch index b4b8c5b0387c..873079b65960 100644 --- a/paper-server/patches/sources/net/minecraft/util/datafix/DataFixTypes.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/datafix/DataFixTypes.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/util/datafix/DataFixTypes.java +++ b/net/minecraft/util/datafix/DataFixTypes.java -@@ -15,6 +_,7 @@ +@@ -14,6 +_,7 @@ import net.minecraft.util.datafix.fixes.References; public enum DataFixTypes { @@ -8,7 +8,7 @@ LEVEL(References.LEVEL), LEVEL_SUMMARY(References.LIGHTWEIGHT_LEVEL), PLAYER(References.PLAYER), -@@ -81,6 +_,7 @@ +@@ -76,6 +_,7 @@ } public Dynamic update(final DataFixer fixerUpper, final Dynamic input, final int fromVersion, final int toVersion) { diff --git a/paper-server/patches/sources/net/minecraft/util/datafix/fixes/ItemStackTheFlatteningFix.java.patch b/paper-server/patches/sources/net/minecraft/util/datafix/fixes/ItemStackTheFlatteningFix.java.patch index 6573728534eb..8a0b310f822e 100644 --- a/paper-server/patches/sources/net/minecraft/util/datafix/fixes/ItemStackTheFlatteningFix.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/datafix/fixes/ItemStackTheFlatteningFix.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/util/datafix/fixes/ItemStackTheFlatteningFix.java +++ b/net/minecraft/util/datafix/fixes/ItemStackTheFlatteningFix.java -@@ -423,7 +_,7 @@ - if (DAMAGE_IDS.contains(id.get().getSecond())) { - Typed tag = input.getOrCreateTyped(tagF); - Dynamic tagRest = tag.get(DSL.remainderFinder()); -- tagRest = tagRest.set("Damage", tagRest.createInt(data)); -+ if (data != 0) tagRest = tagRest.set("Damage", tagRest.createInt(data)); // CraftBukkit - output = output.set(tagF, tag.set(DSL.remainderFinder(), tagRest)); - } +@@ -424,7 +_,7 @@ + if (DAMAGE_IDS.contains(id.get().getSecond())) { + Typed tag = input.getOrCreateTyped(tagF); + Dynamic tagRest = tag.get(DSL.remainderFinder()); +- tagRest = tagRest.set("Damage", tagRest.createInt(data)); ++ if (data != 0) tagRest = tagRest.set("Damage", tagRest.createInt(data)); // CraftBukkit + output = output.set(tagF, tag.set(DSL.remainderFinder(), tagRest)); + } diff --git a/paper-server/patches/sources/net/minecraft/util/parsing/packrat/Scope.java.patch b/paper-server/patches/sources/net/minecraft/util/parsing/packrat/Scope.java.patch index 8f7f4e9277be..77e33b2b417c 100644 --- a/paper-server/patches/sources/net/minecraft/util/parsing/packrat/Scope.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/parsing/packrat/Scope.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/util/parsing/packrat/Scope.java +++ b/net/minecraft/util/parsing/packrat/Scope.java -@@ -279,4 +_,31 @@ +@@ -265,4 +_,31 @@ return true; } diff --git a/paper-server/patches/sources/net/minecraft/world/Container.java.patch b/paper-server/patches/sources/net/minecraft/world/Container.java.patch index 3cb5c688c52b..3c41d7c7df52 100644 --- a/paper-server/patches/sources/net/minecraft/world/Container.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/Container.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/Container.java +++ b/net/minecraft/world/Container.java -@@ -32,9 +_,7 @@ +@@ -31,9 +_,7 @@ void setItem(int slot, ItemStack itemStack); @@ -11,7 +11,7 @@ default int getMaxStackSize(final ItemStack itemStack) { return Math.min(this.getMaxStackSize(), itemStack.getMaxStackSize()); -@@ -147,4 +_,22 @@ +@@ -142,4 +_,22 @@ } } } diff --git a/paper-server/patches/sources/net/minecraft/world/InteractionResult.java.patch b/paper-server/patches/sources/net/minecraft/world/InteractionResult.java.patch index f5ed75b9f4a5..d5f39ad87c76 100644 --- a/paper-server/patches/sources/net/minecraft/world/InteractionResult.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/InteractionResult.java.patch @@ -1,19 +1,19 @@ --- a/net/minecraft/world/InteractionResult.java +++ b/net/minecraft/world/InteractionResult.java @@ -30,18 +_,34 @@ - public record Pass() implements InteractionResult { + record Pass() implements InteractionResult { } -- public record Success(InteractionResult.SwingSource swingSource, InteractionResult.ItemContext itemContext) implements InteractionResult { +- record Success(InteractionResult.SwingSource swingSource, InteractionResult.ItemContext itemContext) implements InteractionResult { + // Paper start - track more context in interaction result -+ public record PaperSuccessContext(net.minecraft.core.@Nullable BlockPos placedPos) { ++ record PaperSuccessContext(net.minecraft.core.@Nullable BlockPos placedPos) { + static PaperSuccessContext DEFAULT = new PaperSuccessContext(null); + + public PaperSuccessContext placedBlockAt(final net.minecraft.core.BlockPos pos) { + return new PaperSuccessContext(pos); + } + } -+ public record Success(InteractionResult.SwingSource swingSource, InteractionResult.ItemContext itemContext, PaperSuccessContext paperSuccessContext) implements InteractionResult { ++ record Success(InteractionResult.SwingSource swingSource, InteractionResult.ItemContext itemContext, PaperSuccessContext paperSuccessContext) implements InteractionResult { + public InteractionResult.Success configurePaper(final java.util.function.UnaryOperator edit) { + return new InteractionResult.Success(this.swingSource, this.itemContext, edit.apply(this.paperSuccessContext)); + } @@ -21,7 +21,7 @@ + public Success(final InteractionResult.SwingSource swingSource, final InteractionResult.ItemContext itemContext) { + this(swingSource, itemContext, PaperSuccessContext.DEFAULT); + } -+ // Paper end - track more context in interaction result ++ // Paper end - track more context in interaction result @Override public boolean consumesAction() { return true; diff --git a/paper-server/patches/sources/net/minecraft/world/LockCode.java.patch b/paper-server/patches/sources/net/minecraft/world/LockCode.java.patch index 951cc1765580..fe3410c3f32e 100644 --- a/paper-server/patches/sources/net/minecraft/world/LockCode.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/LockCode.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/LockCode.java +++ b/net/minecraft/world/LockCode.java -@@ -23,8 +_,14 @@ +@@ -22,8 +_,14 @@ } } diff --git a/paper-server/patches/sources/net/minecraft/world/RandomizableContainer.java.patch b/paper-server/patches/sources/net/minecraft/world/RandomizableContainer.java.patch index 9cacb279dc3b..5de024776af7 100644 --- a/paper-server/patches/sources/net/minecraft/world/RandomizableContainer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/RandomizableContainer.java.patch @@ -20,19 +20,18 @@ } default boolean trySaveLootTable(final ValueOutput base) { -@@ -60,26 +_,42 @@ - return false; - } else { - base.store("LootTable", LootTable.KEY_CODEC, lootTable); -+ if (this.lootableData() != null) this.lootableData().saveNbt(base); // Paper - LootTable API - long lootTableSeed = this.getLootTableSeed(); - if (lootTableSeed != 0L) { - base.putLong("LootTableSeed", lootTableSeed); - } +@@ -61,25 +_,41 @@ + } -- return true; -+ return this.lootableData() == null; // Paper - only track the loot table if there is chance for replenish + base.store("LootTable", LootTable.KEY_CODEC, lootTable); ++ if (this.lootableData() != null) this.lootableData().saveNbt(base); // Paper - LootTable API + long lootTableSeed = this.getLootTableSeed(); + if (lootTableSeed != 0L) { + base.putLong("LootTableSeed", lootTableSeed); } + +- return true; ++ return this.lootableData() == null; // Paper - only track the loot table if there is chance for replenish } default void unpackLootTable(final @Nullable Player player) { diff --git a/paper-server/patches/sources/net/minecraft/world/effect/MobEffectInstance.java.patch b/paper-server/patches/sources/net/minecraft/world/effect/MobEffectInstance.java.patch index a037d0743c48..35a27d0e23c2 100644 --- a/paper-server/patches/sources/net/minecraft/world/effect/MobEffectInstance.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/effect/MobEffectInstance.java.patch @@ -1,13 +1,13 @@ --- a/net/minecraft/world/effect/MobEffectInstance.java +++ b/net/minecraft/world/effect/MobEffectInstance.java -@@ -227,6 +_,7 @@ - } else { - int tickCount = this.isInfiniteDuration() ? target.tickCount : this.duration; - if (this.effect.value().shouldApplyEffectTickThisTick(tickCount, this.amplifier) -+ && new io.papermc.paper.event.entity.EntityEffectTickEvent(target.getBukkitLivingEntity(), org.bukkit.craftbukkit.potion.CraftPotionEffectType.minecraftHolderToBukkit(this.effect), this.amplifier).callEvent() // Paper - Add EntityEffectTickEvent - && !this.effect.value().applyEffectTick(serverLevel, target, this.amplifier)) { - return false; - } else { +@@ -228,6 +_,7 @@ + + int tickCount = this.isInfiniteDuration() ? target.tickCount : this.duration; + if (this.effect.value().shouldApplyEffectTickThisTick(tickCount, this.amplifier) ++ && new io.papermc.paper.event.entity.EntityEffectTickEvent(target.getBukkitLivingEntity(), org.bukkit.craftbukkit.potion.CraftPotionEffectType.minecraftHolderToBukkit(this.effect), this.amplifier).callEvent() // Paper - Add EntityEffectTickEvent + && !this.effect.value().applyEffectTick(serverLevel, target, this.amplifier)) { + return false; + } @@ -262,13 +_,16 @@ } diff --git a/paper-server/patches/sources/net/minecraft/world/effect/WeavingMobEffect.java.patch b/paper-server/patches/sources/net/minecraft/world/effect/WeavingMobEffect.java.patch index 711b4be6fc30..5656eff4b856 100644 --- a/paper-server/patches/sources/net/minecraft/world/effect/WeavingMobEffect.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/effect/WeavingMobEffect.java.patch @@ -17,8 +17,8 @@ @@ -48,6 +_,7 @@ } - for (BlockPos blockPosx : positionsToTransform) { -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, blockPosx, Blocks.COBWEB.defaultBlockState())) continue; // Paper - Fire EntityChangeBlockEvent in more places - level.setBlock(blockPosx, Blocks.COBWEB.defaultBlockState(), Block.UPDATE_ALL); - level.levelEvent(LevelEvent.ANIMATION_SPAWN_COBWEB, blockPosx, 0); + for (BlockPos blockPos : positionsToTransform) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, blockPos, Blocks.COBWEB.defaultBlockState())) continue; // Paper - Fire EntityChangeBlockEvent in more places + level.setBlock(blockPos, Blocks.COBWEB.defaultBlockState(), Block.UPDATE_ALL); + level.levelEvent(LevelEvent.ANIMATION_SPAWN_COBWEB, blockPos, 0); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch index cfc2d384c698..9953d5da41d4 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/Entity.java.patch @@ -242,7 +242,7 @@ + // due to interactions on the client. + public void resendPossiblyDesyncedEntityData(ServerPlayer player) { + if (player.getBukkitEntity().canSee(this.getBukkitEntity())) { -+ ServerLevel level = (net.minecraft.server.level.ServerLevel) this.level(); ++ ServerLevel level = (ServerLevel) this.level(); + net.minecraft.server.level.ChunkMap.TrackedEntity tracker = level == null ? null : level.getChunkSource().chunkMap.entityMap.get(this.getId()); + if (tracker == null) { + return; @@ -572,25 +572,25 @@ BlockPos getOnPos = this.mainSupportingBlockPos.get(); if (!(offset > 1.0E-5F)) { return getOnPos; -@@ -1263,7 +_,7 @@ - if (insideBlock) { - try { - boolean isPrecise = movedFar || deflatedBoundingBoxAtTarget.intersects(blockIntersection); -- effectCollector.advanceStep(iteration); -+ effectCollector.advanceStep(iteration, blockIntersection); // Paper - track position inside effect was triggered on - state.entityInside(this.level(), blockIntersection, this, effectCollector, isPrecise); - this.onInsideBlock(state); - } catch (Throwable var20) { -@@ -1277,7 +_,7 @@ - } - - if (insideFluid) { +@@ -1266,7 +_,7 @@ + if (insideBlock) { + try { + boolean isPrecise = movedFar || deflatedBoundingBoxAtTarget.intersects(blockIntersection); - effectCollector.advanceStep(iteration); + effectCollector.advanceStep(iteration, blockIntersection); // Paper - track position inside effect was triggered on - state.getFluidState().entityInside(this.level(), blockIntersection, this, effectCollector); - } + state.entityInside(this.level(), blockIntersection, this, effectCollector, isPrecise); + this.onInsideBlock(state); + } catch (Throwable t) { +@@ -1280,7 +_,7 @@ + } + + if (insideFluid) { +- effectCollector.advanceStep(iteration); ++ effectCollector.advanceStep(iteration, blockIntersection); // Paper - track position inside effect was triggered on + state.getFluidState().entityInside(this.level(), blockIntersection, this, effectCollector); + } -@@ -1690,6 +_,7 @@ +@@ -1692,6 +_,7 @@ this.setXRot(Mth.clamp(xRot, -90.0F, 90.0F) % 360.0F); this.yRotO = this.getYRot(); this.xRotO = this.getXRot(); @@ -598,7 +598,7 @@ } public void absSnapTo(final double x, final double y, final double z) { -@@ -1699,6 +_,7 @@ +@@ -1701,6 +_,7 @@ this.yo = y; this.zo = cz; this.setPos(cx, y, cz); @@ -606,7 +606,7 @@ } public void snapTo(final Vec3 pos) { -@@ -1723,6 +_,7 @@ +@@ -1725,6 +_,7 @@ this.setXRot(xRot); this.setOldPosAndRot(); this.reapplyPosition(); @@ -614,7 +614,7 @@ } public final void setOldPosAndRot() { -@@ -1789,6 +_,7 @@ +@@ -1791,6 +_,7 @@ public void push(final Entity entity) { if (!this.isPassengerOfSameVehicle(entity)) { if (!entity.noPhysics && !this.noPhysics) { @@ -622,7 +622,7 @@ double xa = entity.getX() - this.getX(); double za = entity.getZ() - this.getZ(); double dd = Mth.absMax(xa, za); -@@ -1824,8 +_,24 @@ +@@ -1826,8 +_,24 @@ } public void push(final double xa, final double ya, final double za) { @@ -648,7 +648,7 @@ this.needsSync = true; } } -@@ -1932,8 +_,20 @@ +@@ -1934,8 +_,20 @@ } public boolean isPushable() { @@ -669,7 +669,7 @@ public void awardKillScore(final Entity victim, final DamageSource killingBlow) { if (victim instanceof ServerPlayer) { -@@ -1960,15 +_,23 @@ +@@ -1962,17 +_,25 @@ } public boolean saveAsPassenger(final ValueOutput output) { @@ -684,20 +684,22 @@ + // CraftBukkit end + if (this.removalReason != null && !this.removalReason.shouldSave() && !forceSerialization) { // Paper - Raw entity serialization API return false; - } else { -- String id = this.getEncodeId(); -- if (id == null) { -+ String id = this.getEncodeId(includeNonSaveable); // Paper - Raw entity serialization API -+ if ((!this.persist && !forceSerialization) || id == null) { // CraftBukkit - persist flag // Paper - Raw entity serialization API - return false; - } else { - output.putString("id", id); -- this.saveWithoutId(output); -+ this.saveWithoutId(output, includeAll, includeNonSaveable, forceSerialization); // CraftBukkit - pass on includeAll // Paper - Raw entity serialization API - return true; - } } -@@ -1979,14 +_,34 @@ + +- String id = this.getEncodeId(); +- if (id == null) { ++ String id = this.getEncodeId(includeNonSaveable); // Paper - Raw entity serialization API ++ if ((!this.persist && !forceSerialization) || id == null) { // CraftBukkit - persist flag // Paper - Raw entity serialization API + return false; + } + + output.putString("id", id); +- this.saveWithoutId(output); ++ this.saveWithoutId(output, includeAll, includeNonSaveable, forceSerialization); // CraftBukkit - pass on includeAll // Paper - Raw entity serialization API + return true; + } + +@@ -1981,14 +_,34 @@ } public void saveWithoutId(final ValueOutput output) { @@ -732,7 +734,7 @@ output.store("Rotation", Vec2.CODEC, new Vec2(this.getYRot(), this.getXRot())); output.putDouble("fall_distance", this.fallDistance); output.putShort("Fire", (short)this.remainingFireTicks); -@@ -1994,7 +_,29 @@ +@@ -1996,7 +_,29 @@ output.putBoolean("OnGround", this.onGround()); output.putBoolean("Invulnerable", this.invulnerable); output.putInt("PortalCooldown", this.portalCooldown); @@ -762,7 +764,7 @@ output.storeNullable("CustomName", ComponentSerialization.CODEC, this.getCustomName()); if (this.isCustomNameVisible()) { output.putBoolean("CustomNameVisible", this.isCustomNameVisible()); -@@ -2017,9 +_,14 @@ +@@ -2019,9 +_,14 @@ output.putInt("TicksFrozen", this.getTicksFrozen()); } @@ -780,7 +782,7 @@ if (!this.tags.isEmpty()) { output.store("Tags", TAG_LIST_CODEC, List.copyOf(this.tags)); -@@ -2029,13 +_,13 @@ +@@ -2031,13 +_,13 @@ output.store("data", CustomData.CODEC, this.customData); } @@ -796,11 +798,10 @@ passengersList.discardLast(); } } -@@ -2044,6 +_,34 @@ +@@ -2046,6 +_,33 @@ output.discard("Passengers"); } } -+ + // CraftBukkit start - stores eventually existing bukkit values + if (this.bukkitEntity != null) { + this.bukkitEntity.storeBukkitValues(output); @@ -828,10 +829,10 @@ + output.putBoolean("Paper.FreezeLock", true); + } + // Paper end - } catch (Throwable var7) { - CrashReport report = CrashReport.forThrowable(var7, "Saving entity NBT"); + } catch (Throwable t) { + CrashReport report = CrashReport.forThrowable(t, "Saving entity NBT"); CrashReportCategory category = report.addCategory("Entity being saved"); -@@ -2089,7 +_,20 @@ +@@ -2093,7 +_,20 @@ this.setNoGravity(input.getBooleanOr("NoGravity", false)); this.setGlowingTag(input.getBooleanOr("Glowing", false)); this.setTicksFrozen(input.getIntOr("TicksFrozen", 0)); @@ -853,11 +854,10 @@ this.customData = input.read("data", CustomData.CODEC).orElse(CustomData.EMPTY); this.tags.clear(); input.read("Tags", TAG_LIST_CODEC).ifPresent(this.tags::addAll); -@@ -2100,6 +_,59 @@ +@@ -2104,6 +_,58 @@ } else { throw new IllegalStateException("Entity has invalid rotation"); } -+ + // CraftBukkit start + // Spigot start + if (this instanceof net.minecraft.world.entity.LivingEntity) { @@ -910,10 +910,10 @@ + } + freezeLocked = input.getBooleanOr("Paper.FreezeLock", false); + // Paper end - } catch (Throwable var7) { - CrashReport report = CrashReport.forThrowable(var7, "Loading entity NBT"); + } catch (Throwable t) { + CrashReport report = CrashReport.forThrowable(t, "Loading entity NBT"); CrashReportCategory category = report.addCategory("Entity being loaded"); -@@ -2113,7 +_,13 @@ +@@ -2117,7 +_,13 @@ } public final @Nullable String getEncodeId() { @@ -926,9 +926,9 @@ + if (!includeNonSaveable && !this.getType().canSerialize()) { + // Paper end - Raw entity serialization API return null; - } else { - ResourceKey> typeId = this.typeHolder().unwrapKey().orElseThrow(() -> new IllegalStateException("Unregistered entity")); -@@ -2123,6 +_,12 @@ + } + +@@ -2127,6 +_,12 @@ protected abstract void readAdditionalSaveData(ValueInput input); @@ -941,7 +941,7 @@ protected abstract void addAdditionalSaveData(ValueOutput output); public @Nullable ItemEntity spawnAtLocation(final ServerLevel level, final ItemLike resource) { -@@ -2134,11 +_,59 @@ +@@ -2138,12 +_,57 @@ } public @Nullable ItemEntity spawnAtLocation(final ServerLevel level, final ItemStack itemStack, final Vec3 offset) { @@ -967,26 +967,26 @@ + // Paper end - Restore vanilla drops behavior if (itemStack.isEmpty()) { return null; - } else { -+ // CraftBukkit start - Capture drops for death event -+ if (this instanceof net.minecraft.world.entity.LivingEntity && !this.forceDrops) { -+ // Paper start - Restore vanilla drops behavior -+ ((net.minecraft.world.entity.LivingEntity)this).drops.add(new net.minecraft.world.entity.Entity.DefaultDrop(itemStack, dropStack -> { -+ ItemEntity dropEntity = new ItemEntity(this.level, this.getX() + offset.x, this.getY() + offset.y, this.getZ() + offset.z, dropStack); // stack is copied before consumer -+ dropEntity.setDefaultPickUpDelay(); -+ this.level.addFreshEntity(dropEntity); -+ if (delayedAddConsumer != null) delayedAddConsumer.accept(dropEntity); -+ })); -+ // Paper end - Restore vanilla drops behavior -+ return null; -+ } -+ // CraftBukkit end - ItemEntity entity = new ItemEntity(level, this.getX() + offset.x, this.getY() + offset.y, this.getZ() + offset.z, itemStack); -- entity.setDefaultPickUpDelay(); -+ entity.setDefaultPickUpDelay(); // Paper - diff on change (in dropConsumer) -+ // Paper start - Call EntityDropItemEvent -+ return this.spawnAtLocation(level, entity); + } +- ++ // CraftBukkit start - Capture drops for death event ++ if (!this.forceDrops && this instanceof LivingEntity livingEntity) { ++ // Paper start - Restore vanilla drops behavior ++ livingEntity.drops.add(new DefaultDrop(itemStack, dropStack -> { ++ ItemEntity dropEntity = new ItemEntity(this.level, this.getX() + offset.x, this.getY() + offset.y, this.getZ() + offset.z, dropStack); // stack is copied before consumer ++ dropEntity.setDefaultPickUpDelay(); ++ this.level.addFreshEntity(dropEntity); ++ if (delayedAddConsumer != null) delayedAddConsumer.accept(dropEntity); ++ })); ++ // Paper end - Restore vanilla drops behavior ++ return null; + } ++ // CraftBukkit end + ItemEntity entity = new ItemEntity(level, this.getX() + offset.x, this.getY() + offset.y, this.getZ() + offset.z, itemStack); +- entity.setDefaultPickUpDelay(); ++ entity.setDefaultPickUpDelay(); // Paper - diff on change (in dropConsumer) ++ // Paper start - Call EntityDropItemEvent ++ return this.spawnAtLocation(level, entity); + } + + public @Nullable ItemEntity spawnAtLocation(final ServerLevel level, final ItemEntity entity) { @@ -998,11 +998,10 @@ + return null; + } + // CraftBukkit end -+ { - level.addFreshEntity(entity); - return entity; - } -@@ -2183,6 +_,15 @@ + level.addFreshEntity(entity); + return entity; + } +@@ -2187,6 +_,15 @@ for (Leashable mob : mobsToLeash) { if (mob.canHaveALeashAttachedTo(this)) { @@ -1018,7 +1017,7 @@ mob.setLeashedTo(this, true); anyLeashed = true; } -@@ -2197,7 +_,7 @@ +@@ -2201,7 +_,7 @@ } ItemStack heldItem = player.getItemInHand(hand); @@ -1027,17 +1026,17 @@ heldItem.hurtAndBreak(1, player, hand); return InteractionResult.SUCCESS; } else if (this instanceof Mob target -@@ -2210,11 +_,13 @@ - if (this.isAlive() && this instanceof Leashable leashablex) { - if (leashablex.getLeashHolder() == player) { +@@ -2214,11 +_,13 @@ + if (this.isAlive() && this instanceof Leashable leashable) { + if (leashable.getLeashHolder() == player) { if (!this.level().isClientSide()) { - if (player.hasInfiniteMaterials()) { -- leashablex.removeLeash(); +- leashable.removeLeash(); - } else { -- leashablex.dropLeash(); +- leashable.dropLeash(); + // Paper start - EntityUnleashEvent + if (!org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerUnleashEntityEvent( -+ leashablex, player, hand, !player.hasInfiniteMaterials(), true ++ leashable, player, hand, !player.hasInfiniteMaterials(), true + )) { + return InteractionResult.PASS; } @@ -1045,31 +1044,31 @@ this.gameEvent(GameEvent.ENTITY_INTERACT, player); this.playSound(SoundEvents.LEAD_UNTIED); -@@ -2231,9 +_,22 @@ +@@ -2235,9 +_,22 @@ - if (leashablex.canHaveALeashAttachedTo(player)) { - if (leashablex.isLeashed()) { -- leashablex.dropLeash(); + if (leashable.canHaveALeashAttachedTo(player)) { + if (leashable.isLeashed()) { +- leashable.dropLeash(); + // Paper start - EntityUnleashEvent + if (!org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerUnleashEntityEvent( -+ leashablex, player, hand, true, true ++ leashable, player, hand, true, true + )) { + return InteractionResult.PASS; + } + // Paper end - EntityUnleashEvent -+ // leashablex.dropLeash(); // Paper - EntityUnleashEvent - moved into handlePlayerUnleashEntityEvent ++ // leashable.dropLeash(); // Paper - EntityUnleashEvent - moved into handlePlayerUnleashEntityEvent } + // Paper start - EntityLeashEvent + if (org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerLeashEntityEvent(this, player, player, hand).isCancelled()) { -+ ((ServerPlayer) player).connection.send(new net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket(this, leashablex.getLeashHolder())); ++ ((ServerPlayer) player).connection.send(new net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket(this, leashable.getLeashHolder())); + return InteractionResult.PASS; + } + // Paper end - EntityLeashEvent - leashablex.setLeashedTo(player, true); + leashable.setLeashedTo(player, true); this.playSound(SoundEvents.LEAD_TIED); itemStack.shrink(1); -@@ -2247,7 +_,13 @@ +@@ -2251,7 +_,13 @@ } public boolean shearOffAllLeashConnections(final @Nullable Player player) { @@ -1084,7 +1083,7 @@ if (dropped && this.level() instanceof ServerLevel serverLevel) { serverLevel.playSound(null, this.blockPosition(), SoundEvents.SHEARS_SNIP, player != null ? player.getSoundSource() : this.getSoundSource()); } -@@ -2256,15 +_,39 @@ +@@ -2260,15 +_,39 @@ } public boolean dropAllLeashConnections(final @Nullable Player player) { @@ -1128,7 +1127,7 @@ } if (dropped) { -@@ -2288,7 +_,9 @@ +@@ -2292,7 +_,9 @@ this.gameEvent(GameEvent.SHEAR, player); this.playSound(equippable.shearingSound().value()); if (this.level() instanceof ServerLevel serverLevel) { @@ -1138,37 +1137,31 @@ CriteriaTriggers.PLAYER_SHEARED_EQUIPMENT.trigger((ServerPlayer)player, itemStack, target); } -@@ -2356,11 +_,11 @@ +@@ -2360,7 +_,7 @@ } public boolean startRiding(final Entity entityToRide, final boolean force, final boolean sendEventAndTriggers) { - if (entityToRide == this.vehicle) { + if (entityToRide == this.vehicle || entityToRide.level != this.level) { // Paper - Ensure entity passenger world matches ridden entity (bad plugins) return false; - } else if (!entityToRide.couldAcceptPassenger()) { + } + +@@ -2368,7 +_,7 @@ return false; -- } else if (!this.level().isClientSide() && !entityToRide.type.canSerialize()) { -+ } else if (!force && !this.level().isClientSide() && !entityToRide.type.canSerialize()) { // SPIGOT-7947: Allow force riding all entities + } + +- if (!this.level().isClientSide() && !entityToRide.type.canSerialize()) { ++ if (!force && !this.level().isClientSide() && !entityToRide.type.canSerialize()) { // SPIGOT-7947: Allow force riding all entities return false; - } else { - for (Entity vehicleEntity = entityToRide; vehicleEntity.vehicle != null; vehicleEntity = vehicleEntity.vehicle) { -@@ -2370,6 +_,27 @@ - } + } - if (force || this.canRide(entityToRide) && entityToRide.canAddPassenger(this)) { -+ // CraftBukkit start -+ if (entityToRide.getBukkitEntity() instanceof org.bukkit.entity.Vehicle && this.getBukkitEntity() instanceof org.bukkit.entity.LivingEntity) { -+ org.bukkit.event.vehicle.VehicleEnterEvent event = new org.bukkit.event.vehicle.VehicleEnterEvent((org.bukkit.entity.Vehicle) entityToRide.getBukkitEntity(), this.getBukkitEntity()); -+ // Suppress during worldgen -+ if (this.valid) { -+ org.bukkit.Bukkit.getPluginManager().callEvent(event); -+ } -+ if (event.isCancelled()) { -+ return false; -+ } -+ } -+ -+ org.bukkit.event.entity.EntityMountEvent event = new org.bukkit.event.entity.EntityMountEvent(this.getBukkitEntity(), entityToRide.getBukkitEntity()); +@@ -2379,6 +_,27 @@ + } + + if (force || this.canRide(entityToRide) && entityToRide.canAddPassenger(this)) { ++ // CraftBukkit start ++ if (entityToRide.getBukkitEntity() instanceof org.bukkit.entity.Vehicle && this.getBukkitEntity() instanceof org.bukkit.entity.LivingEntity) { ++ org.bukkit.event.vehicle.VehicleEnterEvent event = new org.bukkit.event.vehicle.VehicleEnterEvent((org.bukkit.entity.Vehicle) entityToRide.getBukkitEntity(), this.getBukkitEntity()); + // Suppress during worldgen + if (this.valid) { + org.bukkit.Bukkit.getPluginManager().callEvent(event); @@ -1176,11 +1169,21 @@ + if (event.isCancelled()) { + return false; + } -+ // CraftBukkit end - if (this.isPassenger()) { - this.stopRiding(); - } -@@ -2402,10 +_,16 @@ ++ } ++ ++ org.bukkit.event.entity.EntityMountEvent event = new org.bukkit.event.entity.EntityMountEvent(this.getBukkitEntity(), entityToRide.getBukkitEntity()); ++ // Suppress during worldgen ++ if (this.valid) { ++ org.bukkit.Bukkit.getPluginManager().callEvent(event); ++ } ++ if (event.isCancelled()) { ++ return false; ++ } ++ // CraftBukkit end + if (this.isPassenger()) { + this.stopRiding(); + } +@@ -2410,10 +_,16 @@ } public void removeVehicle() { @@ -1198,7 +1201,7 @@ Entity.RemovalReason removalReason = this.getRemovalReason(); if (removalReason == null || removalReason.shouldDestroy()) { this.level().gameEvent(this, GameEvent.ENTITY_DISMOUNT, oldVehicle.position); -@@ -2414,7 +_,13 @@ +@@ -2422,7 +_,13 @@ } public void stopRiding() { @@ -1213,7 +1216,7 @@ } protected void addPassenger(final Entity passenger) { -@@ -2436,10 +_,44 @@ +@@ -2444,11 +_,44 @@ } } @@ -1227,47 +1230,47 @@ + // Paper end - Force entity dismount during teleportation if (passenger.getVehicle() == this) { throw new IllegalStateException("Use x.stopRiding(y), not y.removePassenger(x)"); - } else { -+ // CraftBukkit start -+ org.bukkit.craftbukkit.entity.CraftEntity craft = (org.bukkit.craftbukkit.entity.CraftEntity) passenger.getBukkitEntity().getVehicle(); -+ Entity orig = craft == null ? null : craft.getHandle(); -+ if (this.getBukkitEntity() instanceof org.bukkit.entity.Vehicle && passenger.getBukkitEntity() instanceof org.bukkit.entity.LivingEntity) { -+ org.bukkit.event.vehicle.VehicleExitEvent event = new org.bukkit.event.vehicle.VehicleExitEvent( -+ (org.bukkit.entity.Vehicle) this.getBukkitEntity(), -+ (org.bukkit.entity.LivingEntity) passenger.getBukkitEntity(), !suppressCancellation // Paper - Force entity dismount during teleportation -+ ); -+ // Suppress during worldgen -+ if (this.valid) { -+ org.bukkit.Bukkit.getPluginManager().callEvent(event); -+ } -+ org.bukkit.craftbukkit.entity.CraftEntity craftn = (org.bukkit.craftbukkit.entity.CraftEntity) passenger.getBukkitEntity().getVehicle(); -+ Entity n = craftn == null ? null : craftn.getHandle(); -+ if (event.isCancelled() || n != orig) { -+ return false; -+ } -+ } -+ -+ org.bukkit.event.entity.EntityDismountEvent event = new org.bukkit.event.entity.EntityDismountEvent(passenger.getBukkitEntity(), this.getBukkitEntity(), !suppressCancellation); // Paper - Force entity dismount during teleportation + } ++ // CraftBukkit start ++ org.bukkit.craftbukkit.entity.CraftEntity craft = (org.bukkit.craftbukkit.entity.CraftEntity) passenger.getBukkitEntity().getVehicle(); ++ Entity orig = craft == null ? null : craft.getHandle(); ++ if (this.getBukkitEntity() instanceof org.bukkit.entity.Vehicle && passenger.getBukkitEntity() instanceof org.bukkit.entity.LivingEntity) { ++ org.bukkit.event.vehicle.VehicleExitEvent event = new org.bukkit.event.vehicle.VehicleExitEvent( ++ (org.bukkit.entity.Vehicle) this.getBukkitEntity(), ++ (org.bukkit.entity.LivingEntity) passenger.getBukkitEntity(), !suppressCancellation // Paper - Force entity dismount during teleportation ++ ); + // Suppress during worldgen + if (this.valid) { + org.bukkit.Bukkit.getPluginManager().callEvent(event); + } -+ if (event.isCancelled()) { ++ org.bukkit.craftbukkit.entity.CraftEntity craftn = (org.bukkit.craftbukkit.entity.CraftEntity) passenger.getBukkitEntity().getVehicle(); ++ Entity n = craftn == null ? null : craftn.getHandle(); ++ if (event.isCancelled() || n != orig) { + return false; + } -+ // CraftBukkit end - if (this.passengers.size() == 1 && this.passengers.get(0) == passenger) { - this.passengers = ImmutableList.of(); - } else { -@@ -2448,6 +_,7 @@ ++ } - passenger.boardingCooldown = 60; ++ org.bukkit.event.entity.EntityDismountEvent event = new org.bukkit.event.entity.EntityDismountEvent(passenger.getBukkitEntity(), this.getBukkitEntity(), !suppressCancellation); // Paper - Force entity dismount during teleportation ++ // Suppress during worldgen ++ if (this.valid) { ++ org.bukkit.Bukkit.getPluginManager().callEvent(event); ++ } ++ if (event.isCancelled()) { ++ return false; ++ } ++ // CraftBukkit end + if (this.passengers.size() == 1 && this.passengers.get(0) == passenger) { + this.passengers = ImmutableList.of(); + } else { +@@ -2456,6 +_,7 @@ } + + passenger.boardingCooldown = 60; + return true; // CraftBukkit } protected boolean canAddPassenger(final Entity passenger) { -@@ -2630,7 +_,7 @@ +@@ -2638,7 +_,7 @@ } public boolean isCrouching() { @@ -1276,7 +1279,7 @@ } public boolean isSprinting() { -@@ -2646,7 +_,7 @@ +@@ -2654,7 +_,7 @@ } public boolean isVisuallySwimming() { @@ -1285,7 +1288,7 @@ } public boolean isVisuallyCrawling() { -@@ -2654,6 +_,13 @@ +@@ -2662,6 +_,13 @@ } public void setSwimming(final boolean swimming) { @@ -1299,7 +1302,7 @@ this.setSharedFlag(FLAG_SWIMMING, swimming); } -@@ -2691,6 +_,7 @@ +@@ -2699,6 +_,7 @@ } public @Nullable PlayerTeam getTeam() { @@ -1307,7 +1310,7 @@ return this.level().getScoreboard().getPlayersTeam(this.getScoreboardName()); } -@@ -2707,7 +_,11 @@ +@@ -2715,7 +_,11 @@ } public void setInvisible(final boolean invisible) { @@ -1320,7 +1323,7 @@ } public boolean getSharedFlag(@Entity.Flags final int flag) { -@@ -2724,7 +_,7 @@ +@@ -2732,7 +_,7 @@ } public int getMaxAirSupply() { @@ -1329,7 +1332,7 @@ } public int getAirSupply() { -@@ -2732,10 +_,24 @@ +@@ -2740,10 +_,24 @@ } public void setAirSupply(final int supply) { @@ -1355,7 +1358,7 @@ this.setTicksFrozen(0); } -@@ -2762,11 +_,42 @@ +@@ -2770,11 +_,42 @@ public void thunderHit(final ServerLevel level, final LightningBolt lightningBolt) { this.setRemainingFireTicks(this.remainingFireTicks + 1); @@ -1402,7 +1405,7 @@ } public void onAboveBubbleColumn(final boolean dragDown, final BlockPos pos) { -@@ -2916,26 +_,30 @@ +@@ -2924,26 +_,30 @@ return this.removalReason != null ? String.format( Locale.ROOT, @@ -1436,7 +1439,7 @@ ); } -@@ -2959,6 +_,13 @@ +@@ -2967,6 +_,13 @@ } public void restoreFrom(final Entity oldEntity) { @@ -1450,7 +1453,7 @@ try (ProblemReporter.ScopedCollector reporter = new ProblemReporter.ScopedCollector(this.problemPath(), LOGGER)) { TagValueOutput entityData = TagValueOutput.createWithContext(reporter, oldEntity.registryAccess()); oldEntity.saveWithoutId(entityData); -@@ -2969,8 +_,66 @@ +@@ -2977,8 +_,66 @@ this.portalProcess = oldEntity.portalProcess; } @@ -1518,24 +1521,24 @@ ServerLevel newLevel = transition.newLevel(); boolean otherDimension = newLevel.dimension() != serverLevel.dimension(); if (!transition.asPassenger()) { -@@ -3019,10 +_,15 @@ - profiler.pop(); +@@ -3028,10 +_,15 @@ return null; - } else { -+ // Paper start - Fix item duplication and teleport issues -+ if (this instanceof Leashable leashable) { -+ leashable.dropLeash(); // Paper drop lead -+ } -+ // Paper end - Fix item duplication and teleport issues - newEntity.restoreFrom(this); - this.removeAfterChangingDimensions(); - newEntity.teleportSetPosition(PositionMoveRotation.of(this), PositionMoveRotation.of(transition), transition.relatives()); -- newLevel.addDuringTeleport(newEntity); -+ if (this.inWorld) newLevel.addDuringTeleport(newEntity); // CraftBukkit - Don't spawn the new entity if the current entity isn't spawned + } + ++ // Paper start - Fix item duplication and teleport issues ++ if (this instanceof Leashable leashable) { ++ leashable.dropLeash(); // Paper drop lead ++ } ++ // Paper end - Fix item duplication and teleport issues + newEntity.restoreFrom(this); + this.removeAfterChangingDimensions(); + newEntity.teleportSetPosition(PositionMoveRotation.of(this), PositionMoveRotation.of(transition), transition.relatives()); +- newLevel.addDuringTeleport(newEntity); ++ if (this.inWorld) newLevel.addDuringTeleport(newEntity); // CraftBukkit - Don't spawn the new entity if the current entity isn't spawned - for (Entity newPassenger : newPassengers) { - newPassenger.startRiding(newEntity, true, false); -@@ -3109,9 +_,17 @@ + for (Entity newPassenger : newPassengers) { + newPassenger.startRiding(newEntity, true, false); +@@ -3117,9 +_,17 @@ } protected void removeAfterChangingDimensions() { @@ -1556,7 +1559,7 @@ } if (this instanceof WaypointTransmitter waypoint && this.level instanceof ServerLevel serverLevel) { -@@ -3128,6 +_,7 @@ +@@ -3136,6 +_,7 @@ } public boolean canTeleport(final Level from, final Level to) { @@ -1564,7 +1567,7 @@ if (from.dimension() == Level.END && to.dimension() == Level.OVERWORLD) { for (Entity passenger : this.getPassengers()) { if (passenger instanceof ServerPlayer player && !player.seenCredits) { -@@ -3246,7 +_,7 @@ +@@ -3254,7 +_,7 @@ } } @@ -1573,7 +1576,7 @@ final ServerLevel level, final double x, final double y, -@@ -3256,14 +_,30 @@ +@@ -3264,14 +_,30 @@ final float newXRot, final boolean resetCamera ) { @@ -1606,7 +1609,7 @@ } public void teleportTo(final double x, final double y, final double z) { -@@ -3374,7 +_,26 @@ +@@ -3382,7 +_,26 @@ } public final void setBoundingBox(final AABB bb) { @@ -1634,7 +1637,7 @@ } public final float getEyeHeight(final Pose pose) { -@@ -3398,6 +_,12 @@ +@@ -3406,6 +_,12 @@ } public void stopSeenByPlayer(final ServerPlayer player) { @@ -1647,7 +1650,7 @@ } public float rotate(final Rotation rotation) { -@@ -3456,21 +_,32 @@ +@@ -3464,21 +_,32 @@ } private Stream getIndirectPassengersStream() { @@ -1681,7 +1684,7 @@ } public int countPlayerPassengers() { -@@ -3478,6 +_,7 @@ +@@ -3486,6 +_,7 @@ } public boolean hasExactlyOnePlayerPassenger() { @@ -1689,7 +1692,7 @@ return this.countPlayerPassengers() == 1; } -@@ -3558,9 +_,38 @@ +@@ -3566,9 +_,38 @@ return 0; } @@ -1729,7 +1732,7 @@ this.position(), this.getRotationVector(), level, -@@ -3658,7 +_,9 @@ +@@ -3666,7 +_,9 @@ public void setDeltaMovement(final Vec3 deltaMovement) { if (deltaMovement.isFinite()) { @@ -1739,7 +1742,7 @@ } } -@@ -3729,8 +_,34 @@ +@@ -3737,8 +_,34 @@ } public final void setPosRaw(final double x, final double y, final double z) { @@ -1774,7 +1777,7 @@ int fx = Mth.floor(x); int fy = Mth.floor(y); int fz = Mth.floor(z); -@@ -3752,7 +_,18 @@ +@@ -3760,7 +_,18 @@ serverLevel.getWaypointManager().updatePlayer(player); } } @@ -1794,7 +1797,7 @@ } public void checkDespawn() { -@@ -3804,6 +_,12 @@ +@@ -3812,6 +_,12 @@ return this.getTicksFrozen() > 0; } @@ -1807,7 +1810,7 @@ public float getYRot() { return this.yRot; } -@@ -3854,7 +_,9 @@ +@@ -3862,7 +_,9 @@ } @Override @@ -1818,7 +1821,7 @@ if (this.removalReason == null) { this.removalReason = reason; } -@@ -3866,12 +_,28 @@ +@@ -3874,12 +_,28 @@ this.getPassengers().forEach(Entity::stopRiding); this.levelCallback.onRemove(reason); this.onRemoval(reason); @@ -1847,7 +1850,7 @@ @Override public void setLevelCallback(final EntityInLevelCallback levelCallback) { this.levelCallback = levelCallback; -@@ -4093,4 +_,14 @@ +@@ -4101,4 +_,14 @@ return this.save; } } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/EntitySelector.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/EntitySelector.java.patch index 7cd390264779..25036bc72c6f 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/EntitySelector.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/EntitySelector.java.patch @@ -23,18 +23,20 @@ private EntitySelector() { } -@@ -33,12 +_,12 @@ +@@ -33,14 +_,14 @@ ? Predicates.alwaysFalse() : NO_SPECTATORS.and( input -> { - if (!input.isPushable()) { + if (!input.isPushable() || !input.canCollideWithBukkit(entity) || !entity.canCollideWithBukkit(input)) { // CraftBukkit - collidable API // Paper - Climbing should not bypass cramming gamerule return false; - } else if (!entity.level().isClientSide() || input instanceof Player player && player.isLocalPlayer()) { + } + + if (!entity.level().isClientSide() || input instanceof Player player && player.isLocalPlayer()) { Team theirTeam = input.getTeam(); Team.CollisionRule theirCollisionRule = theirTeam == null ? Team.CollisionRule.ALWAYS : theirTeam.getCollisionRule(); - if (theirCollisionRule == Team.CollisionRule.NEVER) { + if (theirCollisionRule == Team.CollisionRule.NEVER || (input instanceof Player && !io.papermc.paper.configuration.GlobalConfiguration.get().collisions.enablePlayerCollisions)) { // Paper - Configurable player collision return false; - } else { - boolean sameTeam = ownTeam != null && ownTeam.isAlliedTo(theirTeam); + } + diff --git a/paper-server/patches/sources/net/minecraft/world/entity/EntityType.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/EntityType.java.patch index 849af41b4e84..e6b3913dced5 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/EntityType.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/EntityType.java.patch @@ -159,7 +159,7 @@ ); } -@@ -1616,8 +_,23 @@ +@@ -1610,8 +_,23 @@ return this.builtInRegistryHolder; } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ExperienceOrb.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ExperienceOrb.java.patch index c63e98f57f82..dfeb863c74a4 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ExperienceOrb.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ExperienceOrb.java.patch @@ -148,15 +148,15 @@ } private void setUnderwaterMovement() { -@@ -250,7 +_,7 @@ - this.markHurt(); - this.health = (int)(this.health - damage); - if (this.health <= 0) { -- this.discard(); -+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause - } +@@ -251,7 +_,7 @@ + this.markHurt(); + this.health = (int)(this.health - damage); + if (this.health <= 0) { +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause + } - return true; + return true; @@ -261,32 +_,34 @@ protected void addAdditionalSaveData(final ValueOutput output) { output.putShort("Health", (short)this.health); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/InsideBlockEffectApplier.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/InsideBlockEffectApplier.java.patch index d459738f55c7..ff81da3f9853 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/InsideBlockEffectApplier.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/InsideBlockEffectApplier.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/entity/InsideBlockEffectApplier.java +++ b/net/minecraft/world/entity/InsideBlockEffectApplier.java @@ -32,7 +_,7 @@ - public static class StepBasedCollector implements InsideBlockEffectApplier { + class StepBasedCollector implements InsideBlockEffectApplier { private static final InsideBlockEffectType[] APPLY_ORDER = InsideBlockEffectType.values(); private static final int NO_STEP = -1; - private final Set effectsInStep = EnumSet.noneOf(InsideBlockEffectType.class); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/InsideBlockEffectType.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/InsideBlockEffectType.java.patch index 1666a8003cf8..3090807a9501 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/InsideBlockEffectType.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/InsideBlockEffectType.java.patch @@ -18,11 +18,11 @@ - private final Consumer effect; + private final Applier effect; // Paper - track position inside effect was triggered on - private InsideBlockEffectType(final Consumer effect) { + InsideBlockEffectType(final Consumer effect) { + // Paper start - track position inside effect was triggered on + this((entity, block) -> effect.accept(entity)); + } -+ private InsideBlockEffectType(final Applier effect) { ++ InsideBlockEffectType(final Applier effect) { + // Paper end - track position inside effect was triggered on this.effect = effect; } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch index e6413834b5a7..4fa53fc2e934 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch @@ -140,40 +140,40 @@ + // Paper end - Extend dropItem API if (itemStack.isEmpty()) { return null; - } else if (this.level().isClientSide()) { -@@ -764,6 +_,31 @@ - } else { - ItemEntity entity = this.createItemStackToDrop(itemStack, randomly, thrownFromHand); - if (entity != null) { -+ // CraftBukkit start - fire PlayerDropItemEvent -+ if (entityOperation != null) entityOperation.accept((org.bukkit.entity.Item) entity.getBukkitEntity()); -+ if (callEvent && this.getBukkitEntity() instanceof org.bukkit.entity.Player player) { -+ org.bukkit.entity.Item drop = (org.bukkit.entity.Item) entity.getBukkitEntity(); -+ -+ org.bukkit.event.player.PlayerDropItemEvent event = new org.bukkit.event.player.PlayerDropItemEvent(player, drop); -+ this.level().getCraftServer().getPluginManager().callEvent(event); -+ -+ if (event.isCancelled()) { -+ org.bukkit.inventory.ItemStack inHandItem = player.getInventory().getItemInMainHand(); -+ if (thrownFromHand && inHandItem.getAmount() == 0) { -+ // The complete stack was dropped -+ player.getInventory().setItemInMainHand(drop.getItemStack()); -+ } else if (thrownFromHand && inHandItem.isSimilar(drop.getItemStack()) && inHandItem.getAmount() < inHandItem.getMaxStackSize() && drop.getItemStack().getAmount() == 1) { -+ // Only one item is dropped -+ inHandItem.setAmount(inHandItem.getAmount() + 1); -+ player.getInventory().setItemInMainHand(inHandItem); -+ } else { -+ // Fallback -+ player.getInventory().addItem(drop.getItemStack()); -+ } -+ return null; + } +@@ -767,6 +_,31 @@ + + ItemEntity entity = this.createItemStackToDrop(itemStack, randomly, thrownFromHand); + if (entity != null) { ++ // CraftBukkit start - fire PlayerDropItemEvent ++ if (entityOperation != null) entityOperation.accept((org.bukkit.entity.Item) entity.getBukkitEntity()); ++ if (callEvent && this.getBukkitEntity() instanceof org.bukkit.entity.Player player) { ++ org.bukkit.entity.Item drop = (org.bukkit.entity.Item) entity.getBukkitEntity(); ++ ++ org.bukkit.event.player.PlayerDropItemEvent event = new org.bukkit.event.player.PlayerDropItemEvent(player, drop); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ org.bukkit.inventory.ItemStack inHandItem = player.getInventory().getItemInMainHand(); ++ if (thrownFromHand && inHandItem.getAmount() == 0) { ++ // The complete stack was dropped ++ player.getInventory().setItemInMainHand(drop.getItemStack()); ++ } else if (thrownFromHand && inHandItem.isSimilar(drop.getItemStack()) && inHandItem.getAmount() < inHandItem.getMaxStackSize() && drop.getItemStack().getAmount() == 1) { ++ // Only one item is dropped ++ inHandItem.setAmount(inHandItem.getAmount() + 1); ++ player.getInventory().setItemInMainHand(inHandItem); ++ } else { ++ // Fallback ++ player.getInventory().addItem(drop.getItemStack()); + } ++ return null; + } -+ // CraftBukkit end - this.level().addFreshEntity(entity); - } ++ } ++ // CraftBukkit end + this.level().addFreshEntity(entity); + } -@@ -773,7 +_,22 @@ +@@ -775,7 +_,22 @@ @Override protected void readAdditionalSaveData(final ValueInput input) { @@ -197,7 +197,7 @@ if (this.level() != null && !this.level().isClientSide()) { input.read("attributes", AttributeInstance.Packed.LIST_CODEC).ifPresent(this.getAttributes()::apply); } -@@ -786,6 +_,11 @@ +@@ -788,6 +_,11 @@ this.effectsDirty = true; } @@ -209,7 +209,7 @@ this.setHealth(input.getFloatOr("Health", this.getMaxHealth())); this.hurtTime = input.getShortOr("HurtTime", (short)0); this.deathTime = input.getShortOr("DeathTime", (short)0); -@@ -793,6 +_,7 @@ +@@ -795,6 +_,7 @@ input.getString("Team").ifPresent(teamName -> { Scoreboard scoreboard = this.level().getScoreboard(); PlayerTeam team = scoreboard.getPlayerTeam(teamName); @@ -217,7 +217,7 @@ boolean success = team != null && scoreboard.addPlayerToTeam(this.getStringUUID(), team); if (!success) { LOGGER.warn("Unable to add mob to team \"{}\" (that team probably doesn't exist)", teamName); -@@ -800,11 +_,13 @@ +@@ -802,11 +_,13 @@ }); this.setSharedFlag(Entity.FLAG_FALL_FLYING, input.getBooleanOr("FallFlying", false)); input.read("sleeping_pos", BlockPos.CODEC).ifPresentOrElse(sleepingPos -> { @@ -231,7 +231,7 @@ }, this::clearSleepingPos); input.read("Brain", Brain.Packed.CODEC).ifPresent(packedBrain -> this.brain = this.makeBrain(packedBrain)); this.lastHurtByPlayer = EntityReference.read(input, "last_hurt_by_player"); -@@ -823,15 +_,44 @@ +@@ -825,15 +_,44 @@ this.updateDirtyEffects(); } @@ -276,7 +276,7 @@ iterator.remove(); this.onEffectsRemoved(List.of(effect)); } else if (effect.getDuration() % 600 == 0) { -@@ -840,6 +_,18 @@ +@@ -842,6 +_,18 @@ } } catch (ConcurrentModificationException var6) { } @@ -295,7 +295,7 @@ } else { for (MobEffectInstance effect : this.activeEffects.values()) { effect.tickClient(); -@@ -950,15 +_,33 @@ +@@ -952,6 +_,11 @@ } public boolean removeAllEffects() { @@ -306,34 +306,36 @@ + // CraftBukkit end if (this.level().isClientSide()) { return false; - } else if (this.activeEffects.isEmpty()) { + } +@@ -960,10 +_,23 @@ return false; - } else { -- Map, MobEffectInstance> copy = Maps.newHashMap(this.activeEffects); -- this.activeEffects.clear(); -- this.onEffectsRemoved(copy.values()); -- return true; -+ // CraftBukkit start -+ List toRemove = new java.util.LinkedList<>(); -+ Iterator iterator = this.activeEffects.values().iterator(); -+ while (iterator.hasNext()) { -+ MobEffectInstance effect = iterator.next(); -+ EntityPotionEffectEvent event = CraftEventFactory.callEntityPotionEffectChangeEvent(this, effect, null, cause, EntityPotionEffectEvent.Action.CLEARED); -+ if (event.isCancelled()) { -+ continue; -+ } -+ -+ iterator.remove(); -+ toRemove.add(effect); + } + +- Map, MobEffectInstance> copy = Maps.newHashMap(this.activeEffects); +- this.activeEffects.clear(); +- this.onEffectsRemoved(copy.values()); +- return true; ++ // CraftBukkit start ++ List toRemove = new java.util.LinkedList<>(); ++ Iterator iterator = this.activeEffects.values().iterator(); ++ while (iterator.hasNext()) { ++ MobEffectInstance effect = iterator.next(); ++ EntityPotionEffectEvent event = CraftEventFactory.callEntityPotionEffectChangeEvent(this, effect, null, cause, EntityPotionEffectEvent.Action.CLEARED); ++ if (event.isCancelled()) { ++ continue; + } + -+ this.onEffectsRemoved(toRemove); -+ return !toRemove.isEmpty(); -+ // CraftBukkit end - } ++ iterator.remove(); ++ toRemove.add(effect); ++ } ++ ++ this.onEffectsRemoved(toRemove); ++ return !toRemove.isEmpty(); ++ // CraftBukkit end } -@@ -984,23 +_,71 @@ + public Collection getActiveEffects() { +@@ -988,24 +_,69 @@ } public final boolean addEffect(final MobEffectInstance newEffect) { @@ -364,50 +366,48 @@ + // CraftBukkit end if (!this.canBeAffected(newEffect)) { return false; - } else { - MobEffectInstance effect = this.activeEffects.get(newEffect.getEffect()); - boolean changed = false; -+ // CraftBukkit start -+ boolean override = false; -+ // Paper start - Properly update hidden effects -+ boolean addAsHiddenEffect = false; -+ if (effect != null) { -+ override = new MobEffectInstance(effect).update(newEffect); -+ addAsHiddenEffect = effect.getAmplifier() > newEffect.getAmplifier() && effect.isShorterDurationThan(newEffect); -+ // Paper end - Properly update hidden effects -+ } + } + + MobEffectInstance effect = this.activeEffects.get(newEffect.getEffect()); + boolean changed = false; ++ // Paper start ++ boolean override = false; ++ boolean addAsHiddenEffect = false; ++ if (effect != null) { ++ override = new MobEffectInstance(effect).update(newEffect); ++ addAsHiddenEffect = effect.getAmplifier() > newEffect.getAmplifier() && effect.isShorterDurationThan(newEffect); ++ } + -+ if (fireEvent) { // Paper - Don't fire sync event during generation ++ if (fireEvent) { + EntityPotionEffectEvent event = CraftEventFactory.callEntityPotionEffectChangeEvent(this, effect, newEffect, cause, override); -+ override = event.isOverride(); // Paper - Don't fire sync event during generation ++ override = event.isOverride(); + if (event.isCancelled()) { + return false; + } -+ } // Paper - Don't fire sync event during generation -+ // CraftBukkit end - if (effect == null) { - this.activeEffects.put(newEffect.getEffect(), newEffect); - this.onEffectAdded(newEffect, source); - changed = true; - newEffect.onEffectAdded(this); -- } else if (effect.update(newEffect)) { -+ // CraftBukkit start -+ } else if (override) { // Paper - Don't fire sync event during generation -+ effect.update(newEffect); - this.onEffectUpdated(effect, true, source); - changed = true; -+ // Paper start - Properly update hidden effects -+ } else if (addAsHiddenEffect) { -+ if (effect.hiddenEffect == null) { -+ effect.hiddenEffect = new MobEffectInstance(newEffect); -+ } else { -+ effect.hiddenEffect.update(newEffect); -+ } -+ // Paper end - Properly update hidden effects - } ++ } ++ // Paper end + if (effect == null) { + this.activeEffects.put(newEffect.getEffect(), newEffect); + this.onEffectAdded(newEffect, source); + changed = true; + newEffect.onEffectAdded(this); +- } else if (effect.update(newEffect)) { ++ } else if (override) { // Paper - Don't fire sync event during generation ++ effect.update(newEffect); // Paper + this.onEffectUpdated(effect, true, source); + changed = true; ++ // Paper start - Properly update hidden effects ++ } else if (addAsHiddenEffect) { ++ if (effect.hiddenEffect == null) { ++ effect.hiddenEffect = new MobEffectInstance(newEffect); ++ } else { ++ effect.hiddenEffect.update(newEffect); ++ } ++ // Paper end - Properly update hidden effects + } - newEffect.onEffectStarted(this); -@@ -1035,11 +_,35 @@ + newEffect.onEffectStarted(this); +@@ -1039,11 +_,35 @@ } public final @Nullable MobEffectInstance removeEffectNoUpdate(final Holder effect) { @@ -444,7 +444,7 @@ if (effectInstance != null) { this.onEffectsRemoved(List.of(effectInstance)); return true; -@@ -1130,17 +_,62 @@ +@@ -1134,17 +_,62 @@ } public void heal(final float heal) { @@ -509,135 +509,134 @@ this.entityData.set(DATA_HEALTH_ID, Mth.clamp(health, 0.0F, this.getMaxHealth())); } -@@ -1152,7 +_,7 @@ - public boolean hurtServer(final ServerLevel level, final DamageSource source, float damage) { - if (this.isInvulnerableTo(level, source)) { +@@ -1158,7 +_,7 @@ return false; -- } else if (this.isDeadOrDying()) { -+ } else if (this.isRemoved() || this.dead || this.getHealth() <= 0.0F) { // CraftBukkit - Don't allow entities that got set to dead/killed elsewhere to get damaged and die - return false; - } else if (source.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) { + } + +- if (this.isDeadOrDying()) { ++ if (this.isRemoved() || this.dead || this.getHealth() <= 0.0F) { // CraftBukkit - Don't allow entities that got set to dead/killed elsewhere to get damaged and die return false; -@@ -1168,35 +_,58 @@ - - ItemStack itemInUse = this.getUseItem(); - float originalDamage = damage; -- float damageBlocked = this.applyItemBlocking(level, source, damage); -- damage -= damageBlocked; -+ float damageBlocked = this.applyItemBlocking(level, source, damage, true); // Paper -+ // damage -= damageBlocked; // CraftBukkit - Moved into handleEntityDamage(DamageSource, float) to allow modification - boolean blocked = damageBlocked > 0.0F; -- if (source.is(DamageTypeTags.IS_FREEZING) && this.is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES)) { -+ // CraftBukkit - Moved into handleEntityDamage(DamageSource, float) to get amount -+ if (false && source.is(DamageTypeTags.IS_FREEZING) && this.is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES)) { - damage *= 5.0F; + } + +@@ -1177,14 +_,16 @@ + + float originalDamage = damage; + ItemStack itemInUse = this.getUseItem(); +- float damageBlocked = this.applyItemBlocking(level, source, damage); +- damage -= damageBlocked; ++ float damageBlocked = this.applyItemBlocking(level, source, damage, true); // Paper ++ // damage -= damageBlocked; // CraftBukkit - Moved into handleEntityDamage(DamageSource, float) to allow modification + boolean blocked = damageBlocked > 0.0F; +- if (source.is(DamageTypeTags.IS_FREEZING) && this.is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES)) { ++ // CraftBukkit - Moved into handleEntityDamage(DamageSource, float) to get amount ++ if (false && source.is(DamageTypeTags.IS_FREEZING) && this.is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES)) { + damage *= 5.0F; + } + +- if (source.is(DamageTypeTags.DAMAGES_HELMET) && !this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { ++ // CraftBukkit - Moved into handleEntityDamage(DamageSource, float) to get amount and actuallyHurt(DamageSource, float, EntityDamageEvent) for handle damage ++ if (false && source.is(DamageTypeTags.DAMAGES_HELMET) && !this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { + this.hurtHelmet(source, damage); + damage *= 0.75F; + } +@@ -1193,19 +_,40 @@ + damage = Float.MAX_VALUE; + } + ++ EntityDamageEvent event; // CraftBukkit // Paper - move this into the actual invuln check.... + boolean tookFullDamage = true; +- if (this.invulnerableTime > 10.0F && !source.is(DamageTypeTags.BYPASSES_COOLDOWN)) { ++ if (this.invulnerableTime > (float)this.invulnerableDuration / 2.0F && !source.is(DamageTypeTags.BYPASSES_COOLDOWN)) { // CraftBukkit - restore use of maxNoDamageTicks + if (damage <= this.lastHurt) { + return false; } -- if (source.is(DamageTypeTags.DAMAGES_HELMET) && !this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { -+ // CraftBukkit - Moved into handleEntityDamage(DamageSource, float) to get amount and actuallyHurt(DamageSource, float, EntityDamageEvent) for handle damage -+ if (false && source.is(DamageTypeTags.DAMAGES_HELMET) && !this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { - this.hurtHelmet(source, damage); - damage *= 0.75F; +- this.actuallyHurt(level, source, damage - this.lastHurt); ++ // Paper start - only call damage event when actuallyHurt will be called - move call logic down ++ event = this.handleEntityDamage(source, damage, this.lastHurt); // Paper - fix invulnerability reduction in EntityDamageEvent - pass lastDamage reduction ++ damage = this.computeAmountFromEntityDamageEvent(event); ++ // Paper end - only call damage event when actuallyHurt will be called - move call logic down ++ ++ // CraftBukkit start ++ if (!this.actuallyHurt(level, source, (float)event.getFinalDamage(), event)) { // Paper - fix invulnerability reduction in EntityDamageEvent - no longer subtract lastHurt, that is part of the damage event calc now ++ return false; ++ } ++ if (this instanceof ServerPlayer && event.getDamage() == 0 && originalDamage == 0) return false; // Paper - revert to vanilla damage - players are not affected by damage that is 0 - skip damage if the vanilla damage is 0 and was not modified by plugins in the event. ++ // CraftBukkit end + this.lastHurt = damage; + tookFullDamage = false; + } else { ++ // Paper start - only call damage event when actuallyHurt will be called - move call logic down ++ event = this.handleEntityDamage(source, damage, 0); // Paper - fix invulnerability reduction in EntityDamageEvent - pass lastDamage reduction (none in this branch) ++ damage = this.computeAmountFromEntityDamageEvent(event); ++ // Paper end - only call damage event when actuallyHurt will be called - move call logic down ++ // CraftBukkit start ++ if (!this.actuallyHurt(level, source, (float)event.getFinalDamage(), event)) { ++ return false; ++ } ++ if (this instanceof ServerPlayer && event.getDamage() == 0 && originalDamage == 0) return false; // Paper - revert to vanilla damage - players are not affected by damage that is 0 - skip damage if the vanilla damage is 0 and was not modified by plugins in the event. + this.lastHurt = damage; +- this.invulnerableTime = 20; +- this.actuallyHurt(level, source, damage); ++ this.invulnerableTime = this.invulnerableDuration; // CraftBukkit - restore use of maxNoDamageTicks ++ // this.actuallyHurt(level, source, damage); ++ // CraftBukkit end + this.hurtDuration = 10; + this.hurtTime = this.hurtDuration; + } +@@ -1220,7 +_,7 @@ + level.broadcastDamageEvent(this, source); } -+ EntityDamageEvent event; // CraftBukkit // Paper - move this into the actual invuln check.... - if (Float.isNaN(damage) || Float.isInfinite(damage)) { - damage = Float.MAX_VALUE; +- if (!source.is(DamageTypeTags.NO_IMPACT) && (!blocked || damage > 0.0F)) { ++ if (!source.is(DamageTypeTags.NO_IMPACT) && !blocked) { // CraftBukkit - Prevent marking hurt if the damage is blocked + this.markHurt(); } - boolean tookFullDamage = true; -- if (this.invulnerableTime > 10.0F && !source.is(DamageTypeTags.BYPASSES_COOLDOWN)) { -+ if (this.invulnerableTime > (float)this.invulnerableDuration / 2.0F && !source.is(DamageTypeTags.BYPASSES_COOLDOWN)) { // CraftBukkit - restore use of maxNoDamageTicks - if (damage <= this.lastHurt) { - return false; +@@ -1236,7 +_,16 @@ + zd = source.getSourcePosition().z() - this.getZ(); } -- this.actuallyHurt(level, source, damage - this.lastHurt); -+ // Paper start - only call damage event when actuallyHurt will be called - move call logic down -+ event = this.handleEntityDamage(source, damage, this.lastHurt); // Paper - fix invulnerability reduction in EntityDamageEvent - pass lastDamage reduction -+ damage = this.computeAmountFromEntityDamageEvent(event); -+ // Paper end - only call damage event when actuallyHurt will be called - move call logic down -+ -+ // CraftBukkit start -+ if (!this.actuallyHurt(level, source, (float)event.getFinalDamage(), event)) { // Paper - fix invulnerability reduction in EntityDamageEvent - no longer subtract lastHurt, that is part of the damage event calc now -+ return false; +- this.knockback(0.4F, xd, zd); ++ // Paper start - Check distance in entity interactions; see for loop in knockback method ++ if (Math.abs(xd) > 200) { ++ xd = Math.random() - Math.random(); + } -+ if (this instanceof ServerPlayer && event.getDamage() == 0 && originalDamage == 0) return false; // Paper - revert to vanilla damage - players are not affected by damage that is 0 - skip damage if the vanilla damage is 0 and was not modified by plugins in the event. -+ // CraftBukkit end - this.lastHurt = damage; - tookFullDamage = false; - } else { -+ // Paper start - only call damage event when actuallyHurt will be called - move call logic down -+ event = this.handleEntityDamage(source, damage, 0); // Paper - fix invulnerability reduction in EntityDamageEvent - pass lastDamage reduction (none in this branch) -+ damage = this.computeAmountFromEntityDamageEvent(event); -+ // Paper end - only call damage event when actuallyHurt will be called - move call logic down -+ // CraftBukkit start -+ if (!this.actuallyHurt(level, source, (float)event.getFinalDamage(), event)) { -+ return false; ++ if (Math.abs(zd) > 200) { ++ zd = Math.random() - Math.random(); + } -+ if (this instanceof ServerPlayer && event.getDamage() == 0 && originalDamage == 0) return false; // Paper - revert to vanilla damage - players are not affected by damage that is 0 - skip damage if the vanilla damage is 0 and was not modified by plugins in the event. - this.lastHurt = damage; -- this.invulnerableTime = 20; -- this.actuallyHurt(level, source, damage); -+ this.invulnerableTime = this.invulnerableDuration; // CraftBukkit - restore use of maxNoDamageTicks -+ // this.actuallyHurt(level, source, damage); -+ // CraftBukkit end - this.hurtDuration = 10; - this.hurtTime = this.hurtDuration; - } -@@ -1211,7 +_,7 @@ - level.broadcastDamageEvent(this, source); - } - -- if (!source.is(DamageTypeTags.NO_IMPACT) && (!blocked || damage > 0.0F)) { -+ if (!source.is(DamageTypeTags.NO_IMPACT) && !blocked) { // CraftBukkit - Prevent marking hurt if the damage is blocked - this.markHurt(); ++ // Paper end - Check distance in entity interactions ++ ++ this.knockback(0.4F, xd, zd, source.getDirectEntity(), source.getDirectEntity() == null ? io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.DAMAGE : io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events + if (!blocked) { + this.indicateDamage(xd, zd); } +@@ -1245,19 +_,19 @@ -@@ -1226,8 +_,16 @@ - xd = source.getSourcePosition().x() - this.getX(); - zd = source.getSourcePosition().z() - this.getZ(); - } -+ // Paper start - Check distance in entity interactions; see for loop in knockback method -+ if (Math.abs(xd) > 200) { -+ xd = Math.random() - Math.random(); -+ } -+ if (Math.abs(zd) > 200) { -+ zd = Math.random() - Math.random(); -+ } -+ // Paper end - Check distance in entity interactions - -- this.knockback(0.4F, xd, zd); -+ this.knockback(0.4F, xd, zd, source.getDirectEntity(), source.getDirectEntity() == null ? io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.DAMAGE : io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events - if (!blocked) { - this.indicateDamage(xd, zd); - } -@@ -1236,19 +_,19 @@ - - if (this.isDeadOrDying()) { - if (!this.checkTotemDeathProtection(source)) { -- if (tookFullDamage) { -- this.makeSound(this.getDeathSound()); -- this.playSecondaryHurtSound(source); -- } -+ // Paper start - moved into CraftEventFactory event caller for cancellable death event -+ this.silentDeath = !tookFullDamage; // mark entity as dying silently -+ // Paper end + if (this.isDeadOrDying()) { + if (!this.checkTotemDeathProtection(source)) { +- if (tookFullDamage) { +- this.makeSound(this.getDeathSound()); +- this.playSecondaryHurtSound(source); +- } ++ // Paper start - moved into CraftEventFactory event caller for cancellable death event ++ this.silentDeath = !tookFullDamage; // mark entity as dying silently ++ // Paper end - this.die(source); -+ this.silentDeath = false; // Paper - cancellable death event - reset to default - } - } else if (tookFullDamage) { - this.playHurtSound(source); - this.playSecondaryHurtSound(source); + this.die(source); ++ this.silentDeath = false; // Paper - cancellable death event - reset to default } + } else if (tookFullDamage) { + this.playHurtSound(source); + this.playSecondaryHurtSound(source); + } -- boolean success = !blocked || damage > 0.0F; -+ boolean success = !blocked; // CraftBukkit - Ensure to return false if damage is blocked - if (success) { - this.lastDamageSource = source; - this.lastDamageStamp = this.level().getGameTime(); -@@ -1274,6 +_,12 @@ +- boolean success = !blocked || damage > 0.0F; ++ boolean success = !blocked; // CraftBukkit - Ensure to return false if damage is blocked + if (success) { + this.lastDamageSource = source; + this.lastDamageStamp = this.level().getGameTime(); +@@ -1282,6 +_,12 @@ } public float applyItemBlocking(final ServerLevel level, final DamageSource source, final float damage) { @@ -649,22 +648,22 @@ + // Paper end if (damage <= 0.0F) { return 0.0F; - } else { -@@ -1298,10 +_,12 @@ - } - - float damageBlocked = blocksAttacks.resolveBlockedDamage(source, damage, angle); -+ if (!dryRun) { // Paper - blocksAttacks.hurtBlockingItem(this.level(), blockingWith, this, this.getUsedItemHand(), damageBlocked); -- if (damageBlocked > 0.0F && !source.is(DamageTypeTags.IS_PROJECTILE) && source.getDirectEntity() instanceof LivingEntity livingEntity) { -+ if (damageBlocked > 0.0F && !source.is(DamageTypeTags.IS_PROJECTILE) && source.getDirectEntity() instanceof LivingEntity livingEntity && livingEntity.distanceToSqr(this) <= Mth.square(200.0)) { // Paper - Fix shield disable inconsistency & Check distance in entity interactions - this.blockUsingItem(level, livingEntity); - } -+ } // Paper - - return damageBlocked; - } -@@ -1312,6 +_,59 @@ + } +@@ -1308,10 +_,12 @@ + } + + float damageBlocked = blocksAttacks.resolveBlockedDamage(source, damage, angle); ++ if (!dryRun) { // Paper + blocksAttacks.hurtBlockingItem(this.level(), blockingWith, this, this.getUsedItemHand(), damageBlocked); +- if (damageBlocked > 0.0F && !source.is(DamageTypeTags.IS_PROJECTILE) && source.getDirectEntity() instanceof LivingEntity livingEntity) { ++ if (damageBlocked > 0.0F && !source.is(DamageTypeTags.IS_PROJECTILE) && source.getDirectEntity() instanceof LivingEntity livingEntity && livingEntity.distanceToSqr(this) <= Mth.square(200.0)) { // Paper - Fix shield disable inconsistency & Check distance in entity interactions + this.blockUsingItem(level, livingEntity); + } ++ } // Paper + + return damageBlocked; + } +@@ -1320,6 +_,59 @@ } } @@ -672,50 +671,50 @@ + public boolean canBlockAttack(DamageSource source, float damage) { + if (damage <= 0.0F) { + return false; -+ } else { -+ ItemStack blockingWith = this.getItemBlockingWith(); -+ if (blockingWith == null) { ++ } ++ ++ ItemStack blockingWith = this.getItemBlockingWith(); ++ if (blockingWith == null) { ++ return false; ++ } ++ ++ BlocksAttacks blocksAttacks = blockingWith.get(DataComponents.BLOCKS_ATTACKS); ++ if (blocksAttacks != null && !blocksAttacks.bypassedBy().map(t -> t.contains(source.typeHolder())).orElse(false)) { ++ if (source.getDirectEntity() instanceof AbstractArrow abstractArrow && abstractArrow.getPierceLevel() > 0) { + return false; + } else { -+ BlocksAttacks blocksAttacks = blockingWith.get(DataComponents.BLOCKS_ATTACKS); -+ if (blocksAttacks != null && !blocksAttacks.bypassedBy().map(t -> t.contains(source.typeHolder())).orElse(false)) { -+ if (source.getDirectEntity() instanceof AbstractArrow abstractArrow && abstractArrow.getPierceLevel() > 0) { -+ return false; -+ } else { -+ return true; -+ } -+ } else { -+ return false; -+ } ++ return true; + } ++ } else { ++ return false; + } + } + -+ public float resolveBlockedDamage(DamageSource damageSource, float damageAmount) { -+ Vec3 sourcePosition = damageSource.getSourcePosition(); -+ double acos; ++ public float resolveBlockedDamage(DamageSource source, float damageAmount) { ++ Vec3 sourcePosition = source.getSourcePosition(); ++ double angle; + if (sourcePosition != null) { -+ Vec3 vec3 = this.calculateViewVector(0.0F, this.getYHeadRot()); -+ Vec3 vec31 = sourcePosition.subtract(this.position()); -+ vec31 = new Vec3(vec31.x, 0.0, vec31.z).normalize(); -+ acos = Math.acos(vec31.dot(vec3)); ++ Vec3 viewVector = this.calculateViewVector(0.0F, this.getYHeadRot()); ++ Vec3 vectorTo = sourcePosition.subtract(this.position()); ++ vectorTo = new Vec3(vectorTo.x, 0.0, vectorTo.z).normalize(); ++ angle = Math.acos(vectorTo.dot(viewVector)); + } else { -+ acos = (float) Math.PI; ++ angle = (float) Math.PI; + } + + BlocksAttacks blocksAttacks = this.getItemBlockingWith().get(DataComponents.BLOCKS_ATTACKS); -+ return blocksAttacks.resolveBlockedDamage(damageSource, damageAmount, acos); ++ return blocksAttacks.resolveBlockedDamage(source, damageAmount, angle); + } + -+ public void blockingItemEffects(ServerLevel level, DamageSource damageSource, float f) { -+ ItemStack itemBlockingWith = this.getItemBlockingWith(); -+ if (itemBlockingWith == null) return; ++ public void blockingItemEffects(ServerLevel level, DamageSource source, float damageBlocked) { ++ ItemStack blockingWith = this.getItemBlockingWith(); ++ if (blockingWith == null) return; + -+ BlocksAttacks blocksAttacks = itemBlockingWith.get(DataComponents.BLOCKS_ATTACKS); ++ BlocksAttacks blocksAttacks = blockingWith.get(DataComponents.BLOCKS_ATTACKS); + if (blocksAttacks == null) return; + -+ blocksAttacks.hurtBlockingItem(this.level(), itemBlockingWith, this, this.getUsedItemHand(), f); -+ if (f > 0.0F && !damageSource.is(DamageTypeTags.IS_PROJECTILE) && damageSource.getDirectEntity() instanceof LivingEntity livingEntity && livingEntity.distanceToSqr(this) <= Mth.square(200.0)) { // Paper - Fix shield disable inconsistency & Check distance in entity interactions ++ blocksAttacks.hurtBlockingItem(this.level(), blockingWith, this, this.getUsedItemHand(), damageBlocked); ++ if (damageBlocked > 0.0F && !source.is(DamageTypeTags.IS_PROJECTILE) && source.getDirectEntity() instanceof LivingEntity livingEntity && livingEntity.distanceToSqr(this) <= Mth.square(200.0)) { // Paper - Fix shield disable inconsistency & Check distance in entity interactions + this.blockUsingItem(level, livingEntity); + } + } @@ -724,7 +723,7 @@ public void playSecondaryHurtSound(final DamageSource source) { if (source.is(DamageTypes.THORNS)) { SoundSource soundSource = this instanceof Player ? SoundSource.PLAYERS : SoundSource.HOSTILE; -@@ -1343,12 +_,24 @@ +@@ -1351,12 +_,24 @@ return EntityReference.getPlayer(this.lastHurtByPlayer, this.level()); } @@ -750,54 +749,54 @@ } private boolean checkTotemDeathProtection(final DamageSource killingDamage) { -@@ -1358,18 +_,39 @@ - ItemStack protectionItem = null; - DeathProtection protection = null; +@@ -1367,18 +_,39 @@ + ItemStack protectionItem = null; + DeathProtection protection = null; -+ // CraftBukkit start -+ InteractionHand usedHand = null; -+ ItemStack itemStack = ItemStack.EMPTY; - for (InteractionHand hand : InteractionHand.values()) { -- ItemStack itemStack = this.getItemInHand(hand); -+ itemStack = this.getItemInHand(hand); - protection = itemStack.get(DataComponents.DEATH_PROTECTION); - if (protection != null) { -+ usedHand = hand; - protectionItem = itemStack.copy(); -+ // itemStack.shrink(1); -+ break; -+ } ++ // CraftBukkit start ++ InteractionHand usedHand = null; ++ ItemStack itemStack = ItemStack.EMPTY; + for (InteractionHand hand : InteractionHand.values()) { +- ItemStack itemStack = this.getItemInHand(hand); ++ itemStack = this.getItemInHand(hand); + protection = itemStack.get(DataComponents.DEATH_PROTECTION); + if (protection != null) { ++ usedHand = hand; + protectionItem = itemStack.copy(); ++ // itemStack.shrink(1); ++ break; + } ++ } + -+ final org.bukkit.inventory.EquipmentSlot handSlot = (usedHand != null) ? org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(usedHand) : null; -+ final EntityResurrectEvent event = new EntityResurrectEvent((org.bukkit.entity.LivingEntity) this.getBukkitEntity(), handSlot); -+ event.setCancelled(protectionItem == null); -+ this.level().getCraftServer().getPluginManager().callEvent(event); -+ if (event.isCancelled()) { -+ // Set death protection to null as the event was cancelled. Prevent any attempt at resurrection. -+ protection = null; -+ } else { -+ if (!itemStack.isEmpty() && protectionItem != null) { // Paper - only reduce item if actual totem was found - itemStack.shrink(1); -- break; -- } ++ final org.bukkit.inventory.EquipmentSlot handSlot = (usedHand != null) ? org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(usedHand) : null; ++ final EntityResurrectEvent event = new EntityResurrectEvent((org.bukkit.entity.LivingEntity) this.getBukkitEntity(), handSlot); ++ event.setCancelled(protectionItem == null); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ // Set death protection to null as the event was cancelled. Prevent any attempt at resurrection. ++ protection = null; ++ } else { ++ if (!itemStack.isEmpty() && protectionItem != null) { // Paper - only reduce item if actual totem was found + itemStack.shrink(1); +- break; - } +- } - -- if (protectionItem != null) { -- if (this instanceof ServerPlayer player) { -+ } -+ // Paper start - fix NPE when pre-cancelled EntityResurrectEvent is uncancelled -+ // restore the previous behavior in that case by defaulting to vanilla's totem of undying effect -+ if (protection == null) { -+ protection = DeathProtection.TOTEM_OF_UNDYING; -+ } -+ // Paper end - fix NPE when pre-cancelled EntityResurrectEvent is uncancelled -+ if (protectionItem != null && this instanceof final ServerPlayer player) { -+ // CraftBukkit end - player.awardStat(Stats.ITEM_USED.get(protectionItem.getItem())); - CriteriaTriggers.USED_TOTEM.trigger(player, protectionItem); - protectionItem.causeUseVibration(this, GameEvent.ITEM_INTERACT_FINISH); -@@ -1420,6 +_,7 @@ +- if (protectionItem != null) { +- if (this instanceof ServerPlayer player) { ++ } ++ // Paper start - fix NPE when pre-cancelled EntityResurrectEvent is uncancelled ++ // restore the previous behavior in that case by defaulting to vanilla's totem of undying effect ++ if (protection == null) { ++ protection = DeathProtection.TOTEM_OF_UNDYING; ++ } ++ // Paper end - fix NPE when pre-cancelled EntityResurrectEvent is uncancelled ++ if (protectionItem != null && this instanceof final ServerPlayer player) { ++ // CraftBukkit end + player.awardStat(Stats.ITEM_USED.get(protectionItem.getItem())); + CriteriaTriggers.USED_TOTEM.trigger(player, protectionItem); + protectionItem.causeUseVibration(this, GameEvent.ITEM_INTERACT_FINISH); +@@ -1428,6 +_,7 @@ if (!this.isRemoved() && !this.dead) { Entity sourceEntity = source.getEntity(); LivingEntity killer = this.getKillCredit(); @@ -805,7 +804,7 @@ if (killer != null) { killer.awardKillScore(this, source); } -@@ -1430,68 +_,147 @@ +@@ -1438,68 +_,147 @@ this.stopUsingItem(); if (!this.level().isClientSide() && this.hasCustomName()) { @@ -967,7 +966,7 @@ } protected void dropCustomDeathLoot(final ServerLevel level, final DamageSource source, final boolean killedByPlayer) { -@@ -1603,9 +_,14 @@ +@@ -1611,9 +_,14 @@ } public void knockback(double power, double xd, double zd) { @@ -984,7 +983,7 @@ Vec3 deltaMovement = this.getDeltaMovement(); while (xd * xd + zd * zd < 1.0E-5F) { -@@ -1614,11 +_,22 @@ +@@ -1622,11 +_,22 @@ } Vec3 deltaVector = new Vec3(xd, 0.0, zd).normalize().scale(power); @@ -1008,7 +1007,7 @@ } } -@@ -1709,7 +_,7 @@ +@@ -1717,7 +_,7 @@ @Override public boolean isAlive() { @@ -1017,7 +1016,7 @@ } public boolean isLookingAtMe( -@@ -1764,10 +_,15 @@ +@@ -1772,10 +_,15 @@ boolean damaged = super.causeFallDamage(effectiveFallDistance, damageModifier, damageSource); int dmg = this.calculateFallDamage(effectiveFallDistance, damageModifier); if (dmg > 0) { @@ -1034,7 +1033,7 @@ return true; } else { return damaged; -@@ -1865,7 +_,7 @@ +@@ -1873,7 +_,7 @@ protected float getDamageAfterArmorAbsorb(final DamageSource damageSource, float damage) { if (!damageSource.is(DamageTypeTags.BYPASSES_ARMOR)) { @@ -1043,18 +1042,18 @@ damage = CombatRules.getDamageAfterAbsorb( this, damage, damageSource, this.getArmorValue(), (float)this.getAttributeValue(Attributes.ARMOR_TOUGHNESS) ); -@@ -1878,7 +_,8 @@ - if (damageSource.is(DamageTypeTags.BYPASSES_EFFECTS)) { +@@ -1887,7 +_,8 @@ return damage; - } else { -- if (this.hasEffect(MobEffects.RESISTANCE) && !damageSource.is(DamageTypeTags.BYPASSES_RESISTANCE)) { -+ // CraftBukkit - Moved to handleEntityDamage(DamageSource, float) -+ if (false && this.hasEffect(MobEffects.RESISTANCE) && !damageSource.is(DamageTypeTags.BYPASSES_RESISTANCE)) { - int absorbValue = (this.getEffect(MobEffects.RESISTANCE).getAmplifier() + 1) * 5; - int absorb = 25 - absorbValue; - float v = damage * absorb; -@@ -1915,24 +_,181 @@ } + +- if (this.hasEffect(MobEffects.RESISTANCE) && !damageSource.is(DamageTypeTags.BYPASSES_RESISTANCE)) { ++ // CraftBukkit - Moved to handleEntityDamage(DamageSource, float) ++ if (false && this.hasEffect(MobEffects.RESISTANCE) && !damageSource.is(DamageTypeTags.BYPASSES_RESISTANCE)) { + int absorbValue = (this.getEffect(MobEffects.RESISTANCE).getAmplifier() + 1) * 5; + int absorb = 25 - absorbValue; + float v = damage * absorb; +@@ -1925,25 +_,181 @@ + return damage; } - protected void actuallyHurt(final ServerLevel level, final DamageSource source, float dmg) { @@ -1140,9 +1139,10 @@ if (!this.isInvulnerableTo(level, source)) { - dmg = this.getDamageAfterArmorAbsorb(source, dmg); - dmg = this.getDamageAfterMagicAbsorb(source, dmg); -- float var10 = Math.max(dmg - this.getAbsorptionAmount(), 0.0F); -- this.setAbsorptionAmount(this.getAbsorptionAmount() - (dmg - var10)); -- float absorbedDamage = dmg - var10; +- float originalDamage = dmg; +- dmg = Math.max(dmg - this.getAbsorptionAmount(), 0.0F); +- this.setAbsorptionAmount(this.getAbsorptionAmount() - (originalDamage - dmg)); +- float absorbedDamage = originalDamage - dmg; + if (event.isCancelled()) { + return false; + } @@ -1197,12 +1197,9 @@ serverPlayer.awardStat(Stats.DAMAGE_DEALT_ABSORBED, Math.round(absorbedDamage * 10.0F)); } -- if (var10 != 0.0F) { -- this.getCombatTracker().recordDamage(source, var10); -- this.setHealth(this.getHealth() - var10); -- this.setAbsorptionAmount(this.getAbsorptionAmount() - var10); +- if (dmg != 0.0F) { + // CraftBukkit start -+ if (dmg > 0 || !human) { ++ if (dmg > 0.0F || !human) { + if (human) { + // PAIL: Be sure to drag all this code from the EntityHuman subclass each update. + ((net.minecraft.world.entity.player.Player)this).causeFoodExhaustion(source.getFoodExhaustion(), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.DAMAGED); // CraftBukkit - EntityExhaustionEvent @@ -1211,11 +1208,11 @@ + } + } + // CraftBukkit end -+ this.getCombatTracker().recordDamage(source, dmg); -+ this.setHealth(this.getHealth() - dmg); + this.getCombatTracker().recordDamage(source, dmg); + this.setHealth(this.getHealth() - dmg); + // CraftBukkit start + if (!human) { -+ this.setAbsorptionAmount(this.getAbsorptionAmount() - dmg); + this.setAbsorptionAmount(this.getAbsorptionAmount() - dmg); + } this.gameEvent(GameEvent.ENTITY_DAMAGE); + return true; @@ -1245,7 +1242,7 @@ } public CombatTracker getCombatTracker() { -@@ -1960,7 +_,17 @@ +@@ -1971,7 +_,17 @@ } public final void setArrowCount(final int count) { @@ -1264,7 +1261,7 @@ } public final int getStingerCount() { -@@ -2010,7 +_,7 @@ +@@ -2021,7 +_,7 @@ @Override public void handleDamageEvent(final DamageSource source) { this.walkAnimation.setSpeed(1.5F); @@ -1273,7 +1270,7 @@ this.hurtDuration = 10; this.hurtTime = this.hurtDuration; SoundEvent hurtSound = this.getHurtSound(source); -@@ -2139,7 +_,7 @@ +@@ -2150,7 +_,7 @@ @Override protected void onBelowWorld() { @@ -1282,7 +1279,7 @@ } protected void updateSwingTime() { -@@ -2246,7 +_,13 @@ +@@ -2257,7 +_,13 @@ } public void setItemSlot(final EquipmentSlot slot, final ItemStack itemStack) { @@ -1297,7 +1294,7 @@ } public float getArmorCoverPercentage() { -@@ -2339,14 +_,27 @@ +@@ -2350,14 +_,27 @@ return this.hasEffect(MobEffects.JUMP_BOOST) ? 0.1F * (this.getEffect(MobEffects.JUMP_BOOST).getAmplifier() + 1.0F) : 0.0F; } @@ -1318,14 +1315,14 @@ + } + } + // Paper end - Prevent excessive velocity through repeated crits - this.setDeltaMovement(movement.x, Math.max((double)jumpPower, movement.y), movement.z); + this.setDeltaMovement(movement.x, Math.max(jumpPower, movement.y), movement.z); if (this.isSprinting()) { float angle = this.getYRot() * Mth.DEG_TO_RAD; + if (canCrit) // Paper - Prevent excessive velocity through repeated crits this.addDeltaMovement(new Vec3(-Mth.sin(angle) * 0.2, 0.0, Mth.cos(angle) * 0.2)); } -@@ -2533,8 +_,10 @@ +@@ -2544,8 +_,10 @@ } public void stopFallFlying() { @@ -1336,7 +1333,7 @@ } private Vec3 updateFallFlyingMovement(Vec3 movement) { -@@ -2678,7 +_,7 @@ +@@ -2689,7 +_,7 @@ public void causeExtraKnockback(final Entity target, final float knockback, final Vec3 oldMovement) { if (knockback > 0.0F && target instanceof LivingEntity livingTarget) { @@ -1345,7 +1342,7 @@ this.setDeltaMovement(this.getDeltaMovement().multiply(0.6, 1.0, 0.6)); } } -@@ -2754,37 +_,15 @@ +@@ -2765,37 +_,15 @@ profiler.pop(); profiler.push("rangeChecks"); @@ -1392,7 +1389,7 @@ profiler.pop(); if (this.isFallFlying()) { -@@ -2865,6 +_,11 @@ +@@ -2877,6 +_,11 @@ } public void onAttack() { @@ -1404,7 +1401,7 @@ } public void detectEquipmentUpdates() { -@@ -2879,16 +_,39 @@ +@@ -2891,16 +_,39 @@ private @Nullable Map collectEquipmentChanges() { Map changedItems = null; @@ -1444,7 +1441,7 @@ AttributeMap attributes = this.getAttributes(); if (!previous.isEmpty()) { this.stopLocationBasedEffects(previous, slot, attributes); -@@ -2913,6 +_,8 @@ +@@ -2925,6 +_,8 @@ } } } @@ -1453,7 +1450,7 @@ } return changedItems; -@@ -2944,7 +_,7 @@ +@@ -2956,7 +_,7 @@ itemsToSend.add(Pair.of(slot, newItemToStore)); this.lastEquipmentItems.put(slot, newItemToStore); }); @@ -1462,7 +1459,7 @@ } protected void tickHeadTurn(final float yBodyRotT) { -@@ -3030,8 +_,10 @@ +@@ -3042,8 +_,10 @@ if (!inWaterAndHasFluidHeight || this.onGround() && !(fluidHeight > fluidJumpThreshold)) { if (!this.isInLava() || this.onGround() && !(fluidHeight > fluidJumpThreshold)) { if ((this.onGround() || inWaterAndHasFluidHeight && fluidHeight <= fluidJumpThreshold) && this.noJumpDelay == 0) { @@ -1473,7 +1470,7 @@ } } else { this.jumpInLiquid(FluidTags.LAVA); -@@ -3072,7 +_,7 @@ +@@ -3084,7 +_,7 @@ profiler.pop(); if (this.level() instanceof ServerLevel serverLevel) { profiler.push("freezing"); @@ -1482,7 +1479,7 @@ this.setTicksFrozen(Math.max(0, this.getTicksFrozen() - 2)); } -@@ -3093,6 +_,20 @@ +@@ -3105,6 +_,20 @@ this.pushEntities(); profiler.pop(); @@ -1503,7 +1500,7 @@ if (this.level() instanceof ServerLevel serverLevel && this.isSensitiveToWater() && this.isInWaterOrRain()) { this.hurtServer(serverLevel, this.damageSources().drown(), 1.0F); } -@@ -3115,6 +_,7 @@ +@@ -3127,6 +_,7 @@ this.checkFallDistanceAccumulation(); if (!this.level().isClientSide()) { if (!this.canGlide()) { @@ -1511,7 +1508,7 @@ this.setSharedFlag(Entity.FLAG_FALL_FLYING, false); return; } -@@ -3151,10 +_,25 @@ +@@ -3163,10 +_,25 @@ } protected void pushEntities() { @@ -1538,24 +1535,24 @@ if (maxCramming > 0 && pushableEntities.size() > maxCramming - 1 && this.random.nextInt(4) == 0) { int count = 0; -@@ -3170,7 +_,16 @@ +@@ -3182,7 +_,16 @@ } } + // Paper start - Cap entity collisions + this.numCollisions = Math.max(0, this.numCollisions - this.level().paperConfig().collisions.maxEntityCollisions); - for (Entity entityx : pushableEntities) { + for (Entity entity : pushableEntities) { + if (this.numCollisions >= this.level().paperConfig().collisions.maxEntityCollisions) { + break; + } + -+ entityx.numCollisions++; ++ entity.numCollisions++; + this.numCollisions++; + // Paper end - Cap entity collisions - this.doPush(entityx); + this.doPush(entity); } } -@@ -3179,16 +_,32 @@ +@@ -3191,16 +_,32 @@ protected void checkAutoSpinAttack(final AABB old, final AABB current) { AABB minmax = old.minmax(current); List entities = this.level().getEntities(this, minmax); @@ -1589,7 +1586,7 @@ this.autoSpinAttackTicks = 0; } -@@ -3211,10 +_,10 @@ +@@ -3223,10 +_,10 @@ } @Override @@ -1603,7 +1600,7 @@ this.dismountVehicle(oldVehicle); } } -@@ -3241,7 +_,7 @@ +@@ -3253,7 +_,7 @@ } public void onItemPickup(final ItemEntity entity) { @@ -1612,7 +1609,7 @@ if (thrower instanceof ServerPlayer) { CriteriaTriggers.THROWN_ITEM_PICKED_UP_BY_ENTITY.trigger((ServerPlayer)thrower, entity.getItem(), this); } -@@ -3253,7 +_,7 @@ +@@ -3265,7 +_,7 @@ && (entity instanceof ItemEntity || entity instanceof AbstractArrow || entity instanceof ExperienceOrb)) { ((ServerLevel)this.level()) .getChunkSource() @@ -1621,17 +1618,17 @@ } } -@@ -3269,7 +_,8 @@ - } else { - Vec3 from = new Vec3(this.getX(), this.getEyeY(), this.getZ()); - Vec3 to = new Vec3(target.getX(), eyeHeight, target.getZ()); -- return !(to.distanceTo(from) > 128.0) -+ // Paper - diff on change - used in CraftLivingEntity#hasLineOfSight(Location) and CraftWorld#lineOfSightExists -+ return !(to.distanceToSqr(from) > Mth.square(128.0)) // Paper - Perf: Use distance squared - && this.level().clip(new ClipContext(from, to, blockCollidingContext, fluidCollidingContext, this)).getType() == HitResult.Type.MISS; - } +@@ -3282,7 +_,8 @@ + + Vec3 from = new Vec3(this.getX(), this.getEyeY(), this.getZ()); + Vec3 to = new Vec3(target.getX(), eyeHeight, target.getZ()); +- return !(to.distanceTo(from) > 128.0) ++ // Paper - diff on change - used in CraftLivingEntity#hasLineOfSight(Location) and CraftWorld#lineOfSightExists ++ return !(to.distanceToSqr(from) > Mth.square(128.0)) // Paper - Perf: Use distance squared + && this.level().clip(new ClipContext(from, to, blockCollidingContext, fluidCollidingContext, this)).getType() == HitResult.Type.MISS; } -@@ -3290,13 +_,27 @@ + +@@ -3302,13 +_,27 @@ @Override public boolean isPickable() { @@ -1662,7 +1659,7 @@ @Override public float getYHeadRot() { -@@ -3327,7 +_,7 @@ +@@ -3339,7 +_,7 @@ } public final void setAbsorptionAmount(final float absorptionAmount) { @@ -1671,7 +1668,7 @@ } protected void internalSetAbsorptionAmount(final float absorptionAmount) { -@@ -3354,6 +_,15 @@ +@@ -3366,6 +_,15 @@ return (this.entityData.get(DATA_LIVING_ENTITY_FLAGS) & 2) > 0 ? InteractionHand.OFF_HAND : InteractionHand.MAIN_HAND; } @@ -1687,7 +1684,7 @@ private void updatingUsingItem() { if (this.isUsingItem()) { if (ItemStack.isSameItem(this.getItemInHand(this.getUsedItemHand()), this.useItem)) { -@@ -3401,7 +_,12 @@ +@@ -3413,7 +_,12 @@ protected void updateUsingItem(final ItemStack useItem) { useItem.onUseTick(this.level(), this, this.getUseItemRemainingTicks()); @@ -1701,7 +1698,7 @@ this.completeUsingItem(); } } -@@ -3427,10 +_,19 @@ +@@ -3439,10 +_,19 @@ } public void startUsingItem(final InteractionHand hand) { @@ -1723,7 +1720,7 @@ if (!this.level().isClientSide()) { this.setLivingEntityFlag(LIVING_ENTITY_FLAG_IS_USING, true); this.setLivingEntityFlag(LIVING_ENTITY_FLAG_OFF_HAND, hand == InteractionHand.OFF_HAND); -@@ -3457,7 +_,10 @@ +@@ -3469,7 +_,10 @@ } } else if (!this.isUsingItem() && !this.useItem.isEmpty()) { this.useItem = ItemStack.EMPTY; @@ -1735,7 +1732,7 @@ } } } -@@ -3500,9 +_,41 @@ +@@ -3512,9 +_,41 @@ this.releaseUsingItem(); } else { if (!this.useItem.isEmpty() && this.isUsingItem()) { @@ -1778,7 +1775,7 @@ } this.stopUsingItem(); -@@ -3534,6 +_,7 @@ +@@ -3546,6 +_,7 @@ ItemStack itemInUsedHand = this.getItemInHand(this.getUsedItemHand()); if (!this.useItem.isEmpty() && ItemStack.isSameItem(itemInUsedHand, this.useItem)) { this.useItem = itemInUsedHand; @@ -1786,7 +1783,7 @@ this.useItem.releaseUsing(this.level(), this, this.getUseItemRemainingTicks()); if (this.useItem.useOnRelease()) { this.updatingUsingItem(); -@@ -3554,7 +_,10 @@ +@@ -3566,7 +_,10 @@ } this.useItem = ItemStack.EMPTY; @@ -1798,8 +1795,8 @@ } public boolean isBlocking() { -@@ -3577,6 +_,60 @@ - } +@@ -3589,6 +_,60 @@ + return null; } + // CraftBukkit start @@ -1859,7 +1856,7 @@ public boolean isSuppressingSlidingDownLadder() { return this.isShiftKeyDown(); } -@@ -3595,6 +_,12 @@ +@@ -3607,6 +_,12 @@ } public boolean randomTeleport(final double xx, final double yy, final double zz, final boolean showParticles) { @@ -1872,7 +1869,7 @@ double xo = this.getX(); double yo = this.getY(); double zo = this.getZ(); -@@ -3617,16 +_,39 @@ +@@ -3629,16 +_,39 @@ } if (landed) { @@ -1912,15 +1909,15 @@ - return false; + // this.teleportTo(xo, yo, zo); // CraftBukkit - already set the location back + return Optional.of(false); // CraftBukkit - } else { - if (showParticles) { - level.broadcastEntityEvent(this, EntityEvent.TELEPORT); -@@ -3636,7 +_,7 @@ - pathfinderMob.getNavigation().stop(); - } + } -- return true; -+ return Optional.of(true); // CraftBukkit + if (showParticles) { +@@ -3649,7 +_,7 @@ + pathfinderMob.getNavigation().stop(); } + +- return true; ++ return Optional.of(true); // CraftBukkit } + public boolean isAffectedByPotions() { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/Mob.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/Mob.java.patch index fa3e3bce9f23..d677fa937ba7 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/Mob.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/Mob.java.patch @@ -161,26 +161,27 @@ EquipmentSlot slot = this.getEquipmentSlotForItem(itemStack); if (!this.isEquippableInSlot(itemStack, slot)) { return ItemStack.EMPTY; -@@ -539,10 +_,18 @@ - canReplace = current.isEmpty(); +@@ -539,11 +_,18 @@ + current = this.getItemBySlot(slot); + canReplace = current.isEmpty(); + } +- +- if (canReplace && this.canHoldItem(itemStack)) { ++ // CraftBukkit start ++ boolean canPickup = canReplace && this.canHoldItem(itemStack); ++ if (entity != null) { ++ canPickup = !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(this, entity, 0, !canPickup).isCancelled(); ++ } ++ if (canPickup) { ++ // CraftBukkit end + double dropChance = this.dropChances.byEquipment(slot); + if (!current.isEmpty() && Math.max(this.random.nextFloat() - 0.1F, 0.0F) < dropChance) { ++ this.forceDrops = true; // CraftBukkit + this.spawnAtLocation(level, current); ++ this.forceDrops = false; // CraftBukkit } -- if (canReplace && this.canHoldItem(itemStack)) { -+ // CraftBukkit start -+ boolean canPickup = canReplace && this.canHoldItem(itemStack); -+ if (entity != null) { -+ canPickup = !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(this, entity, 0, !canPickup).isCancelled(); -+ } -+ if (canPickup) { -+ // CraftBukkit end - double dropChance = this.dropChances.byEquipment(slot); - if (!current.isEmpty() && Math.max(this.random.nextFloat() - 0.1F, 0.0F) < dropChance) { -+ this.forceDrops = true; // CraftBukkit - this.spawnAtLocation(level, current); -+ this.forceDrops = false; // CraftBukkit - } - - ItemStack toEquip = slot.limit(itemStack); + ItemStack toEquip = slot.limit(itemStack); @@ -651,25 +_,38 @@ return this.isPassenger() || this.isLeashed(); } @@ -249,7 +250,7 @@ ProfilerFiller profiler = Profiler.get(); profiler.push("sensing"); this.sensing.tick(); -@@ -859,14 +_,69 @@ +@@ -855,14 +_,69 @@ public boolean stillValid(final Player player) { return player.getVehicle() == Mob.this || player.isWithinEntityInteractionRange(Mob.this, 4.0); } @@ -319,7 +320,7 @@ ItemStack itemStack = this.getItemBySlot(slot); float dropChance = this.dropChances.byEquipment(slot); if (dropChance != 0.0F) { -@@ -886,7 +_,13 @@ +@@ -882,7 +_,13 @@ } this.spawnAtLocation(level, itemStack); @@ -333,7 +334,7 @@ } } } -@@ -910,7 +_,9 @@ +@@ -906,7 +_,9 @@ slotsPreventedFromDropping.add(slot); } else if (this.dropChances.isPreserved(slot)) { this.setItemSlot(slot, ItemStack.EMPTY); @@ -343,7 +344,7 @@ } } } -@@ -1210,6 +_,22 @@ +@@ -1206,6 +_,22 @@ final EntitySpawnReason spawnReason, final ConversionParams.AfterConversion afterConversion ) { @@ -365,35 +366,35 @@ + // Paper end - entity zap event - allow cancellation of conversion post creation if (this.isRemoved()) { return null; - } else { -@@ -1218,13 +_,23 @@ - return null; - } else { - params.type().convert(this, newMob, params); -- afterConversion.finalizeConversion(newMob); -+ if (!afterConversion.finalizeConversionOrCancel(newMob)) return null; // Paper - entity zap event - return null if conversion was cancelled -+ // CraftBukkit start -+ if (transformReason == null) { -+ // Special handling for slime split and pig lightning -+ return newMob; -+ } + } +@@ -1216,13 +_,23 @@ + } + + params.type().convert(this, newMob, params); +- afterConversion.finalizeConversion(newMob); ++ if (!afterConversion.finalizeConversionOrCancel(newMob)) return null; // Paper - entity zap event - return null if conversion was cancelled ++ // CraftBukkit start ++ if (transformReason == null) { ++ // Special handling for slime split and pig lightning ++ return newMob; ++ } + -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTransformEvent(this, newMob, transformReason).isCancelled()) { -+ return null; -+ } -+ // CraftBukkit end - if (this.level() instanceof ServerLevel serverLevel) { -- serverLevel.addFreshEntity(newMob); -+ serverLevel.addFreshEntity(newMob, creatureSpawnReason); // CraftBukkit - } ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTransformEvent(this, newMob, transformReason).isCancelled()) { ++ return null; ++ } ++ // CraftBukkit end + if (this.level() instanceof ServerLevel serverLevel) { +- serverLevel.addFreshEntity(newMob); ++ serverLevel.addFreshEntity(newMob, creatureSpawnReason); // CraftBukkit + } - if (params.type().shouldDiscardAfterConversion()) { -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.TRANSFORMATION); // CraftBukkit - add Bukkit remove cause - } + if (params.type().shouldDiscardAfterConversion()) { +- this.discard(); ++ this.discard(EntityRemoveEvent.Cause.TRANSFORMATION); // CraftBukkit - add Bukkit remove cause + } - return newMob; -@@ -1235,7 +_,17 @@ + return newMob; +@@ -1231,7 +_,17 @@ public @Nullable T convertTo( final EntityType entityType, final ConversionParams params, final ConversionParams.AfterConversion afterConversion ) { @@ -412,7 +413,7 @@ } @Override -@@ -1276,7 +_,17 @@ +@@ -1272,7 +_,17 @@ public boolean startRiding(final Entity entity, final boolean force, final boolean sendEventAndTriggers) { boolean result = super.startRiding(entity, force, sendEventAndTriggers); if (result && this.isLeashed()) { @@ -431,7 +432,7 @@ } return result; -@@ -1439,7 +_,7 @@ +@@ -1435,7 +_,7 @@ Set availableGoals = this.goalSelector.getAvailableGoals(); List goalInfo = new ArrayList<>(availableGoals.size()); availableGoals.forEach( diff --git a/paper-server/patches/sources/net/minecraft/world/entity/NeutralMob.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/NeutralMob.java.patch index d225c0e9b8a8..1c620fa1f0b8 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/NeutralMob.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/NeutralMob.java.patch @@ -13,7 +13,7 @@ } } -@@ -134,7 +_,7 @@ +@@ -136,7 +_,7 @@ default void stopBeingAngry() { this.setLastHurtByMob(null); this.setPersistentAngerTarget(null); @@ -22,7 +22,7 @@ this.setPersistentAngerEndTime(-1L); } -@@ -144,9 +_,21 @@ +@@ -146,9 +_,21 @@ void setTarget(final @Nullable LivingEntity target); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/TamableAnimal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/TamableAnimal.java.patch index e298b1df0110..f3b22e359887 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/TamableAnimal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/TamableAnimal.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/TamableAnimal.java +++ b/net/minecraft/world/entity/TamableAnimal.java -@@ -80,7 +_,7 @@ +@@ -79,7 +_,7 @@ } this.orderedToSit = input.getBooleanOr("Sitting", false); @@ -9,7 +9,7 @@ } @Override -@@ -136,7 +_,7 @@ +@@ -135,7 +_,7 @@ protected void feed(final Player player, final InteractionHand hand, final ItemStack itemStack, final float healingFactor, final float defaultHeal) { FoodProperties foodProperties = itemStack.get(DataComponents.FOOD); this.usePlayerItem(player, hand, itemStack); @@ -18,7 +18,7 @@ this.playEatingSound(); } -@@ -145,6 +_,13 @@ +@@ -144,6 +_,13 @@ } public void setInSittingPose(final boolean value) { @@ -32,7 +32,7 @@ byte current = this.entityData.get(DATA_FLAGS_ID); if (value) { this.entityData.set(DATA_FLAGS_ID, (byte)(current | 1)); -@@ -225,7 +_,12 @@ +@@ -224,7 +_,12 @@ if (this.level() instanceof ServerLevel serverLevel && serverLevel.getGameRules().get(GameRules.SHOW_DEATH_MESSAGES) && this.getOwner() instanceof ServerPlayer serverPlayer) { @@ -47,18 +47,18 @@ super.die(source); @@ -268,7 +_,14 @@ - if (!this.canTeleportTo(new BlockPos(x, y, z))) { return false; - } else { -- this.snapTo(x + 0.5, y, z + 0.5, this.getYRot(), this.getXRot()); -+ // CraftBukkit start -+ org.bukkit.event.entity.EntityTeleportEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTeleportEvent(this, x + 0.5, y, z + 0.5); -+ if (event.isCancelled() || event.getTo() == null) { -+ return false; -+ } -+ org.bukkit.Location to = event.getTo(); -+ this.snapTo(to.getX(), to.getY(), to.getZ(), to.getYaw(), to.getPitch()); -+ // CraftBukkit end - this.navigation.stop(); - return true; } + +- this.snapTo(x + 0.5, y, z + 0.5, this.getYRot(), this.getXRot()); ++ // CraftBukkit start ++ org.bukkit.event.entity.EntityTeleportEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTeleportEvent(this, x + 0.5, y, z + 0.5); ++ if (event.isCancelled() || event.getTo() == null) { ++ return false; ++ } ++ org.bukkit.Location to = event.getTo(); ++ this.snapTo(to.getX(), to.getY(), to.getZ(), to.getYaw(), to.getPitch()); ++ // CraftBukkit end + this.navigation.stop(); + return true; + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/AcquirePoi.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/AcquirePoi.java.patch index e4e2c1f5d828..1f3d07b60b34 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/AcquirePoi.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/AcquirePoi.java.patch @@ -1,10 +1,10 @@ --- a/net/minecraft/world/entity/ai/behavior/AcquirePoi.java +++ b/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -@@ -74,6 +_,7 @@ - return false; - } else { - nextScheduledStart.setValue(timestamp + 20L + random.nextInt(20)); -+ if (level.paperConfig().entities.behavior.stuckEntityPoiRetryDelay.enabled() && body.getNavigation().isStuck()) nextScheduledStart.add(level.paperConfig().entities.behavior.stuckEntityPoiRetryDelay.intValue()); // Paper - Next stuck check delay config - PoiManager poiManager = level.getPoiManager(); - batchCache.long2ObjectEntrySet().removeIf(entry -> !entry.getValue().isStillValid(timestamp)); - Predicate cacheTest = pos -> { +@@ -78,6 +_,7 @@ + } + + nextScheduledStart.setValue(timestamp + 20L + random.nextInt(20)); ++ if (level.paperConfig().entities.behavior.stuckEntityPoiRetryDelay.enabled() && body.getNavigation().isStuck()) nextScheduledStart.add(level.paperConfig().entities.behavior.stuckEntityPoiRetryDelay.intValue()); // Paper - Next stuck check delay config + PoiManager poiManager = level.getPoiManager(); + batchCache.long2ObjectEntrySet().removeIf(entry -> !entry.getValue().isStillValid(timestamp)); + Predicate cacheTest = pos -> { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/AssignProfessionFromJobSite.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/AssignProfessionFromJobSite.java.patch index d6f0def83860..481256ff5b4f 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/AssignProfessionFromJobSite.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/AssignProfessionFromJobSite.java.patch @@ -1,18 +1,18 @@ --- a/net/minecraft/world/entity/ai/behavior/AssignProfessionFromJobSite.java +++ b/net/minecraft/world/entity/ai/behavior/AssignProfessionFromJobSite.java -@@ -39,7 +_,14 @@ - .findFirst() - ) - .ifPresent(profession -> { -- body.setVillagerData(body.getVillagerData().withProfession(profession)); -+ // CraftBukkit start - Fire VillagerCareerChangeEvent where Villager gets employed -+ org.bukkit.event.entity.VillagerCareerChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callVillagerCareerChangeEvent(body, org.bukkit.craftbukkit.entity.CraftVillager.CraftProfession.minecraftHolderToBukkit(profession), org.bukkit.event.entity.VillagerCareerChangeEvent.ChangeReason.EMPLOYED); -+ if (event.isCancelled()) { -+ return; -+ } +@@ -41,7 +_,14 @@ + .findFirst() + ) + .ifPresent(profession -> { +- body.setVillagerData(body.getVillagerData().withProfession(profession)); ++ // CraftBukkit start - Fire VillagerCareerChangeEvent where Villager gets employed ++ org.bukkit.event.entity.VillagerCareerChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callVillagerCareerChangeEvent(body, org.bukkit.craftbukkit.entity.CraftVillager.CraftProfession.minecraftHolderToBukkit(profession), org.bukkit.event.entity.VillagerCareerChangeEvent.ChangeReason.EMPLOYED); ++ if (event.isCancelled()) { ++ return; ++ } + -+ body.setVillagerData(body.getVillagerData().withProfession(org.bukkit.craftbukkit.entity.CraftVillager.CraftProfession.bukkitToMinecraftHolder(event.getProfession()))); -+ // CraftBukkit end - body.refreshBrain(level); - }); - return true; ++ body.setVillagerData(body.getVillagerData().withProfession(org.bukkit.craftbukkit.entity.CraftVillager.CraftProfession.bukkitToMinecraftHolder(event.getProfession()))); ++ // CraftBukkit end + body.refreshBrain(level); + }); + return true; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java.patch index 8d8868ad1659..3832201368a2 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java +++ b/net/minecraft/world/entity/ai/behavior/HarvestFarmland.java -@@ -108,7 +_,9 @@ +@@ -110,7 +_,9 @@ Block block = blockState.getBlock(); Block blockBelow = level.getBlockState(this.aboveFarmlandPos.below()).getBlock(); if (block instanceof CropBlock && ((CropBlock)block).isMaxAge(blockState)) { @@ -10,7 +10,7 @@ } if (blockState.isAir() && blockBelow instanceof FarmlandBlock && body.hasFarmSeeds()) { -@@ -119,9 +_,11 @@ +@@ -121,9 +_,11 @@ boolean ok = false; if (!itemStack.isEmpty() && itemStack.is(ItemTags.VILLAGER_PLANTABLE_SEEDS) && itemStack.getItem() instanceof BlockItem blockItem) { BlockState place = blockItem.getBlock().defaultBlockState(); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/SleepInBed.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/SleepInBed.java.patch index c293d55736e8..588370453f24 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/SleepInBed.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/SleepInBed.java.patch @@ -1,12 +1,12 @@ --- a/net/minecraft/world/entity/ai/behavior/SleepInBed.java +++ b/net/minecraft/world/entity/ai/behavior/SleepInBed.java -@@ -55,7 +_,8 @@ - } - } - -- BlockState blockState = level.getBlockState(target.pos()); -+ BlockState blockState = level.getBlockStateIfLoaded(target.pos()); // Paper - Prevent sync chunk loads when villagers try to find beds -+ if (blockState == null) { return false; } // Paper - Prevent sync chunk loads when villagers try to find beds - return target.pos().closerToCenterThan(body.position(), 2.0) && blockState.is(BlockTags.BEDS) && !blockState.getValue(BedBlock.OCCUPIED); +@@ -57,7 +_,8 @@ } } + +- BlockState blockState = level.getBlockState(target.pos()); ++ BlockState blockState = level.getBlockStateIfLoaded(target.pos()); // Paper - Prevent sync chunk loads when villagers try to find beds ++ if (blockState == null) return false; // Paper - Prevent sync chunk loads when villagers try to find beds + return target.pos().closerToCenterThan(body.position(), 2.0) && blockState.is(BlockTags.BEDS) && !blockState.getValue(BedBlock.OCCUPIED); + } + diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/StartAttacking.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/StartAttacking.java.patch index 8dcd2a659c5e..fc02b6e3da3f 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/StartAttacking.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/StartAttacking.java.patch @@ -1,20 +1,20 @@ --- a/net/minecraft/world/entity/ai/behavior/StartAttacking.java +++ b/net/minecraft/world/entity/ai/behavior/StartAttacking.java -@@ -29,6 +_,17 @@ - if (!body.canAttack(targetEntity)) { - return false; - } else { -+ // CraftBukkit start -+ org.bukkit.event.entity.EntityTargetEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetLivingEvent(body, targetEntity, (targetEntity instanceof net.minecraft.server.level.ServerPlayer) ? org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER : org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_ENTITY); -+ if (event.isCancelled()) { -+ return false; -+ } -+ if (event.getTarget() == null) { -+ attackTarget.erase(); -+ return true; -+ } -+ targetEntity = ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getTarget()).getHandle(); -+ // CraftBukkit end - attackTarget.set(targetEntity); - cantReachSince.erase(); - return true; +@@ -32,6 +_,17 @@ + return false; + } + ++ // CraftBukkit start ++ org.bukkit.event.entity.EntityTargetEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetLivingEvent(body, targetEntity, (targetEntity instanceof net.minecraft.server.level.ServerPlayer) ? org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER : org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_ENTITY); ++ if (event.isCancelled()) { ++ return false; ++ } ++ if (event.getTarget() == null) { ++ attackTarget.erase(); ++ return true; ++ } ++ targetEntity = ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getTarget()).getHandle(); ++ // CraftBukkit end + attackTarget.set(targetEntity); + cantReachSince.erase(); + return true; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java.patch index 92fca8fa6ab9..8b6e1cb9e9ad 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java +++ b/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java -@@ -40,6 +_,30 @@ - && !stopAttackingWhen.test(level, target)) { +@@ -41,6 +_,30 @@ return true; - } else { + } + + // Paper start - better track target change reason + final org.bukkit.event.entity.EntityTargetEvent.TargetReason reason; + if (!body.canAttack(target)) { @@ -28,6 +28,6 @@ + return true; + } + // CraftBukkit end - onTargetErased.accept(level, body, target); - attackTarget.erase(); - return true; + onTargetErased.accept(level, body, target); + attackTarget.erase(); + return true; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/TransportItemsBetweenContainers.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/TransportItemsBetweenContainers.java.patch index d5c3556c7c9a..daad4f2a12d8 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/TransportItemsBetweenContainers.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/TransportItemsBetweenContainers.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/entity/ai/behavior/TransportItemsBetweenContainers.java +++ b/net/minecraft/world/entity/ai/behavior/TransportItemsBetweenContainers.java -@@ -327,7 +_,10 @@ - } else { - boolean isValidTarget = this.isWantedBlock(body, transportItemTarget.state) - && !this.isPositionAlreadyVisited(visitedPositions, unreachablePositions, transportItemTarget, level) -- && !this.isContainerLocked(transportItemTarget); -+ // Paper start - ItemTransportingEntityValidateTargetEvent -+ && !this.isContainerLocked(transportItemTarget) -+ && org.bukkit.craftbukkit.event.CraftEventFactory.callTransporterValidateTarget(body, level, transportItemTarget.pos); -+ // Paper end - ItemTransportingEntityValidateTargetEvent - return isValidTarget ? transportItemTarget : null; - } - } +@@ -329,7 +_,10 @@ + + boolean isValidTarget = this.isWantedBlock(body, transportItemTarget.state) + && !this.isPositionAlreadyVisited(visitedPositions, unreachablePositions, transportItemTarget, level) +- && !this.isContainerLocked(transportItemTarget); ++ // Paper start - ItemTransportingEntityValidateTargetEvent ++ && !this.isContainerLocked(transportItemTarget) ++ && org.bukkit.craftbukkit.event.CraftEventFactory.callTransporterValidateTarget(body, level, transportItemTarget.pos); ++ // Paper end - ItemTransportingEntityValidateTargetEvent + return isValidTarget ? transportItemTarget : null; + } + diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java.patch index 5ad8af6c0131..2fe52726d4ad 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java.patch @@ -1,23 +1,23 @@ --- a/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java +++ b/net/minecraft/world/entity/ai/behavior/VillagerMakeLove.java -@@ -111,11 +_,17 @@ - if (child == null) { +@@ -112,11 +_,17 @@ return Optional.empty(); - } else { -- source.setAge(6000); -- target.setAge(6000); - child.setAge(-24000); -+ // Paper - Move age setting down - child.snapTo(source.getX(), source.getY(), source.getZ(), 0.0F, 0.0F); -- level.addFreshEntityWithPassengers(child); -+ // CraftBukkit start - call EntityBreedEvent -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreedEvent(child, source, target, null, null, 0).isCancelled()) { -+ return Optional.empty(); -+ } -+ source.setAge(6000); -+ target.setAge(6000); -+ level.addFreshEntityWithPassengers(child, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); -+ // CraftBukkit end - call EntityBreedEvent - level.broadcastEntityEvent(child, EntityEvent.LOVE_HEARTS); - return Optional.of(child); } + +- source.setAge(6000); +- target.setAge(6000); ++ // Paper - Move age setting down + child.setAge(-24000); + child.snapTo(source.getX(), source.getY(), source.getZ(), 0.0F, 0.0F); +- level.addFreshEntityWithPassengers(child); ++ // CraftBukkit start - call EntityBreedEvent ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreedEvent(child, source, target, null, null, 0).isCancelled()) { ++ return Optional.empty(); ++ } ++ source.setAge(6000); ++ target.setAge(6000); ++ level.addFreshEntityWithPassengers(child, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); ++ // CraftBukkit end - call EntityBreedEvent + level.broadcastEntityEvent(child, EntityEvent.LOVE_HEARTS); + return Optional.of(child); + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java.patch index f1da063b5129..fb545187280b 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java +++ b/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java -@@ -71,7 +_,7 @@ +@@ -75,7 +_,7 @@ public void tick() { boolean isOwnerFarAway = this.tamable.shouldTryTeleportToOwner(); if (!isOwnerFarAway) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/Goal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/Goal.java.patch index 6a67fd5bf5a9..2f8f7ce9781c 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/Goal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/Goal.java.patch @@ -33,7 +33,7 @@ + } + // Paper end - Mob goal api + - public static enum Flag { + public enum Flag { + UNKNOWN_BEHAVIOR, // Paper - add UNKNOWN_BEHAVIOR MOVE, LOOK, diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java.patch index 624465630772..a5f1d9673c95 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java.patch @@ -12,7 +12,7 @@ level.removeBlock(eatPos, false); if (!level.isClientSide()) { for (int i = 0; i < 20; i++) { -@@ -119,13 +_,16 @@ +@@ -119,14 +_,17 @@ } private @Nullable BlockPos getPosWithBlock(final BlockPos pos, final BlockGetter level) { @@ -21,16 +21,17 @@ + if (state == null) return null; // Paper - Prevent AI rules from loading chunks + if (state.is(this.blockToRemove)) { // Paper - Prevent AI rules from loading chunks return pos; - } else { - BlockPos[] neighbours = new BlockPos[]{pos.below(), pos.west(), pos.east(), pos.north(), pos.south(), pos.below().below()}; + } - for (BlockPos neighborPos : neighbours) { -- if (level.getBlockState(neighborPos).is(this.blockToRemove)) { -+ net.minecraft.world.level.block.state.BlockState neighborState = level.getBlockStateIfLoaded(neighborPos); // Paper - Prevent AI rules from loading chunks -+ if (neighborState != null && neighborState.is(this.blockToRemove)) { // Paper - Prevent AI rules from loading chunks - return neighborPos; - } + BlockPos[] neighbours = new BlockPos[]{pos.below(), pos.west(), pos.east(), pos.north(), pos.south(), pos.below().below()}; + + for (BlockPos neighborPos : neighbours) { +- if (level.getBlockState(neighborPos).is(this.blockToRemove)) { ++ net.minecraft.world.level.block.state.BlockState neighborState = level.getBlockStateIfLoaded(neighborPos); // Paper - Prevent AI rules from loading chunks ++ if (neighborState != null && neighborState.is(this.blockToRemove)) { // Paper - Prevent AI rules from loading chunks + return neighborPos; } + } @@ -136,7 +_,7 @@ @Override diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/target/TargetGoal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/target/TargetGoal.java.patch index 0c6f02b444d1..7ca76b3686cf 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/target/TargetGoal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/goal/target/TargetGoal.java.patch @@ -1,15 +1,15 @@ --- a/net/minecraft/world/entity/ai/goal/target/TargetGoal.java +++ b/net/minecraft/world/entity/ai/goal/target/TargetGoal.java -@@ -62,7 +_,7 @@ - } - } - -- this.mob.setTarget(target); -+ this.mob.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_ENTITY); // CraftBukkit - return true; - } +@@ -67,7 +_,7 @@ } -@@ -82,7 +_,7 @@ + } + +- this.mob.setTarget(target); ++ this.mob.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_ENTITY); // CraftBukkit + return true; + } + +@@ -84,7 +_,7 @@ @Override public void stop() { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java.patch index 690e75c20979..73fb01ecad5e 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java.patch @@ -9,15 +9,15 @@ LevelChunk chunk = this.level.getChunkSource().getChunkNow(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())); if (chunk == null) { return null; -@@ -51,7 +_,7 @@ - pos = this.findSurfacePosition(chunk, pos, reachRange); - } - -- return super.createPath(pos, reachRange); -+ return super.createPath(pos, entity, reachRange); // Paper - EntityPathfindEvent +@@ -52,7 +_,7 @@ + pos = this.findSurfacePosition(chunk, pos, reachRange); } + +- return super.createPath(pos, reachRange); ++ return super.createPath(pos, entity, reachRange); // Paper - EntityPathfindEvent } + final BlockPos findSurfacePosition(final LevelChunk chunk, BlockPos pos, final int reachRange) { @@ -91,7 +_,7 @@ @Override diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/PathNavigation.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/PathNavigation.java.patch index eabd006e9a8a..edd296d0a661 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/PathNavigation.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/navigation/PathNavigation.java.patch @@ -39,33 +39,33 @@ + // Paper end - EntityPathfindEvent if (targets.isEmpty()) { return null; - } else if (this.mob.getY() < this.level.getMinY()) { -@@ -149,6 +_,23 @@ - } else if (this.path != null && !this.path.isDone() && targets.contains(this.targetPos)) { + } +@@ -156,6 +_,23 @@ return this.path; - } else { -+ // Paper start - EntityPathfindEvent -+ boolean copiedSet = false; -+ for (BlockPos possibleTarget : targets) { -+ if (!this.mob.level().getWorldBorder().isWithinBounds(possibleTarget) || !new com.destroystokyo.paper.event.entity.EntityPathfindEvent(this.mob.getBukkitEntity(), // Paper - don't path out of world border -+ org.bukkit.craftbukkit.util.CraftLocation.toBukkit(possibleTarget, this.mob.level()), target == null ? null : target.getBukkitEntity()).callEvent()) { -+ if (!copiedSet) { -+ copiedSet = true; -+ targets = new java.util.HashSet<>(targets); -+ } -+ // note: since we copy the set this remove call is safe, since we're iterating over the old copy -+ targets.remove(possibleTarget); -+ if (targets.isEmpty()) { -+ return null; -+ } + } + ++ // Paper start - EntityPathfindEvent ++ boolean copiedSet = false; ++ for (BlockPos possibleTarget : targets) { ++ if (!this.mob.level().getWorldBorder().isWithinBounds(possibleTarget) || !new com.destroystokyo.paper.event.entity.EntityPathfindEvent(this.mob.getBukkitEntity(), // Paper - don't path out of world border ++ org.bukkit.craftbukkit.util.CraftLocation.toBukkit(possibleTarget, this.mob.level()), target == null ? null : target.getBukkitEntity()).callEvent()) { ++ if (!copiedSet) { ++ copiedSet = true; ++ targets = new java.util.HashSet<>(targets); ++ } ++ // note: since we copy the set this remove call is safe, since we're iterating over the old copy ++ targets.remove(possibleTarget); ++ if (targets.isEmpty()) { ++ return null; + } + } -+ // Paper end - EntityPathfindEvent - ProfilerFiller profiler = Profiler.get(); - profiler.push("pathfind"); - BlockPos fromPos = above ? this.mob.blockPosition().above() : this.mob.blockPosition(); -@@ -168,6 +_,11 @@ - } ++ } ++ // Paper end - EntityPathfindEvent + ProfilerFiller profiler = Profiler.get(); + profiler.push("pathfind"); + BlockPos fromPos = above ? this.mob.blockPosition().above() : this.mob.blockPosition(); +@@ -172,6 +_,11 @@ + return path; } + // Paper start - Perf: Optimise pathfinding @@ -76,7 +76,7 @@ public boolean moveTo(final double x, final double y, final double z, final double speedModifier) { return this.moveTo(this.createPath(x, y, z, 1), speedModifier); } -@@ -177,8 +_,23 @@ +@@ -181,8 +_,23 @@ } public boolean moveTo(final Entity target, final double speedModifier) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ai/village/VillageSiege.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ai/village/VillageSiege.java.patch index c4ded0a08a6a..36798fdc2f68 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ai/village/VillageSiege.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ai/village/VillageSiege.java.patch @@ -2,9 +2,9 @@ +++ b/net/minecraft/world/entity/ai/village/VillageSiege.java @@ -102,11 +_,12 @@ zombie.finalizeSpawn(level, level.getCurrentDifficultyAt(zombie.blockPosition()), EntitySpawnReason.EVENT, null); - } catch (Exception var5) { - LOGGER.warn("Failed to create zombie for village siege at {}", spawnPos, var5); -+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(var5); // Paper - ServerExceptionEvent + } catch (Exception e) { + LOGGER.warn("Failed to create zombie for village siege at {}", spawnPos, e); ++ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(e); // Paper - ServerExceptionEvent return; } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/ambient/Bat.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/ambient/Bat.java.patch index 78d43b3d6a2a..3a1e67502bbd 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/ambient/Bat.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/ambient/Bat.java.patch @@ -34,12 +34,12 @@ this.setResting(true); } } -@@ -200,7 +_,7 @@ - if (this.isInvulnerableTo(level, source)) { +@@ -201,7 +_,7 @@ return false; - } else { -- if (this.isResting()) { -+ if (this.isResting() && org.bukkit.craftbukkit.event.CraftEventFactory.handleBatToggleSleepEvent(this, true)) { // CraftBukkit - Call BatToggleSleepEvent - this.setResting(false); - } + } + +- if (this.isResting()) { ++ if (this.isResting() && org.bukkit.craftbukkit.event.CraftEventFactory.handleBatToggleSleepEvent(this, true)) { // CraftBukkit - Call BatToggleSleepEvent + this.setResting(false); + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/allay/Allay.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/allay/Allay.java.patch index 6bff6c78716a..4f0f4e0f07d2 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/allay/Allay.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/allay/Allay.java.patch @@ -44,7 +44,7 @@ this.level().broadcastEntityEvent(this, EntityEvent.IN_LOVE_HEARTS); this.level().playSound(player, this, SoundEvents.AMETHYST_BLOCK_CHIME, SoundSource.NEUTRAL, 2.0F, 1.0F); this.removeInteractionItem(player, interactionItem); -@@ -381,6 +_,7 @@ +@@ -385,6 +_,7 @@ } private boolean shouldStopDancing() { @@ -52,7 +52,7 @@ return this.jukeboxPos == null || !this.jukeboxPos.closerToCenterThan(this.position(), GameEvent.JUKEBOX_PLAY.value().notificationRadius()) || !this.level().getBlockState(this.jukeboxPos).is(Blocks.JUKEBOX); -@@ -433,7 +_,7 @@ +@@ -437,7 +_,7 @@ super.readAdditionalSaveData(input); this.readInventoryFromTag(input); this.vibrationData = input.read("listener", VibrationSystem.Data.CODEC).orElseGet(VibrationSystem.Data::new); @@ -61,7 +61,7 @@ } @Override -@@ -452,15 +_,17 @@ +@@ -456,15 +_,17 @@ this.entityData.set(DATA_CAN_DUPLICATE, duplicationCooldown == 0L); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/armadillo/Armadillo.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/armadillo/Armadillo.java.patch index 77e4f5dc38d0..eebfeca11a01 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/armadillo/Armadillo.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/armadillo/Armadillo.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/animal/armadillo/Armadillo.java +++ b/net/minecraft/world/entity/animal/armadillo/Armadillo.java -@@ -145,10 +_,12 @@ +@@ -144,10 +_,12 @@ ArmadilloAi.updateActivity(this); profiler.pop(); if (this.isAlive() && --this.scuteTime <= 0 && this.shouldDropLoot(level)) { @@ -13,7 +13,7 @@ this.scuteTime = this.pickNextScuteDropTime(); } -@@ -285,8 +_,11 @@ +@@ -284,8 +_,11 @@ } @Override @@ -27,7 +27,7 @@ if (!this.isNoAi() && !this.isDeadOrDying()) { if (source.getEntity() instanceof LivingEntity) { this.getBrain().setMemoryWithExpiry(MemoryModuleType.DANGER_DETECTED_RECENTLY, true, 80L); -@@ -297,6 +_,7 @@ +@@ -296,6 +_,7 @@ this.rollOut(); } } @@ -36,12 +36,12 @@ @Override @@ -315,7 +_,9 @@ - return false; - } else { - if (this.level() instanceof ServerLevel level) { -+ this.forceDrops = true; // CraftBukkit - this.dropFromEntityInteractLootTable(level, BuiltInLootTables.ARMADILLO_BRUSH, interactingEntity, tool, this::spawnAtLocation); -+ this.forceDrops = false; // CraftBukkit - this.playSound(SoundEvents.ARMADILLO_BRUSH); - this.gameEvent(GameEvent.ENTITY_INTERACT); - } + } + + if (this.level() instanceof ServerLevel level) { ++ this.forceDrops = true; // CraftBukkit + this.dropFromEntityInteractLootTable(level, BuiltInLootTables.ARMADILLO_BRUSH, interactingEntity, tool, this::spawnAtLocation); ++ this.forceDrops = false; // CraftBukkit + this.playSound(SoundEvents.ARMADILLO_BRUSH); + this.gameEvent(GameEvent.ENTITY_INTERACT); + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/axolotl/Axolotl.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/axolotl/Axolotl.java.patch index 4b25ea0df6ad..dbfa9347d75d 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/axolotl/Axolotl.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/axolotl/Axolotl.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/animal/axolotl/Axolotl.java +++ b/net/minecraft/world/entity/animal/axolotl/Axolotl.java -@@ -270,7 +_,7 @@ +@@ -269,7 +_,7 @@ @Override public int getMaxAirSupply() { @@ -9,7 +9,7 @@ } public Axolotl.Variant getVariant() { -@@ -484,10 +_,10 @@ +@@ -483,10 +_,10 @@ if (regenEffect == null || regenEffect.endsWithin(2399)) { int previousDuration = regenEffect != null ? regenEffect.getDuration() : 0; int regenDuration = Math.min(2400, 100 + previousDuration); @@ -22,7 +22,7 @@ } @Override -@@ -565,6 +_,13 @@ +@@ -564,6 +_,13 @@ ) { return level.getBlockState(pos.below()).is(BlockTags.AXOLOTLS_SPAWNABLE_ON); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/bee/Bee.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/bee/Bee.java.patch index 9764afc7614d..d34102f08aa1 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/bee/Bee.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/bee/Bee.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/animal/bee/Bee.java +++ b/net/minecraft/world/entity/animal/bee/Bee.java -@@ -150,10 +_,26 @@ +@@ -149,10 +_,26 @@ private Bee.BeeGoToHiveGoal goToHiveGoal; private Bee.BeeGoToKnownFlowerGoal goToKnownFlowerGoal; private int underWaterTicks; @@ -28,7 +28,7 @@ this.lookControl = new Bee.BeeLookControl(this); this.setPathfindingMalus(PathType.FIRE_IN_NEIGHBOR, -1.0F); this.setPathfindingMalus(PathType.WATER, -1.0F); -@@ -200,9 +_,18 @@ +@@ -199,9 +_,18 @@ @Override protected void addAdditionalSaveData(final ValueOutput output) { @@ -47,7 +47,7 @@ output.putBoolean("HasNectar", this.hasNectar()); output.putBoolean("HasStung", this.hasStung()); output.putInt("TicksSincePollination", this.ticksWithoutNectarSinceExitingHive); -@@ -240,7 +_,7 @@ +@@ -239,7 +_,7 @@ } if (poisonTime > 0) { @@ -56,7 +56,7 @@ } } -@@ -483,7 +_,11 @@ +@@ -482,7 +_,11 @@ if (this.hivePos == null) { return null; } else { @@ -69,7 +69,7 @@ } } -@@ -515,7 +_,8 @@ +@@ -514,7 +_,8 @@ return this.getFlag(FLAG_ROLL); } @@ -79,7 +79,7 @@ this.setFlag(FLAG_ROLL, rolling); } -@@ -576,7 +_,7 @@ +@@ -571,7 +_,7 @@ if (effect != null) { this.usePlayerItem(player, hand, heldItem); if (!this.level().isClientSide()) { @@ -88,18 +88,18 @@ } return InteractionResult.SUCCESS; -@@ -644,8 +_,9 @@ - if (this.isInvulnerableTo(level, source)) { +@@ -640,8 +_,9 @@ return false; - } else { -+ if (!super.hurtServer(level, source, damage)) return false; // CraftBukkit - Only stop pollinating if entity was damaged - this.beePollinateGoal.stopPollinating(); -- return super.hurtServer(level, source, damage); -+ return true; // CraftBukkit - Only stop pollinating if entity was damaged } + ++ if (!super.hurtServer(level, source, damage)) return false; // CraftBukkit - Only stop pollinating if entity was damaged + this.beePollinateGoal.stopPollinating(); +- return super.hurtServer(level, source, damage); ++ return true; // CraftBukkit - Only stop pollinating if entity was damaged } -@@ -1007,7 +_,7 @@ + @Override +@@ -981,7 +_,7 @@ } } @@ -108,7 +108,7 @@ Bee.this.level().levelEvent(LevelEvent.PARTICLES_BEE_GROWTH, belowPos, 15); Bee.this.level().setBlockAndUpdate(belowPos, growState); Bee.this.incrementNumCropsGrownSincePollination(); -@@ -1032,7 +_,7 @@ +@@ -1005,7 +_,7 @@ @Override protected void alertOther(final Mob other, final LivingEntity hurtByMob) { if (other instanceof Bee && this.mob.hasLineOfSight(hurtByMob)) { @@ -117,7 +117,7 @@ } } } -@@ -1198,7 +_,7 @@ +@@ -1162,7 +_,7 @@ Bee.this.dropFlower(); this.pollinating = false; Bee.this.remainingCooldownBeforeLocatingNewFlower = 200; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/camel/Camel.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/camel/Camel.java.patch index 1514f5e2c95c..f8b8732305f8 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/camel/Camel.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/camel/Camel.java.patch @@ -1,21 +1,21 @@ --- a/net/minecraft/world/entity/animal/camel/Camel.java +++ b/net/minecraft/world/entity/animal/camel/Camel.java @@ -419,12 +_,12 @@ - } else { - boolean couldHeal = this.getHealth() < this.getMaxHealth(); - if (couldHeal) { -- this.heal(2.0F); -+ this.heal(2.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.EATING); // Paper - Add missing regain reason - } - - boolean couldSetInLove = this.isTamed() && this.getAge() == 0 && this.canFallInLove(); - if (couldSetInLove) { -- this.setInLove(player); -+ this.setInLove(player, itemStack.copy()); // Paper - Fix EntityBreedEvent copying - } - - boolean couldAgeUp = this.canAgeUp(); -@@ -482,9 +_,13 @@ + + boolean couldHeal = this.getHealth() < this.getMaxHealth(); + if (couldHeal) { +- this.heal(2.0F); ++ this.heal(2.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.EATING); // Paper - Add missing regain reason + } + + boolean couldSetInLove = this.isTamed() && this.getAge() == 0 && this.canFallInLove(); + if (couldSetInLove) { +- this.setInLove(player); ++ this.setInLove(player, itemStack.copy()); // Paper - Fix EntityBreedEvent copying + } + + boolean couldAgeUp = this.canAgeUp(); +@@ -481,9 +_,13 @@ } @Override @@ -31,7 +31,7 @@ } @Override -@@ -581,7 +_,7 @@ +@@ -580,7 +_,7 @@ } public void sitDown() { @@ -40,7 +40,7 @@ this.makeSound(this.getSitDownSound()); this.setPose(Pose.SITTING); this.gameEvent(GameEvent.ENTITY_ACTION); -@@ -590,7 +_,7 @@ +@@ -589,7 +_,7 @@ } public void standUp() { @@ -49,7 +49,7 @@ this.makeSound(this.getStandUpSound()); this.setPose(Pose.STANDING); this.gameEvent(GameEvent.ENTITY_ACTION); -@@ -607,6 +_,7 @@ +@@ -606,6 +_,7 @@ } public void standUpInstantly() { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/dolphin/Dolphin.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/dolphin/Dolphin.java.patch index 566982fdccc6..9d5f60997782 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/dolphin/Dolphin.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/dolphin/Dolphin.java.patch @@ -58,7 +58,7 @@ } } } -@@ -573,7 +_,7 @@ +@@ -571,7 +_,7 @@ 0.3F * Mth.sin(Dolphin.this.getXRot() * Mth.DEG_TO_RAD) * 1.5F, 0.3F * Mth.cos(Dolphin.this.getYRot() * Mth.DEG_TO_RAD) * Mth.cos(Dolphin.this.getXRot() * Mth.DEG_TO_RAD) + Mth.sin(dir) * pow2 ); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/AbstractChestedHorse.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/AbstractChestedHorse.java.patch index 5e1eb25224f2..f0d60ff3e63d 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/AbstractChestedHorse.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/AbstractChestedHorse.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/animal/equine/AbstractChestedHorse.java +++ b/net/minecraft/world/entity/animal/equine/AbstractChestedHorse.java -@@ -75,6 +_,12 @@ +@@ -74,6 +_,12 @@ super.dropEquipment(level); if (this.hasChest()) { this.spawnAtLocation(level, Blocks.CHEST); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/AbstractHorse.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/AbstractHorse.java.patch index 73571e79cb8a..c29009405f50 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/AbstractHorse.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/equine/AbstractHorse.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/animal/equine/AbstractHorse.java +++ b/net/minecraft/world/entity/animal/equine/AbstractHorse.java -@@ -125,6 +_,7 @@ +@@ -124,6 +_,7 @@ protected boolean canGallop = true; protected int gallopSoundCounter; public @Nullable EntityReference owner; @@ -8,7 +8,7 @@ protected AbstractHorse(final EntityType type, final Level level) { super(type, level); -@@ -253,7 +_,7 @@ +@@ -252,7 +_,7 @@ } @Override @@ -17,7 +17,7 @@ return !this.isVehicle(); } -@@ -300,7 +_,7 @@ +@@ -299,7 +_,7 @@ public void createInventory() { SimpleContainer old = this.inventory; @@ -26,7 +26,7 @@ if (old != null) { int max = Math.min(old.getContainerSize(), this.inventory.getContainerSize()); -@@ -392,7 +_,7 @@ +@@ -391,7 +_,7 @@ } public int getMaxTemper() { @@ -35,7 +35,7 @@ } @Override -@@ -455,7 +_,7 @@ +@@ -454,7 +_,7 @@ temper = 5; if (!this.level().isClientSide() && this.isTamed() && this.getAge() == 0 && !this.isInLove()) { itemUsed = true; @@ -44,7 +44,7 @@ } } else if (itemStack.is(Items.GOLDEN_APPLE) || itemStack.is(Items.ENCHANTED_GOLDEN_APPLE)) { heal = 10.0F; -@@ -463,12 +_,12 @@ +@@ -462,12 +_,12 @@ temper = 10; if (!this.level().isClientSide() && this.isTamed() && this.getAge() == 0 && !this.isInLove()) { itemUsed = true; @@ -59,7 +59,7 @@ itemUsed = true; } -@@ -539,7 +_,7 @@ +@@ -538,7 +_,7 @@ super.aiStep(); if (this.level() instanceof ServerLevel level && this.isAlive()) { if (this.random.nextInt(900) == 0 && this.deathTime == 0) { @@ -68,7 +68,7 @@ } if (this.canEatGrass()) { -@@ -641,6 +_,16 @@ +@@ -640,6 +_,16 @@ } } @@ -85,7 +85,7 @@ @Override public InteractionResult mobInteract(final Player player, final InteractionHand hand) { if (this.isVehicle() || this.isBaby()) { -@@ -792,6 +_,7 @@ +@@ -793,6 +_,7 @@ output.putInt("Temper", this.getTemper()); output.putBoolean("Tame", this.isTamed()); EntityReference.store(this.owner, output, "Owner"); @@ -93,7 +93,7 @@ } @Override -@@ -802,6 +_,7 @@ +@@ -803,6 +_,7 @@ this.setTemper(input.getIntOr("Temper", 0)); this.setTamed(input.getBooleanOr("Tame", false)); this.owner = EntityReference.readWithOldOwnerConversion(input, "Owner", this.level()); @@ -101,7 +101,7 @@ } @Override -@@ -895,6 +_,17 @@ +@@ -896,6 +_,17 @@ @Override public void handleStartJump(final int jumpScale) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/feline/Cat.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/feline/Cat.java.patch index b759422d79b9..d2befdb881c0 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/feline/Cat.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/feline/Cat.java.patch @@ -21,7 +21,7 @@ this.tame(player); this.setOrderedToSit(true); this.level().broadcastEntityEvent(this, EntityEvent.TAMING_SUCCEEDED); -@@ -601,15 +_,20 @@ +@@ -603,15 +_,20 @@ .dropFromGiftLootTable( getServerLevel(this.cat), BuiltInLootTables.CAT_MORNING_GIFT, @@ -46,7 +46,7 @@ ); } -@@ -635,7 +_,7 @@ +@@ -637,7 +_,7 @@ } private static class CatTemptGoal extends TemptGoal { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/fox/Fox.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/fox/Fox.java.patch index 19a985077464..0a4c063705b7 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/fox/Fox.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/fox/Fox.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/animal/fox/Fox.java +++ b/net/minecraft/world/entity/animal/fox/Fox.java -@@ -447,7 +_,7 @@ +@@ -446,7 +_,7 @@ input.read("Trusted", TRUSTED_LIST_CODEC).orElse(List.of()).forEach(this::addTrustedEntity); this.setSleeping(input.getBooleanOr("Sleeping", false)); this.setVariant(input.read("Type", Fox.Variant.CODEC).orElse(Fox.Variant.DEFAULT)); @@ -9,7 +9,7 @@ this.setIsCrouching(input.getBooleanOr("Crouching", false)); if (this.level() instanceof ServerLevel) { this.setTargetGoals(); -@@ -464,6 +_,12 @@ +@@ -463,6 +_,12 @@ } public void setSitting(final boolean value) { @@ -22,19 +22,19 @@ this.setFlag(FLAG_SITTING, value); } -@@ -523,19 +_,20 @@ +@@ -522,19 +_,20 @@ thrownItem.setPickUpDelay(40); thrownItem.setThrower(this); this.playSound(SoundEvents.FOX_SPIT, 1.0F, 1.0F); - this.level().addFreshEntity(thrownItem); -+ this.spawnAtLocation((net.minecraft.server.level.ServerLevel) this.level(), thrownItem); // Paper - Call EntityDropItemEvent ++ this.spawnAtLocation((ServerLevel) this.level(), thrownItem); // Paper - Call EntityDropItemEvent } } private void dropItemStack(final ItemStack itemStack) { ItemEntity itemEntity = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), itemStack); - this.level().addFreshEntity(itemEntity); -+ this.spawnAtLocation((net.minecraft.server.level.ServerLevel) this.level(), itemEntity); // Paper - Call EntityDropItemEvent ++ this.spawnAtLocation((ServerLevel) this.level(), itemEntity); // Paper - Call EntityDropItemEvent } @Override @@ -46,7 +46,7 @@ int count = itemStack.getCount(); if (count > 1) { this.dropItemStack(itemStack.split(count - 1)); -@@ -546,7 +_,7 @@ +@@ -545,7 +_,7 @@ this.setItemSlot(EquipmentSlot.MAINHAND, itemStack.split(1)); this.setGuaranteedDrop(EquipmentSlot.MAINHAND); this.take(entity, itemStack.getCount()); @@ -55,7 +55,7 @@ this.ticksSinceEaten = 0; } } -@@ -637,12 +_,12 @@ +@@ -636,12 +_,12 @@ } @Override @@ -70,7 +70,7 @@ } private void wakeUp() { -@@ -703,15 +_,33 @@ +@@ -702,15 +_,33 @@ return this.getTrustedEntities().anyMatch(trusted -> trusted.matches(entity)); } @@ -108,7 +108,7 @@ } public static boolean isPathClear(final Fox fox, final LivingEntity target) { -@@ -896,6 +_,19 @@ +@@ -883,6 +_,19 @@ offspring.addTrustedEntity(partnerLoveCause); } @@ -128,7 +128,7 @@ if (loveCause != null) { loveCause.awardStat(Stats.ANIMALS_BRED); CriteriaTriggers.BRED_ANIMALS.trigger(loveCause, this.animal, this.partner, offspring); -@@ -905,14 +_,12 @@ +@@ -892,14 +_,12 @@ this.partner.setAge(6000); this.animal.resetLove(); this.partner.resetLove(); @@ -146,7 +146,7 @@ ); } } -@@ -977,6 +_,7 @@ +@@ -963,6 +_,7 @@ private void pickSweetBerries(final BlockState state) { int age = state.getValue(SweetBerryBushBlock.AGE); state.setValue(SweetBerryBushBlock.AGE, 1); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/goat/Goat.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/goat/Goat.java.patch index c227d33d1bac..9f0ecb43c037 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/goat/Goat.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/goat/Goat.java.patch @@ -17,17 +17,17 @@ + ItemStack bucketOrMilkBucket = ItemUtils.createFilledResult(heldItem, player, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack())); // CraftBukkit player.setItemInHand(hand, bucketOrMilkBucket); return InteractionResult.SUCCESS; - } else { -@@ -328,8 +_,7 @@ - double deltaY = Mth.randomBetween(this.random, 0.3F, 0.7F); - double deltaZ = Mth.randomBetween(this.random, -0.2F, 0.2F); - ItemEntity itemEntity = new ItemEntity(this.level(), bodyPosition.x(), bodyPosition.y(), bodyPosition.z(), item, deltaX, deltaY, deltaZ); -- this.level().addFreshEntity(itemEntity); -- return true; -+ return this.spawnAtLocation((net.minecraft.server.level.ServerLevel) this.level(), itemEntity) != null; // Paper - Call EntityDropItemEvent - } } +@@ -330,8 +_,7 @@ + double deltaY = Mth.randomBetween(this.random, 0.3F, 0.7F); + double deltaZ = Mth.randomBetween(this.random, -0.2F, 0.2F); + ItemEntity itemEntity = new ItemEntity(this.level(), bodyPosition.x(), bodyPosition.y(), bodyPosition.z(), item, deltaX, deltaY, deltaZ); +- this.level().addFreshEntity(itemEntity); +- return true; ++ return this.spawnAtLocation((ServerLevel) this.level(), itemEntity) != null; // Paper - Call EntityDropItemEvent } + + public boolean isScreamingGoat() { @@ -352,4 +_,15 @@ ) { return level.getBlockState(pos.below()).is(BlockTags.GOATS_SPAWNABLE_ON) && isBrightEnoughToSpawn(level, pos); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/golem/CopperGolem.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/golem/CopperGolem.java.patch index e5842b62dbdd..a9689ab74200 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/golem/CopperGolem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/golem/CopperGolem.java.patch @@ -37,7 +37,7 @@ this.gameEvent(GameEvent.SHEAR, player); itemStack.hurtAndBreak(1, player, hand); } -@@ -281,20 +_,27 @@ +@@ -287,20 +_,27 @@ private void turnToStatue(final ServerLevel level) { BlockPos pos = this.blockPosition(); @@ -71,7 +71,7 @@ this.playSound(SoundEvents.COPPER_GOLEM_BECOME_STATUE); if (this.isLeashed()) { if (level.getGameRules().get(GameRules.ENTITY_DROPS)) { -@@ -424,12 +_,32 @@ +@@ -430,12 +_,32 @@ } @Override @@ -108,7 +108,7 @@ @Override public boolean readyForShearing() { -@@ -443,9 +_,13 @@ +@@ -449,9 +_,13 @@ } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/golem/IronGolem.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/golem/IronGolem.java.patch index afbb13319fe3..88a50e071cab 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/golem/IronGolem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/golem/IronGolem.java.patch @@ -16,5 +16,5 @@ - if (!below.entityCanStandOn(level, belowPos, this)) { + if (!below.entityCanStandOn(level, belowPos, this) && !this.level().paperConfig().entities.spawning.ironGolemsCanSpawnInAir) { // Paper - Add option to allow iron golems to spawn in air return false; - } else { - for (int i = 1; i < 3; i++) { + } + diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/happyghast/HappyGhast.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/happyghast/HappyGhast.java.patch index e201972bc875..270b632f02a4 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/happyghast/HappyGhast.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/happyghast/HappyGhast.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/animal/happyghast/HappyGhast.java +++ b/net/minecraft/world/entity/animal/happyghast/HappyGhast.java -@@ -300,7 +_,7 @@ +@@ -299,7 +_,7 @@ @Override protected void addPassenger(final Entity passenger) { if (!this.isVehicle()) { @@ -9,7 +9,7 @@ } super.addPassenger(passenger); -@@ -314,16 +_,21 @@ +@@ -313,16 +_,21 @@ } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/nautilus/AbstractNautilus.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/nautilus/AbstractNautilus.java.patch index 3d324243e54b..2acdfb97c877 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/nautilus/AbstractNautilus.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/nautilus/AbstractNautilus.java.patch @@ -23,7 +23,7 @@ } } } -@@ -431,7 +_,7 @@ +@@ -433,7 +_,7 @@ } private void tryToTame(final Player player) { @@ -32,7 +32,7 @@ this.tame(player); this.navigation.stop(); this.level().broadcastEntityEvent(this, EntityEvent.TAMING_SUCCEEDED); -@@ -486,7 +_,7 @@ +@@ -488,7 +_,7 @@ protected void createInventory() { SimpleContainer old = this.inventory; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/panda/Panda.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/panda/Panda.java.patch index 422c65d8fdf1..91e231893a2b 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/panda/Panda.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/panda/Panda.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/animal/panda/Panda.java +++ b/net/minecraft/world/entity/animal/panda/Panda.java -@@ -133,6 +_,7 @@ +@@ -132,6 +_,7 @@ } public void sit(final boolean value) { @@ -8,7 +8,7 @@ this.setFlag(FLAG_SIT, value); } -@@ -517,24 +_,28 @@ +@@ -516,24 +_,28 @@ for (Panda panda : level.getEntitiesOfClass(Panda.class, this.getBoundingBox().inflate(10.0))) { if (!panda.isBaby() && panda.onGround() && !panda.isInWater() && panda.canPerformAction()) { @@ -39,7 +39,7 @@ } } -@@ -629,8 +_,9 @@ +@@ -632,8 +_,9 @@ } if (!this.level().isClientSide() && this.getAge() == 0 && this.canFallInLove()) { @@ -50,7 +50,7 @@ } else { if (!(this.level() instanceof ServerLevel level) || this.isSitting() || this.isInWater()) { return InteractionResult.PASS; -@@ -640,7 +_,9 @@ +@@ -643,7 +_,9 @@ this.eat(true); ItemStack pandasCurrentItem = this.getItemBySlot(EquipmentSlot.MAINHAND); if (!pandasCurrentItem.isEmpty() && !player.hasInfiniteMaterials()) { @@ -60,7 +60,7 @@ } this.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(interactionItemStack.getItem(), 1)); -@@ -862,7 +_,7 @@ +@@ -867,7 +_,7 @@ @Override protected void alertOther(final Mob other, final LivingEntity hurtByMob) { if (other instanceof Panda && other.isAggressive()) { @@ -69,7 +69,7 @@ } } } -@@ -1093,7 +_,9 @@ +@@ -1094,7 +_,9 @@ public void stop() { ItemStack itemStack = Panda.this.getItemBySlot(EquipmentSlot.MAINHAND); if (!itemStack.isEmpty()) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/parrot/Parrot.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/parrot/Parrot.java.patch index d5100bd9db08..8eb4f36a6677 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/parrot/Parrot.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/parrot/Parrot.java.patch @@ -29,18 +29,18 @@ } @Override -@@ -400,8 +_,13 @@ - if (this.isInvulnerableTo(level, source)) { +@@ -401,8 +_,13 @@ return false; - } else { -+ // CraftBukkit start -+ if (!super.hurtServer(level, source, damage)) { -+ return false; -+ } - this.setOrderedToSit(false); -- return super.hurtServer(level, source, damage); -+ return true; -+ // CraftBukkit } + ++ // CraftBukkit start ++ if (!super.hurtServer(level, source, damage)) { ++ return false; ++ } ++ // CraftBukkit end + this.setOrderedToSit(false); +- return super.hurtServer(level, source, damage); ++ return true; // CraftBukkit } + public Parrot.Variant getVariant() { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/pig/Pig.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/pig/Pig.java.patch index 1876e579f8ef..a2a9d4c236a9 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/pig/Pig.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/pig/Pig.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/animal/pig/Pig.java +++ b/net/minecraft/world/entity/animal/pig/Pig.java -@@ -198,7 +_,14 @@ +@@ -196,7 +_,14 @@ ZombifiedPiglin zombifiedPiglin = this.convertTo(EntityType.ZOMBIFIED_PIGLIN, ConversionParams.single(this, false, true), zp -> { zp.populateDefaultEquipmentSlots(this.getRandom(), level.getCurrentDifficultyAt(this.blockPosition())); zp.setPersistenceRequired(); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/wolf/Wolf.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/wolf/Wolf.java.patch index 601db61365af..baad5b92c99b 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/animal/wolf/Wolf.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/wolf/Wolf.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/entity/animal/wolf/Wolf.java +++ b/net/minecraft/world/entity/animal/wolf/Wolf.java -@@ -396,16 +_,18 @@ - if (this.isInvulnerableTo(level, source)) { +@@ -396,15 +_,18 @@ return false; - } else { -+ if (!super.hurtServer(level, source, damage)) return false; // CraftBukkit - this.setOrderedToSit(false); -- return super.hurtServer(level, source, damage); -+ return true; // CraftBukkit } + ++ if (!super.hurtServer(level, source, damage)) return false; // CraftBukkit + this.setOrderedToSit(false); +- return super.hurtServer(level, source, damage); ++ return true; // CraftBukkit ++ } @Override @@ -22,7 +22,7 @@ ItemStack armorBefore = this.getBodyArmorItem(); int damageBefore = armorBefore.getDamageValue(); int maxDamage = armorBefore.getMaxDamage(); -@@ -417,6 +_,7 @@ +@@ -416,6 +_,7 @@ ); } } @@ -30,7 +30,7 @@ } private boolean canArmorAbsorb(final DamageSource source) { -@@ -427,7 +_,7 @@ +@@ -426,7 +_,7 @@ protected void applyTamingSideEffects() { if (this.isTame()) { this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(40.0); @@ -39,7 +39,7 @@ } else { this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(8.0); } -@@ -477,7 +_,7 @@ +@@ -476,7 +_,7 @@ this.setOrderedToSit(!this.isOrderedToSit()); this.jumping = false; this.navigation.stop(); @@ -48,7 +48,7 @@ return InteractionResult.SUCCESS.withoutItem(); } -@@ -486,6 +_,25 @@ +@@ -485,6 +_,25 @@ DyeColor color = itemStack.get(DataComponents.DYE); if (color != null && color != this.getCollarColor()) { @@ -74,7 +74,7 @@ this.setCollarColor(color); itemStack.consume(1, player); return InteractionResult.SUCCESS; -@@ -500,7 +_,7 @@ +@@ -499,7 +_,7 @@ } private void tryToTame(final Player player) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch index 7900660e9112..6c255ac04f2e 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java.patch @@ -48,30 +48,30 @@ } @Override -@@ -92,10 +_,24 @@ - return false; - } else { - if (!this.isRemoved()) { -- this.remove(Entity.RemovalReason.KILLED); -+ // CraftBukkit start - All non-living entities need this -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, damage, false)) { +@@ -95,10 +_,24 @@ + } + + if (!this.isRemoved()) { +- this.remove(Entity.RemovalReason.KILLED); ++ // CraftBukkit start - All non-living entities need this ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, damage, false)) { ++ return false; ++ } ++ // CraftBukkit end + if (!source.is(DamageTypeTags.IS_EXPLOSION)) { + DamageSource damageSource = source.getEntity() != null ? this.damageSources().explosion(this, source.getEntity()) : null; +- level.explode(this, damageSource, null, this.getX(), this.getY(), this.getZ(), 6.0F, false, Level.ExplosionInteraction.BLOCK); ++ // CraftBukkit start ++ org.bukkit.event.entity.ExplosionPrimeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExplosionPrimeEvent(this, 6.0F, false); ++ if (event.isCancelled()) { + return false; + } -+ // CraftBukkit end - if (!source.is(DamageTypeTags.IS_EXPLOSION)) { - DamageSource damageSource = source.getEntity() != null ? this.damageSources().explosion(this, source.getEntity()) : null; -- level.explode(this, damageSource, null, this.getX(), this.getY(), this.getZ(), 6.0F, false, Level.ExplosionInteraction.BLOCK); -+ // CraftBukkit start -+ org.bukkit.event.entity.ExplosionPrimeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExplosionPrimeEvent(this, 6.0F, false); -+ if (event.isCancelled()) { -+ return false; -+ } + -+ this.remove(Entity.RemovalReason.KILLED, org.bukkit.event.entity.EntityRemoveEvent.Cause.EXPLODE); // Paper - add Bukkit remove cause -+ level.explode(this, damageSource, null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.BLOCK); -+ } else { -+ this.remove(Entity.RemovalReason.KILLED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DEATH); // Paper - add Bukkit remove cause -+ // CraftBukkit end - } ++ this.remove(Entity.RemovalReason.KILLED, org.bukkit.event.entity.EntityRemoveEvent.Cause.EXPLODE); // Paper - add Bukkit remove cause ++ level.explode(this, damageSource, null, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.BLOCK); ++ } else { ++ this.remove(Entity.RemovalReason.KILLED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DEATH); // Paper - add Bukkit remove cause ++ // CraftBukkit end + } - this.onDestroyedBy(level, source); + this.onDestroyedBy(level, source); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch index 291d4a74687c..b7c12399fc8e 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java.patch @@ -233,7 +233,7 @@ this.gameEvent(GameEvent.ENTITY_DIE); } } -@@ -738,6 +_,7 @@ +@@ -739,6 +_,7 @@ super.addAdditionalSaveData(output); output.putInt("DragonPhase", this.phaseManager.getCurrentPhase().getPhase().getId()); output.putInt("DragonDeathTime", this.dragonDeathTime); @@ -241,7 +241,7 @@ } @Override -@@ -745,6 +_,7 @@ +@@ -746,6 +_,7 @@ super.readAdditionalSaveData(input); input.getInt("DragonPhase").ifPresent(phaseId -> this.phaseManager.setPhase(EnderDragonPhase.getById(phaseId))); this.dragonDeathTime = input.getIntOr("DragonDeathTime", 0); @@ -249,7 +249,7 @@ } @Override -@@ -785,7 +_,7 @@ +@@ -786,7 +_,7 @@ EnderDragonPhase phase = phaseInstance.getPhase(); Vec3 result; if (phase == EnderDragonPhase.LANDING || phase == EnderDragonPhase.TAKEOFF) { @@ -258,7 +258,7 @@ float dist = Math.max((float)Math.sqrt(egg.distToCenterSqr(this.position())) / 4.0F, 1.0F); float yOffset = 6.0F / dist; float xRotOld = this.getXRot(); -@@ -872,4 +_,19 @@ +@@ -873,4 +_,19 @@ protected float sanitizeScale(final float scale) { return 1.0F; } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch index ecb892c4f6a5..8301b5f05a36 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/boss/wither/WitherBoss.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/boss/wither/WitherBoss.java +++ b/net/minecraft/world/entity/boss/wither/WitherBoss.java -@@ -74,6 +_,7 @@ +@@ -73,6 +_,7 @@ private final int[] nextHeadUpdate = new int[2]; private final int[] idleHeadUpdates = new int[2]; private int destroyBlocksTick; @@ -8,7 +8,7 @@ public final ServerBossEvent bossEvent = Util.make( new ServerBossEvent(Mth.createInsecureUUID(this.random), this.getDisplayName(), BossEvent.BossBarColor.PURPLE, BossEvent.BossBarOverlay.PROGRESS), e -> e.setDarkenScreen(true) -@@ -265,15 +_,40 @@ +@@ -264,15 +_,40 @@ int newCount = this.getInvulnerableTicks() - 1; this.bossEvent.setProgress(1.0F - newCount / 220.0F); if (newCount <= 0) { @@ -52,7 +52,7 @@ } } else { super.customServerAiStep(level); -@@ -307,6 +_,7 @@ +@@ -306,6 +_,7 @@ ); if (!entities.isEmpty()) { LivingEntity selected = entities.get(this.random.nextInt(entities.size())); @@ -60,7 +60,7 @@ this.setAlternativeTarget(i, selected.getId()); } } -@@ -336,6 +_,11 @@ +@@ -335,6 +_,11 @@ )) { BlockState state = level.getBlockState(blockPos); if (canDestroy(state)) { @@ -72,7 +72,7 @@ destroyed = level.destroyBlock(blockPos, true, this) || destroyed; } } -@@ -347,7 +_,7 @@ +@@ -346,7 +_,7 @@ } if (this.tickCount % 20 == 0) { @@ -81,7 +81,7 @@ } this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth()); -@@ -485,16 +_,16 @@ +@@ -488,16 +_,16 @@ @Override protected void dropCustomDeathLoot(final ServerLevel level, final DamageSource source, final boolean killedByPlayer) { super.dropCustomDeathLoot(level, source, killedByPlayer); @@ -102,7 +102,7 @@ } else { this.noActionTime = 0; } -@@ -549,12 +_,18 @@ +@@ -552,12 +_,18 @@ @Override public boolean canUsePortal(final boolean ignorePassenger) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/decoration/ArmorStand.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/decoration/ArmorStand.java.patch index 8a895d311c68..d56896d3e894 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/decoration/ArmorStand.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/decoration/ArmorStand.java.patch @@ -80,13 +80,10 @@ for (Entity entity : this.level().getEntities(this, this.getBoundingBox(), RIDABLE_MINECARTS)) { if (this.distanceToSqr(entity) <= 0.2) { entity.push(this); -@@ -248,7 +_,25 @@ +@@ -256,6 +_,23 @@ return false; - } else if (itemStack.isEmpty() && (this.disabledSlots & 1 << slot.getFilterBit(16)) != 0) { - return false; -- } else if (player.hasInfiniteMaterials() && itemStack.isEmpty() && !playerItemStack.isEmpty()) { -+ } -+ + } + + // CraftBukkit start + org.bukkit.inventory.ItemStack armorStandItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack); + org.bukkit.inventory.ItemStack playerHeldItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(playerItemStack); @@ -103,14 +100,14 @@ + return true; + } + // CraftBukkit end -+ if (player.hasInfiniteMaterials() && itemStack.isEmpty() && !playerItemStack.isEmpty()) { ++ + if (player.hasInfiniteMaterials() && itemStack.isEmpty() && !playerItemStack.isEmpty()) { this.setItemSlot(slot, playerItemStack.copyWithCount(1)); return true; - } else if (playerItemStack.isEmpty() || playerItemStack.getCount() <= 1) { -@@ -270,15 +_,32 @@ - } else if (!level.getGameRules().get(GameRules.MOB_GRIEFING) && source.getEntity() instanceof Mob) { - return false; - } else if (source.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) { +@@ -286,21 +_,38 @@ + } + + if (source.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) { - this.kill(level); + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, damage)) { @@ -119,10 +116,14 @@ + this.kill(level, source); // CraftBukkit + // CraftBukkit end return false; -- } else if (this.isInvulnerableTo(level, source) || this.invisible || this.isMarker()) { -+ } else if (this.isInvulnerableTo(level, source) /*|| this.invisible*/ || this.isMarker()) { // CraftBukkit + } + +- if (this.isInvulnerableTo(level, source) || this.invisible || this.isMarker()) { ++ if (this.isInvulnerableTo(level, source) /*|| this.invisible*/ || this.isMarker()) { // CraftBukkit return false; - } else if (source.is(DamageTypeTags.IS_EXPLOSION)) { + } + + if (source.is(DamageTypeTags.IS_EXPLOSION)) { - this.brokenByAnything(level, source); - this.kill(level); + // CraftBukkit start @@ -135,7 +136,9 @@ + if (!event.isCancelled()) this.kill(level, source, false); // CraftBukkit + // Paper end return false; - } else if (source.is(DamageTypeTags.IGNITES_ARMOR_STANDS)) { + } + + if (source.is(DamageTypeTags.IGNITES_ARMOR_STANDS)) { + // CraftBukkit start + if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, damage, true, this.invisible)) { + return false; @@ -144,7 +147,7 @@ if (this.isOnFire()) { this.causeDamage(level, source, 0.15F); } else { -@@ -287,9 +_,19 @@ +@@ -309,9 +_,19 @@ return false; } else if (source.is(DamageTypeTags.BURNS_ARMOR_STANDS) && this.getHealth() > 0.5F) { @@ -164,16 +167,16 @@ boolean allowIncrementalBreaking = source.is(DamageTypeTags.CAN_BREAK_ARMOR_STAND); boolean shouldKill = source.is(DamageTypeTags.ALWAYS_KILLS_ARMOR_STANDS); if (!allowIncrementalBreaking && !shouldKill) { -@@ -299,7 +_,7 @@ - } else if (source.isCreativePlayer()) { - this.playBrokenSound(); - this.showBreakingParticles(); -- this.kill(level); -+ this.kill(level, source); // CraftBukkit - return true; - } else { - long time = level.getGameTime(); -@@ -308,9 +_,9 @@ +@@ -322,7 +_,7 @@ + if (source.isCreativePlayer()) { + this.playBrokenSound(); + this.showBreakingParticles(); +- this.kill(level); ++ this.kill(level, source); // CraftBukkit + return true; + } + +@@ -332,9 +_,9 @@ this.gameEvent(GameEvent.ENTITY_DAMAGE, source.getEntity()); this.lastHit = time; } else { @@ -185,7 +188,7 @@ } return true; -@@ -362,31 +_,42 @@ +@@ -386,31 +_,42 @@ float health = this.getHealth(); health -= dmg; if (health <= 0.5F) { @@ -239,7 +242,7 @@ } private void playBrokenSound() { -@@ -434,9 +_,40 @@ +@@ -458,9 +_,40 @@ return this.isSmall(); } @@ -281,7 +284,7 @@ this.gameEvent(GameEvent.ENTITY_DIE); } -@@ -683,4 +_,13 @@ +@@ -707,4 +_,13 @@ .apply(i, ArmorStand.ArmorStandPose::new) ); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/decoration/BlockAttachedEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/decoration/BlockAttachedEntity.java.patch index b6722f3451a3..1f290f04eaaa 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/decoration/BlockAttachedEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/decoration/BlockAttachedEntity.java.patch @@ -38,29 +38,29 @@ this.dropItem(level, null); } } -@@ -75,6 +_,21 @@ - return false; - } else { - if (!this.isRemoved()) { -+ // CraftBukkit start - fire break events -+ Entity damager = source.getDirectEntity(); -+ final org.bukkit.event.hanging.HangingBreakEvent event; -+ if (damager != null) { -+ event = new org.bukkit.event.hanging.HangingBreakByEntityEvent((org.bukkit.entity.Hanging) this.getBukkitEntity(), damager.getBukkitEntity(), new org.bukkit.craftbukkit.damage.CraftDamageSource(source), source.is(net.minecraft.tags.DamageTypeTags.IS_EXPLOSION) ? org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.EXPLOSION : org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.ENTITY); -+ } else { -+ event = new org.bukkit.event.hanging.HangingBreakEvent((org.bukkit.entity.Hanging) this.getBukkitEntity(), source.is(net.minecraft.tags.DamageTypeTags.IS_EXPLOSION) ? org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.EXPLOSION : org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.DEFAULT); -+ } +@@ -78,6 +_,21 @@ + } + + if (!this.isRemoved()) { ++ // CraftBukkit start - fire break events ++ Entity damager = source.getDirectEntity(); ++ final org.bukkit.event.hanging.HangingBreakEvent event; ++ if (damager != null) { ++ event = new org.bukkit.event.hanging.HangingBreakByEntityEvent((org.bukkit.entity.Hanging) this.getBukkitEntity(), damager.getBukkitEntity(), new org.bukkit.craftbukkit.damage.CraftDamageSource(source), source.is(net.minecraft.tags.DamageTypeTags.IS_EXPLOSION) ? org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.EXPLOSION : org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.ENTITY); ++ } else { ++ event = new org.bukkit.event.hanging.HangingBreakEvent((org.bukkit.entity.Hanging) this.getBukkitEntity(), source.is(net.minecraft.tags.DamageTypeTags.IS_EXPLOSION) ? org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.EXPLOSION : org.bukkit.event.hanging.HangingBreakEvent.RemoveCause.DEFAULT); ++ } + -+ event.callEvent(); ++ event.callEvent(); + -+ if (this.isRemoved() || event.isCancelled()) { -+ return true; -+ } -+ // CraftBukkit end - this.kill(level); - this.markHurt(); - this.dropItem(level, source.getEntity()); -@@ -93,18 +_,36 @@ ++ if (this.isRemoved() || event.isCancelled()) { ++ return true; ++ } ++ // CraftBukkit end + this.kill(level); + this.markHurt(); + this.dropItem(level, source.getEntity()); +@@ -95,18 +_,36 @@ @Override public void move(final MoverType moverType, final Vec3 delta) { if (this.level() instanceof ServerLevel level && !this.isRemoved() && delta.lengthSqr() > 0.0) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/decoration/ItemFrame.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/decoration/ItemFrame.java.patch index 4af212abab10..29cd1f73ffd7 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/decoration/ItemFrame.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/decoration/ItemFrame.java.patch @@ -20,7 +20,7 @@ float shiftToBlockWall = 0.46875F; Vec3 position = Vec3.atCenterOf(blockPos).relative(direction, -0.46875); float width = hasFramedMap ? 1.0F : 0.75F; -@@ -142,9 +_,9 @@ +@@ -144,9 +_,9 @@ } @Override @@ -32,7 +32,7 @@ } } -@@ -173,6 +_,18 @@ +@@ -175,6 +_,18 @@ if (this.isInvulnerableToBase(source)) { return false; } else if (this.shouldDamageDropItem(source)) { @@ -51,7 +51,7 @@ this.dropItem(level, source.getEntity(), false); this.gameEvent(GameEvent.BLOCK_CHANGE, source.getEntity()); this.playSound(this.getRemoveItemSound(), 1.0F, 1.0F); -@@ -256,6 +_,13 @@ +@@ -258,6 +_,13 @@ return this.getEntityData().get(DATA_ITEM); } @@ -65,7 +65,7 @@ public @Nullable MapId getFramedMapId(final ItemStack itemStack) { return itemStack.get(DataComponents.MAP_ID); } -@@ -269,13 +_,19 @@ +@@ -271,13 +_,19 @@ } public void setItem(ItemStack itemStack, final boolean updateNeighbours) { @@ -86,7 +86,7 @@ this.playSound(this.getAddItemSound(), 1.0F, 1.0F); } -@@ -302,6 +_,7 @@ +@@ -304,6 +_,7 @@ } private void onItemChanged(final ItemStack item) { @@ -94,22 +94,22 @@ this.recalculateBoundingBox(); } -@@ -366,7 +_,13 @@ - if (data != null && data.isTrackedCountOverLimit(256)) { +@@ -371,7 +_,13 @@ return InteractionResult.FAIL; - } else { -- this.setItem(itemStack); -+ // Paper start - Add PlayerItemFrameChangeEvent -+ io.papermc.paper.event.player.PlayerItemFrameChangeEvent event = new io.papermc.paper.event.player.PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), itemStack.asBukkitCopy(), io.papermc.paper.event.player.PlayerItemFrameChangeEvent.ItemFrameChangeAction.PLACE); -+ if (!event.callEvent()) { -+ return InteractionResult.FAIL; -+ } -+ this.setItem(ItemStack.fromBukkitCopy(event.getItemStack())); -+ // Paper end - Add PlayerItemFrameChangeEvent - this.gameEvent(GameEvent.BLOCK_CHANGE, player); - itemStack.consume(1, player); - return InteractionResult.SUCCESS; -@@ -375,6 +_,13 @@ + } + +- this.setItem(itemStack); ++ // Paper start - Add PlayerItemFrameChangeEvent ++ io.papermc.paper.event.player.PlayerItemFrameChangeEvent event = new io.papermc.paper.event.player.PlayerItemFrameChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.ItemFrame) this.getBukkitEntity(), itemStack.asBukkitCopy(), io.papermc.paper.event.player.PlayerItemFrameChangeEvent.ItemFrameChangeAction.PLACE); ++ if (!event.callEvent()) { ++ return InteractionResult.FAIL; ++ } ++ this.setItem(ItemStack.fromBukkitCopy(event.getItemStack())); ++ // Paper end - Add PlayerItemFrameChangeEvent + this.gameEvent(GameEvent.BLOCK_CHANGE, player); + itemStack.consume(1, player); + return InteractionResult.SUCCESS; +@@ -379,6 +_,13 @@ return InteractionResult.PASS; } } else { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java.patch index de163b618697..df6708a939c7 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java.patch @@ -1,23 +1,23 @@ --- a/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java +++ b/net/minecraft/world/entity/decoration/LeashFenceKnotEntity.java -@@ -85,7 +_,7 @@ - boolean attachedMob = false; +@@ -86,7 +_,7 @@ + boolean attachedMob = false; - for (Leashable leashable : Leashable.leashableLeashedTo(player)) { -- if (leashable.canHaveALeashAttachedTo(this)) { -+ if (leashable.canHaveALeashAttachedTo(this) && org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerLeashEntityEvent(leashable, this, player, hand)) { // Paper - leash event - leashable.setLeashedTo(this, true); - attachedMob = true; + for (Leashable leashable : Leashable.leashableLeashedTo(player)) { +- if (leashable.canHaveALeashAttachedTo(this)) { ++ if (leashable.canHaveALeashAttachedTo(this) && org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerLeashEntityEvent(leashable, this, player, hand)) { // Paper - leash event + leashable.setLeashedTo(this, true); + attachedMob = true; + } +@@ -95,7 +_,7 @@ + boolean anyDropped = false; + if (!attachedMob && !player.isSecondaryUseActive()) { + for (Leashable mob : Leashable.leashableLeashedTo(this)) { +- if (mob.canHaveALeashAttachedTo(player)) { ++ if (mob.canHaveALeashAttachedTo(player) && org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerLeashEntityEvent(mob, player, player, hand)) { // Paper - leash event + mob.setLeashedTo(player, true); + anyDropped = true; } -@@ -94,7 +_,7 @@ - boolean anyDropped = false; - if (!attachedMob && !player.isSecondaryUseActive()) { - for (Leashable mob : Leashable.leashableLeashedTo(this)) { -- if (mob.canHaveALeashAttachedTo(player)) { -+ if (mob.canHaveALeashAttachedTo(player) && org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerLeashEntityEvent(mob, player, player, hand)) { // Paper - leash event - mob.setLeashedTo(player, true); - anyDropped = true; - } @@ -114,7 +_,7 @@ @Override public void notifyLeasheeRemoved(final Leashable entity) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/item/ItemEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/item/ItemEntity.java.patch index 0ef8416a98e3..57f1315b9295 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/item/ItemEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/item/ItemEntity.java.patch @@ -118,26 +118,26 @@ } } -@@ -288,12 +_,17 @@ - } else if (!this.getItem().canBeHurtBy(source)) { +@@ -293,12 +_,17 @@ return false; - } else { -+ // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, damage)) { -+ return false; -+ } -+ // CraftBukkit end - this.markHurt(); - this.health = (int)(this.health - damage); - this.gameEvent(GameEvent.ENTITY_DAMAGE, source.getEntity()); - if (this.health <= 0) { - this.getItem().onDestroyed(this); -- this.discard(); -+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause - } + } + ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(this, source, damage)) { ++ return false; ++ } ++ // CraftBukkit end + this.markHurt(); + this.health = (int)(this.health - damage); + this.gameEvent(GameEvent.ENTITY_DAMAGE, source.getEntity()); + if (this.health <= 0) { + this.getItem().onDestroyed(this); +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause + } - return true; -@@ -315,6 +_,11 @@ + return true; +@@ -319,6 +_,11 @@ if (!this.getItem().isEmpty()) { output.store("Item", ItemStack.CODEC, this.getItem()); } @@ -149,7 +149,7 @@ } @Override -@@ -325,8 +_,17 @@ +@@ -329,8 +_,17 @@ this.target = input.read("Owner", UUIDUtil.CODEC).orElse(null); this.thrower = EntityReference.read(input, "Thrower"); this.setItem(input.read("Item", ItemStack.CODEC).orElse(ItemStack.EMPTY)); @@ -168,7 +168,7 @@ } } -@@ -336,10 +_,73 @@ +@@ -340,10 +_,73 @@ ItemStack itemStack = this.getItem(); Item item = itemStack.getItem(); int orgCount = itemStack.getCount(); @@ -243,7 +243,7 @@ itemStack.setCount(orgCount); } -@@ -376,6 +_,7 @@ +@@ -380,6 +_,7 @@ public void setItem(final ItemStack itemStack) { this.getEntityData().set(DATA_ITEM, itemStack); @@ -251,7 +251,7 @@ } public void setTarget(final @Nullable UUID target) { -@@ -420,7 +_,7 @@ +@@ -424,7 +_,7 @@ public void makeFakeItem() { this.setNeverPickUp(); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/EnderMan.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/EnderMan.java.patch index 2e6fd539b7c9..98d01196ade7 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/EnderMan.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/EnderMan.java.patch @@ -56,33 +56,33 @@ this.setTarget(null); this.teleport(); } -@@ -354,21 +_,25 @@ - return false; - } else { - AbstractThrownPotion thrownPotion = source.getDirectEntity() instanceof AbstractThrownPotion potion ? potion : null; -- if (!source.is(DamageTypeTags.IS_PROJECTILE) && thrownPotion == null) { -+ if (!source.is(DamageTypeTags.IS_PROJECTILE) && thrownPotion == null) { // Paper - EndermanEscapeEvent - diff on change - below logic relies on this path covering non-projectile damage. - boolean result = super.hurtServer(level, source, damage); - if (!(source.getEntity() instanceof LivingEntity) && this.random.nextInt(10) != 0) { -+ if (this.tryEscape(source.is(net.minecraft.tags.DamageTypeTags.IS_DROWNING) ? com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.DROWN : com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.CRITICAL_HIT)) { // Paper - EndermanEscapeEvent - this.teleport(); -+ } // Paper - EndermanEscapeEvent - } - - return result; - } else { - boolean hurtWithCleanWater = thrownPotion != null && this.hurtWithCleanWater(level, source, thrownPotion, damage); +@@ -355,21 +_,25 @@ + } -+ if (this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.INDIRECT)) { // Paper - EndermanEscapeEvent - for (int i = 0; i < 64; i++) { - if (this.teleport()) { - return true; - } - } + AbstractThrownPotion thrownPotion = source.getDirectEntity() instanceof AbstractThrownPotion potion ? potion : null; +- if (!source.is(DamageTypeTags.IS_PROJECTILE) && thrownPotion == null) { ++ if (!source.is(DamageTypeTags.IS_PROJECTILE) && thrownPotion == null) { // Paper - EndermanEscapeEvent - diff on change - below logic relies on this path covering non-projectile damage. + boolean result = super.hurtServer(level, source, damage); + if (!(source.getEntity() instanceof LivingEntity) && this.random.nextInt(10) != 0) { ++ if (this.tryEscape(source.is(DamageTypeTags.IS_DROWNING) ? com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.DROWN : com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.CRITICAL_HIT)) { // Paper - EndermanEscapeEvent + this.teleport(); + } // Paper - EndermanEscapeEvent + } + + return result; + } else { + boolean hurtWithCleanWater = thrownPotion != null && this.hurtWithCleanWater(level, source, thrownPotion, damage); - return hurtWithCleanWater; ++ if (this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.INDIRECT)) { // Paper - EndermanEscapeEvent + for (int i = 0; i < 64; i++) { + if (this.teleport()) { + return true; + } } ++ } // Paper - EndermanEscapeEvent + + return hurtWithCleanWater; + } @@ -393,6 +_,16 @@ this.entityData.set(DATA_STARED_AT, true); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Endermite.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Endermite.java.patch index e88d19baa7eb..a11c50cc2da3 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/Endermite.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Endermite.java.patch @@ -9,12 +9,12 @@ } } } -@@ -136,7 +_,7 @@ - } else if (EntitySpawnReason.isSpawner(spawnReason)) { +@@ -139,7 +_,7 @@ return true; - } else { -- Player nearestPlayer = level.getNearestPlayer(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, 5.0, true); -+ Player nearestPlayer = level.getNearestPlayerThatAffectsSpawning(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, 5.0, true); // Paper - Affects Spawning API - return nearestPlayer == null; } + +- Player nearestPlayer = level.getNearestPlayer(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, 5.0, true); ++ Player nearestPlayer = level.getNearestPlayerThatAffectsSpawning(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, 5.0, true); // Paper - Affects Spawning API + return nearestPlayer == null; } + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Ghast.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Ghast.java.patch index 831086353ed5..9206393a4921 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/Ghast.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Ghast.java.patch @@ -13,7 +13,7 @@ private static boolean isReflectedFireball(final DamageSource source) { return source.getDirectEntity() instanceof LargeFireball && source.getEntity() instanceof Player; } -@@ -375,6 +_,7 @@ +@@ -377,6 +_,7 @@ } LargeFireball entity = new LargeFireball(level, this.ghast, direction.normalize(), this.ghast.getExplosionPower()); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Monster.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Monster.java.patch index 2e282f76bf20..3ec4199e6dfb 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/Monster.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Monster.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/entity/monster/Monster.java +++ b/net/minecraft/world/entity/monster/Monster.java -@@ -88,7 +_,7 @@ +@@ -89,7 +_,7 @@ + } + + DimensionType dimensionType = level.dimensionType(); +- int blockLightLimit = dimensionType.monsterSpawnBlockLightLimit(); ++ int blockLightLimit = level.getLevel().paperConfig().entities.spawning.monsterSpawnMaxLightLevel.or(dimensionType.monsterSpawnBlockLightLimit()); // Paper - Configurable max block light for monster spawning + if (blockLightLimit < 15 && level.getBrightness(LightLayer.BLOCK, pos) > blockLightLimit) { return false; - } else { - DimensionType dimensionType = level.dimensionType(); -- int blockLightLimit = dimensionType.monsterSpawnBlockLightLimit(); -+ int blockLightLimit = level.getLevel().paperConfig().entities.spawning.monsterSpawnMaxLightLevel.or(dimensionType.monsterSpawnBlockLightLimit()); // Paper - Configurable max block light for monster spawning - if (blockLightLimit < 15 && level.getBrightness(LightLayer.BLOCK, pos) > blockLightLimit) { - return false; - } else { + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Phantom.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Phantom.java.patch index 26878838bcfa..c4f045dd2a00 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/Phantom.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Phantom.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/monster/Phantom.java +++ b/net/minecraft/world/entity/monster/Phantom.java -@@ -50,6 +_,10 @@ +@@ -49,6 +_,10 @@ private Vec3 moveTargetPoint = Vec3.ZERO; public @Nullable BlockPos anchorPoint; private Phantom.AttackPhase attackPhase = Phantom.AttackPhase.CIRCLE; @@ -11,7 +11,7 @@ public Phantom(final EntityType type, final Level level) { super(type, level); -@@ -137,6 +_,13 @@ +@@ -136,6 +_,13 @@ } } @@ -25,7 +25,7 @@ @Override protected void checkFallDamage(final double ya, final boolean onGround, final BlockState onState, final BlockPos pos) { } -@@ -165,6 +_,10 @@ +@@ -164,6 +_,10 @@ super.readAdditionalSaveData(input); this.anchorPoint = input.read("anchor_pos", BlockPos.CODEC).orElse(null); this.setPhantomSize(input.getIntOr("size", 0)); @@ -36,7 +36,7 @@ } @Override -@@ -172,6 +_,10 @@ +@@ -171,6 +_,10 @@ super.addAdditionalSaveData(output); output.storeNullable("anchor_pos", BlockPos.CODEC, this.anchorPoint); output.putInt("size", this.getPhantomSize()); @@ -47,15 +47,15 @@ } @Override -@@ -240,8 +_,10 @@ +@@ -233,8 +_,10 @@ - for (Player player : players) { - if (Phantom.this.canAttack(level, player, TargetingConditions.DEFAULT)) { -- Phantom.this.setTarget(player); -+ if (!level().paperConfig().entities.behavior.phantomsOnlyAttackInsomniacs || EntitySelector.IS_INSOMNIAC.test(player)) { // Paper - Add phantom creative and insomniac controls -+ Phantom.this.setTarget(player, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER); // CraftBukkit - reason - return true; -+ } // Paper - Add phantom creative and insomniac controls - } + for (Player player : players) { + if (Phantom.this.canAttack(level, player, TargetingConditions.DEFAULT)) { +- Phantom.this.setTarget(player); ++ if (!level().paperConfig().entities.behavior.phantomsOnlyAttackInsomniacs || EntitySelector.IS_INSOMNIAC.test(player)) { // Paper - Add phantom creative and insomniac controls ++ Phantom.this.setTarget(player, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER); // CraftBukkit - reason + return true; ++ } // Paper - Add phantom creative and insomniac controls } } + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Shulker.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Shulker.java.patch index 877221a21da5..c0103a325d3a 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/Shulker.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Shulker.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/monster/Shulker.java +++ b/net/minecraft/world/entity/monster/Shulker.java -@@ -277,8 +_,10 @@ +@@ -276,8 +_,10 @@ } @Override @@ -13,7 +13,7 @@ if (this.level().isClientSide()) { this.clientOldAttachPosition = this.blockPosition(); } -@@ -389,6 +_,14 @@ +@@ -388,6 +_,14 @@ && this.level().getWorldBorder().isWithinBounds(target) && this.level().noCollision(this, new AABB(target).deflate(1.0E-6))) { Direction attachmentDirection = this.findAttachableSurface(target); @@ -28,7 +28,7 @@ if (attachmentDirection != null) { this.unRide(); this.setAttachFace(attachmentDirection); -@@ -453,7 +_,12 @@ +@@ -452,7 +_,12 @@ if (baby != null) { baby.setVariant(this.getVariant()); baby.snapTo(oldPosition); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Silverfish.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Silverfish.java.patch index 0bf09e3dd85b..aa80f388768c 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/Silverfish.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Silverfish.java.patch @@ -1,15 +1,15 @@ --- a/net/minecraft/world/entity/monster/Silverfish.java +++ b/net/minecraft/world/entity/monster/Silverfish.java -@@ -117,7 +_,7 @@ - } else if (EntitySpawnReason.isSpawner(spawnReason)) { +@@ -120,7 +_,7 @@ return true; - } else { -- Player nearestPlayer = level.getNearestPlayer(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, 5.0, true); -+ Player nearestPlayer = level.getNearestPlayerThatAffectsSpawning(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, 5.0, true); // Paper - Affects Spawning API - return nearestPlayer == null; } + +- Player nearestPlayer = level.getNearestPlayer(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, 5.0, true); ++ Player nearestPlayer = level.getNearestPlayerThatAffectsSpawning(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, 5.0, true); // Paper - Affects Spawning API + return nearestPlayer == null; } -@@ -168,9 +_,14 @@ + +@@ -172,9 +_,14 @@ BlockPos pos = BlockPos.containing(this.mob.getX(), this.mob.getY() + 0.5, this.mob.getZ()).relative(this.selectedDirection); BlockState blockState = level.getBlockState(pos); if (InfestedBlock.isCompatibleHostBlock(blockState)) { @@ -25,7 +25,7 @@ } } } -@@ -210,6 +_,12 @@ +@@ -214,6 +_,12 @@ BlockState blockState = level.getBlockState(testPos); Block block = blockState.getBlock(); if (block instanceof InfestedBlock) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Vex.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Vex.java.patch index aa33a3442320..aab60ca41e1f 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/Vex.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Vex.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/monster/Vex.java +++ b/net/minecraft/world/entity/monster/Vex.java -@@ -293,7 +_,7 @@ +@@ -288,7 +_,7 @@ @Override public void start() { Mob owner = Vex.this.getOwner(); @@ -9,7 +9,7 @@ super.start(); } } -@@ -355,7 +_,10 @@ +@@ -347,7 +_,10 @@ for (int attempts = 0; attempts < 3; attempts++) { BlockPos testPos = boundOrigin.offset(Vex.this.random.nextInt(15) - 7, Vex.this.random.nextInt(11) - 5, Vex.this.random.nextInt(15) - 7); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/creaking/Creaking.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/creaking/Creaking.java.patch index e1f7aa867c05..309b070b4b0b 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/creaking/Creaking.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/creaking/Creaking.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/monster/creaking/Creaking.java +++ b/net/minecraft/world/entity/monster/creaking/Creaking.java -@@ -191,9 +_,9 @@ +@@ -193,9 +_,9 @@ } @Override @@ -12,7 +12,7 @@ } } -@@ -318,7 +_,7 @@ +@@ -320,7 +_,7 @@ } this.makeSound(this.getDeathSound()); @@ -21,7 +21,7 @@ } public void creakingDeathEffects(final DamageSource source) { -@@ -446,9 +_,9 @@ +@@ -448,9 +_,9 @@ } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Evoker.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Evoker.java.patch index 48f194a1f2da..41c71c41f3d6 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Evoker.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Evoker.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/monster/illager/Evoker.java +++ b/net/minecraft/world/entity/monster/illager/Evoker.java -@@ -271,7 +_,7 @@ +@@ -254,7 +_,7 @@ serverLevel.getScoreboard().addPlayerToTeam(vex.getScoreboardName(), evokerTeam); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Illusioner.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Illusioner.java.patch index 9be002440e38..110a69882b7e 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Illusioner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/Illusioner.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/monster/illager/Illusioner.java +++ b/net/minecraft/world/entity/monster/illager/Illusioner.java -@@ -175,7 +_,8 @@ +@@ -174,7 +_,8 @@ @Override public void performRangedAttack(final LivingEntity target, final float power) { @@ -10,7 +10,7 @@ ItemStack projectile = this.getProjectile(bowItem); AbstractArrow arrow = ProjectileUtil.getMobArrow(this, projectile, power, bowItem); double xd = target.getX() - this.getX(); -@@ -183,9 +_,21 @@ +@@ -182,9 +_,21 @@ double zd = target.getZ() - this.getZ(); double distanceToTarget = Math.sqrt(xd * xd + zd * zd); if (this.level() instanceof ServerLevel serverLevel) { @@ -33,7 +33,7 @@ } this.playSound(SoundEvents.SKELETON_SHOOT, 1.0F, 1.0F / (this.getRandom().nextFloat() * 0.4F + 0.8F)); -@@ -237,7 +_,7 @@ +@@ -231,7 +_,7 @@ @Override protected void performSpellCasting() { @@ -42,7 +42,7 @@ } @Override -@@ -274,7 +_,7 @@ +@@ -263,7 +_,7 @@ @Override protected void performSpellCasting() { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/SpellcasterIllager.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/SpellcasterIllager.java.patch index 3c1ea820e027..e2bfaa22c116 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/SpellcasterIllager.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/illager/SpellcasterIllager.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/monster/illager/SpellcasterIllager.java +++ b/net/minecraft/world/entity/monster/illager/SpellcasterIllager.java -@@ -216,6 +_,11 @@ +@@ -208,6 +_,11 @@ public void tick() { this.attackWarmupDelay--; if (this.attackWarmupDelay == 0) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/Piglin.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/Piglin.java.patch index cc9ead32c126..c24dbb871d6b 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/Piglin.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/Piglin.java.patch @@ -54,18 +54,17 @@ this.setItemSlot(EquipmentSlot.OFFHAND, itemStack); this.setGuaranteedDrop(EquipmentSlot.OFFHAND); } else { -@@ -384,8 +_,8 @@ - return false; - } else { - TagKey preferredWeaponType = this.getPreferredWeaponType(); -- boolean newItemWanted = PiglinAi.isLovedItem(newItemStack) || preferredWeaponType != null && newItemStack.is(preferredWeaponType); -- boolean currentItemWanted = PiglinAi.isLovedItem(currentItemStack) || preferredWeaponType != null && currentItemStack.is(preferredWeaponType); -+ boolean newItemWanted = PiglinAi.isLovedItem(newItemStack, this) || preferredWeaponType != null && newItemStack.is(preferredWeaponType); // CraftBukkit -+ boolean currentItemWanted = PiglinAi.isLovedItem(currentItemStack, this) || preferredWeaponType != null && currentItemStack.is(preferredWeaponType); // CraftBukkit - return newItemWanted && !currentItemWanted - || (newItemWanted || !currentItemWanted) && super.canReplaceCurrentItem(newItemStack, currentItemStack, slot); +@@ -385,15 +_,15 @@ } -@@ -393,7 +_,7 @@ + + TagKey preferredWeaponType = this.getPreferredWeaponType(); +- boolean newItemWanted = PiglinAi.isLovedItem(newItemStack) || preferredWeaponType != null && newItemStack.is(preferredWeaponType); +- boolean currentItemWanted = PiglinAi.isLovedItem(currentItemStack) || preferredWeaponType != null && currentItemStack.is(preferredWeaponType); ++ boolean newItemWanted = PiglinAi.isLovedItem(newItemStack, this) || preferredWeaponType != null && newItemStack.is(preferredWeaponType); // CraftBukkit ++ boolean currentItemWanted = PiglinAi.isLovedItem(currentItemStack, this) || preferredWeaponType != null && currentItemStack.is(preferredWeaponType); // CraftBukkit + return newItemWanted && !currentItemWanted + || (newItemWanted || !currentItemWanted) && super.canReplaceCurrentItem(newItemStack, currentItemStack, slot); + } @Override protected void pickUpItem(final ServerLevel level, final ItemEntity entity) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch index ae7121d1021c..0d41994c6fd3 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch @@ -76,7 +76,7 @@ body.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY); } } -@@ -467,7 +_,7 @@ +@@ -466,7 +_,7 @@ return false; } else if (isAdmiringDisabled(body) && body.getBrain().hasMemoryValue(MemoryModuleType.ATTACK_TARGET)) { return false; @@ -85,7 +85,7 @@ return isNotHoldingLovedItemInOffHand(body); } else { boolean hasSpace = body.canAddToInventory(itemStack); -@@ -476,11 +_,16 @@ +@@ -475,11 +_,16 @@ } else if (isFood(itemStack)) { return !hasEatenRecently(body) && hasSpace; } else { @@ -103,7 +103,7 @@ protected static boolean isLovedItem(final ItemStack itemStack) { return itemStack.is(ItemTags.PIGLIN_LOVED); } -@@ -540,6 +_,7 @@ +@@ -537,6 +_,7 @@ } public static void angerNearbyPiglins(final ServerLevel level, final Player player, final boolean onlyIfTheySeeThePlayer) { @@ -111,7 +111,7 @@ List nearbyPiglins = player.level().getEntitiesOfClass(Piglin.class, player.getBoundingBox().inflate(16.0)); nearbyPiglins.stream().filter(PiglinAi::isIdle).filter(piglin -> !onlyIfTheySeeThePlayer || BehaviorUtils.canSee(piglin, player)).forEach(piglin -> { if (level.getGameRules().get(GameRules.UNIVERSAL_ANGER)) { -@@ -564,7 +_,7 @@ +@@ -561,7 +_,7 @@ } protected static boolean canAdmire(final Piglin body, final ItemStack playerHeldItemStack) { @@ -120,7 +120,7 @@ } protected static void wasHurtBy(final ServerLevel level, final Piglin body, final LivingEntity attacker) { -@@ -813,6 +_,11 @@ +@@ -811,6 +_,11 @@ return body.getBrain().hasMemoryValue(MemoryModuleType.ADMIRING_ITEM); } @@ -132,7 +132,7 @@ private static boolean isBarterCurrency(final ItemStack itemStack) { return itemStack.is(BARTERING_ITEM); } -@@ -850,7 +_,7 @@ +@@ -848,7 +_,7 @@ } private static boolean isNotHoldingLovedItemInOffHand(final Piglin body) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java.patch index 0f515a9b2f00..e74512076626 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java +++ b/net/minecraft/world/entity/monster/skeleton/AbstractSkeleton.java -@@ -71,6 +_,7 @@ +@@ -66,6 +_,7 @@ AbstractSkeleton.this.setAggressive(true); } }; @@ -8,7 +8,7 @@ protected AbstractSkeleton(final EntityType type, final Level level) { super(type, level); -@@ -95,6 +_,21 @@ +@@ -90,6 +_,21 @@ return Monster.createMonsterAttributes().add(Attributes.MOVEMENT_SPEED, 0.25); } @@ -30,7 +30,7 @@ @Override protected void playStepSound(final BlockPos pos, final BlockState blockState) { this.playSound(this.getStepSound(), 0.15F, 1.0F); -@@ -125,7 +_,7 @@ +@@ -120,7 +_,7 @@ this.populateDefaultEquipmentSlots(random, difficulty); this.populateDefaultEquipmentEnchantments(level, random, difficulty); this.reassessWeaponGoal(); @@ -39,7 +39,7 @@ if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty() && SpecialDates.isHalloween() && random.nextFloat() < 0.25F) { this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(random.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN)); this.setDropChance(EquipmentSlot.HEAD, 0.0F); -@@ -163,7 +_,8 @@ +@@ -158,7 +_,8 @@ @Override public void performRangedAttack(final LivingEntity target, final float power) { @@ -49,7 +49,7 @@ ItemStack projectile = this.getProjectile(bowItem); AbstractArrow arrow = this.getArrow(projectile, power, bowItem); double xd = target.getX() - this.getX(); -@@ -171,9 +_,21 @@ +@@ -166,9 +_,21 @@ double zd = target.getZ() - this.getZ(); double distanceToTarget = Math.sqrt(xd * xd + zd * zd); if (this.level() instanceof ServerLevel serverLevel) { @@ -72,7 +72,7 @@ } this.playSound(SoundEvents.SKELETON_SHOOT, 1.0F, 1.0F / (this.getRandom().nextFloat() * 0.4F + 0.8F)); -@@ -197,11 +_,14 @@ +@@ -192,11 +_,14 @@ protected void readAdditionalSaveData(final ValueInput input) { super.readAdditionalSaveData(input); this.reassessWeaponGoal(); @@ -89,7 +89,7 @@ if (!this.level().isClientSide()) { this.reassessWeaponGoal(); } -@@ -215,4 +_,12 @@ +@@ -210,4 +_,12 @@ public boolean wantsToPickUp(final ServerLevel level, final ItemStack itemStack) { return !itemStack.is(ItemTags.SPEARS) && super.wantsToPickUp(level, itemStack); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java.patch index 0ddacc7eb85a..c1bb12ba5eae 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java +++ b/net/minecraft/world/entity/monster/skeleton/WitherSkeleton.java -@@ -95,7 +_,7 @@ - return false; - } else { - if (target instanceof LivingEntity) { -- ((LivingEntity)target).addEffect(new MobEffectInstance(MobEffects.WITHER, 200), this); -+ ((LivingEntity)target).addEffect(new MobEffectInstance(MobEffects.WITHER, 200), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit - } +@@ -96,7 +_,7 @@ + } - return true; + if (target instanceof LivingEntity) { +- ((LivingEntity)target).addEffect(new MobEffectInstance(MobEffects.WITHER, 200), this); ++ ((LivingEntity)target).addEffect(new MobEffectInstance(MobEffects.WITHER, 200), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit + } + + return true; @@ -111,6 +_,6 @@ @Override diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/warden/Warden.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/warden/Warden.java.patch index 576a3eeafcaa..0350347f6d76 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/warden/Warden.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/warden/Warden.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/monster/warden/Warden.java +++ b/net/minecraft/world/entity/monster/warden/Warden.java -@@ -404,7 +_,7 @@ +@@ -403,7 +_,7 @@ public static void applyDarknessAround(final ServerLevel level, final Vec3 position, final @Nullable Entity source, final int darknessRadius) { MobEffectInstance darkness = new MobEffectInstance(MobEffects.DARKNESS, 260, 0, false, false); @@ -9,7 +9,7 @@ } @Override -@@ -446,8 +_,17 @@ +@@ -445,8 +_,17 @@ } @VisibleForTesting diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Zombie.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Zombie.java.patch index ec8291af250e..8d29fc28d428 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Zombie.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/zombie/Zombie.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/monster/zombie/Zombie.java +++ b/net/minecraft/world/entity/monster/zombie/Zombie.java -@@ -71,8 +_,10 @@ +@@ -70,8 +_,10 @@ public class Zombie extends Monster { private static final Identifier SPEED_MODIFIER_BABY_ID = Identifier.withDefaultNamespace("baby"); @@ -13,7 +13,7 @@ ); private static final Identifier REINFORCEMENT_CALLER_CHARGE_ID = Identifier.withDefaultNamespace("reinforcement_caller_charge"); private static final AttributeModifier ZOMBIE_REINFORCEMENT_CALLEE_CHARGE = new AttributeModifier( -@@ -96,13 +_,15 @@ +@@ -95,13 +_,15 @@ private static final boolean DEFAULT_BABY = false; private static final boolean DEFAULT_CAN_BREAK_DOORS = false; private static final int DEFAULT_IN_WATER_TIME = 0; @@ -30,7 +30,7 @@ } public Zombie(final Level level) { -@@ -111,7 +_,7 @@ +@@ -110,7 +_,7 @@ @Override protected void registerGoals() { @@ -39,7 +39,7 @@ this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); this.addBehaviourGoals(); -@@ -124,7 +_,7 @@ +@@ -123,7 +_,7 @@ this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0)); this.targetSelector.addGoal(1, new HurtByTargetGoal(this).setAlertOthers(ZombifiedPiglin.class)); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); @@ -48,7 +48,7 @@ this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true)); this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, true, false, Turtle.BABY_ON_LAND_SELECTOR)); } -@@ -178,11 +_,16 @@ +@@ -177,11 +_,16 @@ @Override protected int getBaseExperienceReward(final ServerLevel level) { @@ -66,7 +66,7 @@ } @Override -@@ -233,6 +_,13 @@ +@@ -232,6 +_,13 @@ super.tick(); } @@ -80,7 +80,7 @@ public void startUnderWaterConversion(final int time) { this.conversionTime = time; this.getEntityData().set(DATA_DROWNED_CONVERSION_ID, true); -@@ -246,17 +_,28 @@ +@@ -245,17 +_,28 @@ } protected void convertToZombieType(final ServerLevel level, final EntityType zombieType) { @@ -113,7 +113,7 @@ ZombieVillager zombieVillager = villager.convertTo( EntityType.ZOMBIE_VILLAGER, ConversionParams.single(villager, true, true), -@@ -268,17 +_,24 @@ +@@ -267,17 +_,24 @@ zombie.setGossips(villager.getGossips().copy()); zombie.setTradeOffers(villager.getOffers().copy()); zombie.setVillagerXp(villager.getVillagerXp()); @@ -145,26 +145,24 @@ @Override public boolean hurtServer(final ServerLevel level, final DamageSource source, final float damage) { -@@ -311,15 +_,15 @@ - if (SpawnPlacements.isSpawnPositionOk(type, level, spawnPos) - && SpawnPlacements.checkSpawnRules(type, level, EntitySpawnReason.REINFORCEMENT, spawnPos, level.getRandom())) { - reinforcement.setPos(xt, yt, zt); -- if (!level.hasNearbyAlivePlayer(xt, yt, zt, 7.0) -+ if (!level.hasNearbyAlivePlayerThatAffectsSpawning(xt, yt, zt, 7.0) // Paper - affects spawning api - && level.isUnobstructed(reinforcement) - && level.noCollision(reinforcement) - && (reinforcement.canSpawnInLiquids() || !level.containsAnyLiquid(reinforcement.getBoundingBox()))) { -- reinforcement.setTarget(target); -+ reinforcement.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.REINFORCEMENT_TARGET); // CraftBukkit - reinforcement.finalizeSpawn( - level, level.getCurrentDifficultyAt(reinforcement.blockPosition()), EntitySpawnReason.REINFORCEMENT, null - ); -- level.addFreshEntityWithPassengers(reinforcement); -+ level.addFreshEntityWithPassengers(reinforcement, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.REINFORCEMENTS); // CraftBukkit - AttributeInstance attribute = this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE); - AttributeModifier modifier = attribute.getModifier(REINFORCEMENT_CALLER_CHARGE_ID); - double existingAmount = modifier != null ? modifier.amount() : 0.0; -@@ -344,7 +_,12 @@ +@@ -311,13 +_,13 @@ + if (SpawnPlacements.isSpawnPositionOk(type, level, spawnPos) + && SpawnPlacements.checkSpawnRules(type, level, EntitySpawnReason.REINFORCEMENT, spawnPos, level.getRandom())) { + reinforcement.setPos(xt, yt, zt); +- if (!level.hasNearbyAlivePlayer(xt, yt, zt, 7.0) ++ if (!level.hasNearbyAlivePlayerThatAffectsSpawning(xt, yt, zt, 7.0) // Paper - affects spawning api + && level.isUnobstructed(reinforcement) + && level.noCollision(reinforcement) + && (reinforcement.canSpawnInLiquids() || !level.containsAnyLiquid(reinforcement.getBoundingBox()))) { +- reinforcement.setTarget(target); ++ reinforcement.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.REINFORCEMENT_TARGET); // CraftBukkit + reinforcement.finalizeSpawn(level, level.getCurrentDifficultyAt(reinforcement.blockPosition()), EntitySpawnReason.REINFORCEMENT, null); +- level.addFreshEntityWithPassengers(reinforcement); ++ level.addFreshEntityWithPassengers(reinforcement, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.REINFORCEMENTS); // CraftBukkit + AttributeInstance attribute = this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE); + AttributeModifier modifier = attribute.getModifier(REINFORCEMENT_CALLER_CHARGE_ID); + double existingAmount = modifier != null ? modifier.amount() : 0.0; +@@ -341,7 +_,12 @@ if (result) { float difficulty = level.getCurrentDifficultyAt(this.blockPosition()).getEffectiveDifficulty(); if (this.getMainHandItem().isEmpty() && this.isOnFire() && this.random.nextFloat() < difficulty * 0.3F) { @@ -178,7 +176,7 @@ } } -@@ -406,6 +_,7 @@ +@@ -403,6 +_,7 @@ output.putBoolean("CanBreakDoors", this.canBreakDoors()); output.putInt("InWaterTime", this.isInWater() ? this.inWaterTime : -1); output.putInt("DrownedConversionTime", this.isUnderWaterConverting() ? this.conversionTime : -1); @@ -186,7 +184,7 @@ } @Override -@@ -420,13 +_,15 @@ +@@ -417,13 +_,15 @@ } else { this.getEntityData().set(DATA_DROWNED_CONVERSION_ID, false); } @@ -204,7 +202,7 @@ return perished; } -@@ -461,7 +_,7 @@ +@@ -458,7 +_,7 @@ groupData = super.finalizeSpawn(level, difficulty, spawnReason, groupData); float difficultyModifier = difficulty.getSpecialMultiplier(); if (spawnReason != EntitySpawnReason.CONVERSION) { @@ -213,7 +211,7 @@ } if (groupData == null) { -@@ -488,7 +_,7 @@ +@@ -485,7 +_,7 @@ chicken.finalizeSpawn(level, difficulty, EntitySpawnReason.JOCKEY, null); chicken.setChickenJockey(true); this.startRiding(chicken, false, false); @@ -222,7 +220,7 @@ } } } -@@ -514,7 +_,7 @@ +@@ -511,7 +_,7 @@ protected void onOffspringSpawnedFromEgg(final Player spawner, final Mob offspring) { if (this.level() instanceof ServerLevel serverLevel) { float difficultyModifier = serverLevel.getCurrentDifficultyAt(offspring.blockPosition()).getSpecialMultiplier(); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/npc/villager/AbstractVillager.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/npc/villager/AbstractVillager.java.patch index 2cba8c7b6ee2..2f2138fa9c6a 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/npc/villager/AbstractVillager.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/npc/villager/AbstractVillager.java.patch @@ -23,7 +23,7 @@ + // Paper start - Villager#resetOffers + public void resetOffers() { + this.offers = new MerchantOffers(); -+ this.updateTrades((net.minecraft.server.level.ServerLevel) this.level()); ++ this.updateTrades((ServerLevel) this.level()); + } + // Paper end - Villager#resetOffers + diff --git a/paper-server/patches/sources/net/minecraft/world/entity/npc/villager/Villager.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/npc/villager/Villager.java.patch index 80d743b511a9..781915b36cfa 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/npc/villager/Villager.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/npc/villager/Villager.java.patch @@ -9,7 +9,7 @@ } } -@@ -376,7 +_,12 @@ +@@ -378,7 +_,12 @@ this.updateDemand(); for (MerchantOffer offer : this.getOffers()) { @@ -23,7 +23,7 @@ } this.resendOffersToTradingPlayer(); -@@ -437,7 +_,12 @@ +@@ -439,7 +_,12 @@ int missedUpdates = 2 - this.numberOfRestocksToday; if (missedUpdates > 0) { for (MerchantOffer offer : this.getOffers()) { @@ -37,7 +37,7 @@ } } -@@ -458,6 +_,7 @@ +@@ -460,6 +_,7 @@ int reputation = this.getPlayerReputation(player); if (reputation != 0) { for (MerchantOffer offer : this.getOffers()) { @@ -45,7 +45,7 @@ offer.addToSpecialPriceDiff(-Mth.floor(reputation * offer.getPriceMultiplier())); } } -@@ -467,6 +_,7 @@ +@@ -469,6 +_,7 @@ int amplifier = effect.getAmplifier(); for (MerchantOffer offer : this.getOffers()) { @@ -53,7 +53,7 @@ double modifier = 0.3 + 0.0625 * amplifier; int costReduction = (int)Math.floor(modifier * offer.getBaseCostA().getCount()); offer.addToSpecialPriceDiff(-Math.max(costReduction, 1)); -@@ -582,7 +_,7 @@ +@@ -584,7 +_,7 @@ } if (offer.shouldRewardExp()) { @@ -62,7 +62,7 @@ } } -@@ -600,7 +_,7 @@ +@@ -602,7 +_,7 @@ @Override public void die(final DamageSource source) { @@ -71,7 +71,7 @@ Entity murderer = source.getEntity(); if (murderer != null) { this.tellWitnessesThatIWasMurdered(murderer); -@@ -699,7 +_,7 @@ +@@ -701,7 +_,7 @@ return VillagerData.canLevelUp(currentLevel) && this.villagerXp >= VillagerData.getMaxXpPerLevel(currentLevel); } @@ -80,7 +80,7 @@ this.setVillagerData(this.getVillagerData().withLevel(this.getVillagerData().level() + 1)); this.updateTrades(level); } -@@ -762,12 +_,19 @@ +@@ -764,12 +_,19 @@ @Override public void thunderHit(final ServerLevel level, final LightningBolt lightningBolt) { if (level.getDifficulty() != Difficulty.PEACEFUL) { @@ -102,7 +102,7 @@ if (witch == null) { super.thunderHit(level, lightningBolt); } -@@ -807,15 +_,23 @@ +@@ -809,15 +_,23 @@ @Override protected void updateTrades(final ServerLevel level) { @@ -127,7 +127,7 @@ } public void gossip(final ServerLevel level, final Villager target, final long timestamp) { -@@ -847,7 +_,7 @@ +@@ -849,7 +_,7 @@ .limit(5L) .toList(); if (nearbyVillagersThatWantAGolem.size() >= villagersNeededToAgree) { @@ -136,7 +136,7 @@ EntityType.IRON_GOLEM, EntitySpawnReason.MOB_SUMMONED, level, -@@ -856,9 +_,11 @@ +@@ -858,9 +_,11 @@ 8, 6, SpawnUtil.Strategy.LEGACY_IRON_GOLEM, diff --git a/paper-server/patches/sources/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java.patch index 0c52d50e362a..5258a43a862f 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java +++ b/net/minecraft/world/entity/npc/wanderingtrader/WanderingTrader.java -@@ -52,6 +_,10 @@ +@@ -51,6 +_,10 @@ private static final int DEFAULT_DESPAWN_DELAY = 0; private @Nullable BlockPos wanderTarget; private int despawnDelay = 0; @@ -11,7 +11,7 @@ public WanderingTrader(final EntityType type, final Level level) { super(type, level); -@@ -67,14 +_,14 @@ +@@ -66,14 +_,14 @@ this, PotionContents.createItemStack(Items.POTION, Potions.INVISIBILITY), SoundEvents.WANDERING_TRADER_DISAPPEARED, @@ -28,7 +28,7 @@ ) ); this.goalSelector.addGoal(1, new TradeWithPlayerGoal(this)); -@@ -159,7 +_,7 @@ +@@ -158,7 +_,7 @@ protected void rewardTradeXp(final MerchantOffer offer) { if (offer.shouldRewardExp()) { int popXp = 3 + this.random.nextInt(4); @@ -37,7 +37,7 @@ } } -@@ -211,7 +_,7 @@ +@@ -210,7 +_,7 @@ private void maybeDespawn() { if (this.despawnDelay > 0 && !this.isTrading() && --this.despawnDelay == 0) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/npc/wanderingtrader/WanderingTraderSpawner.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/npc/wanderingtrader/WanderingTraderSpawner.java.patch index 1c205cd062e8..96b800ecd908 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/npc/wanderingtrader/WanderingTraderSpawner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/npc/wanderingtrader/WanderingTraderSpawner.java.patch @@ -47,23 +47,23 @@ } } -@@ -90,13 +_,13 @@ - return false; - } +@@ -93,13 +_,13 @@ + return false; + } -- WanderingTrader trader = EntityType.WANDERING_TRADER.spawn(level, spawnPosition, EntitySpawnReason.EVENT); -+ WanderingTrader trader = EntityType.WANDERING_TRADER.spawn(level, wanderingTrader -> wanderingTrader.setDespawnDelay(48000), spawnPosition, EntitySpawnReason.EVENT, false, false, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit // Paper - set despawnTimer before spawn events called - if (trader != null) { - for (int i = 0; i < 2; i++) { - this.tryToSpawnLlamaFor(level, trader, 4); - } +- WanderingTrader trader = EntityType.WANDERING_TRADER.spawn(level, spawnPosition, EntitySpawnReason.EVENT); ++ WanderingTrader trader = EntityType.WANDERING_TRADER.spawn(level, wanderingTrader -> wanderingTrader.setDespawnDelay(48000), spawnPosition, EntitySpawnReason.EVENT, false, false, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit // Paper - set despawnTimer before spawn events called + if (trader != null) { + for (int i = 0; i < 2; i++) { + this.tryToSpawnLlamaFor(level, trader, 4); + } -- trader.setDespawnDelay(48000); -+ // trader.setDespawnDelay(48000); // Paper - moved above, modifiable by plugins on CreatureSpawnEvent - trader.setWanderTarget(referencePos); - trader.setHomeTo(referencePos, 16); - return true; -@@ -110,7 +_,7 @@ +- trader.setDespawnDelay(48000); ++ // trader.setDespawnDelay(48000); // Paper - moved above, modifiable by plugins on CreatureSpawnEvent + trader.setWanderTarget(referencePos); + trader.setHomeTo(referencePos, 16); + return true; +@@ -112,7 +_,7 @@ private void tryToSpawnLlamaFor(final ServerLevel level, final WanderingTrader trader, final int radius) { BlockPos spawnPosition = this.findSpawnPositionNear(level, trader.blockPosition(), radius); if (spawnPosition != null) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch index d32965b732e3..f13116920ae6 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/player/Player.java +++ b/net/minecraft/world/entity/player/Player.java -@@ -150,7 +_,7 @@ +@@ -149,7 +_,7 @@ private static final int DEFAULT_SCORE = 0; public static final float CREATIVE_ENTITY_INTERACTION_RANGE_MODIFIER_VALUE = 2.0F; private final Inventory inventory; @@ -9,7 +9,7 @@ public final InventoryMenu inventoryMenu; public AbstractContainerMenu containerMenu; protected FoodData foodData = new FoodData(); -@@ -172,6 +_,18 @@ +@@ -171,6 +_,18 @@ private Optional lastDeathLocation = Optional.empty(); public @Nullable FishingHook fishing; public float hurtDir; @@ -28,7 +28,7 @@ public Player(final Level level, final GameProfile gameProfile) { super(EntityType.PLAYER, level); -@@ -238,6 +_,13 @@ +@@ -241,6 +_,13 @@ if (this.isSleeping()) { this.sleepCounter++; @@ -42,7 +42,7 @@ if (this.sleepCounter > 100) { this.sleepCounter = 100; } -@@ -267,7 +_,7 @@ +@@ -270,7 +_,7 @@ ItemStack mainHandItemStack = this.getMainHandItem(); if (!ItemStack.matches(this.lastItemInMainHand, mainHandItemStack)) { if (!ItemStack.isSameItem(this.lastItemInMainHand, mainHandItemStack)) { @@ -51,7 +51,7 @@ } this.lastItemInMainHand = mainHandItemStack.copy(); -@@ -318,7 +_,7 @@ +@@ -321,7 +_,7 @@ } private void turtleHelmetTick() { @@ -60,7 +60,7 @@ } private boolean isEquipped(final Item item) { -@@ -419,6 +_,18 @@ +@@ -422,6 +_,18 @@ } } @@ -79,7 +79,7 @@ public void closeContainer() { this.containerMenu = this.inventoryMenu; } -@@ -430,8 +_,14 @@ +@@ -433,8 +_,14 @@ public void rideTick() { if (!this.level().isClientSide() && this.wantsToStopRiding() && this.isPassenger()) { this.stopRiding(); @@ -96,36 +96,36 @@ super.rideTick(); } } -@@ -684,10 +_,10 @@ - if (this.isDeadOrDying()) { - return false; - } else { -- this.removeEntitiesOnShoulder(); -+ // this.removeEntitiesOnShoulder(); // CraftBukkit - moved down - if (source.scalesWithDifficulty()) { - if (level.getDifficulty() == Difficulty.PEACEFUL) { -- damage = 0.0F; -+ return false; // CraftBukkit - damage = 0.0F -> return false - } +@@ -691,10 +_,10 @@ + return false; + } - if (level.getDifficulty() == Difficulty.EASY) { -@@ -699,7 +_,14 @@ - } - } +- this.removeEntitiesOnShoulder(); ++ // this.removeEntitiesOnShoulder(); // CraftBukkit - moved down + if (source.scalesWithDifficulty()) { + if (level.getDifficulty() == Difficulty.PEACEFUL) { +- damage = 0.0F; ++ return false; // CraftBukkit - damage = 0.0F -> return false + } -- return damage != 0.0F && super.hurtServer(level, source, damage); -+ // return damage != 0.0F && super.hurtServer(level, source, damage); -+ // CraftBukkit start - Don't filter out 0 damage -+ boolean damaged = super.hurtServer(level, source, damage); -+ if (damaged) { -+ this.removeEntitiesOnShoulder(); -+ } -+ return damaged; -+ // CraftBukkit end + if (level.getDifficulty() == Difficulty.EASY) { +@@ -706,7 +_,14 @@ } } + +- return damage != 0.0F && super.hurtServer(level, source, damage); ++ // return damage != 0.0F && super.hurtServer(level, source, damage); ++ // CraftBukkit start - Don't filter out 0 damage ++ boolean damaged = super.hurtServer(level, source, damage); ++ if (damaged) { ++ this.removeEntitiesOnShoulder(); ++ } ++ return damaged; ++ // CraftBukkit end } -@@ -711,7 +_,7 @@ + + @Override +@@ -716,7 +_,7 @@ BlocksAttacks blocksAttacks = itemBlockingWith != null ? itemBlockingWith.get(DataComponents.BLOCKS_ATTACKS) : null; float secondsToDisableBlocking = attacker.getSecondsToDisableBlocking(); if (secondsToDisableBlocking > 0.0F && blocksAttacks != null) { @@ -134,7 +134,7 @@ } } -@@ -721,9 +_,29 @@ +@@ -726,9 +_,29 @@ } public boolean canHarmPlayer(final Player target) { @@ -167,7 +167,7 @@ } @Override -@@ -737,7 +_,12 @@ +@@ -742,7 +_,12 @@ } @Override @@ -181,16 +181,16 @@ if (!this.isInvulnerableTo(level, source)) { dmg = this.getDamageAfterArmorAbsorb(source, dmg); dmg = this.getDamageAfterMagicAbsorb(source, dmg); -@@ -749,7 +_,7 @@ +@@ -755,7 +_,7 @@ } - if (var8 != 0.0F) { + if (dmg != 0.0F) { - this.causeFoodExhaustion(source.getFoodExhaustion()); + this.causeFoodExhaustion(source.getFoodExhaustion(), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.DAMAGED); // CraftBukkit - EntityExhaustionEvent - this.getCombatTracker().recordDamage(source, var8); - this.setHealth(this.getHealth() - var8); - if (var8 < 3.4028235E37F) { -@@ -759,6 +_,7 @@ + this.getCombatTracker().recordDamage(source, dmg); + this.setHealth(this.getHealth() - dmg); + if (dmg < 3.4028235E37F) { +@@ -765,6 +_,7 @@ this.gameEvent(GameEvent.ENTITY_DAMAGE); } } @@ -198,7 +198,7 @@ } public boolean isTextFilteringEnabled() { -@@ -852,14 +_,16 @@ +@@ -858,14 +_,16 @@ } @Override @@ -218,7 +218,7 @@ } @Override -@@ -938,15 +_,25 @@ +@@ -946,15 +_,25 @@ } public void attack(final Entity entity) { @@ -248,7 +248,7 @@ if (baseDamage > 0.0F || magicBoost > 0.0F) { boolean fullStrengthAttack = attackStrengthScale > 0.9F; boolean knockbackAttack; -@@ -959,7 +_,9 @@ +@@ -967,7 +_,9 @@ baseDamage += attackingItemStack.getItem().getAttackDamageBonus(entity, baseDamage, damageSource); boolean criticalAttack = fullStrengthAttack && this.canCriticalAttack(entity); @@ -258,7 +258,7 @@ baseDamage *= 1.5F; } -@@ -982,7 +_,7 @@ +@@ -990,7 +_,7 @@ this.setLastHurtMob(entity); this.itemAttackInteraction(entity, attackingItemStack, damageSource, true); this.damageStatsAndHearts(entity, oldLivingEntityHealth); @@ -267,7 +267,7 @@ } else { this.playServerSideSound(SoundEvents.PLAYER_ATTACK_NODAMAGE); } -@@ -994,7 +_,7 @@ +@@ -1002,7 +_,7 @@ } private void playServerSideSound(final SoundEvent sound) { @@ -276,7 +276,7 @@ } private DamageSource createAttackSource(final ItemStack attackingItemStack) { -@@ -1005,11 +_,12 @@ +@@ -1013,11 +_,12 @@ return !entity.isAttackable() || entity.skipAttackInteraction(this); } @@ -291,7 +291,7 @@ return true; } else { return false; -@@ -1109,19 +_,40 @@ +@@ -1117,19 +_,40 @@ public void causeExtraKnockback(final Entity entity, final float knockbackAmount, final Vec3 oldMovement) { if (knockbackAmount > 0.0F) { if (entity instanceof LivingEntity livingTarget) { @@ -334,7 +334,7 @@ } } -@@ -1142,8 +_,11 @@ +@@ -1150,8 +_,11 @@ && !(nearby instanceof ArmorStand armorStand && armorStand.isMarker()) && this.distanceToSqr(nearby) < 9.0) { float enchantedDamage = this.getEnchantedDamage(nearby, var12, damageSource) * attackStrengthScale; @@ -348,7 +348,7 @@ EnchantmentHelper.doPostAttackEffects(serverLevel, nearby, damageSource); } } -@@ -1176,7 +_,16 @@ +@@ -1184,7 +_,16 @@ public boolean stabAttack( final EquipmentSlot slot, final Entity target, float baseDamage, final boolean dealsDamage, final boolean dealsKnockback, final boolean dismounts ) { @@ -364,28 +364,28 @@ + if (!playerAttackEntityEvent.callEvent() || cannotAttack) { // Logic moved to cannotAttack local variable. + // Paper end - PlayerAttackEntityEvent return false; - } else { - ItemStack weaponItem = this.getItemBySlot(slot); -@@ -1187,7 +_,8 @@ - baseDamage *= this.baseDamageScaleFactor(); - } + } -- if (dealsKnockback && this.deflectProjectile(target)) { -+ final float dmgFinal = magicBoost; // Paper - damage events -+ if (dealsKnockback && this.deflectProjectile(target, () -> !org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(target, damageSource, dmgFinal, false))) { // Paper - damage events - return true; - } else { - float totalDamage = dealsDamage ? baseDamage + magicBoost : 0.0F; -@@ -1215,7 +_,7 @@ - this.setLastHurtMob(target); - this.itemAttackInteraction(target, weaponItem, damageSource, wasHurt); - this.damageStatsAndHearts(target, oldLivingEntityHealth); -- this.causeFoodExhaustion(0.1F); -+ this.causeFoodExhaustion(this.level().spigotConfig.combatExhaustion, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.ATTACK); // CraftBukkit - EntityExhaustionEvent // Spigot - Change to use configurable value - return true; - } - } -@@ -1226,8 +_,8 @@ +@@ -1196,7 +_,8 @@ + baseDamage *= this.baseDamageScaleFactor(); + } + +- if (dealsKnockback && this.deflectProjectile(target)) { ++ final float dmgFinal = magicBoost; // Paper - damage events ++ if (dealsKnockback && this.deflectProjectile(target, () -> !org.bukkit.craftbukkit.event.CraftEventFactory.handleNonLivingEntityDamageEvent(target, damageSource, dmgFinal, false))) { // Paper - damage events + return true; + } + +@@ -1226,7 +_,7 @@ + this.setLastHurtMob(target); + this.itemAttackInteraction(target, weaponItem, damageSource, wasHurt); + this.damageStatsAndHearts(target, oldLivingEntityHealth); +- this.causeFoodExhaustion(0.1F); ++ this.causeFoodExhaustion(this.level().spigotConfig.combatExhaustion, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.ATTACK); // CraftBukkit - EntityExhaustionEvent // Spigot - Change to use configurable value + return true; + } + +@@ -1234,8 +_,8 @@ } @Override @@ -396,7 +396,7 @@ this.inventoryMenu.removed(this); if (this.hasContainerOpen()) { this.doCloseContainer(); -@@ -1295,6 +_,12 @@ +@@ -1303,6 +_,12 @@ } public Either startSleepInBed(final BlockPos pos) { @@ -409,16 +409,16 @@ this.startSleeping(pos); this.sleepCounter = 0; return Either.right(Unit.INSTANCE); -@@ -1411,7 +_,7 @@ +@@ -1419,7 +_,7 @@ @Override public boolean causeFallDamage(final double fallDistance, final float damageModifier, final DamageSource damageSource) { - if (this.abilities.mayfly) { + if (this.abilities.mayfly && !this.flyingFallDamage.toBooleanOrElse(false)) { // Paper - flying fall damage return false; - } else { - if (fallDistance >= 2.0) { -@@ -1432,7 +_,15 @@ + } + +@@ -1440,7 +_,15 @@ } public void startFallFlying() { @@ -434,7 +434,7 @@ } @Override -@@ -1530,7 +_,7 @@ +@@ -1538,7 +_,7 @@ if (amount > 0 && this.experienceLevel % 5 == 0 && this.lastLevelUpTime < this.tickCount - 100.0F) { float vol = this.experienceLevel > 30 ? 1.0F : this.experienceLevel / 30.0F; @@ -443,7 +443,7 @@ this.lastLevelUpTime = this.tickCount; } } -@@ -1538,15 +_,35 @@ +@@ -1546,15 +_,35 @@ public int getXpNeededForNextLevel() { if (this.experienceLevel >= 30) { return 112 + (this.experienceLevel - 30) * 9; @@ -525,7 +525,7 @@ public void resetOnlyAttackStrengthTicker() { this.attackStrengthTicker = 0; -@@ -1843,17 +_,32 @@ +@@ -1843,19 +_,34 @@ return ImmutableList.of(Pose.STANDING, Pose.CROUCHING, Pose.SWIMMING); } @@ -547,28 +547,30 @@ public ItemStack getProjectile(final ItemStack heldWeapon) { if (!(heldWeapon.getItem() instanceof ProjectileWeaponItem)) { return ItemStack.EMPTY; - } else { -- Predicate supportedProjectiles = ((ProjectileWeaponItem)heldWeapon.getItem()).getSupportedHeldProjectiles(); -+ final org.apache.commons.lang3.mutable.MutableBoolean anyEventCancelled = new org.apache.commons.lang3.mutable.MutableBoolean(); // Paper - PlayerReadyArrowEvent -+ Predicate supportedProjectiles = ((ProjectileWeaponItem)heldWeapon.getItem()).getSupportedHeldProjectiles().and(item -> this.tryReadyArrow(heldWeapon, item, anyEventCancelled)); // Paper - PlayerReadyArrowEvent - ItemStack heldProjectile = ProjectileWeaponItem.getHeldProjectile(this, supportedProjectiles); - if (!heldProjectile.isEmpty()) { - return heldProjectile; - } else { -- supportedProjectiles = ((ProjectileWeaponItem)heldWeapon.getItem()).getAllSupportedProjectiles(); -+ supportedProjectiles = ((ProjectileWeaponItem)heldWeapon.getItem()).getAllSupportedProjectiles().and(item -> this.tryReadyArrow(heldWeapon, item, anyEventCancelled)); // Paper - PlayerReadyArrowEvent + } - for (int i = 0; i < this.inventory.getContainerSize(); i++) { - ItemStack itemStack = this.inventory.getItem(i); -@@ -1862,6 +_,7 @@ - } - } +- Predicate supportedProjectiles = ((ProjectileWeaponItem)heldWeapon.getItem()).getSupportedHeldProjectiles(); ++ final org.apache.commons.lang3.mutable.MutableBoolean anyEventCancelled = new org.apache.commons.lang3.mutable.MutableBoolean(); // Paper - PlayerReadyArrowEvent ++ Predicate supportedProjectiles = ((ProjectileWeaponItem)heldWeapon.getItem()).getSupportedHeldProjectiles().and(item -> this.tryReadyArrow(heldWeapon, item, anyEventCancelled)); // Paper - PlayerReadyArrowEvent + ItemStack heldProjectile = ProjectileWeaponItem.getHeldProjectile(this, supportedProjectiles); + if (!heldProjectile.isEmpty()) { + return heldProjectile; + } + +- supportedProjectiles = ((ProjectileWeaponItem)heldWeapon.getItem()).getAllSupportedProjectiles(); ++ supportedProjectiles = ((ProjectileWeaponItem)heldWeapon.getItem()).getAllSupportedProjectiles().and(item -> this.tryReadyArrow(heldWeapon, item, anyEventCancelled)); // Paper - PlayerReadyArrowEvent -+ if (anyEventCancelled.booleanValue() && !this.abilities.instabuild && this instanceof final ServerPlayer player) this.resyncUsingItem(player); // Paper - resync if no item matched the Predicate - return this.hasInfiniteMaterials() ? new ItemStack(Items.ARROW) : ItemStack.EMPTY; + for (int i = 0; i < this.inventory.getContainerSize(); i++) { + ItemStack itemStack = this.inventory.getItem(i); +@@ -1864,6 +_,7 @@ } } -@@ -2025,5 +_,6 @@ + ++ if (anyEventCancelled.booleanValue() && !this.abilities.instabuild && this instanceof final ServerPlayer player) this.resyncUsingItem(player); // Paper - resync if no item matched the Predicate + return this.hasInfiniteMaterials() ? new ItemStack(Items.ARROW) : ItemStack.EMPTY; + } + +@@ -2027,5 +_,6 @@ public static final Player.BedSleepingProblem OBSTRUCTED = new Player.BedSleepingProblem(Component.translatable("block.minecraft.bed.obstructed")); public static final Player.BedSleepingProblem OTHER_PROBLEM = new Player.BedSleepingProblem(null); public static final Player.BedSleepingProblem NOT_SAFE = new Player.BedSleepingProblem(Component.translatable("block.minecraft.bed.not_safe")); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch index ffa721197df7..7aab1ebaa180 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/Projectile.java.patch @@ -147,7 +147,7 @@ protected ProjectileDeflection hitTargetOrDeflectSelf(final HitResult hitResult) { if (hitResult.getType() == HitResult.Type.ENTITY) { EntityHitResult entityHitResult = (EntityHitResult)hitResult; -@@ -313,15 +_,35 @@ +@@ -313,16 +_,36 @@ } protected void onHitBlock(final BlockHitResult hitResult) { @@ -169,20 +169,21 @@ protected boolean canHitEntity(final Entity entity) { if (!entity.canBeHitByProjectile()) { return false; - } else { - Entity owner = this.getOwner(); -+ // Paper start - Cancel hit for vanished entities -+ if (owner instanceof net.minecraft.server.level.ServerPlayer) { -+ org.bukkit.entity.Entity collided = entity.getBukkitEntity(); -+ org.bukkit.entity.Player shooter = (org.bukkit.entity.Player) owner.getBukkitEntity(); -+ if (!shooter.canSee(collided)) { -+ return false; -+ } -+ } -+ // Paper end - Cancel hit for vanished entities - return owner == null || this.leftOwner || !owner.isPassengerOfSameVehicle(entity); } + + Entity owner = this.getOwner(); ++ // Paper start - Cancel hit for vanished entities ++ if (owner instanceof net.minecraft.server.level.ServerPlayer) { ++ org.bukkit.entity.Entity collided = entity.getBukkitEntity(); ++ org.bukkit.entity.Player shooter = (org.bukkit.entity.Player) owner.getBukkitEntity(); ++ if (!shooter.canSee(collided)) { ++ return false; ++ } ++ } ++ // Paper end - Cancel hit for vanished entities + return owner == null || this.leftOwner || !owner.isPassengerOfSameVehicle(entity); } + @@ -334,13 +_,7 @@ } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/ThrownTrident.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/ThrownTrident.java.patch index 684f6afb5484..d64989c78893 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/ThrownTrident.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/arrow/ThrownTrident.java.patch @@ -54,5 +54,5 @@ - float dmg = 8.0F; + float dmg = (float) this.baseDamage; // Paper - Allow trident custom damage Entity currentOwner = this.getOwner(); - DamageSource damageSource = this.damageSources().trident(this, (Entity)(currentOwner == null ? this : currentOwner)); + DamageSource damageSource = this.damageSources().trident(this, currentOwner == null ? this : currentOwner); if (this.level() instanceof ServerLevel serverLevel) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/Snowball.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/Snowball.java.patch index ece99bf0170f..ccfbd149040b 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/Snowball.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/projectile/throwableitemprojectile/Snowball.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/projectile/throwableitemprojectile/Snowball.java +++ b/net/minecraft/world/entity/projectile/throwableitemprojectile/Snowball.java -@@ -65,7 +_,7 @@ +@@ -63,7 +_,7 @@ super.onHit(hitResult); if (!this.level().isClientSide()) { this.level().broadcastEntityEvent(this, EntityEvent.DEATH); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/raid/Raid.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/raid/Raid.java.patch index 0258d237ed0b..440b9cd9aef2 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/raid/Raid.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/raid/Raid.java.patch @@ -148,5 +148,5 @@ + } + // CraftBukkit end - private static enum RaidStatus implements StringRepresentable { + private enum RaidStatus implements StringRepresentable { ONGOING("ongoing"), diff --git a/paper-server/patches/sources/net/minecraft/world/entity/raid/Raider.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/raid/Raider.java.patch index fc089bfbd33d..3bb1d81c52d4 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/raid/Raider.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/raid/Raider.java.patch @@ -44,11 +44,11 @@ entity.setAggressive(true); } -@@ -393,6 +_,7 @@ +@@ -390,6 +_,7 @@ } private boolean cannotPickUpBanner() { + if (!getServerLevel(this.mob).getGameRules().get(net.minecraft.world.level.gamerules.GameRules.MOB_GRIEFING)) return true; // Paper - respect game and entity rules for picking up items if (!this.mob.hasActiveRaid()) { return true; - } else if (this.mob.getCurrentRaid().isOver()) { + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/raid/Raids.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/raid/Raids.java.patch index 64840baa8750..74239c4658d8 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/raid/Raids.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/raid/Raids.java.patch @@ -8,32 +8,32 @@ } this.nextId = nextId; -@@ -130,11 +_,23 @@ - } +@@ -132,11 +_,23 @@ + } - Raid raid = this.getOrCreateRaid(level, raidCenterPos); -- if (!raid.isStarted() && !this.raidMap.containsValue(raid)) { -- this.raidMap.put(this.getUniqueId(), raid); -- } + Raid raid = this.getOrCreateRaid(level, raidCenterPos); +- if (!raid.isStarted() && !this.raidMap.containsValue(raid)) { +- this.raidMap.put(this.getUniqueId(), raid); +- } - -- if (!raid.isStarted() || raid.getRaidOmenLevel() < raid.getMaxRaidOmenLevel()) { -+ // CraftBukkit - moved down -+ // if (!raid.isStarted() && !this.raidMap.containsValue(raid)) { -+ // this.raidMap.put(this.getUniqueId(), raid); -+ // } +- if (!raid.isStarted() || raid.getRaidOmenLevel() < raid.getMaxRaidOmenLevel()) { ++ // CraftBukkit - moved down ++ // if (!raid.isStarted() && !this.raidMap.containsValue(raid)) { ++ // this.raidMap.put(this.getUniqueId(), raid); ++ // } + -+ if (!raid.isStarted() || (raid.isInProgress() && raid.getRaidOmenLevel() < raid.getMaxRaidOmenLevel())) { // CraftBukkit - fixed a bug with raid: players could add up Bad Omen level even when the raid had finished -+ // CraftBukkit start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callRaidTriggerEvent(level, raid, player)) { -+ player.removeEffect(net.minecraft.world.effect.MobEffects.RAID_OMEN); -+ return null; -+ } ++ if (!raid.isStarted() || (raid.isInProgress() && raid.getRaidOmenLevel() < raid.getMaxRaidOmenLevel())) { // CraftBukkit - fixed a bug with raid: players could add up Bad Omen level even when the raid had finished ++ // CraftBukkit start ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callRaidTriggerEvent(level, raid, player)) { ++ player.removeEffect(net.minecraft.world.effect.MobEffects.RAID_OMEN); ++ return null; ++ } + -+ if (!raid.isStarted() && !this.raidMap.containsValue(raid)) { -+ this.raidMap.put(this.getUniqueId(), raid); -+ raid.idOrNegativeOne = this.nextId; // Paper - expose id of raids while method is kept around as deprecated for removal -+ } -+ // CraftBukkit end - raid.absorbRaidOmen(player); - } ++ if (!raid.isStarted() && !this.raidMap.containsValue(raid)) { ++ this.raidMap.put(this.getUniqueId(), raid); ++ raid.idOrNegativeOne = this.nextId; // Paper - expose id of raids while method is kept around as deprecated for removal ++ } ++ // CraftBukkit end + raid.absorbRaidOmen(player); + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/ContainerEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/ContainerEntity.java.patch index 4ec5f3460b32..ebed84eb4ad1 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/ContainerEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/ContainerEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/vehicle/ContainerEntity.java +++ b/net/minecraft/world/entity/vehicle/ContainerEntity.java -@@ -59,12 +_,12 @@ +@@ -58,12 +_,12 @@ default void addChestVehicleSaveData(final ValueOutput output) { if (this.getContainerLootTable() != null) { output.putString("LootTable", this.getContainerLootTable().identifier().toString()); @@ -15,7 +15,7 @@ } default void readChestVehicleSaveData(final ValueInput input) { -@@ -72,7 +_,12 @@ +@@ -71,7 +_,12 @@ ResourceKey lootTable = input.read("LootTable", LootTable.KEY_CODEC).orElse(null); this.setContainerLootTable(lootTable); this.setContainerLootTableSeed(input.getLongOr("LootTableSeed", 0L)); @@ -29,7 +29,7 @@ ContainerHelper.loadAllItems(input, this.getItemStacks()); } } -@@ -87,19 +_,27 @@ +@@ -86,19 +_,27 @@ } default InteractionResult interactWithContainerVehicle(final Player player) { @@ -60,7 +60,7 @@ LootParams.Builder builder = new LootParams.Builder((ServerLevel)this.level()).withParameter(LootContextParams.ORIGIN, this.position()); if (player != null) { builder.withLuck(player.getLuck()).withParameter(LootContextParams.THIS_ENTITY, player); -@@ -173,4 +_,14 @@ +@@ -168,4 +_,14 @@ default boolean isChestVehicleStillValid(final Player player) { return !this.isRemoved() && player.isWithinEntityInteractionRange(this.getBoundingBox(), 4.0); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/VehicleEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/VehicleEntity.java.patch index 46cf3ef454f7..dc8fbae460a4 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/VehicleEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/VehicleEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/vehicle/VehicleEntity.java +++ b/net/minecraft/world/entity/vehicle/VehicleEntity.java -@@ -32,12 +_,22 @@ +@@ -32,7 +_,7 @@ } @Override @@ -8,37 +8,29 @@ + public boolean hurtServer(final ServerLevel level, final DamageSource source, float damage) { // Paper - unfinal damage if (this.isRemoved()) { return true; - } else if (this.isInvulnerableToBase(source)) { + } +@@ -41,6 +_,16 @@ return false; - } else { -+ // CraftBukkit start -+ org.bukkit.entity.Vehicle vehicle = (org.bukkit.entity.Vehicle) this.getBukkitEntity(); -+ org.bukkit.craftbukkit.damage.CraftDamageSource damageSourceBukkit = new org.bukkit.craftbukkit.damage.CraftDamageSource(source); -+ org.bukkit.entity.Entity attacker = net.minecraft.Optionull.map( -+ source.eventEntityDamager() != null ? source.eventEntityDamager() : source.getDirectEntity(), Entity::getBukkitEntity -+ ); -+ org.bukkit.event.vehicle.VehicleDamageEvent event = new org.bukkit.event.vehicle.VehicleDamageEvent(vehicle, damageSourceBukkit, attacker, damage); -+ if (!event.callEvent()) return false; -+ damage = (float) event.getDamage(); -+ // CraftBukkit end - this.setHurtDir(-this.getHurtDir()); - this.setHurtTime(10); - this.markHurt(); -@@ -46,9 +_,23 @@ - boolean creativePlayer = source.getEntity() instanceof Player player && player.getAbilities().instabuild; - if ((creativePlayer || !(this.getDamage() > 40.0F)) && !this.shouldSourceDestroy(source)) { - if (creativePlayer) { -- this.discard(); -+ // CraftBukkit start -+ org.bukkit.event.vehicle.VehicleDestroyEvent destroyEvent = new org.bukkit.event.vehicle.VehicleDestroyEvent(vehicle, damageSourceBukkit, attacker); -+ if (!destroyEvent.callEvent()) { -+ this.setDamage(40.0F); // Maximize damage so this doesn't get triggered again right away -+ return true; -+ } -+ // CraftBukkit end -+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause - } - } else { + } + ++ // CraftBukkit start ++ org.bukkit.entity.Vehicle vehicle = (org.bukkit.entity.Vehicle) this.getBukkitEntity(); ++ org.bukkit.craftbukkit.damage.CraftDamageSource damageSourceBukkit = new org.bukkit.craftbukkit.damage.CraftDamageSource(source); ++ org.bukkit.entity.Entity attacker = net.minecraft.Optionull.map( ++ source.eventEntityDamager() != null ? source.eventEntityDamager() : source.getDirectEntity(), Entity::getBukkitEntity ++ ); ++ org.bukkit.event.vehicle.VehicleDamageEvent event = new org.bukkit.event.vehicle.VehicleDamageEvent(vehicle, damageSourceBukkit, attacker, damage); ++ if (!event.callEvent()) return false; ++ damage = (float) event.getDamage(); ++ // CraftBukkit end + this.setHurtDir(-this.getHurtDir()); + this.setHurtTime(10); + this.markHurt(); +@@ -49,9 +_,23 @@ + boolean creativePlayer = source.getEntity() instanceof Player player && player.getAbilities().instabuild; + if ((creativePlayer || !(this.getDamage() > 40.0F)) && !this.shouldSourceDestroy(source)) { + if (creativePlayer) { +- this.discard(); + // CraftBukkit start + org.bukkit.event.vehicle.VehicleDestroyEvent destroyEvent = new org.bukkit.event.vehicle.VehicleDestroyEvent(vehicle, damageSourceBukkit, attacker); + if (!destroyEvent.callEvent()) { @@ -46,6 +38,16 @@ + return true; + } + // CraftBukkit end - this.destroy(level, source); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause } + } else { ++ // CraftBukkit start ++ org.bukkit.event.vehicle.VehicleDestroyEvent destroyEvent = new org.bukkit.event.vehicle.VehicleDestroyEvent(vehicle, damageSourceBukkit, attacker); ++ if (!destroyEvent.callEvent()) { ++ this.setDamage(40.0F); // Maximize damage so this doesn't get triggered again right away ++ return true; ++ } ++ // CraftBukkit end + this.destroy(level, source); + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java.patch index aef6bd04c3d5..d540df29e0fb 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java.patch @@ -84,7 +84,7 @@ this.setDeltaMovement(this.getDeltaMovement().multiply(1.0, 0.0, 1.0)); this.lastYd = 0.0; } -@@ -704,12 +_,20 @@ +@@ -702,12 +_,20 @@ } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java.patch index 67ecbf491eed..cb1830a44de1 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/boat/AbstractChestBoat.java.patch @@ -15,7 +15,7 @@ } @Override -@@ -96,8 +_,8 @@ +@@ -98,8 +_,8 @@ @Override public void openCustomInventoryScreen(final Player player) { @@ -26,16 +26,16 @@ this.gameEvent(GameEvent.CONTAINER_OPEN, player); PiglinAi.angerNearbyPiglins(level, player, true); } -@@ -149,7 +_,7 @@ +@@ -151,7 +_,7 @@ @Override public @Nullable AbstractContainerMenu createMenu(final int containerId, final Inventory inventory, final Player player) { - if (this.lootTable != null && player.isSpectator()) { + if (this.lootTable != null && player.isSpectator()) { // Paper - LootTable API (TODO spectators can open chests that aren't ready to be re-generated but this doesn't support that) return null; - } else { - this.unpackLootTable(inventory.player); -@@ -195,4 +_,58 @@ + } + +@@ -197,4 +_,58 @@ public void stopOpen(final ContainerUser containerUser) { this.level().gameEvent(GameEvent.CONTAINER_CLOSE, this.position(), GameEvent.Context.of(containerUser.getLivingEntity())); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/MinecartCommandBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/MinecartCommandBlock.java.patch index b90a4b0a86c3..abead85157c6 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/MinecartCommandBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/MinecartCommandBlock.java.patch @@ -1,15 +1,15 @@ --- a/net/minecraft/world/entity/vehicle/minecart/MinecartCommandBlock.java +++ b/net/minecraft/world/entity/vehicle/minecart/MinecartCommandBlock.java -@@ -88,7 +_,7 @@ +@@ -87,7 +_,7 @@ @Override public InteractionResult interact(final Player player, final InteractionHand hand, final Vec3 location) { - if (!player.canUseGameMasterBlocks()) { + if (!player.canUseGameMasterBlocks() && (!player.isCreative() || !player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission return InteractionResult.PASS; - } else { - if (player.level().isClientSide()) { -@@ -131,7 +_,7 @@ + } + +@@ -125,7 +_,7 @@ MinecartCommandBlock.this.position(), MinecartCommandBlock.this.getRotationVector(), level, @@ -18,7 +18,7 @@ this.getName().getString(), MinecartCommandBlock.this.getDisplayName(), level.getServer(), -@@ -143,5 +_,17 @@ +@@ -137,5 +_,17 @@ public boolean isValid() { return !MinecartCommandBlock.this.isRemoved(); } @@ -26,12 +26,12 @@ + // CraftBukkit start + @Override + public org.bukkit.command.CommandSender getBukkitSender(CommandSourceStack wrapper) { -+ return net.minecraft.world.entity.vehicle.minecart.MinecartCommandBlock.this.getBukkitEntity(); ++ return MinecartCommandBlock.this.getBukkitEntity(); + } + + @Override -+ public net.minecraft.server.level.ServerLevel getLevel() { -+ return (net.minecraft.server.level.ServerLevel) MinecartCommandBlock.this.level(); ++ public ServerLevel getLevel() { ++ return (ServerLevel) MinecartCommandBlock.this.level(); + } + // CraftBukkit end } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/NewMinecartBehavior.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/NewMinecartBehavior.java.patch index bbf4cca13b12..05af618c7eeb 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/NewMinecartBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/NewMinecartBehavior.java.patch @@ -57,17 +57,17 @@ } @@ -552,6 +_,15 @@ } else { - for (Entity entityx : this.level().getEntities(this.minecart, hitbox)) { - if (!this.minecart.hasPassenger(entityx) && entityx.isPushable() && entityx instanceof AbstractMinecart) { + for (Entity entity : this.level().getEntities(this.minecart, hitbox)) { + if (!this.minecart.hasPassenger(entity) && entity.isPushable() && entity instanceof AbstractMinecart) { + // CraftBukkit start + org.bukkit.event.vehicle.VehicleEntityCollisionEvent collisionEvent = new org.bukkit.event.vehicle.VehicleEntityCollisionEvent( + (org.bukkit.entity.Vehicle) this.minecart.getBukkitEntity(), -+ entityx.getBukkitEntity() ++ entity.getBukkitEntity() + ); + if (!collisionEvent.callEvent()) { + continue; + } + // CraftBukkit end - entityx.push(this.minecart); + entity.push(this.minecart); pushed = true; } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/OldMinecartBehavior.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/OldMinecartBehavior.java.patch index 891b315c2eb6..109c8c375e7e 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/OldMinecartBehavior.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/minecart/OldMinecartBehavior.java.patch @@ -25,15 +25,15 @@ } @@ -384,6 +_,12 @@ } else { - for (Entity entityx : this.level().getEntities(this.minecart, hitbox)) { - if (!this.minecart.hasPassenger(entityx) && entityx.isPushable() && entityx instanceof AbstractMinecart) { + for (Entity entity : this.level().getEntities(this.minecart, hitbox)) { + if (!this.minecart.hasPassenger(entity) && entity.isPushable() && entity instanceof AbstractMinecart) { + // CraftBukkit start + org.bukkit.event.vehicle.VehicleEntityCollisionEvent collisionEvent = new org.bukkit.event.vehicle.VehicleEntityCollisionEvent( -+ (org.bukkit.entity.Vehicle) this.minecart.getBukkitEntity(), entityx.getBukkitEntity() ++ (org.bukkit.entity.Vehicle) this.minecart.getBukkitEntity(), entity.getBukkitEntity() + ); + if (!collisionEvent.callEvent()) continue; + // CraftBukkit end - entityx.push(this.minecart); + entity.push(this.minecart); } } @@ -406,11 +_,18 @@ diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/AbstractContainerMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/AbstractContainerMenu.java.patch index aa16cc30a100..acf6056d0032 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/AbstractContainerMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/AbstractContainerMenu.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/inventory/AbstractContainerMenu.java +++ b/net/minecraft/world/inventory/AbstractContainerMenu.java -@@ -65,6 +_,35 @@ +@@ -64,6 +_,35 @@ private final List containerListeners = Lists.newArrayList(); private @Nullable ContainerSynchronizer synchronizer; private boolean suppressRemoteUpdates; @@ -36,7 +36,7 @@ protected AbstractContainerMenu(final @Nullable MenuType menuType, final int containerId) { this.menuType = menuType; -@@ -176,8 +_,43 @@ +@@ -175,8 +_,43 @@ if (this.synchronizer != null) { this.synchronizer.sendInitialData(this, itemsToSend, carried.copy(), this.remoteDataSlots.toIntArray()); @@ -82,7 +82,7 @@ public void removeSlotListener(final ContainerListener listener) { this.containerListeners.remove(listener); -@@ -243,7 +_,7 @@ +@@ -242,7 +_,7 @@ this.lastSlots.set(i, newItem); for (ContainerListener containerListener : this.containerListeners) { @@ -91,7 +91,7 @@ } } } -@@ -351,6 +_,7 @@ +@@ -350,6 +_,7 @@ this.resetQuickCraft(); } } else if (this.quickcraftStatus == QUICKCRAFT_HEADER_CONTINUE) { @@ -99,7 +99,7 @@ Slot slot = this.slots.get(slotIndex); ItemStack carriedItemStack = this.getCarried(); if (canItemQuickReplace(slot, carriedItemStack, true) -@@ -375,6 +_,7 @@ +@@ -374,6 +_,7 @@ } int remaining = this.getCarried().getCount(); @@ -107,7 +107,7 @@ for (Slot slot : this.quickcraftSlots) { ItemStack carriedItemStack = this.getCarried(); -@@ -387,12 +_,42 @@ +@@ -386,12 +_,42 @@ int maxSize = Math.min(source.getMaxStackSize(), slot.getMaxStackSize(source)); int newCount = Math.min(getQuickCraftPlaceCount(this.quickcraftSlots.size(), this.quickcraftType, source) + carry, maxSize); remaining -= newCount - carry; @@ -156,7 +156,7 @@ } this.resetQuickCraft(); -@@ -406,8 +_,11 @@ +@@ -405,8 +_,11 @@ if (slotIndex == -999) { if (!this.getCarried().isEmpty()) { if (clickAction == ClickAction.PRIMARY) { @@ -169,13 +169,13 @@ } else { player.drop(this.getCarried().split(1), true); } -@@ -469,8 +_,18 @@ +@@ -468,8 +_,18 @@ } - slotx.setChanged(); + slot.setChanged(); + // CraftBukkit start - Make sure the client has the right slot contents -+ if (player instanceof ServerPlayer serverPlayer && slotx.getMaxStackSize() != Container.MAX_STACK) { -+ serverPlayer.connection.send(new net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket(this.containerId, this.incrementStateId(), slotx.index, slotx.getItem())); ++ if (player instanceof ServerPlayer serverPlayer && slot.getMaxStackSize() != Container.MAX_STACK) { ++ serverPlayer.connection.send(new net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket(this.containerId, this.incrementStateId(), slot.index, slot.getItem())); + // Updating a crafting inventory makes the client reset the result slot, have to send it again + if (this.getBukkitView().getType() == org.bukkit.event.inventory.InventoryType.WORKBENCH || this.getBukkitView().getType() == org.bukkit.event.inventory.InventoryType.CRAFTING) { + serverPlayer.connection.send(new net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket(this.containerId, this.incrementStateId(), 0, this.getSlot(0).getItem())); @@ -188,10 +188,10 @@ ItemStack source = inventory.getItem(buttonNum); Slot target = this.slots.get(slotIndex); ItemStack targetItemStack = target.getItem(); -@@ -530,7 +_,11 @@ +@@ -529,7 +_,11 @@ } - itemStack = slotx.safeTake(amount, Integer.MAX_VALUE, player); + itemStack = slot.safeTake(amount, Integer.MAX_VALUE, player); - player.drop(itemStack, true); + // CraftBukkit start - SPIGOT-8010: break loop + if (player.drop(itemStack, true) == null) { @@ -201,7 +201,7 @@ player.handleCreativeModeItemDrop(itemStack); } } -@@ -595,14 +_,15 @@ +@@ -590,14 +_,15 @@ if (player instanceof ServerPlayer) { ItemStack carried = this.getCarried(); if (!carried.isEmpty()) { @@ -219,7 +219,7 @@ boolean serverPlayerHasDisconnected = player instanceof ServerPlayer serverPlayer && serverPlayer.hasDisconnected(); if (playerRemovedNotChangingDimension || serverPlayerHasDisconnected) { player.drop(carried, false); -@@ -642,6 +_,14 @@ +@@ -637,6 +_,14 @@ public abstract boolean stillValid(Player player); protected boolean moveItemStackTo(final ItemStack itemStack, final int startSlot, final int endSlot, final boolean backwards) { @@ -234,7 +234,7 @@ boolean anythingChanged = false; int destSlot = startSlot; if (backwards) { -@@ -652,18 +_,27 @@ +@@ -647,18 +_,27 @@ while (!itemStack.isEmpty() && (backwards ? destSlot >= startSlot : destSlot < endSlot)) { Slot slot = this.slots.get(destSlot); ItemStack target = slot.getItem(); @@ -262,29 +262,29 @@ anythingChanged = true; } } -@@ -686,10 +_,21 @@ +@@ -681,10 +_,21 @@ while (backwards ? destSlot >= startSlot : destSlot < endSlot) { - Slot slotx = this.slots.get(destSlot); - ItemStack targetx = slotx.getItem(); + Slot slot = this.slots.get(destSlot); + ItemStack target = slot.getItem(); + // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent + if (isCheck) { -+ targetx = targetx.copy(); ++ target = target.copy(); + } + // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent - if (targetx.isEmpty() && slotx.mayPlace(itemStack)) { - int maxStackSize = slotx.getMaxStackSize(itemStack); + if (target.isEmpty() && slot.mayPlace(itemStack)) { + int maxStackSize = slot.getMaxStackSize(itemStack); + // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent + if (isCheck) { + itemStack.shrink(Math.min(itemStack.getCount(), maxStackSize)); + } else { + // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent - slotx.setByPlayer(itemStack.split(Math.min(itemStack.getCount(), maxStackSize))); - slotx.setChanged(); + slot.setByPlayer(itemStack.split(Math.min(itemStack.getCount(), maxStackSize))); + slot.setChanged(); + } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent anythingChanged = true; break; } -@@ -773,6 +_,11 @@ +@@ -768,6 +_,11 @@ } public ItemStack getCarried() { @@ -296,7 +296,7 @@ return this.carried; } -@@ -826,4 +_,15 @@ +@@ -821,4 +_,15 @@ this.stateId = this.stateId + 1 & 32767; return this.stateId; } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/AbstractCraftingMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/AbstractCraftingMenu.java.patch index 456040a8a52b..4b86f66a63bd 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/AbstractCraftingMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/AbstractCraftingMenu.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/inventory/AbstractCraftingMenu.java +++ b/net/minecraft/world/inventory/AbstractCraftingMenu.java -@@ -13,14 +_,17 @@ +@@ -12,14 +_,17 @@ public abstract class AbstractCraftingMenu extends RecipeBookMenu { private final int width; private final int height; diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/AbstractFurnaceMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/AbstractFurnaceMenu.java.patch index 67a7de55c2ab..b23652ee19a3 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/AbstractFurnaceMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/AbstractFurnaceMenu.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/inventory/AbstractFurnaceMenu.java +++ b/net/minecraft/world/inventory/AbstractFurnaceMenu.java -@@ -35,6 +_,21 @@ +@@ -34,6 +_,21 @@ private final RecipeType recipeType; private final RecipePropertySet acceptedInputs; private final RecipeBookType recipeBookType; @@ -22,7 +22,7 @@ protected AbstractFurnaceMenu( final MenuType menuType, -@@ -69,6 +_,7 @@ +@@ -68,6 +_,7 @@ this.addSlot(new Slot(container, 0, 56, 17)); this.addSlot(new FurnaceFuelSlot(this, container, 1, 56, 53)); this.addSlot(new FurnaceResultSlot(inventory.player, container, 2, 116, 35)); @@ -30,7 +30,7 @@ this.addStandardInventorySlots(inventory, 8, 84); this.addDataSlots(data); } -@@ -86,6 +_,7 @@ +@@ -85,6 +_,7 @@ @Override public boolean stillValid(final Player player) { diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/BeaconMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/BeaconMenu.java.patch index 06b1bf622dd2..fdf2796bc797 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/BeaconMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/BeaconMenu.java.patch @@ -1,14 +1,10 @@ --- a/net/minecraft/world/inventory/BeaconMenu.java +++ b/net/minecraft/world/inventory/BeaconMenu.java -@@ -23,24 +_,14 @@ +@@ -22,20 +_,14 @@ private static final int USE_ROW_SLOT_START = 28; private static final int USE_ROW_SLOT_END = 37; private static final int NO_EFFECT = 0; - private final Container beacon = new SimpleContainer(1) { -- { -- Objects.requireNonNull(BeaconMenu.this); -- } -- - @Override - public boolean canPlaceItem(final int slot, final ItemStack itemStack) { - return itemStack.is(ItemTags.BEACON_PAYMENT_ITEMS); @@ -30,7 +26,7 @@ public BeaconMenu(final int containerId, final Container inventory) { this(containerId, inventory, new SimpleContainerData(3), ContainerLevelAccess.NULL); -@@ -48,6 +_,25 @@ +@@ -43,6 +_,25 @@ public BeaconMenu(final int containerId, final Container inventory, final ContainerData beaconData, final ContainerLevelAccess access) { super(MenuType.BEACON, containerId); @@ -56,7 +52,7 @@ checkContainerDataCount(beaconData, 3); this.beaconData = beaconData; this.access = access; -@@ -70,6 +_,7 @@ +@@ -65,6 +_,7 @@ @Override public boolean stillValid(final Player player) { @@ -64,7 +60,7 @@ return stillValid(this.access, player, Blocks.BEACON); } -@@ -143,13 +_,30 @@ +@@ -138,13 +_,30 @@ public @Nullable Holder getSecondaryEffect() { return decodeEffect(this.beaconData.get(2)); } @@ -98,7 +94,7 @@ } } -@@ -172,4 +_,17 @@ +@@ -167,4 +_,17 @@ return 1; } } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/CartographyTableMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/CartographyTableMenu.java.patch index 6a8a2dbc42a4..2faa1d0a05de 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/CartographyTableMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/CartographyTableMenu.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/inventory/CartographyTableMenu.java +++ b/net/minecraft/world/inventory/CartographyTableMenu.java -@@ -16,6 +_,21 @@ +@@ -15,6 +_,21 @@ import net.minecraft.world.level.saveddata.maps.MapItemSavedData; public class CartographyTableMenu extends AbstractContainerMenu { @@ -22,15 +22,11 @@ public static final int MAP_SLOT = 0; public static final int ADDITIONAL_SLOT = 1; public static final int RESULT_SLOT = 2; -@@ -25,28 +_,8 @@ +@@ -24,20 +_,8 @@ private static final int USE_ROW_SLOT_END = 39; private final ContainerLevelAccess access; private long lastSoundTime; - public final Container container = new SimpleContainer(2) { -- { -- Objects.requireNonNull(CartographyTableMenu.this); -- } -- - @Override - public void setChanged() { - CartographyTableMenu.this.slotsChanged(this); @@ -38,10 +34,6 @@ - } - }; - private final ResultContainer resultContainer = new ResultContainer() { -- { -- Objects.requireNonNull(CartographyTableMenu.this); -- } -- - @Override - public void setChanged() { - CartographyTableMenu.this.slotsChanged(this); @@ -53,7 +45,7 @@ public CartographyTableMenu(final int containerId, final Inventory inventory) { this(containerId, inventory, ContainerLevelAccess.NULL); -@@ -54,6 +_,34 @@ +@@ -45,6 +_,34 @@ public CartographyTableMenu(final int containerId, final Inventory inventory, final ContainerLevelAccess access) { super(MenuType.CARTOGRAPHY_TABLE, containerId); @@ -87,8 +79,8 @@ + // Paper end - Add missing InventoryHolders - move down this.access = access; this.addSlot(new Slot(this.container, 0, 15, 15) { - { -@@ -101,10 +_,12 @@ + @Override +@@ -80,10 +_,12 @@ } }); this.addStandardInventorySlots(inventory, 8, 84); @@ -101,7 +93,7 @@ return stillValid(this.access, player, Blocks.CARTOGRAPHY_TABLE); } -@@ -120,6 +_,7 @@ +@@ -99,6 +_,7 @@ } else { this.resultContainer.removeItemNoUpdate(2); } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch index 9e4ceb9aedc1..c62f1cab4aa6 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/EnchantmentMenu.java.patch @@ -1,14 +1,10 @@ --- a/net/minecraft/world/inventory/EnchantmentMenu.java +++ b/net/minecraft/world/inventory/EnchantmentMenu.java -@@ -32,23 +_,17 @@ +@@ -31,19 +_,17 @@ public class EnchantmentMenu extends AbstractContainerMenu { private static final Identifier EMPTY_SLOT_LAPIS_LAZULI = Identifier.withDefaultNamespace("container/slot/lapis_lazuli"); - private final Container enchantSlots = new SimpleContainer(2) { -- { -- Objects.requireNonNull(EnchantmentMenu.this); -- } -- - @Override - public void setChanged() { - super.setChanged(); @@ -29,7 +25,7 @@ public EnchantmentMenu(final int containerId, final Inventory inventory) { this(containerId, inventory, ContainerLevelAccess.NULL); -@@ -56,6 +_,22 @@ +@@ -51,6 +_,22 @@ public EnchantmentMenu(final int containerId, final Inventory inventory, final ContainerLevelAccess access) { super(MenuType.ENCHANTMENT, containerId); @@ -51,8 +47,8 @@ + // Paper end - Add missing InventoryHolders this.access = access; this.addSlot(new Slot(this.enchantSlots, 0, 15, 47) { - { -@@ -93,13 +_,14 @@ + @Override +@@ -80,13 +_,14 @@ this.addDataSlot(DataSlot.shared(this.levelClue, 0)); this.addDataSlot(DataSlot.shared(this.levelClue, 1)); this.addDataSlot(DataSlot.shared(this.levelClue, 2)); @@ -68,7 +64,7 @@ this.access.execute((level, pos) -> { IdMap> holders = level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).asHolderIdMap(); int bookcases = 0; -@@ -132,6 +_,42 @@ +@@ -119,6 +_,42 @@ } } @@ -111,71 +107,67 @@ this.broadcastChanges(); }); } else { -@@ -158,19 +_,52 @@ - return false; - } else { - this.access.execute((level, pos) -> { -- ItemStack enchantmentItem = itemStack; -+ ItemStack enchantmentItem = itemStack; // Paper - diff on change - List newEnchantment = this.getEnchantmentList(level.registryAccess(), itemStack, buttonId, this.costs[buttonId]); -- if (!newEnchantment.isEmpty()) { -+ // CraftBukkit start -+ IdMap> registry = level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).asHolderIdMap(); -+ if (true || !newEnchantment.isEmpty()) { -+ // player.onEnchantmentPerformed(itemStack, enchantmentCost); // Moved down -+ java.util.Map enchants = new java.util.HashMap<>(); -+ for (EnchantmentInstance instance : newEnchantment) { -+ enchants.put(org.bukkit.craftbukkit.enchantments.CraftEnchantment.minecraftHolderToBukkit(instance.enchantment()), instance.level()); -+ } -+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(enchantmentItem); -+ Holder holder = registry.byId(this.enchantClue[buttonId]); -+ if (holder == null) return; -+ org.bukkit.enchantments.Enchantment hintedEnchantment = org.bukkit.craftbukkit.enchantments.CraftEnchantment.minecraftHolderToBukkit(holder); -+ int hintedEnchantmentLevel = this.levelClue[buttonId]; -+ org.bukkit.event.enchantment.EnchantItemEvent event = new org.bukkit.event.enchantment.EnchantItemEvent((org.bukkit.entity.Player) player.getBukkitEntity(), this.getBukkitView(), this.access.getLocation().getBlock(), craftItemStack, this.costs[buttonId], enchants, hintedEnchantment, hintedEnchantmentLevel, buttonId); -+ level.getCraftServer().getPluginManager().callEvent(event); -+ int itemLevel = event.getExpLevelCost(); -+ if (event.isCancelled() || (itemLevel > player.experienceLevel && !player.getAbilities().instabuild) || event.getEnchantsToAdd().isEmpty()) { -+ return; -+ } -+ // CraftBukkit end -+ // Paper start -+ enchantmentItem = org.bukkit.craftbukkit.inventory.CraftItemStack.getOrCloneOnMutation(craftItemStack, event.getItem()); -+ if (enchantmentItem != itemStack) { -+ this.enchantSlots.setItem(0, enchantmentItem); -+ } -+ if (enchantmentItem.is(Items.BOOK)) { -+ enchantmentItem = enchantmentItem.transmuteCopy(Items.ENCHANTED_BOOK); -+ this.enchantSlots.setItem(0, enchantmentItem); -+ } -+ // Paper end -+ -+ // CraftBukkit start -+ for (java.util.Map.Entry entry : event.getEnchantsToAdd().entrySet()) { -+ Holder enchantment = org.bukkit.craftbukkit.enchantments.CraftEnchantment.bukkitToMinecraftHolder(entry.getKey()); -+ if (enchantment == null) { -+ continue; -+ } +@@ -148,19 +_,52 @@ + } + + this.access.execute((level, pos) -> { +- ItemStack enchantmentItem = itemStack; ++ ItemStack enchantmentItem = itemStack; // Paper - diff on change + List newEnchantment = this.getEnchantmentList(level.registryAccess(), enchantmentItem, buttonId, this.costs[buttonId]); +- if (!newEnchantment.isEmpty()) { +- player.onEnchantmentPerformed(enchantmentItem, enchantmentCost); ++ // CraftBukkit start ++ IdMap> registry = level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).asHolderIdMap(); ++ if (true || !newEnchantment.isEmpty()) { ++ // player.onEnchantmentPerformed(enchantmentItem, enchantmentCost); // Moved down ++ java.util.Map enchants = new java.util.HashMap<>(); ++ for (EnchantmentInstance instance : newEnchantment) { ++ enchants.put(org.bukkit.craftbukkit.enchantments.CraftEnchantment.minecraftHolderToBukkit(instance.enchantment()), instance.level()); ++ } ++ org.bukkit.craftbukkit.inventory.CraftItemStack craftItemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(enchantmentItem); ++ Holder holder = registry.byId(this.enchantClue[buttonId]); ++ if (holder == null) return; ++ org.bukkit.enchantments.Enchantment hintedEnchantment = org.bukkit.craftbukkit.enchantments.CraftEnchantment.minecraftHolderToBukkit(holder); ++ int hintedEnchantmentLevel = this.levelClue[buttonId]; ++ org.bukkit.event.enchantment.EnchantItemEvent event = new org.bukkit.event.enchantment.EnchantItemEvent((org.bukkit.entity.Player) player.getBukkitEntity(), this.getBukkitView(), this.access.getLocation().getBlock(), craftItemStack, this.costs[buttonId], enchants, hintedEnchantment, hintedEnchantmentLevel, buttonId); ++ level.getCraftServer().getPluginManager().callEvent(event); ++ int itemLevel = event.getExpLevelCost(); ++ if (event.isCancelled() || (itemLevel > player.experienceLevel && !player.getAbilities().instabuild) || event.getEnchantsToAdd().isEmpty()) { ++ return; ++ } ++ // CraftBukkit end ++ // Paper start ++ enchantmentItem = org.bukkit.craftbukkit.inventory.CraftItemStack.getOrCloneOnMutation(craftItemStack, event.getItem()); ++ if (enchantmentItem != itemStack) { ++ this.enchantSlots.setItem(0, enchantmentItem); ++ } + if (enchantmentItem.is(Items.BOOK)) { +- enchantmentItem = itemStack.transmuteCopy(Items.ENCHANTED_BOOK); ++ enchantmentItem = enchantmentItem.transmuteCopy(Items.ENCHANTED_BOOK); + this.enchantSlots.setItem(0, enchantmentItem); + } +- +- for (EnchantmentInstance enchantment : newEnchantment) { +- enchantmentItem.enchant(enchantment.enchantment(), enchantment.level()); ++ // Paper end + -+ enchantmentItem.enchant(enchantment, entry.getValue()); ++ // CraftBukkit start ++ for (java.util.Map.Entry entry : event.getEnchantsToAdd().entrySet()) { ++ Holder enchantment = org.bukkit.craftbukkit.enchantments.CraftEnchantment.bukkitToMinecraftHolder(entry.getKey()); ++ if (enchantment == null) { ++ continue; + } -+ // CraftBukkit end - player.onEnchantmentPerformed(itemStack, enchantmentCost); -- if (itemStack.is(Items.BOOK)) { -- enchantmentItem = itemStack.transmuteCopy(Items.ENCHANTED_BOOK); -- this.enchantSlots.setItem(0, enchantmentItem); -- } -- -- for (EnchantmentInstance enchantment : newEnchantment) { -- enchantmentItem.enchant(enchantment.enchantment(), enchantment.level()); -- } -- + -+ // CraftBukkit - TODO: let plugins change this - currency.consume(enchantmentCost, player); - if (currency.isEmpty()) { - this.enchantSlots.setItem(1, ItemStack.EMPTY); -@@ -215,6 +_,12 @@ ++ enchantmentItem.enchant(enchantment, entry.getValue()); + } ++ player.onEnchantmentPerformed(enchantmentItem, enchantmentCost); ++ // CraftBukkit end + ++ // CraftBukkit - TODO: let plugins change this + currency.consume(enchantmentCost, player); + if (currency.isEmpty()) { + this.enchantSlots.setItem(1, ItemStack.EMPTY); +@@ -204,6 +_,12 @@ return goldStack.isEmpty() ? 0 : goldStack.getCount(); } @@ -188,7 +180,7 @@ public int getEnchantmentSeed() { return this.enchantmentSeed.get(); } -@@ -227,6 +_,7 @@ +@@ -216,6 +_,7 @@ @Override public boolean stillValid(final Player player) { @@ -196,7 +188,7 @@ return stillValid(this.access, player, Blocks.ENCHANTING_TABLE); } -@@ -274,4 +_,17 @@ +@@ -263,4 +_,17 @@ return clicked; } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/GrindstoneMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/GrindstoneMenu.java.patch index 62e740e61299..e7b0142bc662 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/GrindstoneMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/GrindstoneMenu.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/inventory/GrindstoneMenu.java +++ b/net/minecraft/world/inventory/GrindstoneMenu.java -@@ -22,6 +_,21 @@ +@@ -21,6 +_,21 @@ import net.minecraft.world.phys.Vec3; public class GrindstoneMenu extends AbstractContainerMenu { @@ -22,16 +22,12 @@ public static final int MAX_NAME_LENGTH = 35; public static final int INPUT_SLOT = 0; public static final int ADDITIONAL_SLOT = 1; -@@ -30,18 +_,8 @@ +@@ -29,14 +_,8 @@ private static final int INV_SLOT_END = 30; private static final int USE_ROW_SLOT_START = 30; private static final int USE_ROW_SLOT_END = 39; - private final Container resultSlots = new ResultContainer(); - private final Container repairSlots = new SimpleContainer(2) { -- { -- Objects.requireNonNull(GrindstoneMenu.this); -- } -- - @Override - public void setChanged() { - super.setChanged(); @@ -43,7 +39,7 @@ private final ContainerLevelAccess access; public GrindstoneMenu(final int containerId, final Inventory inventory) { -@@ -50,6 +_,22 @@ +@@ -45,6 +_,22 @@ public GrindstoneMenu(final int containerId, final Inventory inventory, final ContainerLevelAccess access) { super(MenuType.GRINDSTONE, containerId); @@ -65,8 +61,8 @@ + // Paper end - Add missing InventoryHolders this.access = access; this.addSlot(new Slot(this.repairSlots, 0, 49, 19) { - { -@@ -85,7 +_,11 @@ + @Override +@@ -68,7 +_,11 @@ public void onTake(final Player player, final ItemStack carried) { access.execute((level, pos) -> { if (level instanceof ServerLevel) { @@ -79,7 +75,7 @@ } level.levelEvent(LevelEvent.SOUND_GRINDSTONE_USED, pos, 0); -@@ -122,6 +_,7 @@ +@@ -105,6 +_,7 @@ } }); this.addStandardInventorySlots(inventory, 8, 84); @@ -87,7 +83,7 @@ } @Override -@@ -129,11 +_,13 @@ +@@ -112,11 +_,13 @@ super.slotsChanged(container); if (container == this.repairSlots) { this.createResult(); @@ -102,7 +98,7 @@ this.broadcastChanges(); } -@@ -221,6 +_,7 @@ +@@ -206,6 +_,7 @@ @Override public boolean stillValid(final Player player) { diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/InventoryMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/InventoryMenu.java.patch index 34d8de1b61cd..59b69ac604cb 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/InventoryMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/InventoryMenu.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/inventory/InventoryMenu.java +++ b/net/minecraft/world/inventory/InventoryMenu.java -@@ -45,9 +_,13 @@ +@@ -44,9 +_,13 @@ private static final EquipmentSlot[] SLOT_IDS = new EquipmentSlot[]{EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET}; public final boolean active; private final Player owner; @@ -15,7 +15,7 @@ this.active = active; this.owner = owner; this.addResultSlot(owner, 154, 28); -@@ -193,4 +_,54 @@ +@@ -188,4 +_,54 @@ protected Player owner() { return this.owner; } diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/ItemCombinerMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/ItemCombinerMenu.java.patch index dc86a706abf5..f83035ec169b 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/ItemCombinerMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/ItemCombinerMenu.java.patch @@ -1,14 +1,10 @@ --- a/net/minecraft/world/inventory/ItemCombinerMenu.java +++ b/net/minecraft/world/inventory/ItemCombinerMenu.java -@@ -16,16 +_,7 @@ +@@ -15,12 +_,7 @@ protected final ContainerLevelAccess access; protected final Player player; protected final Container inputSlots; - protected final ResultContainer resultSlots = new ResultContainer() { -- { -- Objects.requireNonNull(ItemCombinerMenu.this); -- } -- - @Override - public void setChanged() { - ItemCombinerMenu.this.slotsChanged(this); @@ -18,16 +14,12 @@ private final int resultSlotIndex; protected boolean mayPickup(final Player player, final boolean hasItem) { -@@ -45,6 +_,18 @@ +@@ -40,6 +_,14 @@ ) { super(menuType, containerId); this.access = access; + // Paper start - Add missing InventoryHolders; delay field init + this.resultSlots = new ResultContainer(this.createBlockHolder(this.access)) { -+ { -+ Objects.requireNonNull(ItemCombinerMenu.this); -+ } -+ + @Override + public void setChanged() { + ItemCombinerMenu.this.slotsChanged(this); @@ -37,7 +29,7 @@ this.player = inventory.player; this.inputSlots = this.createContainer(itemInputSlots.getNumOfInputSlots()); this.resultSlotIndex = itemInputSlots.getResultSlotIndex(); -@@ -54,15 +_,15 @@ +@@ -49,11 +_,11 @@ } private void createInputSlots(final ItemCombinerMenuSlotDefinition itemInputSlots) { @@ -45,10 +37,6 @@ - this.addSlot(new Slot(this.inputSlots, slot.slotIndex(), slot.x(), slot.y()) { + for (final ItemCombinerMenuSlotDefinition.SlotDefinition slotDefinition : itemInputSlots.getSlots()) { // Paper - fix conflicting variable name + this.addSlot(new Slot(this.inputSlots, slotDefinition.slotIndex(), slotDefinition.x(), slotDefinition.y()) { // Paper - fix conflicting variable name - { - Objects.requireNonNull(ItemCombinerMenu.this); - } - @Override public boolean mayPlace(final ItemStack itemStack) { - return slot.mayPlace().test(itemStack); @@ -56,16 +44,16 @@ } }); } -@@ -96,7 +_,7 @@ +@@ -83,7 +_,7 @@ public abstract void createResult(); private SimpleContainer createContainer(final int size) { - return new SimpleContainer(size) { -+ return new SimpleContainer(this.createBlockHolder(this.access), size) { - { - Objects.requireNonNull(ItemCombinerMenu.this); - } -@@ -114,6 +_,7 @@ ++ return new SimpleContainer(this.createBlockHolder(this.access), size) { // Paper - pass block holder + @Override + public void setChanged() { + super.setChanged(); +@@ -97,6 +_,7 @@ super.slotsChanged(container); if (container == this.inputSlots) { this.createResult(); @@ -73,7 +61,7 @@ } } -@@ -125,6 +_,7 @@ +@@ -108,6 +_,7 @@ @Override public boolean stillValid(final Player player) { diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/LecternMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/LecternMenu.java.patch index dc23de136d67..51ed6331b18c 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/LecternMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/LecternMenu.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/inventory/LecternMenu.java +++ b/net/minecraft/world/inventory/LecternMenu.java -@@ -15,12 +_,29 @@ +@@ -14,12 +_,29 @@ public static final int BUTTON_PAGE_JUMP_RANGE_START = 100; private final Container lectern; private final ContainerData lecternData; @@ -36,7 +36,7 @@ super(MenuType.LECTERN, containerId); checkContainerSize(lectern, 1); checkContainerDataCount(lecternData, 1); -@@ -38,10 +_,12 @@ +@@ -33,10 +_,12 @@ } }); this.addDataSlots(lecternData); @@ -49,49 +49,49 @@ if (buttonId >= 100) { int pageToSet = buttonId - 100; this.setData(0, pageToSet); -@@ -50,12 +_,26 @@ - switch (buttonId) { - case 1: { - int currentPage = this.lecternData.get(0); -- this.setData(0, currentPage - 1); -+ // Paper start - Add PlayerLecternPageChangeEvent -+ bukkitView = (org.bukkit.craftbukkit.inventory.CraftInventoryLectern) getBukkitView().getTopInventory(); -+ playerLecternPageChangeEvent = new io.papermc.paper.event.player.PlayerLecternPageChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), bukkitView.getHolder(), bukkitView.getBook(), io.papermc.paper.event.player.PlayerLecternPageChangeEvent.PageChangeDirection.LEFT, currentPage, currentPage - 1); -+ if (!playerLecternPageChangeEvent.callEvent()) { -+ return false; -+ } -+ this.setData(0, playerLecternPageChangeEvent.getNewPage()); -+ // Paper end - Add PlayerLecternPageChangeEvent - return true; - } - case 2: { - int currentPage = this.lecternData.get(0); -- this.setData(0, currentPage + 1); -+ // Paper start - Add PlayerLecternPageChangeEvent -+ bukkitView = (org.bukkit.craftbukkit.inventory.CraftInventoryLectern) getBukkitView().getTopInventory(); -+ playerLecternPageChangeEvent = new io.papermc.paper.event.player.PlayerLecternPageChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), bukkitView.getHolder(), bukkitView.getBook(), io.papermc.paper.event.player.PlayerLecternPageChangeEvent.PageChangeDirection.RIGHT, currentPage, currentPage + 1); -+ if (!playerLecternPageChangeEvent.callEvent()) { -+ return false; -+ } -+ this.setData(0, playerLecternPageChangeEvent.getNewPage()); -+ // Paper end - Add PlayerLecternPageChangeEvent - return true; +@@ -46,12 +_,26 @@ + switch (buttonId) { + case 1: { + int currentPage = this.lecternData.get(0); +- this.setData(0, currentPage - 1); ++ // Paper start - Add PlayerLecternPageChangeEvent ++ bukkitView = (org.bukkit.craftbukkit.inventory.CraftInventoryLectern) getBukkitView().getTopInventory(); ++ playerLecternPageChangeEvent = new io.papermc.paper.event.player.PlayerLecternPageChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), bukkitView.getHolder(), bukkitView.getBook(), io.papermc.paper.event.player.PlayerLecternPageChangeEvent.PageChangeDirection.LEFT, currentPage, currentPage - 1); ++ if (!playerLecternPageChangeEvent.callEvent()) { ++ return false; ++ } ++ this.setData(0, playerLecternPageChangeEvent.getNewPage()); ++ // Paper end - Add PlayerLecternPageChangeEvent + return true; + } + case 2: { + int currentPage = this.lecternData.get(0); +- this.setData(0, currentPage + 1); ++ // Paper start - Add PlayerLecternPageChangeEvent ++ bukkitView = (org.bukkit.craftbukkit.inventory.CraftInventoryLectern) getBukkitView().getTopInventory(); ++ playerLecternPageChangeEvent = new io.papermc.paper.event.player.PlayerLecternPageChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), bukkitView.getHolder(), bukkitView.getBook(), io.papermc.paper.event.player.PlayerLecternPageChangeEvent.PageChangeDirection.RIGHT, currentPage, currentPage + 1); ++ if (!playerLecternPageChangeEvent.callEvent()) { ++ return false; ++ } ++ this.setData(0, playerLecternPageChangeEvent.getNewPage()); ++ // Paper end - Add PlayerLecternPageChangeEvent + return true; + } + case 3: +@@ -59,6 +_,12 @@ + return false; } - case 3: -@@ -63,6 +_,12 @@ - return false; - } -+ // CraftBukkit start - Event for taking the book -+ org.bukkit.event.player.PlayerTakeLecternBookEvent event = new org.bukkit.event.player.PlayerTakeLecternBookEvent(this.player, this.getBukkitView().getTopInventory().getHolder()); -+ if (!event.callEvent()) { -+ return false; -+ } -+ // CraftBukkit end - ItemStack book = this.lectern.removeItemNoUpdate(0); - this.lectern.setChanged(); - if (!player.getInventory().add(book)) { -@@ -89,6 +_,8 @@ ++ // CraftBukkit start - Event for taking the book ++ org.bukkit.event.player.PlayerTakeLecternBookEvent event = new org.bukkit.event.player.PlayerTakeLecternBookEvent(this.player, this.getBukkitView().getTopInventory().getHolder()); ++ if (!event.callEvent()) { ++ return false; ++ } ++ // CraftBukkit end + ItemStack book = this.lectern.removeItemNoUpdate(0); + this.lectern.setChanged(); + if (!player.getInventory().add(book)) { +@@ -84,6 +_,8 @@ @Override public boolean stillValid(final Player player) { diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/LoomMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/LoomMenu.java.patch index 4e4bf954797f..0b1e4e071bbd 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/LoomMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/LoomMenu.java.patch @@ -1,14 +1,10 @@ --- a/net/minecraft/world/inventory/LoomMenu.java +++ b/net/minecraft/world/inventory/LoomMenu.java -@@ -39,29 +_,23 @@ +@@ -38,21 +_,23 @@ private final Slot patternSlot; private final Slot resultSlot; private long lastSoundTime; - private final Container inputContainer = new SimpleContainer(3) { -- { -- Objects.requireNonNull(LoomMenu.this); -- } -- - @Override - public void setChanged() { - super.setChanged(); @@ -17,10 +13,6 @@ - } - }; - private final Container outputContainer = new SimpleContainer(1) { -- { -- Objects.requireNonNull(LoomMenu.this); -- } -- - @Override - public void setChanged() { - super.setChanged(); @@ -47,7 +39,7 @@ public LoomMenu(final int containerId, final Inventory inventory) { this(containerId, inventory, ContainerLevelAccess.NULL); -@@ -70,6 +_,28 @@ +@@ -61,6 +_,28 @@ public LoomMenu(final int containerId, final Inventory inventory, final ContainerLevelAccess access) { super(MenuType.LOOM, containerId); this.access = access; @@ -74,9 +66,9 @@ + }; + // CraftBukkit end this.bannerSlot = this.addSlot(new Slot(this.inputContainer, 0, 13, 26) { - { - Objects.requireNonNull(LoomMenu.this); -@@ -131,6 +_,7 @@ + @Override + public boolean mayPlace(final ItemStack itemStack) { +@@ -106,6 +_,7 @@ this.addStandardInventorySlots(inventory, 8, 84); this.addDataSlot(this.selectedBannerPatternIndex); this.patternGetter = inventory.player.registryAccess().lookupOrThrow(Registries.BANNER_PATTERN); @@ -84,7 +76,7 @@ } private static boolean isPatternItem(final ItemStack itemStack) { -@@ -143,14 +_,39 @@ +@@ -118,14 +_,39 @@ @Override public boolean stillValid(final Player player) { @@ -126,7 +118,7 @@ return true; } else { return false; -@@ -212,7 +_,8 @@ +@@ -187,7 +_,8 @@ this.resultSlot.set(ItemStack.EMPTY); } @@ -136,7 +128,7 @@ } else { this.resultSlot.set(ItemStack.EMPTY); this.selectablePatterns = List.of(); -@@ -302,7 +_,14 @@ +@@ -277,7 +_,14 @@ result.update( DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY, diff --git a/paper-server/patches/sources/net/minecraft/world/inventory/StonecutterMenu.java.patch b/paper-server/patches/sources/net/minecraft/world/inventory/StonecutterMenu.java.patch index 8513d6e3f342..d59204c41915 100644 --- a/paper-server/patches/sources/net/minecraft/world/inventory/StonecutterMenu.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/inventory/StonecutterMenu.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/inventory/StonecutterMenu.java +++ b/net/minecraft/world/inventory/StonecutterMenu.java -@@ -26,7 +_,7 @@ +@@ -25,7 +_,7 @@ private static final int USE_ROW_SLOT_START = 29; private static final int USE_ROW_SLOT_END = 38; private final ContainerLevelAccess access; @@ -9,23 +9,16 @@ private final Level level; private SelectableRecipe.SingleInputSet recipesForInput = SelectableRecipe.SingleInputSet.empty(); private ItemStack input = ItemStack.EMPTY; -@@ -34,19 +_,23 @@ +@@ -33,15 +_,23 @@ final Slot inputSlot; final Slot resultSlot; private Runnable slotUpdateListener = () -> {}; - public final Container container = new SimpleContainer(1) { -- { -- Objects.requireNonNull(StonecutterMenu.this); -- } -- - @Override - public void setChanged() { - super.setChanged(); - StonecutterMenu.this.slotsChanged(this); - StonecutterMenu.this.slotUpdateListener.run(); -- } -- }; -- private final ResultContainer resultContainer = new ResultContainer(); + public final Container container; // Paper - Add missing InventoryHolders - move down + private final ResultContainer resultContainer; // Paper - Add missing InventoryHolders - move down + // CraftBukkit start @@ -36,7 +29,9 @@ + public org.bukkit.craftbukkit.inventory.view.CraftStonecutterView getBukkitView() { + if (this.view != null) { + return this.view; -+ } + } +- }; +- private final ResultContainer resultContainer = new ResultContainer(); + + org.bukkit.craftbukkit.inventory.CraftInventoryStonecutter inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryStonecutter(this.container, this.resultContainer); + this.view = new org.bukkit.craftbukkit.inventory.view.CraftStonecutterView(this.player, inventory, this); @@ -46,7 +41,7 @@ public StonecutterMenu(final int containerId, final Inventory inventory) { this(containerId, inventory, ContainerLevelAccess.NULL); -@@ -56,6 +_,23 @@ +@@ -51,6 +_,23 @@ super(MenuType.STONECUTTER, containerId); this.access = access; this.level = inventory.player.level(); @@ -69,8 +64,8 @@ + // Paper end this.inputSlot = this.addSlot(new Slot(this.container, 0, 20, 33)); this.resultSlot = this.addSlot(new Slot(this.resultContainer, 1, 143, 33) { - { -@@ -92,6 +_,7 @@ + @Override +@@ -83,6 +_,7 @@ }); this.addStandardInventorySlots(inventory, 8, 84); this.addDataSlot(this.selectedRecipeIndex); @@ -78,7 +73,7 @@ } public int getSelectedRecipeIndex() { -@@ -112,6 +_,7 @@ +@@ -103,6 +_,7 @@ @Override public boolean stillValid(final Player player) { @@ -86,44 +81,44 @@ return stillValid(this.access, player, Blocks.STONECUTTER); } -@@ -121,8 +_,34 @@ - return false; - } else { - if (this.isValidRecipeIndex(buttonId)) { -- this.selectedRecipeIndex.set(buttonId); -- this.setupResultSlot(buttonId); -+ // Paper start - Add PlayerStonecutterRecipeSelectEvent -+ int recipeIndex = buttonId; -+ this.selectedRecipeIndex.set(recipeIndex); -+ this.selectedRecipeIndex.checkAndClearUpdateFlag(); // mark as changed -+ paperEventBlock: if (this.isValidRecipeIndex(buttonId)) { -+ final Optional> recipe = this.recipesForInput.entries().get(buttonId).recipe().recipe(); -+ if (recipe.isEmpty()) break paperEventBlock; // The recipe selected does not have an actual server recipe (presumably its the empty one). Cannot call the event, just break. +@@ -113,8 +_,34 @@ + } + + if (this.isValidRecipeIndex(buttonId)) { +- this.selectedRecipeIndex.set(buttonId); +- this.setupResultSlot(buttonId); ++ // Paper start - Add PlayerStonecutterRecipeSelectEvent ++ int recipeIndex = buttonId; ++ this.selectedRecipeIndex.set(recipeIndex); ++ this.selectedRecipeIndex.checkAndClearUpdateFlag(); // mark as changed ++ paperEventBlock: if (this.isValidRecipeIndex(buttonId)) { ++ final Optional> recipe = this.recipesForInput.entries().get(buttonId).recipe().recipe(); ++ if (recipe.isEmpty()) break paperEventBlock; // The recipe selected does not have an actual server recipe (presumably its the empty one). Cannot call the event, just break. + -+ io.papermc.paper.event.player.PlayerStonecutterRecipeSelectEvent event = new io.papermc.paper.event.player.PlayerStonecutterRecipeSelectEvent((org.bukkit.entity.Player) player.getBukkitEntity(), getBukkitView().getTopInventory(), (org.bukkit.inventory.StonecuttingRecipe) recipe.get().toBukkitRecipe()); -+ if (!event.callEvent()) { -+ player.containerMenu.sendAllDataToRemote(); -+ return false; -+ } ++ io.papermc.paper.event.player.PlayerStonecutterRecipeSelectEvent event = new io.papermc.paper.event.player.PlayerStonecutterRecipeSelectEvent((org.bukkit.entity.Player) player.getBukkitEntity(), getBukkitView().getTopInventory(), (org.bukkit.inventory.StonecuttingRecipe) recipe.get().toBukkitRecipe()); ++ if (!event.callEvent()) { ++ player.containerMenu.sendAllDataToRemote(); ++ return false; ++ } + -+ net.minecraft.resources.Identifier key = org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(event.getStonecuttingRecipe().getKey()); -+ if (!recipe.get().id().identifier().equals(key)) { // If the recipe did NOT stay the same -+ for (int newRecipeIndex = 0; newRecipeIndex < this.recipesForInput.entries().size(); newRecipeIndex++) { -+ if (this.recipesForInput.entries().get(newRecipeIndex).recipe().recipe().filter(r -> r.id().identifier().equals(key)).isPresent()) { -+ recipeIndex = newRecipeIndex; -+ break; -+ } ++ net.minecraft.resources.Identifier key = org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(event.getStonecuttingRecipe().getKey()); ++ if (!recipe.get().id().identifier().equals(key)) { // If the recipe did NOT stay the same ++ for (int newRecipeIndex = 0; newRecipeIndex < this.recipesForInput.entries().size(); newRecipeIndex++) { ++ if (this.recipesForInput.entries().get(newRecipeIndex).recipe().recipe().filter(r -> r.id().identifier().equals(key)).isPresent()) { ++ recipeIndex = newRecipeIndex; ++ break; + } + } + } -+ player.containerMenu.sendAllDataToRemote(); -+ this.selectedRecipeIndex.set(recipeIndex); // set new index, so that listeners can read it -+ this.setupResultSlot(recipeIndex); -+ // Paper end - Add PlayerStonecutterRecipeSelectEvent - } ++ } ++ player.containerMenu.sendAllDataToRemote(); ++ this.selectedRecipeIndex.set(recipeIndex); // set new index, so that listeners can read it ++ this.setupResultSlot(recipeIndex); ++ // Paper end - Add PlayerStonecutterRecipeSelectEvent + } - return true; -@@ -140,6 +_,7 @@ + return true; +@@ -131,6 +_,7 @@ this.input = input.copy(); this.setupRecipeList(input); } diff --git a/paper-server/patches/sources/net/minecraft/world/item/ArmorStandItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/ArmorStandItem.java.patch index 2d44e2ce4371..88f4f50a083c 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/ArmorStandItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/ArmorStandItem.java.patch @@ -1,15 +1,15 @@ --- a/net/minecraft/world/item/ArmorStandItem.java +++ b/net/minecraft/world/item/ArmorStandItem.java -@@ -45,6 +_,12 @@ +@@ -46,6 +_,12 @@ - float yRot = Mth.floor((Mth.wrapDegrees(context.getRotation() - 180.0F) + 22.5F) / 45.0F) * 45.0F; - entity.snapTo(entity.getX(), entity.getY(), entity.getZ(), yRot, 0.0F); -+ // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, entity).isCancelled()) { -+ if (context.getPlayer() != null) context.getPlayer().containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync -+ return InteractionResult.FAIL; -+ } -+ // CraftBukkit end - serverLevel.addFreshEntityWithPassengers(entity); - level.playSound(null, entity.getX(), entity.getY(), entity.getZ(), SoundEvents.ARMOR_STAND_PLACE, SoundSource.BLOCKS, 0.75F, 0.8F); - entity.gameEvent(GameEvent.ENTITY_PLACE, context.getPlayer()); + float yRot = Mth.floor((Mth.wrapDegrees(context.getRotation() - 180.0F) + 22.5F) / 45.0F) * 45.0F; + entity.snapTo(entity.getX(), entity.getY(), entity.getZ(), yRot, 0.0F); ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, entity).isCancelled()) { ++ if (context.getPlayer() != null) context.getPlayer().containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync ++ return InteractionResult.FAIL; ++ } ++ // CraftBukkit end + serverLevel.addFreshEntityWithPassengers(entity); + level.playSound(null, entity.getX(), entity.getY(), entity.getZ(), SoundEvents.ARMOR_STAND_PLACE, SoundSource.BLOCKS, 0.75F, 0.8F); + entity.gameEvent(GameEvent.ENTITY_PLACE, context.getPlayer()); diff --git a/paper-server/patches/sources/net/minecraft/world/item/AxeItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/AxeItem.java.patch index 167b36275867..832a16a44bcf 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/AxeItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/AxeItem.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/item/AxeItem.java +++ b/net/minecraft/world/item/AxeItem.java -@@ -70,6 +_,11 @@ - return InteractionResult.PASS; - } else { - ItemStack itemInHand = context.getItemInHand(); -+ // Paper start - EntityChangeBlockEvent -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, pos, newBlock.get())) { -+ return InteractionResult.PASS; -+ } -+ // Paper end - if (player instanceof ServerPlayer) { - CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger((ServerPlayer)player, pos, itemInHand); - } +@@ -72,6 +_,11 @@ + } + + ItemStack itemInHand = context.getItemInHand(); ++ // Paper start - EntityChangeBlockEvent ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, pos, newBlock.get())) { ++ return InteractionResult.PASS; ++ } ++ // Paper end + if (player instanceof ServerPlayer) { + CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger((ServerPlayer)player, pos, itemInHand); + } diff --git a/paper-server/patches/sources/net/minecraft/world/item/BlockItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/BlockItem.java.patch index b528d26d3d34..23859e38c217 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/BlockItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/BlockItem.java.patch @@ -1,61 +1,59 @@ --- a/net/minecraft/world/item/BlockItem.java +++ b/net/minecraft/world/item/BlockItem.java -@@ -56,6 +_,7 @@ - return InteractionResult.FAIL; - } else { - BlockState placementState = this.getPlacementState(updatedPlaceContext); -+ final org.bukkit.block.BlockState previousState = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(updatedPlaceContext.getLevel(), updatedPlaceContext.getClickedPos()); // Paper - Reset placed block on exception - if (placementState == null) { - return InteractionResult.FAIL; - } else if (!this.placeBlock(updatedPlaceContext, placementState)) { -@@ -68,21 +_,45 @@ - BlockState placedState = level.getBlockState(pos); - if (placedState.is(placementState.getBlock())) { - placedState = this.updateBlockStateFromTag(pos, level, itemStack, placedState); -+ // Paper start - Reset placed block on exception -+ try { - this.updateCustomBlockEntityTag(pos, level, player, itemStack, placedState); - updateBlockEntityComponents(level, pos, itemStack); -+ } catch (Exception ex) { -+ ((org.bukkit.craftbukkit.block.CraftBlockState) previousState).revertPlace(); -+ if (player instanceof ServerPlayer serverPlayer) { -+ net.minecraft.server.MinecraftServer.LOGGER.warn("Player {} tried placing invalid block", player.getScoreboardName(), ex); -+ serverPlayer.connection.disconnect(net.minecraft.network.chat.Component.literal("Packet processing error")); -+ return InteractionResult.FAIL; -+ } -+ throw ex; // Rethrow exception if not placed by a player -+ } -+ // Paper end - Reset placed block on exception - placedState.getBlock().setPlacedBy(level, pos, placedState, player, itemStack); -+ // CraftBukkit start - special case for handling block placement with water lilies, frog spawn and snow buckets -+ if (player != null && (this instanceof PlaceOnWaterBlockItem || this instanceof SolidBucketItem)) { -+ org.bukkit.event.block.BlockPlaceEvent placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent((net.minecraft.server.level.ServerLevel) level, player, updatedPlaceContext.getHand(), previousState, pos); -+ if (placeEvent.isCancelled() || !placeEvent.canBuild()) { -+ ((org.bukkit.craftbukkit.block.CraftBlockState) previousState).revertPlace(); -+ -+ player.containerMenu.forceHeldSlot(updatedPlaceContext.getHand()); -+ return InteractionResult.FAIL; -+ } -+ } -+ // CraftBukkit end - if (player instanceof ServerPlayer) { - CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer)player, pos, itemStack); - } - } +@@ -60,6 +_,7 @@ + } - SoundType soundType = placedState.getSoundType(); -+ if (player == null) // Paper - Fix block place logic; reintroduce this for the dispenser (i.e the shulker) - level.playSound( - player, pos, this.getPlaceSound(placedState), SoundSource.BLOCKS, (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F - ); - level.gameEvent(GameEvent.BLOCK_PLACE, pos, GameEvent.Context.of(player, placedState)); - itemStack.consume(1, player); -- return InteractionResult.SUCCESS; -+ return InteractionResult.SUCCESS.configurePaper(e -> e.placedBlockAt(pos.immutable())); // Paper - track placed block position from block item - } + BlockState placementState = this.getPlacementState(updatedPlaceContext); ++ final org.bukkit.block.BlockState previousState = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(updatedPlaceContext.getLevel(), updatedPlaceContext.getClickedPos()); // Paper - Reset placed block on exception + if (placementState == null) { + return InteractionResult.FAIL; + } +@@ -75,19 +_,43 @@ + BlockState placedState = level.getBlockState(pos); + if (placedState.is(placementState.getBlock())) { + placedState = this.updateBlockStateFromTag(pos, level, itemStack, placedState); ++ // Paper start - Reset placed block on exception ++ try { + this.updateCustomBlockEntityTag(pos, level, player, itemStack, placedState); + updateBlockEntityComponents(level, pos, itemStack); ++ } catch (Exception ex) { ++ ((org.bukkit.craftbukkit.block.CraftBlockState) previousState).revertPlace(); ++ if (player instanceof ServerPlayer serverPlayer) { ++ net.minecraft.server.MinecraftServer.LOGGER.warn("Player {} tried placing invalid block", player.getScoreboardName(), ex); ++ serverPlayer.connection.disconnect(net.minecraft.network.chat.Component.literal("Packet processing error")); ++ return InteractionResult.FAIL; ++ } ++ throw ex; // Rethrow exception if not placed by a player ++ } ++ // Paper end - Reset placed block on exception + placedState.getBlock().setPlacedBy(level, pos, placedState, player, itemStack); ++ // CraftBukkit start - special case for handling block placement with water lilies, frog spawn and snow buckets ++ if (player != null && (this instanceof PlaceOnWaterBlockItem || this instanceof SolidBucketItem)) { ++ org.bukkit.event.block.BlockPlaceEvent placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent((net.minecraft.server.level.ServerLevel) level, player, updatedPlaceContext.getHand(), previousState, pos); ++ if (placeEvent.isCancelled() || !placeEvent.canBuild()) { ++ ((org.bukkit.craftbukkit.block.CraftBlockState) previousState).revertPlace(); ++ ++ player.containerMenu.forceHeldSlot(updatedPlaceContext.getHand()); ++ return InteractionResult.FAIL; ++ } ++ } ++ // CraftBukkit end + if (player instanceof ServerPlayer) { + CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer)player, pos, itemStack); } } -@@ -131,8 +_,20 @@ + + SoundType soundType = placedState.getSoundType(); ++ if (player == null) // Paper - Fix block place logic; reintroduce this for the dispenser (i.e the shulker) + level.playSound(player, pos, this.getPlaceSound(placedState), SoundSource.BLOCKS, (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + level.gameEvent(GameEvent.BLOCK_PLACE, pos, GameEvent.Context.of(player, placedState)); + itemStack.consume(1, player); +- return InteractionResult.SUCCESS; ++ return InteractionResult.SUCCESS.configurePaper(e -> e.placedBlockAt(pos.immutable())); // Paper - track placed block position from block item + } + + protected SoundEvent getPlaceSound(final BlockState blockState) { +@@ -133,8 +_,20 @@ protected boolean canPlace(final BlockPlaceContext context, final BlockState stateForPlacement) { Player player = context.getPlayer(); @@ -78,12 +76,12 @@ } protected boolean mustSurvive() { -@@ -156,7 +_,7 @@ - return false; - } +@@ -159,7 +_,7 @@ + return false; + } -- if (!type.onlyOpCanSetNbt() || player != null && player.canUseGameMasterBlocks()) { -+ if (!type.onlyOpCanSetNbt() || player != null && (player.canUseGameMasterBlocks() || (player.getAbilities().instabuild && player.getBukkitEntity().hasPermission("minecraft.nbt.place")))) { // Spigot - add permission - return customData.loadInto(blockEntity, level.registryAccess()); - } +- if (!type.onlyOpCanSetNbt() || player != null && player.canUseGameMasterBlocks()) { ++ if (!type.onlyOpCanSetNbt() || player != null && (player.canUseGameMasterBlocks() || (player.getAbilities().instabuild && player.getBukkitEntity().hasPermission("minecraft.nbt.place")))) { // Spigot - add permission + return customData.loadInto(blockEntity, level.registryAccess()); + } diff --git a/paper-server/patches/sources/net/minecraft/world/item/BoatItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/BoatItem.java.patch index 2c9c26a6af7c..755218427a59 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/BoatItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/BoatItem.java.patch @@ -8,35 +8,35 @@ + net.minecraft.world.phys.BlockHitResult hitResult = getPlayerPOVHitResult(level, player, ClipContext.Fluid.ANY); // Paper if (hitResult.getType() == HitResult.Type.MISS) { return InteractionResult.PASS; - } else { -@@ -51,6 +_,13 @@ + } +@@ -52,6 +_,13 @@ + } + + if (hitResult.getType() == HitResult.Type.BLOCK) { ++ // CraftBukkit start - Boat placement ++ org.bukkit.event.player.PlayerInteractEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent(player, org.bukkit.event.block.Action.RIGHT_CLICK_BLOCK, hitResult.getBlockPos(), hitResult.getDirection(), itemStack, false, hand, hitResult.getLocation()); ++ ++ if (event.isCancelled()) { ++ return InteractionResult.PASS; ++ } ++ // CraftBukkit end + AbstractBoat boat = this.getBoat(level, hitResult, itemStack, player); + if (boat == null) { + return InteractionResult.FAIL; +@@ -63,7 +_,15 @@ } - if (hitResult.getType() == HitResult.Type.BLOCK) { -+ // CraftBukkit start - Boat placement -+ org.bukkit.event.player.PlayerInteractEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent(player, org.bukkit.event.block.Action.RIGHT_CLICK_BLOCK, hitResult.getBlockPos(), hitResult.getDirection(), itemStack, false, hand, hitResult.getLocation()); + if (!level.isClientSide()) { +- level.addFreshEntity(boat); ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(level, hitResult.getBlockPos(), player.getDirection(), player, boat, hand).isCancelled()) { ++ return InteractionResult.FAIL; ++ } + -+ if (event.isCancelled()) { ++ if (!level.addFreshEntity(boat)) { + return InteractionResult.PASS; + } + // CraftBukkit end - AbstractBoat boat = this.getBoat(level, hitResult, itemStack, player); - if (boat == null) { - return InteractionResult.FAIL; -@@ -60,7 +_,15 @@ - return InteractionResult.FAIL; - } else { - if (!level.isClientSide()) { -- level.addFreshEntity(boat); -+ // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(level, hitResult.getBlockPos(), player.getDirection(), player, boat, hand).isCancelled()) { -+ return InteractionResult.FAIL; -+ } -+ -+ if (!level.addFreshEntity(boat)) { -+ return InteractionResult.PASS; -+ } -+ // CraftBukkit end - level.gameEvent(player, GameEvent.ENTITY_PLACE, hitResult.getLocation()); - itemStack.consume(1, player); - } + level.gameEvent(player, GameEvent.ENTITY_PLACE, hitResult.getLocation()); + itemStack.consume(1, player); + } diff --git a/paper-server/patches/sources/net/minecraft/world/item/BowItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/BowItem.java.patch index 6fde4d9f0c9e..739a4d4d0079 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/BowItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/BowItem.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/item/BowItem.java +++ b/net/minecraft/world/item/BowItem.java -@@ -38,7 +_,7 @@ - } else { - List firedProjectiles = draw(itemStack, projectile, player); - if (level instanceof ServerLevel serverLevel && !firedProjectiles.isEmpty()) { -- this.shoot(serverLevel, player, player.getUsedItemHand(), itemStack, firedProjectiles, pow * 3.0F, 1.0F, pow == 1.0F, null); -+ this.shoot(serverLevel, player, player.getUsedItemHand(), itemStack, firedProjectiles, pow * 3.0F, 1.0F, pow == 1.0F, null, pow); // Paper - Pass draw strength - } +@@ -40,7 +_,7 @@ - level.playSound( + List firedProjectiles = draw(itemStack, projectile, player); + if (level instanceof ServerLevel serverLevel && !firedProjectiles.isEmpty()) { +- this.shoot(serverLevel, player, player.getUsedItemHand(), itemStack, firedProjectiles, pow * 3.0F, 1.0F, pow == 1.0F, null); ++ this.shoot(serverLevel, player, player.getUsedItemHand(), itemStack, firedProjectiles, pow * 3.0F, 1.0F, pow == 1.0F, null, pow); // Paper - Pass draw strength + } + + level.playSound( diff --git a/paper-server/patches/sources/net/minecraft/world/item/BucketItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/BucketItem.java.patch index bcc7764e4ea5..511dda21445b 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/BucketItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/BucketItem.java.patch @@ -8,40 +8,40 @@ public final Fluid content; public BucketItem(final Fluid content, final Item.Properties properties) { -@@ -56,12 +_,22 @@ - } else if (this.content == Fluids.EMPTY) { - BlockState blockState = level.getBlockState(pos); - if (blockState.getBlock() instanceof BucketPickup bucketPickupBlock) { -+ // CraftBukkit start -+ ItemStack dummyFluid = bucketPickupBlock.pickupBlock(player, org.bukkit.craftbukkit.util.DummyLevelAccessor.INSTANCE, pos, blockState); -+ if (dummyFluid.isEmpty()) return InteractionResult.FAIL; // Don't fire event if the bucket won't be filled. -+ org.bukkit.event.player.PlayerBucketFillEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent(level, player, pos, pos, hitResult.getDirection(), itemStack, dummyFluid.getItem(), hand); +@@ -61,12 +_,22 @@ + if (this.content == Fluids.EMPTY) { + BlockState blockState = level.getBlockState(pos); + if (blockState.getBlock() instanceof BucketPickup bucketPickupBlock) { ++ // CraftBukkit start ++ ItemStack dummyFluid = bucketPickupBlock.pickupBlock(player, org.bukkit.craftbukkit.util.DummyLevelAccessor.INSTANCE, pos, blockState); ++ if (dummyFluid.isEmpty()) return InteractionResult.FAIL; // Don't fire event if the bucket won't be filled. ++ org.bukkit.event.player.PlayerBucketFillEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent(level, player, pos, pos, hitResult.getDirection(), itemStack, dummyFluid.getItem(), hand); + -+ if (event.isCancelled()) { -+ player.containerMenu.sendAllDataToRemote(); // SPIGOT-4541 -+ return InteractionResult.FAIL; -+ } -+ // CraftBukkit end - ItemStack taken = bucketPickupBlock.pickupBlock(player, level, pos, blockState); - if (!taken.isEmpty()) { - player.awardStat(Stats.ITEM_USED.get(this)); - bucketPickupBlock.getPickupSound().ifPresent(soundEvent -> player.playSound(soundEvent, 1.0F, 1.0F)); - level.gameEvent(player, GameEvent.FLUID_PICKUP, pos); -- ItemStack result = ItemUtils.createFilledResult(itemStack, player, taken); -+ ItemStack result = ItemUtils.createFilledResult(itemStack, player, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack())); // CraftBukkit - if (!level.isClientSide()) { - CriteriaTriggers.FILLED_BUCKET.trigger((ServerPlayer)player, taken); - } -@@ -74,7 +_,7 @@ - } else { - BlockState clicked = level.getBlockState(pos); - BlockPos placePos = clicked.getBlock() instanceof LiquidBlockContainer && this.content == Fluids.WATER ? pos : directionOffsetPos; -- if (this.emptyContents(player, level, placePos, hitResult)) { -+ if (this.emptyContents(player, level, placePos, hitResult, hitResult.getDirection(), pos, itemStack, hand)) { // CraftBukkit - this.checkExtraContent(player, level, itemStack, placePos); - if (player instanceof ServerPlayer) { - CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer)player, placePos, itemStack); -@@ -91,6 +_,13 @@ ++ if (event.isCancelled()) { ++ player.containerMenu.sendAllDataToRemote(); // SPIGOT-4541 ++ return InteractionResult.FAIL; ++ } ++ // CraftBukkit end + ItemStack taken = bucketPickupBlock.pickupBlock(player, level, pos, blockState); + if (!taken.isEmpty()) { + player.awardStat(Stats.ITEM_USED.get(this)); + bucketPickupBlock.getPickupSound().ifPresent(soundEvent -> player.playSound(soundEvent, 1.0F, 1.0F)); + level.gameEvent(player, GameEvent.FLUID_PICKUP, pos); +- ItemStack result = ItemUtils.createFilledResult(itemStack, player, taken); ++ ItemStack result = ItemUtils.createFilledResult(itemStack, player, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack())); // CraftBukkit + if (!level.isClientSide()) { + CriteriaTriggers.FILLED_BUCKET.trigger((ServerPlayer)player, taken); + } +@@ -79,7 +_,7 @@ + } else { + BlockState clicked = level.getBlockState(pos); + BlockPos placePos = clicked.getBlock() instanceof LiquidBlockContainer && this.content == Fluids.WATER ? pos : directionOffsetPos; +- if (this.emptyContents(player, level, placePos, hitResult)) { ++ if (this.emptyContents(player, level, placePos, hitResult, hitResult.getDirection(), pos, itemStack, hand)) { // CraftBukkit + this.checkExtraContent(player, level, itemStack, placePos); + if (player instanceof ServerPlayer) { + CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer)player, placePos, itemStack); +@@ -95,6 +_,13 @@ } public static ItemStack getEmptySuccessItem(final ItemStack itemStack, final Player player) { @@ -55,7 +55,7 @@ return !player.hasInfiniteMaterials() ? new ItemStack(Items.BUCKET) : itemStack; } -@@ -100,6 +_,12 @@ +@@ -104,6 +_,12 @@ @Override public boolean emptyContents(final @Nullable LivingEntity user, final Level level, final BlockPos pos, final @Nullable BlockHitResult hitResult) { @@ -68,7 +68,7 @@ if (!(this.content instanceof FlowingFluid flowingFluid)) { return false; } else { -@@ -110,8 +_,18 @@ +@@ -114,8 +_,18 @@ boolean placeLiquid = mayReplace || block instanceof LiquidBlockContainer container && container.canPlaceLiquid(user, level, pos, blockState, this.content); boolean canPlaceFluidInsideBlock = blockState.isAir() || placeLiquid && (!shiftKeyDown || hitResult == null); @@ -85,6 +85,6 @@ if (!canPlaceFluidInsideBlock) { - return hitResult != null && this.emptyContents(user, level, hitResult.getBlockPos().relative(hitResult.getDirection()), null); + return hitResult != null && this.emptyContents(user, level, hitResult.getBlockPos().relative(hitResult.getDirection()), null, direction, clicked, itemStack, hand); // CraftBukkit - } else if (level.environmentAttributes().getValue(EnvironmentAttributes.WATER_EVAPORATES, pos) && this.content.is(FluidTags.WATER)) { - int x = pos.getX(); - int y = pos.getY(); + } + + if (level.environmentAttributes().getValue(EnvironmentAttributes.WATER_EVAPORATES, pos) && this.content.is(FluidTags.WATER)) { diff --git a/paper-server/patches/sources/net/minecraft/world/item/CrossbowItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/CrossbowItem.java.patch index de368c09a9c5..96811e2e44cd 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/CrossbowItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/CrossbowItem.java.patch @@ -27,9 +27,9 @@ + entity.spawningEntity = shooter.getUUID(); // Paper + return entity; + // Paper end - } else { - Projectile projectileEntity = super.createProjectile(level, shooter, heldItem, projectile, isCrit); - if (projectileEntity instanceof AbstractArrow arrow) { + } + + Projectile projectileEntity = super.createProjectile(level, shooter, heldItem, projectile, isCrit); @@ -187,7 +_,7 @@ if (level instanceof ServerLevel serverLevel) { ChargedProjectiles charged = weapon.set(DataComponents.CHARGED_PROJECTILES, ChargedProjectiles.EMPTY); diff --git a/paper-server/patches/sources/net/minecraft/world/item/DebugStickItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/DebugStickItem.java.patch index 77743d475147..61a37b8ae93b 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/DebugStickItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/DebugStickItem.java.patch @@ -7,5 +7,5 @@ - if (!player.canUseGameMasterBlocks()) { + if (!player.canUseGameMasterBlocks() && !(player.getAbilities().instabuild && player.getBukkitEntity().hasPermission("minecraft.debugstick")) && !player.getBukkitEntity().hasPermission("minecraft.debugstick.always")) { // Spigot return false; - } else { - Holder block = state.typeHolder(); + } + diff --git a/paper-server/patches/sources/net/minecraft/world/item/EmptyMapItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/EmptyMapItem.java.patch index bc25fbb2abdb..de94a65c484b 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/EmptyMapItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/EmptyMapItem.java.patch @@ -16,4 +16,4 @@ + // Paper end - PlayerMapFilledEvent if (itemStack.isEmpty()) { return InteractionResult.SUCCESS.heldItemTransformedTo(map); - } else { + } diff --git a/paper-server/patches/sources/net/minecraft/world/item/EndCrystalItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/EndCrystalItem.java.patch index 3ec27164f56d..b26965ea3b7d 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/EndCrystalItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/EndCrystalItem.java.patch @@ -1,21 +1,21 @@ --- a/net/minecraft/world/item/EndCrystalItem.java +++ b/net/minecraft/world/item/EndCrystalItem.java -@@ -41,11 +_,17 @@ - if (level instanceof ServerLevel) { - EndCrystal crystal = new EndCrystal(level, x + 0.5, y, z + 0.5); - crystal.setShowBottom(false); -+ // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, crystal).isCancelled()) { -+ if (context.getPlayer() != null) context.getPlayer().containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync -+ return InteractionResult.FAIL; -+ } -+ // CraftBukkit end - level.addFreshEntity(crystal); - level.gameEvent(context.getPlayer(), GameEvent.ENTITY_PLACE, above); - EnderDragonFight fight = ((ServerLevel)level).getDragonFight(); - if (fight != null) { -- fight.tryRespawn(); -+ fight.tryRespawn(above); // Paper - Perf: Do crystal-portal proximity check before entity lookup - } - } +@@ -44,11 +_,17 @@ + if (level instanceof ServerLevel) { + EndCrystal crystal = new EndCrystal(level, x + 0.5, y, z + 0.5); + crystal.setShowBottom(false); ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, crystal).isCancelled()) { ++ if (context.getPlayer() != null) context.getPlayer().containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync ++ return InteractionResult.FAIL; ++ } ++ // CraftBukkit end + level.addFreshEntity(crystal); + level.gameEvent(context.getPlayer(), GameEvent.ENTITY_PLACE, above); + EnderDragonFight fight = ((ServerLevel)level).getDragonFight(); + if (fight != null) { +- fight.tryRespawn(); ++ fight.tryRespawn(above); // Paper - Perf: Do crystal-portal proximity check before entity lookup + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/item/EnderEyeItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/EnderEyeItem.java.patch index f5c54962a93a..2e3644f19f92 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/EnderEyeItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/EnderEyeItem.java.patch @@ -1,56 +1,56 @@ --- a/net/minecraft/world/item/EnderEyeItem.java +++ b/net/minecraft/world/item/EnderEyeItem.java -@@ -44,6 +_,11 @@ - return InteractionResult.SUCCESS; - } else { - BlockState newState = targetState.setValue(EndPortalFrameBlock.HAS_EYE, true); -+ // Paper start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(context.getPlayer(), pos, newState)) { -+ return InteractionResult.PASS; -+ } -+ // Paper end - Block.pushEntitiesUp(targetState, newState, level, pos); - level.setBlock(pos, newState, Block.UPDATE_CLIENTS); - level.updateNeighbourForOutputSignal(pos, Blocks.END_PORTAL_FRAME); -@@ -61,7 +_,27 @@ - } - } +@@ -47,6 +_,11 @@ + } -- level.globalLevelEvent(LevelEvent.SOUND_END_PORTAL_SPAWN, blockPos.offset(1, 0, 1), 0); -+ // CraftBukkit start - Use relative location for far away sounds -+ // level.globalLevelEvent(LevelEvent.SOUND_END_PORTAL_SPAWN, blockPos.offset(1, 0, 1), 0); -+ int viewDistance = level.getCraftServer().getViewDistance() * 16; -+ BlockPos soundPos = blockPos.offset(1, 0, 1); -+ final net.minecraft.server.level.ServerLevel serverLevel = (net.minecraft.server.level.ServerLevel) level; // Paper - respect global sound events gamerule - ensured by isClientSide check above -+ for (ServerPlayer player : serverLevel.getPlayersForGlobalSoundGamerule()) { // Paper - respect global sound events gamerule -+ double deltaX = soundPos.getX() - player.getX(); -+ double deltaZ = soundPos.getZ() - player.getZ(); -+ double distanceSquared = deltaX * deltaX + deltaZ * deltaZ; -+ final double soundRadiusSquared = serverLevel.getGlobalSoundRangeSquared(config -> config.endPortalSoundRadius); // Paper - respect global sound events gamerule -+ if (!serverLevel.getGameRules().get(net.minecraft.world.level.gamerules.GameRules.GLOBAL_SOUND_EVENTS) && distanceSquared > soundRadiusSquared) continue; // Spigot // Paper - respect global sound events gamerule -+ if (distanceSquared > viewDistance * viewDistance) { -+ double deltaLength = Math.sqrt(distanceSquared); -+ double relativeX = player.getX() + (deltaX / deltaLength) * viewDistance; -+ double relativeZ = player.getZ() + (deltaZ / deltaLength) * viewDistance; -+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundLevelEventPacket(LevelEvent.SOUND_END_PORTAL_SPAWN, new BlockPos((int) relativeX, (int) soundPos.getY(), (int) relativeZ), 0, true)); -+ } else { -+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundLevelEventPacket(LevelEvent.SOUND_END_PORTAL_SPAWN, soundPos, 0, true)); -+ } -+ } -+ // CraftBukkit end + BlockState newState = targetState.setValue(EndPortalFrameBlock.HAS_EYE, true); ++ // Paper start ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(context.getPlayer(), pos, newState)) { ++ return InteractionResult.PASS; ++ } ++ // Paper end + Block.pushEntitiesUp(targetState, newState, level, pos); + level.setBlock(pos, newState, Block.UPDATE_CLIENTS); + level.updateNeighbourForOutputSignal(pos, Blocks.END_PORTAL_FRAME); +@@ -64,7 +_,27 @@ + } } - return InteractionResult.SUCCESS; -@@ -91,7 +_,11 @@ - eyeOfEnder.setItem(itemStack); - eyeOfEnder.signalTo(Vec3.atLowerCornerOf(nearestMapFeature)); - level.gameEvent(GameEvent.PROJECTILE_SHOOT, eyeOfEnder.position(), GameEvent.Context.of(player)); -- level.addFreshEntity(eyeOfEnder); -+ // CraftBukkit start -+ if (!level.addFreshEntity(eyeOfEnder)) { -+ return InteractionResult.FAIL; +- level.globalLevelEvent(LevelEvent.SOUND_END_PORTAL_SPAWN, blockPos.offset(1, 0, 1), 0); ++ // CraftBukkit start - Use relative location for far away sounds ++ // level.globalLevelEvent(LevelEvent.SOUND_END_PORTAL_SPAWN, blockPos.offset(1, 0, 1), 0); ++ int viewDistance = level.getCraftServer().getViewDistance() * 16; ++ BlockPos soundPos = blockPos.offset(1, 0, 1); ++ final ServerLevel serverLevel = (ServerLevel) level; // Paper - respect global sound events gamerule - ensured by isClientSide check above ++ for (ServerPlayer player : serverLevel.getPlayersForGlobalSoundGamerule()) { // Paper - respect global sound events gamerule ++ double deltaX = soundPos.getX() - player.getX(); ++ double deltaZ = soundPos.getZ() - player.getZ(); ++ double distanceSquared = deltaX * deltaX + deltaZ * deltaZ; ++ final double soundRadiusSquared = serverLevel.getGlobalSoundRangeSquared(config -> config.endPortalSoundRadius); // Paper - respect global sound events gamerule ++ if (!serverLevel.getGameRules().get(net.minecraft.world.level.gamerules.GameRules.GLOBAL_SOUND_EVENTS) && distanceSquared > soundRadiusSquared) continue; // Spigot // Paper - respect global sound events gamerule ++ if (distanceSquared > viewDistance * viewDistance) { ++ double deltaLength = Math.sqrt(distanceSquared); ++ double relativeX = player.getX() + (deltaX / deltaLength) * viewDistance; ++ double relativeZ = player.getZ() + (deltaZ / deltaLength) * viewDistance; ++ player.connection.send(new net.minecraft.network.protocol.game.ClientboundLevelEventPacket(LevelEvent.SOUND_END_PORTAL_SPAWN, new BlockPos((int) relativeX, (int) soundPos.getY(), (int) relativeZ), 0, true)); ++ } else { ++ player.connection.send(new net.minecraft.network.protocol.game.ClientboundLevelEventPacket(LevelEvent.SOUND_END_PORTAL_SPAWN, soundPos, 0, true)); + } -+ // CraftBukkit end - if (player instanceof ServerPlayer serverPlayer) { - CriteriaTriggers.USED_ENDER_EYE.trigger(serverPlayer, nearestMapFeature); - } ++ } ++ // CraftBukkit end + } + + return InteractionResult.SUCCESS; +@@ -94,7 +_,11 @@ + eyeOfEnder.setItem(itemStack); + eyeOfEnder.signalTo(Vec3.atLowerCornerOf(nearestMapFeature)); + level.gameEvent(GameEvent.PROJECTILE_SHOOT, eyeOfEnder.position(), GameEvent.Context.of(player)); +- level.addFreshEntity(eyeOfEnder); ++ // CraftBukkit start ++ if (!level.addFreshEntity(eyeOfEnder)) { ++ return InteractionResult.FAIL; ++ } ++ // CraftBukkit end + if (player instanceof ServerPlayer serverPlayer) { + CriteriaTriggers.USED_ENDER_EYE.trigger(serverPlayer, nearestMapFeature); + } diff --git a/paper-server/patches/sources/net/minecraft/world/item/FireworkRocketItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/FireworkRocketItem.java.patch index 5f39279f9604..d6ddb9b13546 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/FireworkRocketItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/FireworkRocketItem.java.patch @@ -1,31 +1,31 @@ --- a/net/minecraft/world/item/FireworkRocketItem.java +++ b/net/minecraft/world/item/FireworkRocketItem.java -@@ -36,7 +_,7 @@ - ItemStack itemStack = context.getItemInHand(); - Vec3 clickLocation = context.getClickLocation(); - Direction direction = context.getClickedFace(); -- Projectile.spawnProjectile( -+ final Projectile.Delayed fireworkRocketEntity = Projectile.spawnProjectileDelayed( // Paper - PlayerLaunchProjectileEvent - new FireworkRocketEntity( - level, - context.getPlayer(), -@@ -46,9 +_,14 @@ - itemStack - ), - serverLevel, -- itemStack -+ itemStack, f -> f.spawningEntity = context.getPlayer() == null ? null : context.getPlayer().getUUID() // Paper - firework api - assign spawning entity uuid - ); -- itemStack.shrink(1); -+ // Paper start - PlayerLaunchProjectileEvent -+ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) context.getPlayer().getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Firework) fireworkRocketEntity.projectile().getBukkitEntity()); -+ if (!event.callEvent() || !fireworkRocketEntity.attemptSpawn()) return InteractionResult.PASS; -+ if (event.shouldConsume() && !context.getPlayer().hasInfiniteMaterials()) itemStack.shrink(1); -+ else context.getPlayer().containerMenu.forceHeldSlot(context.getHand()); -+ // Paper end - PlayerLaunchProjectileEvent - } +@@ -37,7 +_,7 @@ + ItemStack itemStack = context.getItemInHand(); + Vec3 clickLocation = context.getClickLocation(); + Direction direction = context.getClickedFace(); +- Projectile.spawnProjectile( ++ final Projectile.Delayed fireworkRocketEntity = Projectile.spawnProjectileDelayed( // Paper - PlayerLaunchProjectileEvent + new FireworkRocketEntity( + level, + context.getPlayer(), +@@ -47,9 +_,14 @@ + itemStack + ), + serverLevel, +- itemStack ++ itemStack, f -> f.spawningEntity = context.getPlayer() == null ? null : context.getPlayer().getUUID() // Paper - firework api - assign spawning entity uuid + ); +- itemStack.shrink(1); ++ // Paper start - PlayerLaunchProjectileEvent ++ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) context.getPlayer().getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Firework) fireworkRocketEntity.projectile().getBukkitEntity()); ++ if (!event.callEvent() || !fireworkRocketEntity.attemptSpawn()) return InteractionResult.PASS; ++ if (event.shouldConsume() && !context.getPlayer().hasInfiniteMaterials()) itemStack.shrink(1); ++ else context.getPlayer().containerMenu.forceHeldSlot(context.getHand()); ++ // Paper end - PlayerLaunchProjectileEvent + } - return InteractionResult.SUCCESS; + return InteractionResult.SUCCESS; @@ -60,13 +_,24 @@ if (player.isFallFlying()) { ItemStack itemStack = player.getItemInHand(hand); diff --git a/paper-server/patches/sources/net/minecraft/world/item/HangingEntityItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/HangingEntityItem.java.patch index 363bf1f36218..208052922fe2 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/HangingEntityItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/HangingEntityItem.java.patch @@ -1,23 +1,23 @@ --- a/net/minecraft/world/item/HangingEntityItem.java +++ b/net/minecraft/world/item/HangingEntityItem.java -@@ -62,6 +_,20 @@ - EntityType.createDefaultStackConfig(level, itemInHand, player).accept(entity); - if (entity.survives()) { - if (!level.isClientSide()) { -+ // CraftBukkit start - fire HangingPlaceEvent -+ org.bukkit.entity.Player bukkitPlayer = player == null ? null : (org.bukkit.entity.Player) player.getBukkitEntity(); -+ org.bukkit.block.Block blockClicked = org.bukkit.craftbukkit.block.CraftBlock.at(level, blockPos); -+ org.bukkit.block.BlockFace blockFace = org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(clickedFace); -+ org.bukkit.inventory.EquipmentSlot hand = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(context.getHand()); +@@ -63,6 +_,20 @@ + EntityType.createDefaultStackConfig(level, itemInHand, player).accept(entity); + if (entity.survives()) { + if (!level.isClientSide()) { ++ // CraftBukkit start - fire HangingPlaceEvent ++ org.bukkit.entity.Player bukkitPlayer = player == null ? null : (org.bukkit.entity.Player) player.getBukkitEntity(); ++ org.bukkit.block.Block blockClicked = org.bukkit.craftbukkit.block.CraftBlock.at(level, blockPos); ++ org.bukkit.block.BlockFace blockFace = org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(clickedFace); ++ org.bukkit.inventory.EquipmentSlot hand = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(context.getHand()); + -+ org.bukkit.event.hanging.HangingPlaceEvent event = new org.bukkit.event.hanging.HangingPlaceEvent((org.bukkit.entity.Hanging) entity.getBukkitEntity(), bukkitPlayer, blockClicked, blockFace, hand, org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemInHand)); -+ level.getCraftServer().getPluginManager().callEvent(event); ++ org.bukkit.event.hanging.HangingPlaceEvent event = new org.bukkit.event.hanging.HangingPlaceEvent((org.bukkit.entity.Hanging) entity.getBukkitEntity(), bukkitPlayer, blockClicked, blockFace, hand, org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemInHand)); ++ level.getCraftServer().getPluginManager().callEvent(event); + -+ if (event.isCancelled()) { -+ if (player != null) player.containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync -+ return InteractionResult.FAIL; -+ } -+ // CraftBukkit end - entity.playPlacementSound(); - level.gameEvent(player, GameEvent.ENTITY_PLACE, entity.position()); - level.addFreshEntity(entity); ++ if (event.isCancelled()) { ++ if (player != null) player.containerMenu.sendAllDataToRemote(); // Paper - Fix inventory desync ++ return InteractionResult.FAIL; ++ } ++ // CraftBukkit end + entity.playPlacementSound(); + level.gameEvent(player, GameEvent.ENTITY_PLACE, entity.position()); + level.addFreshEntity(entity); diff --git a/paper-server/patches/sources/net/minecraft/world/item/ItemStack.java.patch b/paper-server/patches/sources/net/minecraft/world/item/ItemStack.java.patch index 1a8cdc021d83..e3f537d542d7 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/ItemStack.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/ItemStack.java.patch @@ -32,174 +32,174 @@ ItemStack.CODEC.encodeStart(ops, itemStack).getOrThrow(DecoderException::new); } -@@ -368,10 +_,165 @@ - return InteractionResult.PASS; - } else { - Item usedItem = this.getItem(); -- InteractionResult result = usedItem.useOn(context); -+ // CraftBukkit start - handle all block place event logic here -+ DataComponentPatch previousPatch = this.components.asPatch(); -+ int previousCount = this.getCount(); -+ ServerLevel level = (ServerLevel) context.getLevel(); -+ boolean isBonemeal = usedItem == Items.BONE_MEAL; +@@ -369,10 +_,165 @@ + } + + Item usedItem = this.getItem(); +- InteractionResult result = usedItem.useOn(context); ++ // CraftBukkit start - handle all block place event logic here ++ DataComponentPatch previousPatch = this.components.asPatch(); ++ int previousCount = this.getCount(); ++ ServerLevel level = (ServerLevel) context.getLevel(); ++ boolean isBonemeal = usedItem == Items.BONE_MEAL; + -+ if (!(usedItem instanceof BucketItem)) { -+ level.captureBlockStates = true; -+ if (isBonemeal) { -+ level.captureTreeGeneration = true; -+ } ++ if (!(usedItem instanceof BucketItem)) { ++ level.captureBlockStates = true; ++ if (isBonemeal) { ++ level.captureTreeGeneration = true; + } -+ InteractionResult result; -+ try { -+ result = usedItem.useOn(context); -+ } finally { -+ level.captureBlockStates = false; ++ } ++ InteractionResult result; ++ try { ++ result = usedItem.useOn(context); ++ } finally { ++ level.captureBlockStates = false; ++ } ++ DataComponentPatch newPatch = this.components.asPatch(); ++ int newCount = this.getCount(); ++ this.setCount(previousCount); ++ this.restorePatch(previousPatch); ++ if (result.consumesAction() && level.captureTreeGeneration && !level.capturedBlockStates.isEmpty()) { ++ level.captureTreeGeneration = false; ++ org.bukkit.Location location = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(pos, level); ++ org.bukkit.TreeType treeType = net.minecraft.world.level.block.SaplingBlock.treeType; ++ net.minecraft.world.level.block.SaplingBlock.treeType = null; ++ List blocks = new java.util.ArrayList<>(level.capturedBlockStates.values()); ++ level.capturedBlockStates.clear(); ++ org.bukkit.event.world.StructureGrowEvent structureEvent = null; ++ if (treeType != null) { ++ structureEvent = new org.bukkit.event.world.StructureGrowEvent(location, treeType, isBonemeal, (org.bukkit.entity.Player) player.getBukkitEntity(), (List) (List) blocks); ++ org.bukkit.Bukkit.getPluginManager().callEvent(structureEvent); + } -+ DataComponentPatch newPatch = this.components.asPatch(); -+ int newCount = this.getCount(); -+ this.setCount(previousCount); -+ this.restorePatch(previousPatch); -+ if (result.consumesAction() && level.captureTreeGeneration && !level.capturedBlockStates.isEmpty()) { -+ level.captureTreeGeneration = false; -+ org.bukkit.Location location = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(pos, level); -+ org.bukkit.TreeType treeType = net.minecraft.world.level.block.SaplingBlock.treeType; -+ net.minecraft.world.level.block.SaplingBlock.treeType = null; -+ List blocks = new java.util.ArrayList<>(level.capturedBlockStates.values()); -+ level.capturedBlockStates.clear(); -+ org.bukkit.event.world.StructureGrowEvent structureEvent = null; -+ if (treeType != null) { -+ structureEvent = new org.bukkit.event.world.StructureGrowEvent(location, treeType, isBonemeal, (org.bukkit.entity.Player) player.getBukkitEntity(), (List) (List) blocks); -+ org.bukkit.Bukkit.getPluginManager().callEvent(structureEvent); ++ ++ org.bukkit.event.block.BlockFertilizeEvent fertilizeEvent = new org.bukkit.event.block.BlockFertilizeEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), (org.bukkit.entity.Player) player.getBukkitEntity(), (List) (List) blocks); ++ fertilizeEvent.setCancelled(structureEvent != null && structureEvent.isCancelled()); ++ org.bukkit.Bukkit.getPluginManager().callEvent(fertilizeEvent); ++ ++ if (!fertilizeEvent.isCancelled()) { ++ // Change the stack to its new contents if it hasn't been tampered with. ++ if (this.getCount() == previousCount && Objects.equals(this.components.asPatch(), previousPatch)) { ++ this.restorePatch(newPatch); ++ this.setCount(newCount); ++ } ++ for (org.bukkit.craftbukkit.block.CraftBlockState snapshot : blocks) { ++ // SPIGOT-7572 - Move fix for SPIGOT-7248 to CapturedBlockState, to allow bees in bee nest ++ snapshot.place(snapshot.getFlags()); ++ level.checkCapturedTreeStateForObserverNotify(pos, snapshot); // Paper - notify observers even if grow failed + } ++ player.awardStat(Stats.ITEM_USED.get(usedItem)); // SPIGOT-7236 - award stat ++ } + -+ org.bukkit.event.block.BlockFertilizeEvent fertilizeEvent = new org.bukkit.event.block.BlockFertilizeEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), (org.bukkit.entity.Player) player.getBukkitEntity(), (List) (List) blocks); -+ fertilizeEvent.setCancelled(structureEvent != null && structureEvent.isCancelled()); -+ org.bukkit.Bukkit.getPluginManager().callEvent(fertilizeEvent); ++ SignItem.openSign = null; // SPIGOT-6758 - Reset on early return ++ return result; ++ } ++ level.captureTreeGeneration = false; + if (player != null && result instanceof InteractionResult.Success success && success.wasItemInteraction()) { +- player.awardStat(Stats.ITEM_USED.get(usedItem)); ++ InteractionHand hand = context.getHand(); ++ org.bukkit.event.block.BlockPlaceEvent placeEvent = null; ++ List blocks = new java.util.ArrayList<>(level.capturedBlockStates.values()); ++ level.capturedBlockStates.clear(); ++ if (blocks.size() > 1) { ++ placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockMultiPlaceEvent(level, player, hand, blocks, pos); ++ } else if (blocks.size() == 1 && usedItem != Items.POWDER_SNOW_BUCKET) { // Paper - Fix cancelled powdered snow bucket placement ++ placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent(level, player, hand, blocks.getFirst(), pos); ++ } + -+ if (!fertilizeEvent.isCancelled()) { -+ // Change the stack to its new contents if it hasn't been tampered with. -+ if (this.getCount() == previousCount && Objects.equals(this.components.asPatch(), previousPatch)) { -+ this.restorePatch(newPatch); -+ this.setCount(newCount); -+ } -+ for (org.bukkit.craftbukkit.block.CraftBlockState snapshot : blocks) { -+ // SPIGOT-7572 - Move fix for SPIGOT-7248 to CapturedBlockState, to allow bees in bee nest -+ snapshot.place(snapshot.getFlags()); -+ level.checkCapturedTreeStateForObserverNotify(pos, snapshot); // Paper - notify observers even if grow failed -+ } -+ player.awardStat(Stats.ITEM_USED.get(usedItem)); // SPIGOT-7236 - award stat ++ if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) { ++ result = InteractionResult.FAIL; // cancel placement ++ // PAIL: Remove this when MC-99075 fixed ++ player.containerMenu.forceHeldSlot(hand); ++ level.capturedTileEntities.clear(); // Paper - Allow chests to be placed with NBT data; clear out block entities as chests and such will pop loot ++ // revert back all captured blocks ++ for (org.bukkit.block.BlockState blockstate : blocks) { ++ ((org.bukkit.craftbukkit.block.CraftBlockState) blockstate).revertPlace(); + } + + SignItem.openSign = null; // SPIGOT-6758 - Reset on early return -+ return result; -+ } -+ level.captureTreeGeneration = false; - if (player != null && result instanceof InteractionResult.Success success && success.wasItemInteraction()) { -- player.awardStat(Stats.ITEM_USED.get(usedItem)); -+ InteractionHand hand = context.getHand(); -+ org.bukkit.event.block.BlockPlaceEvent placeEvent = null; -+ List blocks = new java.util.ArrayList<>(level.capturedBlockStates.values()); -+ level.capturedBlockStates.clear(); -+ if (blocks.size() > 1) { -+ placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockMultiPlaceEvent(level, player, hand, blocks, pos); -+ } else if (blocks.size() == 1 && usedItem != Items.POWDER_SNOW_BUCKET) { // Paper - Fix cancelled powdered snow bucket placement -+ placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent(level, player, hand, blocks.getFirst(), pos); ++ } else { ++ // Change the stack to its new contents if it hasn't been tampered with. ++ if (this.getCount() == previousCount && Objects.equals(this.components.asPatch(), previousPatch)) { ++ this.restorePatch(newPatch); ++ this.setCount(newCount); + } + -+ if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) { -+ result = InteractionResult.FAIL; // cancel placement -+ // PAIL: Remove this when MC-99075 fixed -+ player.containerMenu.forceHeldSlot(hand); -+ level.capturedTileEntities.clear(); // Paper - Allow chests to be placed with NBT data; clear out block entities as chests and such will pop loot -+ // revert back all captured blocks -+ for (org.bukkit.block.BlockState blockstate : blocks) { -+ ((org.bukkit.craftbukkit.block.CraftBlockState) blockstate).revertPlace(); -+ } ++ for (java.util.Map.Entry e : level.capturedTileEntities.entrySet()) { ++ level.setBlockEntity(e.getValue()); ++ } + -+ SignItem.openSign = null; // SPIGOT-6758 - Reset on early return -+ } else { -+ // Change the stack to its new contents if it hasn't been tampered with. -+ if (this.getCount() == previousCount && Objects.equals(this.components.asPatch(), previousPatch)) { -+ this.restorePatch(newPatch); -+ this.setCount(newCount); -+ } ++ for (org.bukkit.block.BlockState blockstate : blocks) { ++ int updateFlags = ((org.bukkit.craftbukkit.block.CraftBlockState) blockstate).getFlags(); ++ net.minecraft.world.level.block.state.BlockState oldBlock = ((org.bukkit.craftbukkit.block.CraftBlockState) blockstate).getHandle(); ++ BlockPos newPos = ((org.bukkit.craftbukkit.block.CraftBlockState) blockstate).getPosition(); ++ net.minecraft.world.level.block.state.BlockState block = level.getBlockState(newPos); + -+ for (java.util.Map.Entry e : level.capturedTileEntities.entrySet()) { -+ level.setBlockEntity(e.getValue()); ++ if (!(block.getBlock() instanceof net.minecraft.world.level.block.BaseEntityBlock)) { // Containers get placed automatically ++ block.onPlace(level, newPos, oldBlock, true, context); + } + -+ for (org.bukkit.block.BlockState blockstate : blocks) { -+ int updateFlags = ((org.bukkit.craftbukkit.block.CraftBlockState) blockstate).getFlags(); -+ net.minecraft.world.level.block.state.BlockState oldBlock = ((org.bukkit.craftbukkit.block.CraftBlockState) blockstate).getHandle(); -+ BlockPos newPos = ((org.bukkit.craftbukkit.block.CraftBlockState) blockstate).getPosition(); -+ net.minecraft.world.level.block.state.BlockState block = level.getBlockState(newPos); ++ level.notifyAndUpdatePhysics(newPos, null, oldBlock, block, level.getBlockState(newPos), updateFlags, net.minecraft.world.level.block.Block.UPDATE_LIMIT); // send null chunk as chunk.k() returns false by this point ++ } + -+ if (!(block.getBlock() instanceof net.minecraft.world.level.block.BaseEntityBlock)) { // Containers get placed automatically -+ block.onPlace(level, newPos, oldBlock, true, context); ++ if (usedItem == Items.WITHER_SKELETON_SKULL) { // Special case skulls to allow wither spawns to be cancelled ++ BlockPos bp = pos; ++ if (!level.getBlockState(pos).canBeReplaced()) { ++ if (!level.getBlockState(pos).isSolid()) { ++ bp = null; ++ } else { ++ bp = bp.relative(context.getClickedFace()); + } -+ -+ level.notifyAndUpdatePhysics(newPos, null, oldBlock, block, level.getBlockState(newPos), updateFlags, net.minecraft.world.level.block.Block.UPDATE_LIMIT); // send null chunk as chunk.k() returns false by this point + } -+ -+ if (usedItem == Items.WITHER_SKELETON_SKULL) { // Special case skulls to allow wither spawns to be cancelled -+ BlockPos bp = pos; -+ if (!level.getBlockState(pos).canBeReplaced()) { -+ if (!level.getBlockState(pos).isSolid()) { -+ bp = null; -+ } else { -+ bp = bp.relative(context.getClickedFace()); -+ } -+ } -+ if (bp != null) { -+ net.minecraft.world.level.block.entity.BlockEntity te = level.getBlockEntity(bp); -+ if (te instanceof net.minecraft.world.level.block.entity.SkullBlockEntity) { -+ net.minecraft.world.level.block.WitherSkullBlock.checkSpawn(level, bp, (net.minecraft.world.level.block.entity.SkullBlockEntity) te); -+ } ++ if (bp != null) { ++ net.minecraft.world.level.block.entity.BlockEntity te = level.getBlockEntity(bp); ++ if (te instanceof net.minecraft.world.level.block.entity.SkullBlockEntity) { ++ net.minecraft.world.level.block.WitherSkullBlock.checkSpawn(level, bp, (net.minecraft.world.level.block.entity.SkullBlockEntity) te); + } + } ++ } + -+ // SPIGOT-4678 -+ if (usedItem instanceof SignItem && SignItem.openSign != null) { -+ try { -+ if (level.getBlockEntity(SignItem.openSign) instanceof net.minecraft.world.level.block.entity.SignBlockEntity blockEntity) { -+ if (level.getBlockState(SignItem.openSign).getBlock() instanceof net.minecraft.world.level.block.SignBlock signBlock) { -+ signBlock.openTextEdit(player, blockEntity, true, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.PLACE); // CraftBukkit // Paper - Add PlayerOpenSignEvent -+ } ++ // SPIGOT-4678 ++ if (usedItem instanceof SignItem && SignItem.openSign != null) { ++ try { ++ if (level.getBlockEntity(SignItem.openSign) instanceof net.minecraft.world.level.block.entity.SignBlockEntity blockEntity) { ++ if (level.getBlockState(SignItem.openSign).getBlock() instanceof net.minecraft.world.level.block.SignBlock signBlock) { ++ signBlock.openTextEdit(player, blockEntity, true, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.PLACE); // CraftBukkit // Paper - Add PlayerOpenSignEvent + } -+ } finally { -+ SignItem.openSign = null; + } ++ } finally { ++ SignItem.openSign = null; + } ++ } + -+ // SPIGOT-7315: Moved from BedBlock#setPlacedBy -+ if (placeEvent != null && usedItem instanceof BedItem) { -+ BlockPos bedPos = ((org.bukkit.craftbukkit.block.CraftBlock) placeEvent.getBlock()).getPosition(); -+ net.minecraft.world.level.block.state.BlockState state = level.getBlockState(bedPos); -+ -+ if (state.getBlock() instanceof net.minecraft.world.level.block.BedBlock) { -+ level.updateNeighborsAt(bedPos, net.minecraft.world.level.block.Blocks.AIR); -+ state.updateNeighbourShapes(level, bedPos, net.minecraft.world.level.block.Block.UPDATE_ALL); -+ } -+ } ++ // SPIGOT-7315: Moved from BedBlock#setPlacedBy ++ if (placeEvent != null && usedItem instanceof BedItem) { ++ BlockPos bedPos = ((org.bukkit.craftbukkit.block.CraftBlock) placeEvent.getBlock()).getPosition(); ++ net.minecraft.world.level.block.state.BlockState state = level.getBlockState(bedPos); + -+ // SPIGOT-1288 - play sound stripped from BlockItem -+ if (usedItem instanceof BlockItem && success.paperSuccessContext().placedPos() != null) { -+ // Paper start - Fix spigot sound playing for BlockItem ItemStacks -+ net.minecraft.world.level.block.state.BlockState state = level.getBlockState(success.paperSuccessContext().placedPos()); -+ net.minecraft.world.level.block.SoundType soundType = state.getSoundType(); -+ // Paper end - Fix spigot sound playing for BlockItem ItemStacks -+ level.playSound(player, pos, soundType.getPlaceSound(), net.minecraft.sounds.SoundSource.BLOCKS, (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); ++ if (state.getBlock() instanceof net.minecraft.world.level.block.BedBlock) { ++ level.updateNeighborsAt(bedPos, net.minecraft.world.level.block.Blocks.AIR); ++ state.updateNeighbourShapes(level, bedPos, net.minecraft.world.level.block.Block.UPDATE_ALL); + } ++ } + -+ player.awardStat(Stats.ITEM_USED.get(usedItem)); ++ // SPIGOT-1288 - play sound stripped from BlockItem ++ if (usedItem instanceof BlockItem && success.paperSuccessContext().placedPos() != null) { ++ // Paper start - Fix spigot sound playing for BlockItem ItemStacks ++ net.minecraft.world.level.block.state.BlockState state = level.getBlockState(success.paperSuccessContext().placedPos()); ++ net.minecraft.world.level.block.SoundType soundType = state.getSoundType(); ++ // Paper end - Fix spigot sound playing for BlockItem ItemStacks ++ level.playSound(player, pos, soundType.getPlaceSound(), net.minecraft.sounds.SoundSource.BLOCKS, (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + } - } -+ level.capturedTileEntities.clear(); -+ level.capturedBlockStates.clear(); -+ // CraftBukkit end - - return result; ++ ++ player.awardStat(Stats.ITEM_USED.get(usedItem)); ++ } } ++ level.capturedTileEntities.clear(); ++ level.capturedBlockStates.clear(); ++ // CraftBukkit end + + return result; + } @@ -448,31 +_,67 @@ return this.isDamageableItem() && this.getDamageValue() >= this.getMaxDamage() - 1; } @@ -320,7 +320,7 @@ ); } } -@@ -748,6 +_,12 @@ +@@ -756,6 +_,12 @@ return this.getItem().useOnRelease(this); } @@ -333,7 +333,7 @@ public @Nullable T set(final DataComponentType type, final @Nullable T value) { return this.components.set(type, value); } -@@ -791,6 +_,28 @@ +@@ -799,6 +_,28 @@ this.components.setAll(components); } @@ -362,7 +362,7 @@ public Component getHoverName() { Component customName = this.getCustomName(); return customName != null ? customName : this.getItemName(); -@@ -1006,6 +_,19 @@ +@@ -1014,6 +_,19 @@ EnchantmentHelper.forEachModifier(this, slot, consumer); } @@ -382,7 +382,7 @@ public Component getDisplayName() { MutableComponent hoverName = Component.empty().append(this.getHoverName()); if (this.has(DataComponents.CUSTOM_NAME)) { -@@ -1070,7 +_,7 @@ +@@ -1078,7 +_,7 @@ } public void consume(final int amount, final @Nullable LivingEntity owner) { diff --git a/paper-server/patches/sources/net/minecraft/world/item/LeadItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/LeadItem.java.patch index 7f93debcac9a..2fdedb1b5b33 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/LeadItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/LeadItem.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/item/LeadItem.java +++ b/net/minecraft/world/item/LeadItem.java -@@ -27,24 +_,36 @@ +@@ -27,14 +_,14 @@ if (state.is(BlockTags.FENCES)) { Player player = context.getPlayer(); if (!level.isClientSide() && player != null) { @@ -17,32 +17,33 @@ List entitiesToLeash = Leashable.leashableInArea(level, Vec3.atCenterOf(pos), l -> l.getLeashHolder() == player); if (entitiesToLeash.isEmpty()) { return InteractionResult.PASS; - } else { - Optional existingKnot = LeashFenceKnotEntity.getKnot(level, pos); - LeashFenceKnotEntity activeKnot = existingKnot.orElseGet(() -> LeashFenceKnotEntity.createKnot(level, pos)); -+ // CraftBukkit start - fire HangingPlaceEvent -+ if (existingKnot.isEmpty()) { -+ org.bukkit.inventory.EquipmentSlot handSlot = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand); -+ org.bukkit.event.hanging.HangingPlaceEvent event = new org.bukkit.event.hanging.HangingPlaceEvent((org.bukkit.entity.Hanging) activeKnot.getBukkitEntity(), player != null ? (org.bukkit.entity.Player) player.getBukkitEntity() : null, org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), org.bukkit.block.BlockFace.SELF, handSlot); -+ level.getCraftServer().getPluginManager().callEvent(event); +@@ -42,10 +_,22 @@ + + Optional existingKnot = LeashFenceKnotEntity.getKnot(level, pos); + LeashFenceKnotEntity activeKnot = existingKnot.orElseGet(() -> LeashFenceKnotEntity.createKnot(level, pos)); ++ // CraftBukkit start - fire HangingPlaceEvent ++ if (existingKnot.isEmpty()) { ++ org.bukkit.inventory.EquipmentSlot handSlot = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand); ++ org.bukkit.event.hanging.HangingPlaceEvent event = new org.bukkit.event.hanging.HangingPlaceEvent((org.bukkit.entity.Hanging) activeKnot.getBukkitEntity(), player != null ? (org.bukkit.entity.Player) player.getBukkitEntity() : null, org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), org.bukkit.block.BlockFace.SELF, handSlot); ++ level.getCraftServer().getPluginManager().callEvent(event); + -+ if (event.isCancelled()) { -+ activeKnot.discard(); -+ return InteractionResult.PASS; -+ } ++ if (event.isCancelled()) { ++ activeKnot.discard(); ++ return InteractionResult.PASS; + } -+ // CraftBukkit end - boolean anyLeashed = false; ++ } ++ // CraftBukkit end + boolean anyLeashed = false; - for (Leashable leashable : entitiesToLeash) { -- if (leashable.canHaveALeashAttachedTo(activeKnot)) { -+ if (leashable.canHaveALeashAttachedTo(activeKnot) && org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerLeashEntityEvent(leashable, activeKnot, player, hand)) { // Paper - leash event - leashable.setLeashedTo(activeKnot, true); - anyLeashed = true; - } -@@ -63,4 +_,10 @@ + for (Leashable leashable : entitiesToLeash) { +- if (leashable.canHaveALeashAttachedTo(activeKnot)) { ++ if (leashable.canHaveALeashAttachedTo(activeKnot) && org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerLeashEntityEvent(leashable, activeKnot, player, hand)) { // Paper - leash event + leashable.setLeashedTo(activeKnot, true); + anyLeashed = true; } - } +@@ -63,4 +_,10 @@ + + return InteractionResult.PASS; } + + // CraftBukkit start diff --git a/paper-server/patches/sources/net/minecraft/world/item/MinecartItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/MinecartItem.java.patch index 70ccca3b2790..490be6f004e7 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/MinecartItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/MinecartItem.java.patch @@ -1,17 +1,17 @@ --- a/net/minecraft/world/item/MinecartItem.java +++ b/net/minecraft/world/item/MinecartItem.java -@@ -57,7 +_,13 @@ - } +@@ -59,7 +_,13 @@ + } - if (level instanceof ServerLevel serverLevel) { -- serverLevel.addFreshEntity(cart); -+ // CraftBukkit start -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, cart).isCancelled()) { -+ if (context.getPlayer() != null) context.getPlayer().containerMenu.forceHeldSlot(context.getHand()); // Paper - Fix inventory desync -+ return InteractionResult.FAIL; -+ } -+ // CraftBukkit end -+ if (!serverLevel.addFreshEntity(cart)) return InteractionResult.PASS; // CraftBukkit - serverLevel.gameEvent(GameEvent.ENTITY_PLACE, pos, GameEvent.Context.of(context.getPlayer(), serverLevel.getBlockState(pos.below()))); - } + if (level instanceof ServerLevel serverLevel) { +- serverLevel.addFreshEntity(cart); ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, cart).isCancelled()) { ++ if (context.getPlayer() != null) context.getPlayer().containerMenu.forceHeldSlot(context.getHand()); // Paper - Fix inventory desync ++ return InteractionResult.FAIL; ++ } ++ // CraftBukkit end ++ if (!serverLevel.addFreshEntity(cart)) return InteractionResult.PASS; // CraftBukkit + serverLevel.gameEvent(GameEvent.ENTITY_PLACE, pos, GameEvent.Context.of(context.getPlayer(), serverLevel.getBlockState(pos.below()))); + } diff --git a/paper-server/patches/sources/net/minecraft/world/item/ProjectileWeaponItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/ProjectileWeaponItem.java.patch index c87d9272fa57..92137878f706 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/ProjectileWeaponItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/ProjectileWeaponItem.java.patch @@ -53,13 +53,13 @@ + // Paper end if (projectile.isEmpty()) { return List.of(); - } else { -@@ -113,7 +_,7 @@ - ItemStack projectileCopy = projectile.copy(); + } +@@ -112,7 +_,7 @@ + ItemStack projectileCopy = projectile.copy(); - for (int i = 0; i < numProjectiles; i++) { -- ItemStack drawnStack = useAmmo(weapon, i == 0 ? projectile : projectileCopy, shooter, i > 0); -+ ItemStack drawnStack = useAmmo(weapon, i == 0 ? projectile : projectileCopy, shooter, i > 0 || !consume); // Paper - if (!drawnStack.isEmpty()) { - drawn.add(drawnStack); - } + for (int i = 0; i < numProjectiles; i++) { +- ItemStack drawnStack = useAmmo(weapon, i == 0 ? projectile : projectileCopy, shooter, i > 0); ++ ItemStack drawnStack = useAmmo(weapon, i == 0 ? projectile : projectileCopy, shooter, i > 0 || !consume); // Paper + if (!drawnStack.isEmpty()) { + drawn.add(drawnStack); + } diff --git a/paper-server/patches/sources/net/minecraft/world/item/ShovelItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/ShovelItem.java.patch index 97a7cf9785fa..088edba8dd0b 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/ShovelItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/ShovelItem.java.patch @@ -1,33 +1,33 @@ --- a/net/minecraft/world/item/ShovelItem.java +++ b/net/minecraft/world/item/ShovelItem.java -@@ -45,20 +_,29 @@ - Player player = context.getPlayer(); - BlockState newState = FLATTENABLES.get(blockState.getBlock()); - BlockState updatedState = null; -+ Runnable afterAction = null; // Paper - if (newState != null && level.getBlockState(pos.above()).isAir()) { -- level.playSound(player, pos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F); -+ afterAction = () -> level.playSound(player, pos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F); // Paper - updatedState = newState; - } else if (blockState.getBlock() instanceof CampfireBlock && blockState.getValue(CampfireBlock.LIT)) { -+ afterAction = () -> { // Paper - if (!level.isClientSide()) { - level.levelEvent(null, LevelEvent.SOUND_EXTINGUISH_FIRE, pos, 0); - } - - CampfireBlock.dowse(context.getPlayer(), level, pos, blockState); -+ }; // Paper - updatedState = blockState.setValue(CampfireBlock.LIT, false); +@@ -46,20 +_,29 @@ + Player player = context.getPlayer(); + BlockState newState = FLATTENABLES.get(blockState.getBlock()); + BlockState updatedState = null; ++ Runnable afterAction = null; // Paper + if (newState != null && level.getBlockState(pos.above()).isAir()) { +- level.playSound(player, pos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F); ++ afterAction = () -> level.playSound(player, pos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F); // Paper + updatedState = newState; + } else if (blockState.getBlock() instanceof CampfireBlock && blockState.getValue(CampfireBlock.LIT)) { ++ afterAction = () -> { // Paper + if (!level.isClientSide()) { + level.levelEvent(null, LevelEvent.SOUND_EXTINGUISH_FIRE, pos, 0); } - if (updatedState != null) { - if (!level.isClientSide()) { -+ // Paper start -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(context.getPlayer(), pos, updatedState)) { -+ return InteractionResult.PASS; -+ } -+ afterAction.run(); -+ // Paper end - level.setBlock(pos, updatedState, Block.UPDATE_ALL_IMMEDIATE); - level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(player, updatedState)); - if (player != null) { + CampfireBlock.dowse(context.getPlayer(), level, pos, blockState); ++ }; // Paper + updatedState = blockState.setValue(CampfireBlock.LIT, false); + } + + if (updatedState != null) { + if (!level.isClientSide()) { ++ // Paper start ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(context.getPlayer(), pos, updatedState)) { ++ return InteractionResult.PASS; ++ } ++ afterAction.run(); ++ // Paper end + level.setBlock(pos, updatedState, Block.UPDATE_ALL_IMMEDIATE); + level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(player, updatedState)); + if (player != null) { diff --git a/paper-server/patches/sources/net/minecraft/world/item/SpawnEggItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/SpawnEggItem.java.patch index 55e947834b83..274ee7f95a33 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/SpawnEggItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/SpawnEggItem.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/item/SpawnEggItem.java +++ b/net/minecraft/world/item/SpawnEggItem.java -@@ -61,6 +_,7 @@ +@@ -63,6 +_,7 @@ return InteractionResult.FAIL; } else { @@ -8,21 +8,21 @@ spawnerHolder.setEntityId(type, level.getRandom()); level.sendBlockUpdated(pos, blockState, blockState, Block.UPDATE_ALL); level.gameEvent(context.getPlayer(), GameEvent.BLOCK_CHANGE, pos); -@@ -91,7 +_,7 @@ - EntityType type = getType(itemStack); - if (type == null) { +@@ -95,7 +_,7 @@ return InteractionResult.FAIL; -- } else if (!type.isAllowedInPeaceful() && level.getDifficulty() == Difficulty.PEACEFUL) { -+ } else if (!type.isAllowedInPeaceful(itemStack.get(DataComponents.ENTITY_DATA).getUnsafe()) && level.getDifficulty() == Difficulty.PEACEFUL) { // Paper - check peaceful override + } + +- if (!type.isAllowedInPeaceful() && level.getDifficulty() == Difficulty.PEACEFUL) { ++ if (!type.isAllowedInPeaceful(itemStack.get(DataComponents.ENTITY_DATA).getUnsafe()) && level.getDifficulty() == Difficulty.PEACEFUL) { // Paper - check peaceful override return InteractionResult.FAIL; - } else { - if (type.spawn((ServerLevel)level, itemStack, user, spawnPos, EntitySpawnReason.SPAWN_ITEM_USE, tryMoveDown, movedUp) != null) { -@@ -163,7 +_,7 @@ - } else { - offspring.snapTo(pos.x(), pos.y(), pos.z(), 0.0F, 0.0F); - offspring.applyComponentsFromItemStack(spawnEggStack); -- level.addFreshEntityWithPassengers(offspring); -+ level.addFreshEntityWithPassengers(offspring, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER_EGG); // CraftBukkit - spawnEggStack.consume(1, player); - return Optional.of(offspring); - } + } + +@@ -174,7 +_,7 @@ + + offspring.snapTo(pos.x(), pos.y(), pos.z(), 0.0F, 0.0F); + offspring.applyComponentsFromItemStack(spawnEggStack); +- level.addFreshEntityWithPassengers(offspring); ++ level.addFreshEntityWithPassengers(offspring, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER_EGG); // CraftBukkit + spawnEggStack.consume(1, player); + return Optional.of(offspring); + } diff --git a/paper-server/patches/sources/net/minecraft/world/item/TridentItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/TridentItem.java.patch index 786ea731da41..b1a73a1154b9 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/TridentItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/TridentItem.java.patch @@ -1,52 +1,52 @@ --- a/net/minecraft/world/item/TridentItem.java +++ b/net/minecraft/world/item/TridentItem.java -@@ -78,18 +_,38 @@ - .orElse(SoundEvents.TRIDENT_THROW); - player.awardStat(Stats.ITEM_USED.get(this)); - if (level instanceof ServerLevel serverLevel) { -- itemStack.hurtWithoutBreaking(1, player); -+ // itemStack.hurtWithoutBreaking(1, player); // CraftBukkit - moved down - if (riptideStrength == 0.0F) { -- ItemStack thrownItemStack = itemStack.consumeAndReturn(1, player); -- ThrownTrident trident = Projectile.spawnProjectileFromRotation( -+ ItemStack thrownItemStack = itemStack.copyWithCount(1); // Paper -+ Projectile.Delayed tridentDelayed = Projectile.spawnProjectileFromRotationDelayed( // Paper - PlayerLaunchProjectileEvent( - ThrownTrident::new, serverLevel, thrownItemStack, player, 0.0F, 2.5F, 1.0F - ); -+ // Paper start - PlayerLaunchProjectileEvent -+ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Projectile) tridentDelayed.projectile().getBukkitEntity()); -+ if (!event.callEvent() || !tridentDelayed.attemptSpawn()) { -+ // CraftBukkit start -+ // Paper end - PlayerLaunchProjectileEvent -+ return false; -+ } -+ ThrownTrident trident = tridentDelayed.projectile(); // Paper - PlayerLaunchProjectileEvent -+ if (event.shouldConsume()) { -+ thrownItemStack.hurtWithoutBreaking(1, player); // Paper - PlayerLaunchProjectileEvent - use thrownItemStack; pickup item damage -+ } -+ trident.pickupItemStack = thrownItemStack.copy(); // SPIGOT-4511 update since damage call moved - use thrownItemStack; count = 1 -+ if (event.shouldConsume()) { -+ itemStack.consume(1, player); -+ } -+ // CraftBukkit end - if (player.hasInfiniteMaterials()) { - trident.pickup = AbstractArrow.Pickup.CREATIVE_ONLY; - } - - level.playSound(null, trident, sound.value(), SoundSource.PLAYERS, 1.0F, 1.0F); - return true; -+ // CraftBukkit start - SPIGOT-5458 also need in this branch :( -+ } else { -+ itemStack.hurtWithoutBreaking(1, player); -+ // CraftBukkit end - } +@@ -80,18 +_,38 @@ + .orElse(SoundEvents.TRIDENT_THROW); + player.awardStat(Stats.ITEM_USED.get(this)); + if (level instanceof ServerLevel serverLevel) { +- itemStack.hurtWithoutBreaking(1, player); ++ // itemStack.hurtWithoutBreaking(1, player); // CraftBukkit - moved down + if (riptideStrength == 0.0F) { +- ItemStack thrownItemStack = itemStack.consumeAndReturn(1, player); +- ThrownTrident trident = Projectile.spawnProjectileFromRotation( ++ ItemStack thrownItemStack = itemStack.copyWithCount(1); // Paper ++ Projectile.Delayed tridentDelayed = Projectile.spawnProjectileFromRotationDelayed( // Paper - PlayerLaunchProjectileEvent( + ThrownTrident::new, serverLevel, thrownItemStack, player, 0.0F, 2.5F, 1.0F + ); ++ // Paper start - PlayerLaunchProjectileEvent ++ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack), (org.bukkit.entity.Projectile) tridentDelayed.projectile().getBukkitEntity()); ++ if (!event.callEvent() || !tridentDelayed.attemptSpawn()) { ++ // CraftBukkit start ++ // Paper end - PlayerLaunchProjectileEvent ++ return false; ++ } ++ ThrownTrident trident = tridentDelayed.projectile(); // Paper - PlayerLaunchProjectileEvent ++ if (event.shouldConsume()) { ++ thrownItemStack.hurtWithoutBreaking(1, player); // Paper - PlayerLaunchProjectileEvent - use thrownItemStack; pickup item damage ++ } ++ trident.pickupItemStack = thrownItemStack.copy(); // SPIGOT-4511 update since damage call moved - use thrownItemStack; count = 1 ++ if (event.shouldConsume()) { ++ itemStack.consume(1, player); ++ } ++ // CraftBukkit end + if (player.hasInfiniteMaterials()) { + trident.pickup = AbstractArrow.Pickup.CREATIVE_ONLY; } -@@ -103,6 +_,7 @@ - xd *= riptideStrength / dist; - yd *= riptideStrength / dist; - zd *= riptideStrength / dist; -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerRiptideEvent(player, itemStack, xd, yd, zd)) return false; // Paper - Add player riptide event - player.push(xd, yd, zd); - player.startAutoSpinAttack(20, 8.0F, itemStack); - if (player.onGround()) { + level.playSound(null, trident, sound.value(), SoundSource.PLAYERS, 1.0F, 1.0F); + return true; ++ // CraftBukkit start - SPIGOT-5458 also need in this branch :( ++ } else { ++ itemStack.hurtWithoutBreaking(1, player); ++ // CraftBukkit end + } + } + +@@ -105,6 +_,7 @@ + xd *= riptideStrength / dist; + yd *= riptideStrength / dist; + zd *= riptideStrength / dist; ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerRiptideEvent(player, itemStack, xd, yd, zd)) return false; // Paper - Add player riptide event + player.push(xd, yd, zd); + player.startAutoSpinAttack(20, 8.0F, itemStack); + if (player.onGround()) { diff --git a/paper-server/patches/sources/net/minecraft/world/item/alchemy/PotionBrewing.java.patch b/paper-server/patches/sources/net/minecraft/world/item/alchemy/PotionBrewing.java.patch index 03fbf04cd2f2..e08b63a5bed7 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/alchemy/PotionBrewing.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/alchemy/PotionBrewing.java.patch @@ -29,20 +29,20 @@ return this.isContainer(source) && (this.hasContainerMix(source, ingredient) || this.hasPotionMix(source, ingredient)); } -@@ -109,6 +_,13 @@ - if (potion.isEmpty()) { - return source; - } else { -+ // Paper start - Custom Potion Mixes -+ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) { -+ if (mix.input().test(source) && mix.ingredient().test(ingredient)) { -+ return mix.result().copy(); -+ } -+ } -+ // Paper end - Custom Potion Mixes - for (PotionBrewing.Mix mix : this.containerMixes) { - if (source.is(mix.from) && mix.ingredient.test(ingredient)) { - return PotionContents.createItemStack(mix.to.value(), potion.get()); +@@ -111,6 +_,13 @@ + return source; + } + ++ // Paper start - Custom Potion Mixes ++ for (io.papermc.paper.potion.PaperPotionMix mix : this.customMixes.values()) { ++ if (mix.input().test(source) && mix.ingredient().test(ingredient)) { ++ return mix.result().copy(); ++ } ++ } ++ // Paper end - Custom Potion Mixes + for (PotionBrewing.Mix mix : this.containerMixes) { + if (source.is(mix.from) && mix.ingredient.test(ingredient)) { + return PotionContents.createItemStack(mix.to.value(), potion.get()); @@ -191,6 +_,50 @@ builder.addMix(Potions.AWKWARD, Items.PHANTOM_MEMBRANE, Potions.SLOW_FALLING); builder.addMix(Potions.SLOW_FALLING, Items.REDSTONE, Potions.LONG_SLOW_FALLING); diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/LodestoneTracker.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/LodestoneTracker.java.patch index 6a668d9014f3..4ab4beab795e 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/LodestoneTracker.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/LodestoneTracker.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/item/component/LodestoneTracker.java +++ b/net/minecraft/world/item/component/LodestoneTracker.java -@@ -29,7 +_,7 @@ - return this; - } else { - BlockPos blockPos = this.target.get().pos(); -- return level.isInWorldBounds(blockPos) && level.getPoiManager().existsAtPosition(PoiTypes.LODESTONE, blockPos) -+ return level.isInWorldBounds(blockPos) && (!level.hasChunkAt(blockPos) || level.getPoiManager().existsAtPosition(PoiTypes.LODESTONE, blockPos)) // Paper - Prevent compass from loading chunks - ? this - : new LodestoneTracker(Optional.empty(), true); +@@ -30,7 +_,7 @@ } + + BlockPos blockPos = this.target.get().pos(); +- return level.isInWorldBounds(blockPos) && level.getPoiManager().existsAtPosition(PoiTypes.LODESTONE, blockPos) ++ return level.isInWorldBounds(blockPos) && (!level.hasChunkAt(blockPos) || level.getPoiManager().existsAtPosition(PoiTypes.LODESTONE, blockPos)) // Paper - Prevent compass from loading chunks + ? this + : new LodestoneTracker(Optional.empty(), true); + } else { diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/ResolvableProfile.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/ResolvableProfile.java.patch index 8d73c45ced2a..cb5804796867 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/ResolvableProfile.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/ResolvableProfile.java.patch @@ -4,8 +4,8 @@ private static ResolvableProfile create(final Either value, final PlayerSkin.Patch patch) { return value.map( full -> new ResolvableProfile.Static(Either.left(full), patch), -- partial -> (ResolvableProfile)(partial.properties.isEmpty() && partial.id.isPresent() != partial.name.isPresent() -+ partial -> (ResolvableProfile)(partial.properties.isEmpty() && partial.id.isPresent() != partial.name.isPresent() // Paper - diff on change - heuristic for dynamic vs static resolvable profile - used in CraftPlayerProfile#buildResolvable +- partial -> partial.properties.isEmpty() && partial.id.isPresent() != partial.name.isPresent() ++ partial -> partial.properties.isEmpty() && partial.id.isPresent() != partial.name.isPresent() // Paper - diff on change - heuristic for dynamic vs static resolvable profile - used in CraftPlayerProfile#buildResolvable ? partial.name .map(s -> new ResolvableProfile.Dynamic(Either.left(s), patch)) .orElseGet(() -> new ResolvableProfile.Dynamic(Either.right(partial.id.get()), patch)) diff --git a/paper-server/patches/sources/net/minecraft/world/item/component/TypedEntityData.java.patch b/paper-server/patches/sources/net/minecraft/world/item/component/TypedEntityData.java.patch index 2d3b87168c1e..835dc089562f 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/component/TypedEntityData.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/component/TypedEntityData.java.patch @@ -33,7 +33,7 @@ public static TypedEntityData of(final T type, final CompoundTag data) { return new TypedEntityData<>(type, data); } -@@ -182,7 +_,7 @@ +@@ -179,7 +_,7 @@ ) { if (this.type.getClass() == EntityType.class) { EntityType type = (EntityType)this.type; diff --git a/paper-server/patches/sources/net/minecraft/world/item/consume_effects/ApplyStatusEffectsConsumeEffect.java.patch b/paper-server/patches/sources/net/minecraft/world/item/consume_effects/ApplyStatusEffectsConsumeEffect.java.patch index 412ccec493e3..b6adac3ac829 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/consume_effects/ApplyStatusEffectsConsumeEffect.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/consume_effects/ApplyStatusEffectsConsumeEffect.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/item/consume_effects/ApplyStatusEffectsConsumeEffect.java +++ b/net/minecraft/world/item/consume_effects/ApplyStatusEffectsConsumeEffect.java -@@ -46,14 +_,14 @@ +@@ -46,7 +_,7 @@ } @Override @@ -8,12 +8,13 @@ + public boolean apply(final Level level, final ItemStack stack, final LivingEntity user, final org.bukkit.event.entity.EntityPotionEffectEvent.Cause cause) { // CraftBukkit if (user.getRandom().nextFloat() >= this.probability) { return false; - } else { - boolean anyApplied = false; + } +@@ -54,7 +_,7 @@ + boolean anyApplied = false; - for (MobEffectInstance effect : this.effects) { -- if (user.addEffect(new MobEffectInstance(effect))) { -+ if (user.addEffect(new MobEffectInstance(effect), cause)) { // CraftBukkit - anyApplied = true; - } + for (MobEffectInstance effect : this.effects) { +- if (user.addEffect(new MobEffectInstance(effect))) { ++ if (user.addEffect(new MobEffectInstance(effect), cause)) { // CraftBukkit + anyApplied = true; } + } diff --git a/paper-server/patches/sources/net/minecraft/world/item/consume_effects/ConsumeEffect.java.patch b/paper-server/patches/sources/net/minecraft/world/item/consume_effects/ConsumeEffect.java.patch index 95ff41a54c96..08fabd6c26a0 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/consume_effects/ConsumeEffect.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/consume_effects/ConsumeEffect.java.patch @@ -15,5 +15,5 @@ + } + // CraftBukkit end - public record Type(MapCodec codec, StreamCodec streamCodec) { + record Type(MapCodec codec, StreamCodec streamCodec) { public static final ConsumeEffect.Type APPLY_EFFECTS = register( diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/Ingredient.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/Ingredient.java.patch index 688cfaa2d6ef..45d5ff42e209 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/crafting/Ingredient.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/Ingredient.java.patch @@ -24,7 +24,7 @@ private Ingredient(final HolderSet values) { values.unwrap().ifRight(directValues -> { -@@ -60,6 +_,17 @@ +@@ -62,6 +_,17 @@ @Override public boolean test(final ItemStack input) { @@ -42,7 +42,7 @@ return input.is(this.values); } -@@ -70,7 +_,7 @@ +@@ -72,7 +_,7 @@ @Override public boolean equals(final Object o) { diff --git a/paper-server/patches/sources/net/minecraft/world/item/crafting/SmithingTrimRecipe.java.patch b/paper-server/patches/sources/net/minecraft/world/item/crafting/SmithingTrimRecipe.java.patch index 8fd6968d7fbd..1651b9de70b9 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/crafting/SmithingTrimRecipe.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/crafting/SmithingTrimRecipe.java.patch @@ -38,15 +38,15 @@ Holder material = materialItem.get(DataComponents.PROVIDES_TRIM_MATERIAL); if (material != null) { ArmorTrim existingTrim = baseItem.get(DataComponents.TRIM); -@@ -71,7 +_,7 @@ - if (Objects.equals(existingTrim, newTrim)) { +@@ -72,7 +_,7 @@ return ItemStack.EMPTY; - } else { -- ItemStack trimmedItem = baseItem.copyWithCount(1); -+ ItemStack trimmedItem = copyDataComponents ? baseItem.copyWithCount(1) : new ItemStack(baseItem.getItem(), 1); // Paper - Option to prevent data components copy - trimmedItem.set(DataComponents.TRIM, newTrim); - return trimmedItem; } + +- ItemStack trimmedItem = baseItem.copyWithCount(1); ++ ItemStack trimmedItem = copyDataComponents ? baseItem.copyWithCount(1) : new ItemStack(baseItem.getItem(), 1); // Paper - Option to prevent data components copy + trimmedItem.set(DataComponents.TRIM, newTrim); + return trimmedItem; + } else { @@ -120,4 +_,10 @@ ) ); diff --git a/paper-server/patches/sources/net/minecraft/world/item/enchantment/EnchantmentHelper.java.patch b/paper-server/patches/sources/net/minecraft/world/item/enchantment/EnchantmentHelper.java.patch index 710eb1e8c82e..6613a6b8b455 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/enchantment/EnchantmentHelper.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/enchantment/EnchantmentHelper.java.patch @@ -15,4 +15,4 @@ + ItemEnchantments oldEnchantments = createComponentIfMissing ? itemStack.getOrDefault(componentType, ItemEnchantments.EMPTY) : itemStack.get(componentType); // Paper - allowing updating enchantments on items without component if (oldEnchantments == null) { return ItemEnchantments.EMPTY; - } else { + } diff --git a/paper-server/patches/sources/net/minecraft/world/item/trading/MerchantOffer.java.patch b/paper-server/patches/sources/net/minecraft/world/item/trading/MerchantOffer.java.patch index f20ec063cada..502f80ea046b 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/trading/MerchantOffer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/trading/MerchantOffer.java.patch @@ -71,16 +71,15 @@ } public ItemStack assemble() { -@@ -222,7 +_,11 @@ - if (!this.satisfiedBy(buyA, buyB)) { +@@ -223,7 +_,11 @@ return false; - } else { -- buyA.shrink(this.getCostA().getCount()); -+ // CraftBukkit start -+ if (!this.getCostA().isEmpty()) { -+ buyA.shrink(this.getCostA().getCount()); -+ } -+ // CraftBukkit end - if (!this.getCostB().isEmpty()) { - buyB.shrink(this.getCostB().getCount()); - } + } + ++ // CraftBukkit start ++ if (!this.getCostA().isEmpty()) { + buyA.shrink(this.getCostA().getCount()); ++ } ++ // CraftBukkit end + if (!this.getCostB().isEmpty()) { + buyB.shrink(this.getCostB().getCount()); + } diff --git a/paper-server/patches/sources/net/minecraft/world/level/BaseCommandBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/BaseCommandBlock.java.patch index c7a01f579a58..22f1af104fd4 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/BaseCommandBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/BaseCommandBlock.java.patch @@ -11,23 +11,23 @@ public int getSuccessCount() { return this.successCount; -@@ -107,7 +_,13 @@ - this.successCount++; - } - }); -- level.getServer().getCommands().performPrefixedCommand(commandSourceStack, this.command); -+ // Paper start - ServerCommandEvent -+ org.bukkit.event.server.ServerCommandEvent event = new org.bukkit.event.server.ServerCommandEvent(commandSourceStack.getBukkitSender(), net.minecraft.commands.Commands.trimOptionalPrefix(this.command)); -+ if (!event.callEvent()) { -+ return true; -+ } -+ level.getServer().getCommands().performPrefixedCommand(commandSourceStack, event.getCommand()); -+ // Paper end - ServerCommandEvent - } - } catch (Throwable var7) { - CrashReport report = CrashReport.forThrowable(var7, "Executing command block"); -@@ -128,8 +_,8 @@ - } +@@ -109,7 +_,13 @@ + this.successCount++; + } + }); +- level.getServer().getCommands().performPrefixedCommand(commandSourceStack, this.command); ++ // Paper start - ServerCommandEvent ++ org.bukkit.event.server.ServerCommandEvent event = new org.bukkit.event.server.ServerCommandEvent(commandSourceStack.getBukkitSender(), net.minecraft.commands.Commands.trimOptionalPrefix(this.command)); ++ if (!event.callEvent()) { ++ return true; ++ } ++ level.getServer().getCommands().performPrefixedCommand(commandSourceStack, event.getCommand()); ++ // Paper end - ServerCommandEvent + } + } catch (Throwable t) { + CrashReport report = CrashReport.forThrowable(t, "Executing command block"); +@@ -129,8 +_,8 @@ + return true; } - private BaseCommandBlock.@Nullable CloseableCommandBlockSource createSource(final ServerLevel level) { @@ -37,7 +37,7 @@ } public Component getName() { -@@ -162,15 +_,23 @@ +@@ -163,13 +_,21 @@ public abstract boolean isValid(); @@ -51,8 +51,6 @@ + // Paper start - add back source when output disabled + private final boolean trackOutput; + public CloseableCommandBlockSource(final ServerLevel level, final boolean trackOutput) { - Objects.requireNonNull(BaseCommandBlock.this); - super(); this.level = level; + this.trackOutput = trackOutput; + } @@ -63,7 +61,7 @@ } @Override -@@ -180,7 +_,7 @@ +@@ -179,7 +_,7 @@ @Override public boolean acceptsFailure() { @@ -72,7 +70,7 @@ } @Override -@@ -190,7 +_,8 @@ +@@ -189,7 +_,8 @@ @Override public void sendSystemMessage(final Component message) { @@ -82,7 +80,7 @@ BaseCommandBlock.this.lastOutput = Component.literal("[" + TIME_FORMAT.format(ZonedDateTime.now()) + "] ").append(message); BaseCommandBlock.this.onUpdated(this.level); } -@@ -200,5 +_,12 @@ +@@ -199,5 +_,12 @@ public void close() throws Exception { this.closed = true; } diff --git a/paper-server/patches/sources/net/minecraft/world/level/EntityGetter.java.patch b/paper-server/patches/sources/net/minecraft/world/level/EntityGetter.java.patch index e5eb23c97b83..3d43378d1551 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/EntityGetter.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/EntityGetter.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/level/EntityGetter.java +++ b/net/minecraft/world/level/EntityGetter.java @@ -71,6 +_,12 @@ - } + return shapes.build(); } + // Paper start - Affects Spawning API diff --git a/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch b/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch index e51510437f3b..8216ce67ef5d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/Level.java.patch @@ -281,110 +281,105 @@ + // CraftBukkit end if (!this.isInValidBounds(pos)) { return false; - } else if (!this.isClientSide() && this.isDebug()) { -@@ -224,11 +_,31 @@ - } else { - LevelChunk chunk = this.getChunkAt(pos); - Block block = blockState.getBlock(); -+ // CraftBukkit start - capture blockstates -+ boolean captured = false; -+ if (this.captureBlockStates) { -+ final CraftBlockState snapshot; -+ if (!this.capturedBlockStates.containsKey(pos)) { -+ snapshot = (CraftBlockState) org.bukkit.craftbukkit.block.CraftBlock.at(this, pos).getState(); // Paper - use CB getState to get a suitable snapshot -+ this.capturedBlockStates.put(pos.immutable(), snapshot); -+ captured = true; -+ } else { -+ snapshot = this.capturedBlockStates.get(pos); -+ } -+ snapshot.setFlags(updateFlags); // Paper - always set the flag of the most recent call to mitigate issues with multiple update at the same pos with different flags + } +@@ -227,12 +_,32 @@ + + LevelChunk chunk = this.getChunkAt(pos); + Block block = blockState.getBlock(); ++ // CraftBukkit start - capture blockstates ++ boolean captured = false; ++ if (this.captureBlockStates) { ++ final CraftBlockState snapshot; ++ if (!this.capturedBlockStates.containsKey(pos)) { ++ snapshot = (CraftBlockState) org.bukkit.craftbukkit.block.CraftBlock.at(this, pos).getState(); // Paper - use CB getState to get a suitable snapshot ++ this.capturedBlockStates.put(pos.immutable(), snapshot); ++ captured = true; ++ } else { ++ snapshot = this.capturedBlockStates.get(pos); + } -+ // CraftBukkit end - capture blockstates - BlockState oldState = chunk.setBlockState(pos, blockState, updateFlags); - if (oldState == null) { -+ // CraftBukkit start - remove blockstate if failed (or the same) -+ if (this.captureBlockStates && captured) { -+ this.capturedBlockStates.remove(pos); -+ } -+ // CraftBukkit end - return false; - } else { - BlockState newState = this.getBlockState(pos); -+ /* // CraftBukkit - if (newState == blockState) { - if (oldState != newState) { - this.setBlocksDirty(pos, oldState, newState); -@@ -256,12 +_,69 @@ - - this.updatePOIOnBlockStateChange(pos, oldState, newState); - } -+ */ // CraftBukkit -+ -+ // CraftBukkit start -+ if (!this.captureBlockStates) { // Don't notify clients or update physics while capturing blockstates -+ // Modularize client and physic updates -+ // Spigot start -+ try { -+ this.notifyAndUpdatePhysics(pos, chunk, oldState, blockState, newState, updateFlags, updateLimit); -+ } catch (StackOverflowError ex) { -+ Level.lastPhysicsProblem = pos.immutable(); -+ } -+ // Spigot end -+ } -+ // CraftBukkit end ++ snapshot.setFlags(updateFlags); // Paper - always set the flag of the most recent call to mitigate issues with multiple update at the same pos with different flags ++ } ++ // CraftBukkit end - capture blockstates + BlockState oldState = chunk.setBlockState(pos, blockState, updateFlags); + if (oldState == null) { ++ // CraftBukkit start - remove blockstate if failed (or the same) ++ if (this.captureBlockStates && captured) { ++ this.capturedBlockStates.remove(pos); ++ } ++ // CraftBukkit end + return false; + } - return true; - } + BlockState newState = this.getBlockState(pos); ++ /* // CraftBukkit + if (newState == blockState) { + if (oldState != newState) { + this.setBlocksDirty(pos, oldState, newState); +@@ -260,9 +_,63 @@ + + this.updatePOIOnBlockStateChange(pos, oldState, newState); } - } ++ */ // CraftBukkit ++ ++ // CraftBukkit start ++ if (!this.captureBlockStates) { // Don't notify clients or update physics while capturing blockstates ++ // Modularize client and physic updates ++ // Spigot start ++ try { ++ this.notifyAndUpdatePhysics(pos, chunk, oldState, blockState, newState, updateFlags, updateLimit); ++ } catch (StackOverflowError ex) { ++ Level.lastPhysicsProblem = pos.immutable(); ++ } ++ // Spigot end ++ } ++ // CraftBukkit end + return true; + } ++ + // CraftBukkit start - Split off from above in order to directly send client and physic updates -+ public void notifyAndUpdatePhysics(BlockPos pos, LevelChunk chunkAt, BlockState oldState, BlockState newState, BlockState currentState, @Block.UpdateFlags int flags, int recursionLeft) { -+ BlockState state = newState; -+ BlockState blockState = oldState; -+ BlockState blockState1 = currentState; -+ if (blockState1 == state) { -+ if (blockState != blockState1) { -+ this.setBlocksDirty(pos, blockState, blockState1); ++ public void notifyAndUpdatePhysics(BlockPos pos, LevelChunk chunk, BlockState oldState, BlockState blockState, BlockState newState, @Block.UpdateFlags int updateFlags, int updateLimit) { ++ if (newState == blockState) { ++ if (oldState != newState) { ++ this.setBlocksDirty(pos, oldState, newState); + } + -+ if ((flags & Block.UPDATE_CLIENTS) != 0 && (!this.isClientSide() || (flags & Block.UPDATE_INVISIBLE) == 0) && (this.isClientSide() || chunkAt == null || (chunkAt.getFullStatus() != null && chunkAt.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING)))) { // allow chunk to be null here as chunk.isReady() is false when we send our notification during block placement -+ this.sendBlockUpdated(pos, blockState, state, flags); ++ if ((updateFlags & Block.UPDATE_CLIENTS) != 0 && (!this.isClientSide() || (updateFlags & Block.UPDATE_INVISIBLE) == 0) && (this.isClientSide() || chunk == null || (chunk.getFullStatus() != null && chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING)))) { // allow chunk to be null here as chunk.isReady() is false when we send our notification during block placement ++ this.sendBlockUpdated(pos, oldState, blockState, updateFlags); + } + -+ if ((flags & Block.UPDATE_NEIGHBORS) != 0) { -+ this.updateNeighborsAt(pos, blockState.getBlock()); -+ if (!this.isClientSide() && state.hasAnalogOutputSignal()) { -+ this.updateNeighbourForOutputSignal(pos, newState.getBlock()); ++ if ((updateFlags & Block.UPDATE_NEIGHBORS) != 0) { ++ this.updateNeighborsAt(pos, oldState.getBlock()); ++ if (!this.isClientSide() && blockState.hasAnalogOutputSignal()) { ++ this.updateNeighbourForOutputSignal(pos, blockState.getBlock()); + } + } + -+ if ((flags & Block.UPDATE_KNOWN_SHAPE) == 0 && recursionLeft > 0) { -+ int i = flags & ~(Block.UPDATE_SUPPRESS_DROPS | Block.UPDATE_NEIGHBORS); ++ if ((updateFlags & Block.UPDATE_KNOWN_SHAPE) == 0 && updateLimit > 0) { ++ int neighbourUpdateFlags = updateFlags & ~(Block.UPDATE_SUPPRESS_DROPS | Block.UPDATE_NEIGHBORS); + + // CraftBukkit start -+ blockState.updateIndirectNeighbourShapes(this, pos, i, recursionLeft - 1); // Don't call an event for the old block to limit event spam ++ oldState.updateIndirectNeighbourShapes(this, pos, neighbourUpdateFlags, updateLimit - 1); // Don't call an event for the old block to limit event spam + boolean cancelledUpdates = false; // Paper - Fix block place logic + if (((ServerLevel)this).hasPhysicsEvent) { // Paper - BlockPhysicsEvent -+ org.bukkit.event.block.BlockPhysicsEvent event = new org.bukkit.event.block.BlockPhysicsEvent(org.bukkit.craftbukkit.block.CraftBlock.at(this, pos), state.asBlockData()); ++ org.bukkit.event.block.BlockPhysicsEvent event = new org.bukkit.event.block.BlockPhysicsEvent(org.bukkit.craftbukkit.block.CraftBlock.at(this, pos), blockState.asBlockData()); + cancelledUpdates = !event.callEvent(); // Paper - Fix block place logic + } + // CraftBukkit end + if (!cancelledUpdates) { // Paper - Fix block place logic -+ state.updateNeighbourShapes(this, pos, i, recursionLeft - 1); -+ state.updateIndirectNeighbourShapes(this, pos, i, recursionLeft - 1); ++ blockState.updateNeighbourShapes(this, pos, neighbourUpdateFlags, updateLimit - 1); ++ blockState.updateIndirectNeighbourShapes(this, pos, neighbourUpdateFlags, updateLimit - 1); + } // Paper - Fix block place logic + } + -+ this.updatePOIOnBlockStateChange(pos, blockState, blockState1); ++ this.updatePOIOnBlockStateChange(pos, oldState, newState); + } + } + // CraftBukkit end -+ + public void updatePOIOnBlockStateChange(final BlockPos pos, final BlockState oldState, final BlockState newState) { } - -@@ -272,19 +_,37 @@ +@@ -274,20 +_,38 @@ } @Override @@ -393,40 +388,41 @@ BlockState blockState = this.getBlockState(pos); if (blockState.isAir()) { return false; - } else { - FluidState fluidState = this.getFluidState(pos); -- if (!(blockState.getBlock() instanceof BaseFireBlock)) { -- this.levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, pos, Block.getId(blockState)); -+ // Paper start - BlockDestroyEvent; while the above removeBlock method looks very similar -+ // they are NOT used with same intent and the above should not fire this event. The above method is more of a BlockSetToAirEvent, -+ // it doesn't imply destruction of a block that plays a sound effect / drops an item. -+ boolean playEffect = true; -+ BlockState effectType = blockState; -+ int xp = blockState.getBlock().getExpDrop(blockState, (ServerLevel) this, pos, ItemStack.EMPTY, true); -+ if (com.destroystokyo.paper.event.block.BlockDestroyEvent.getHandlerList().getRegisteredListeners().length > 0) { -+ com.destroystokyo.paper.event.block.BlockDestroyEvent event = new com.destroystokyo.paper.event.block.BlockDestroyEvent(org.bukkit.craftbukkit.block.CraftBlock.at(this, pos), fluidState.createLegacyBlock().asBlockData(), effectType.asBlockData(), xp, dropResources); -+ if (!event.callEvent()) { -+ return false; -+ } -+ effectType = ((CraftBlockData) event.getEffectBlock()).getState(); -+ playEffect = event.playEffect(); -+ dropResources = event.willDrop(); -+ xp = event.getExpToDrop(); + } + + FluidState fluidState = this.getFluidState(pos); +- if (!(blockState.getBlock() instanceof BaseFireBlock)) { +- this.levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, pos, Block.getId(blockState)); ++ // Paper start - BlockDestroyEvent; while the above removeBlock method looks very similar ++ // they are NOT used with same intent and the above should not fire this event. The above method is more of a BlockSetToAirEvent, ++ // it doesn't imply destruction of a block that plays a sound effect / drops an item. ++ boolean playEffect = true; ++ BlockState effectType = blockState; ++ int xp = blockState.getBlock().getExpDrop(blockState, (ServerLevel) this, pos, ItemStack.EMPTY, true); ++ if (com.destroystokyo.paper.event.block.BlockDestroyEvent.getHandlerList().getRegisteredListeners().length > 0) { ++ com.destroystokyo.paper.event.block.BlockDestroyEvent event = new com.destroystokyo.paper.event.block.BlockDestroyEvent(org.bukkit.craftbukkit.block.CraftBlock.at(this, pos), fluidState.createLegacyBlock().asBlockData(), effectType.asBlockData(), xp, dropResources); ++ if (!event.callEvent()) { ++ return false; + } -+ // Paper end - BlockDestroyEvent -+ if (playEffect && !(blockState.getBlock() instanceof BaseFireBlock)) { // Paper - BlockDestroyEvent -+ this.levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, pos, Block.getId(effectType)); // Paper - BlockDestroyEvent - } ++ effectType = ((CraftBlockData) event.getEffectBlock()).getState(); ++ playEffect = event.playEffect(); ++ dropResources = event.willDrop(); ++ xp = event.getExpToDrop(); ++ } ++ // Paper end - BlockDestroyEvent ++ if (playEffect && !(blockState.getBlock() instanceof BaseFireBlock)) { // Paper - BlockDestroyEvent ++ this.levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, pos, Block.getId(effectType)); // Paper - BlockDestroyEvent + } - if (dropResources) { - BlockEntity blockEntity = blockState.hasBlockEntity() ? this.getBlockEntity(pos) : null; -- Block.dropResources(blockState, this, pos, blockEntity, breaker, ItemStack.EMPTY); -+ Block.dropResources(blockState, this, pos, blockEntity, breaker, ItemStack.EMPTY, false); // Paper - Properly handle xp dropping -+ blockState.getBlock().popExperience((ServerLevel) this, pos, xp, breaker); // Paper - Properly handle xp dropping; custom amount - } + if (dropResources) { + BlockEntity blockEntity = blockState.hasBlockEntity() ? this.getBlockEntity(pos) : null; +- Block.dropResources(blockState, this, pos, blockEntity, breaker, ItemStack.EMPTY); ++ Block.dropResources(blockState, this, pos, blockEntity, breaker, ItemStack.EMPTY, false); // Paper - Properly handle xp dropping ++ blockState.getBlock().popExperience((ServerLevel) this, pos, xp, breaker); // Paper - Properly handle xp dropping; custom amount + } - boolean destroyed = this.setBlock(pos, fluidState.createLegacyBlock(), Block.UPDATE_ALL, updateLimit); -@@ -359,10 +_,18 @@ + boolean destroyed = this.setBlock(pos, fluidState.createLegacyBlock(), Block.UPDATE_ALL, updateLimit); +@@ -361,11 +_,19 @@ @Override public BlockState getBlockState(final BlockPos pos) { @@ -440,13 +436,14 @@ + // CraftBukkit end if (!this.isInValidBounds(pos)) { return Blocks.VOID_AIR.defaultBlockState(); - } else { -- LevelChunk chunk = this.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())); -+ ChunkAccess chunk = this.getChunk(pos.getX() >> 4, pos.getZ() >> 4, ChunkStatus.FULL, true); // Paper - manually inline to reduce hops and avoid unnecessary null check to reduce total byte code size, this should never return null and if it does we will see it the next line but the real stack trace will matter in the chunk engine - return chunk.getBlockState(pos); } + +- LevelChunk chunk = this.getChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())); ++ ChunkAccess chunk = this.getChunk(pos.getX() >> 4, pos.getZ() >> 4, ChunkStatus.FULL, true); // Paper - manually inline to reduce hops and avoid unnecessary null check to reduce total byte code size, this should never return null and if it does we will see it the next line but the real stack trace will matter in the chunk engine + return chunk.getBlockState(pos); } -@@ -523,6 +_,7 @@ + +@@ -525,6 +_,7 @@ } public void addBlockEntityTicker(final TickingBlockEntity ticker) { @@ -454,7 +451,7 @@ (this.tickingBlockEntities ? this.pendingBlockEntityTickers : this.blockEntityTickers).add(ticker); } -@@ -533,18 +_,23 @@ +@@ -535,18 +_,23 @@ this.pendingBlockEntityTickers.clear(); } @@ -482,18 +479,18 @@ this.tickingBlockEntities = false; } -@@ -552,12 +_,23 @@ +@@ -554,12 +_,23 @@ try { tick.accept(entity); - } catch (Throwable var6) { -- CrashReport report = CrashReport.forThrowable(var6, "Ticking entity"); + } catch (Throwable t) { +- CrashReport report = CrashReport.forThrowable(t, "Ticking entity"); - CrashReportCategory category = report.addCategory("Entity being ticked"); - entity.fillCrashReportCategory(category); - throw new ReportedException(report); + // Paper start - Prevent block entity and entity crashes + final String msg = String.format("Entity threw exception at %s:%s,%s,%s", io.papermc.paper.util.MCUtil.getLevelName(entity.level()), entity.getX(), entity.getY(), entity.getZ()); -+ MinecraftServer.LOGGER.error(msg, var6); -+ getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, var6))); // Paper - ServerExceptionEvent ++ MinecraftServer.LOGGER.error(msg, t); ++ getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, t))); // Paper - ServerExceptionEvent + entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); + // Paper end - Prevent block entity and entity crashes } @@ -510,7 +507,7 @@ public boolean shouldTickDeath(final Entity entity) { return true; -@@ -691,6 +_,12 @@ +@@ -693,6 +_,12 @@ @Override public @Nullable BlockEntity getBlockEntity(final BlockPos pos) { @@ -523,7 +520,7 @@ if (!this.isInValidBounds(pos)) { return null; } else { -@@ -703,6 +_,12 @@ +@@ -705,6 +_,12 @@ public void setBlockEntity(final BlockEntity blockEntity) { BlockPos pos = blockEntity.getBlockPos(); if (this.isInValidBounds(pos)) { @@ -536,7 +533,7 @@ this.getChunkAt(pos).addAndRegisterBlockEntity(blockEntity); } } -@@ -1110,7 +_,8 @@ +@@ -1116,7 +_,8 @@ BLOCK("block"), MOB("mob"), TNT("tnt"), @@ -546,7 +543,7 @@ public static final Codec CODEC = StringRepresentable.fromEnum(Level.ExplosionInteraction::values); private final String id; -@@ -1124,4 +_,16 @@ +@@ -1130,4 +_,16 @@ return this.id; } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch b/paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch index d9abff23dc29..4082bf1cc21c 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch @@ -124,7 +124,7 @@ return; } @@ -247,7 +_,15 @@ - } + return Objects.equals(chunkPos, chunk.getPos()) || level.canSpawnEntitiesInChunk(chunkPos); } - private static boolean isValidSpawnPostitionForType( @@ -171,17 +171,17 @@ private static @Nullable Mob getMobForSpawn(final ServerLevel level, final EntityType type) { @@ -275,6 +_,7 @@ LOGGER.warn("Can't spawn entity of type: {}", BuiltInRegistries.ENTITY_TYPE.getKey(type)); - } catch (Exception var4) { - LOGGER.warn("Failed to create mob", (Throwable)var4); -+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(var4); // Paper - ServerExceptionEvent + } catch (Exception e) { + LOGGER.warn("Failed to create mob", e); ++ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(e); // Paper - ServerExceptionEvent } return null; @@ -402,6 +_,7 @@ entity = spawnerData.type().create(level.getLevel(), EntitySpawnReason.NATURAL); - } catch (Exception var27) { - LOGGER.warn("Failed to create mob", (Throwable)var27); -+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(var27); // Paper - ServerExceptionEvent + } catch (Exception e) { + LOGGER.warn("Failed to create mob", e); ++ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(e); // Paper - ServerExceptionEvent continue; } diff --git a/paper-server/patches/sources/net/minecraft/world/level/PathNavigationRegion.java.patch b/paper-server/patches/sources/net/minecraft/world/level/PathNavigationRegion.java.patch index fd876791f3b9..bc5ad2f48be8 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/PathNavigationRegion.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/PathNavigationRegion.java.patch @@ -7,7 +7,7 @@ - if (xc >= 0 && xc < this.chunks.length && zc >= 0 && zc < this.chunks[xc].length) { + if (xc >= 0 && xc < this.chunks.length && zc >= 0 && zc < this.chunks[xc].length) { // Paper - if this changes, update getChunkIfLoaded below ChunkAccess chunk = this.chunks[xc][zc]; - return (ChunkAccess)(chunk != null ? chunk : new EmptyLevelChunk(this.level, new ChunkPos(chunkX, chunkZ), this.plains.get())); + return chunk != null ? chunk : new EmptyLevelChunk(this.level, new ChunkPos(chunkX, chunkZ), this.plains.get()); } else { return new EmptyLevelChunk(this.level, new ChunkPos(chunkX, chunkZ), this.plains.get()); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/ServerExplosion.java.patch b/paper-server/patches/sources/net/minecraft/world/level/ServerExplosion.java.patch index 4da082778cff..f88ec87b1a39 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/ServerExplosion.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/ServerExplosion.java.patch @@ -23,8 +23,8 @@ } private ExplosionDamageCalculator makeDamageCalculator(final @Nullable Entity source) { -@@ -141,7 +_,8 @@ - for (float stepSize = 0.3F; remainingPower > 0.0F; remainingPower -= 0.22500001F) { +@@ -142,7 +_,8 @@ + while (remainingPower > 0.0F) { BlockPos pos = BlockPos.containing(xp, yp, zp); BlockState block = this.level.getBlockState(pos); - FluidState fluid = this.level.getFluidState(pos); @@ -33,7 +33,7 @@ if (!this.level.isInWorldBounds(pos)) { break; } -@@ -153,6 +_,15 @@ +@@ -154,6 +_,15 @@ if (remainingPower > 0.0F && this.damageCalculator.shouldBlockExplode(this, this.level, pos, block, remainingPower)) { toBlowSet.add(pos); @@ -49,7 +49,7 @@ } xp += xd * 0.3F; -@@ -176,8 +_,9 @@ +@@ -178,8 +_,9 @@ int y1 = Mth.floor(this.center.y + doubleRadius + 1.0); int z0 = Mth.floor(this.center.z - doubleRadius - 1.0); int z1 = Mth.floor(this.center.z + doubleRadius + 1.0); @@ -60,7 +60,7 @@ if (!entity.ignoreExplosion(this)) { double dist = Math.sqrt(entity.distanceToSqr(this.center)) / doubleRadius; if (!(dist > 1.0)) { -@@ -185,20 +_,56 @@ +@@ -187,20 +_,56 @@ Vec3 direction = entityOrigin.subtract(this.center).normalize(); boolean shouldDamageEntity = this.damageCalculator.shouldDamageEntity(this, entity); float knockbackMultiplier = this.damageCalculator.getKnockbackMultiplier(entity); @@ -121,7 +121,7 @@ this.hitPlayers.put(player, knockback); } -@@ -213,7 +_,56 @@ +@@ -215,7 +_,56 @@ List stacks = new ArrayList<>(); Util.shuffle(targetBlocks, this.level.random); @@ -178,7 +178,7 @@ this.level.getBlockState(pos).onExplosionHit(this.level, pos, this, (stackx, position) -> addOrAppendStack(stacks, stackx, position)); } -@@ -225,7 +_,11 @@ +@@ -227,7 +_,11 @@ private void createFire(final List targetBlocks) { for (BlockPos pos : targetBlocks) { if (this.level.random.nextInt(3) == 0 && this.level.getBlockState(pos).isAir() && this.level.getBlockState(pos.below()).isSolidRender()) { @@ -191,7 +191,7 @@ } } } -@@ -323,4 +_,85 @@ +@@ -325,4 +_,85 @@ } } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/TicketStorage.java.patch b/paper-server/patches/sources/net/minecraft/world/level/TicketStorage.java.patch index 0687c68c610e..d040e7fcec70 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/TicketStorage.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/TicketStorage.java.patch @@ -9,7 +9,7 @@ } public int getTicketLevelAt(final long key, final boolean simulation) { -@@ -300,7 +_,7 @@ +@@ -302,7 +_,7 @@ } public void deactivateTicketsOnClosing() { @@ -18,7 +18,7 @@ } public void removeTicketIf(final TicketStorage.TicketPredicate predicate, final @Nullable Long2ObjectOpenHashMap> removedTickets) { -@@ -410,4 +_,20 @@ +@@ -412,4 +_,20 @@ public interface TicketPredicate { boolean test(Ticket ticket, long chunkPos); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/BaseFireBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/BaseFireBlock.java.patch index 051186dfaaaf..7586d87f1eff 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/BaseFireBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/BaseFireBlock.java.patch @@ -63,8 +63,8 @@ @Override @@ -219,4 +_,12 @@ - } - } + : Direction.Plane.HORIZONTAL.getRandomAxis(level.getRandom()); + return PortalShape.findEmptyPortalShape(level, pos, preferredAxis).isPresent(); } + + // CraftBukkit start diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/BedBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/BedBlock.java.patch index 112f8088bfe2..bf9483606f7d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/BedBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/BedBlock.java.patch @@ -1,56 +1,55 @@ --- a/net/minecraft/world/level/block/BedBlock.java +++ b/net/minecraft/world/level/block/BedBlock.java -@@ -91,7 +_,7 @@ +@@ -92,7 +_,7 @@ + } + + BedRule bedRule = level.environmentAttributes().getValue(EnvironmentAttributes.BED_RULE, pos); +- if (bedRule.explodes()) { ++ if (false && bedRule.explodes()) { // CraftBukkit - moved world and biome check into Player + bedRule.errorMessage().ifPresent(player::sendOverlayMessage); + level.removeBlock(pos, false); + BlockPos blockPos = pos.relative(state.getValue(FACING).getOpposite()); +@@ -104,21 +_,60 @@ + level.explode(null, level.damageSources().badRespawnPointExplosion(boomPos), null, boomPos, 5.0F, true, Level.ExplosionInteraction.BLOCK); + return InteractionResult.SUCCESS_SERVER; + } else if (state.getValue(OCCUPIED)) { ++ if (bedRule.explodes()) return this.explodeBed(state, level, pos); // Paper - check explode first + if (!this.kickVillagerOutOfBed(level, pos)) { + player.sendOverlayMessage(Component.translatable("block.minecraft.bed.occupied")); } - BedRule bedRule = level.environmentAttributes().getValue(EnvironmentAttributes.BED_RULE, pos); -- if (bedRule.explodes()) { -+ if (false && bedRule.explodes()) { // CraftBukkit - moved world and biome check into Player - bedRule.errorMessage().ifPresent(player::sendOverlayMessage); - level.removeBlock(pos, false); - BlockPos blockPos = pos.relative(state.getValue(FACING).getOpposite()); -@@ -103,22 +_,61 @@ - level.explode(null, level.damageSources().badRespawnPointExplosion(boomPos), null, boomPos, 5.0F, true, Level.ExplosionInteraction.BLOCK); - return InteractionResult.SUCCESS_SERVER; - } else if (state.getValue(OCCUPIED)) { -+ if (bedRule.explodes()) return this.explodeBed(state, level, pos); // Paper - check explode first - if (!this.kickVillagerOutOfBed(level, pos)) { - player.sendOverlayMessage(Component.translatable("block.minecraft.bed.occupied")); + return InteractionResult.SUCCESS_SERVER; + } else { ++ // CraftBukkit start ++ final BlockState finalState = state; ++ final BlockPos finalPos = pos; ++ // CraftBukkit end + player.startSleepInBed(pos).ifLeft(problem -> { +- if (problem.message() != null) { ++ // Paper start - PlayerBedFailEnterEvent ++ if (false && problem.message() != null) { // Moved down + player.sendOverlayMessage(problem.message()); } - - return InteractionResult.SUCCESS_SERVER; - } else { -+ // CraftBukkit start -+ final BlockState finalBlockState = state; -+ final BlockPos finalBlockPos = pos; -+ // CraftBukkit end - player.startSleepInBed(pos).ifLeft(problem -> { -- if (problem.message() != null) { -+ // Paper start - PlayerBedFailEnterEvent -+ if (false && problem.message() != null) { // Moved down - player.sendOverlayMessage(problem.message()); - } -+ if (problem != null) { -+ io.papermc.paper.event.player.PlayerBedFailEnterEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBedFailEnterEvent(player, finalBlockPos, problem); -+ if (event.isCancelled()) { -+ return; -+ } -+ // Paper end - PlayerBedFailEnterEvent -+ // CraftBukkit start - handling bed explosion from below here -+ if (event.getWillExplode()) { // Paper - PlayerBedFailEnterEvent -+ this.explodeBed(finalBlockState, level, finalBlockPos); -+ } -+ // CraftBukkit end -+ // Paper start - PlayerBedFailEnterEvent -+ final net.kyori.adventure.text.Component message = event.getMessage(); -+ if (message != null) { -+ player.sendOverlayMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message)); -+ } ++ if (problem != null) { ++ io.papermc.paper.event.player.PlayerBedFailEnterEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBedFailEnterEvent(player, finalPos, problem); ++ if (event.isCancelled()) { ++ return; + } + // Paper end - PlayerBedFailEnterEvent - }); - return InteractionResult.SUCCESS_SERVER; - } ++ // CraftBukkit start - handling bed explosion from below here ++ if (event.getWillExplode()) { // Paper - PlayerBedFailEnterEvent ++ this.explodeBed(finalState, level, finalPos); ++ } ++ // CraftBukkit end ++ // Paper start - PlayerBedFailEnterEvent ++ final net.kyori.adventure.text.Component message = event.getMessage(); ++ if (message != null) { ++ player.sendOverlayMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(message)); ++ } ++ } ++ // Paper end - PlayerBedFailEnterEvent + }); + return InteractionResult.SUCCESS_SERVER; } } @@ -63,8 +62,8 @@ + level.removeBlock(blockPos, false); + } + -+ Vec3 center = pos.getCenter(); -+ level.explode(null, level.damageSources().badRespawnPointExplosion(center).causingBlockSnapshot(blockState), null, center, 5.0F, true, Level.ExplosionInteraction.BLOCK); // CraftBukkit - add state ++ Vec3 boomPos = pos.getCenter(); ++ level.explode(null, level.damageSources().badRespawnPointExplosion(boomPos).causingBlockSnapshot(blockState), null, boomPos, 5.0F, true, Level.ExplosionInteraction.BLOCK); // CraftBukkit - add state + return InteractionResult.SUCCESS_SERVER; + } + // CraftBukkit end diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/Block.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/Block.java.patch index c2808c1ed09f..36289740b667 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/Block.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/Block.java.patch @@ -65,7 +65,7 @@ private @Nullable Item item; private static final int CACHE_SIZE = 256; private static final ThreadLocal> OCCLUSION_CACHE = ThreadLocal.withInitial(() -> { -@@ -382,6 +_,27 @@ +@@ -386,6 +_,27 @@ return state.getDrops(params); } @@ -93,7 +93,7 @@ public static void dropResources(final BlockState state, final Level level, final BlockPos pos) { if (level instanceof ServerLevel serverLevel) { getDrops(state, serverLevel, pos, null).forEach(stack -> popResource(level, pos, stack)); -@@ -396,6 +_,12 @@ +@@ -400,6 +_,12 @@ } } @@ -106,7 +106,7 @@ public static void dropResources( final BlockState state, final Level level, -@@ -403,10 +_,11 @@ +@@ -407,10 +_,11 @@ final @Nullable BlockEntity blockEntity, final @Nullable Entity breaker, final ItemStack tool @@ -119,7 +119,7 @@ } } -@@ -439,13 +_,25 @@ +@@ -443,13 +_,25 @@ if (level instanceof ServerLevel serverLevel && !itemStack.isEmpty() && serverLevel.getGameRules().get(GameRules.BLOCK_DROPS)) { ItemEntity entity = entityFactory.get(); entity.setDefaultPickUpDelay(); @@ -147,7 +147,7 @@ } } -@@ -463,6 +_,13 @@ +@@ -467,6 +_,13 @@ return this.defaultBlockState(); } @@ -161,7 +161,7 @@ public void playerDestroy( final Level level, final Player player, -@@ -470,10 +_,13 @@ +@@ -474,10 +_,13 @@ final BlockState state, final @Nullable BlockEntity blockEntity, final ItemStack destroyedWith @@ -177,7 +177,7 @@ } public void setPlacedBy(final Level level, final BlockPos pos, final BlockState state, final @Nullable LivingEntity by, final ItemStack itemStack) { -@@ -613,12 +_,20 @@ +@@ -617,12 +_,20 @@ return this.builtInRegistryHolder; } @@ -201,7 +201,7 @@ private record ShapePairKey(VoxelShape first, VoxelShape second) { @Override -@@ -634,6 +_,7 @@ +@@ -638,6 +_,7 @@ @Retention(RetentionPolicy.CLASS) @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE, ElementType.METHOD, ElementType.TYPE_USE}) diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/ButtonBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/ButtonBlock.java.patch index 4546e8981575..3525f3f703f4 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/ButtonBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/ButtonBlock.java.patch @@ -1,17 +1,17 @@ --- a/net/minecraft/world/level/block/ButtonBlock.java +++ b/net/minecraft/world/level/block/ButtonBlock.java -@@ -92,6 +_,11 @@ - if (state.getValue(POWERED)) { +@@ -93,6 +_,11 @@ return InteractionResult.CONSUME; - } else { -+ // Paper start - Call BlockRedstoneEvent -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, true)) { -+ return InteractionResult.SUCCESS; -+ } -+ // Paper end - Call BlockRedstoneEvent - this.press(state, level, pos, player); - return InteractionResult.SUCCESS; } + ++ // Paper start - Call BlockRedstoneEvent ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, pos, true)) { ++ return InteractionResult.SUCCESS; ++ } ++ // Paper end - Call BlockRedstoneEvent + this.press(state, level, pos, player); + return InteractionResult.SUCCESS; + } @@ -102,7 +_,9 @@ final BlockState state, final ServerLevel level, final BlockPos pos, final Explosion explosion, final BiConsumer onHit ) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CakeBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CakeBlock.java.patch index 44157946d3de..0ccf56fb4699 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CakeBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CakeBlock.java.patch @@ -13,34 +13,34 @@ itemStack.consume(1, player); level.playSound(null, pos, SoundEvents.CAKE_ADD_CANDLE, SoundSource.BLOCKS, 1.0F, 1.0F); level.setBlockAndUpdate(pos, CandleCakeBlock.byCandle(candleBlock)); -@@ -95,9 +_,28 @@ - if (!player.canEat(false)) { +@@ -96,9 +_,28 @@ return InteractionResult.PASS; - } else { -+ // Paper start - call change block event -+ int bites = state.getValue(CakeBlock.BITES); -+ final BlockState newState = bites < MAX_BITES ? state.setValue(CakeBlock.BITES, bites + 1) : level.getFluidState(pos).createLegacyBlock(); -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, pos, newState)) { -+ ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity().sendHealthUpdate(); -+ return InteractionResult.PASS; // return a non-consume result to cake blocks don't drop their candles -+ } -+ // Paper end - call change block event - player.awardStat(Stats.EAT_CAKE_SLICE); -- player.getFoodData().eat(2, 0.1F); -- int bites = state.getValue(BITES); -+ // CraftBukkit start -+ // player.getFoodData().eat(2, 0.1F); -+ // int bites = state.getValue(BITES); // Paper - move up -+ int oldFoodLevel = player.getFoodData().foodLevel; + } + ++ // Paper start - call change block event ++ int bites = state.getValue(CakeBlock.BITES); ++ final BlockState newState = bites < MAX_BITES ? state.setValue(CakeBlock.BITES, bites + 1) : level.getFluidState(pos).createLegacyBlock(); ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(player, pos, newState)) { ++ ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity().sendHealthUpdate(); ++ return InteractionResult.PASS; // return a non-consume result to cake blocks don't drop their candles ++ } ++ // Paper end - call change block event + player.awardStat(Stats.EAT_CAKE_SLICE); +- player.getFoodData().eat(2, 0.1F); +- int bites = state.getValue(BITES); ++ // CraftBukkit start ++ // player.getFoodData().eat(2, 0.1F); ++ // int bites = state.getValue(BITES); // Paper - move up ++ int oldFoodLevel = player.getFoodData().foodLevel; + -+ org.bukkit.event.entity.FoodLevelChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callFoodLevelChangeEvent(player, 2 + oldFoodLevel); ++ org.bukkit.event.entity.FoodLevelChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callFoodLevelChangeEvent(player, 2 + oldFoodLevel); + -+ if (!event.isCancelled()) { -+ player.getFoodData().eat(event.getFoodLevel() - oldFoodLevel, 0.1F); -+ } ++ if (!event.isCancelled()) { ++ player.getFoodData().eat(event.getFoodLevel() - oldFoodLevel, 0.1F); ++ } + -+ ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity().sendHealthUpdate(); -+ // CraftBukkit end - level.gameEvent(player, GameEvent.EAT, pos); - if (bites < 6) { - level.setBlock(pos, state.setValue(BITES, bites + 1), Block.UPDATE_ALL); ++ ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity().sendHealthUpdate(); ++ // CraftBukkit end + level.gameEvent(player, GameEvent.EAT, pos); + if (bites < 6) { + level.setBlock(pos, state.setValue(BITES, bites + 1), Block.UPDATE_ALL); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/ChestBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/ChestBlock.java.patch index c774cd0cec40..2f76a675854e 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/ChestBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/ChestBlock.java.patch @@ -1,20 +1,20 @@ --- a/net/minecraft/world/level/block/ChestBlock.java +++ b/net/minecraft/world/level/block/ChestBlock.java -@@ -97,7 +_,7 @@ +@@ -96,7 +_,7 @@ @Override public Optional acceptDouble(final ChestBlockEntity first, final ChestBlockEntity second) { final Container container = new CompoundContainer(first, second); - return Optional.of(new MenuProvider() { + return Optional.of(org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest.Provider.wrap(new MenuProvider() { // CraftBukkit - wrap for identification - { - Objects.requireNonNull(container); - } -@@ -122,10 +_,10 @@ + @Override + public @Nullable AbstractContainerMenu createMenu(final int containerId, final Inventory inventory, final Player player) { + if (first.canOpen(player) && second.canOpen(player)) { +@@ -117,10 +_,10 @@ if (first.hasCustomName()) { return first.getDisplayName(); } else { -- return (Component)(second.hasCustomName() ? second.getDisplayName() : Component.translatable("container.chestDouble")); -+ return (Component)(second.hasCustomName() ? second.getDisplayName() : Component.translatable("container.chestDouble")); // Paper - diff on change - CraftDoubleChestInventoryViewBuilder.defaultTitle +- return second.hasCustomName() ? second.getDisplayName() : Component.translatable("container.chestDouble"); ++ return second.hasCustomName() ? second.getDisplayName() : Component.translatable("container.chestDouble"); // Paper - diff on change - CraftDoubleChestInventoryViewBuilder.defaultTitle } } - }); @@ -22,7 +22,7 @@ } @Override -@@ -268,8 +_,7 @@ +@@ -263,8 +_,7 @@ ) { if (level instanceof ServerLevel serverLevel) { MenuProvider menuProvider = this.getMenuProvider(state, level, pos); @@ -32,7 +32,7 @@ player.awardStat(this.getOpenChestStat()); PiglinAi.angerNearbyPiglins(serverLevel, player, true); } -@@ -310,7 +_,13 @@ +@@ -305,7 +_,13 @@ @Override public @Nullable MenuProvider getMenuProvider(final BlockState state, final Level level, final BlockPos pos) { @@ -47,7 +47,7 @@ } public static DoubleBlockCombiner.Combiner opennessCombiner(final LidBlockEntity entity) { -@@ -352,6 +_,11 @@ +@@ -347,6 +_,11 @@ } private static boolean isCatSittingOnChest(final LevelAccessor level, final BlockPos pos) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/ComparatorBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/ComparatorBlock.java.patch index 7266450ee6ab..02b1fb8e6e41 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/ComparatorBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/ComparatorBlock.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/level/block/ComparatorBlock.java +++ b/net/minecraft/world/level/block/ComparatorBlock.java -@@ -137,7 +_,7 @@ - float pitch = state.getValue(MODE) == ComparatorMode.SUBTRACT ? 0.55F : 0.5F; - level.playSound(player, pos, SoundEvents.COMPARATOR_CLICK, SoundSource.BLOCKS, 0.3F, pitch); - level.setBlock(pos, state, Block.UPDATE_CLIENTS); -- this.refreshOutputState(level, pos, state); -+ if (level.getBlockState(pos).is(this)) { this.refreshOutputState(level, pos, state); } // Paper - Fix blockstate validation issues - return InteractionResult.SUCCESS; - } +@@ -138,7 +_,7 @@ + float pitch = state.getValue(MODE) == ComparatorMode.SUBTRACT ? 0.55F : 0.5F; + level.playSound(player, pos, SoundEvents.COMPARATOR_CLICK, SoundSource.BLOCKS, 0.3F, pitch); + level.setBlock(pos, state, Block.UPDATE_CLIENTS); +- this.refreshOutputState(level, pos, state); ++ if (level.getBlockState(pos).is(this)) { this.refreshOutputState(level, pos, state); } // Paper - Fix blockstate validation issues + return InteractionResult.SUCCESS; } + @@ -168,8 +_,18 @@ boolean sourceOn = this.shouldTurnOn(level, pos, state); boolean isOn = state.getValue(POWERED); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/ComposterBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/ComposterBlock.java.patch index 37f69c8d76c9..2879bcbc8cc9 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/ComposterBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/ComposterBlock.java.patch @@ -48,7 +48,7 @@ if (!level.isClientSide()) { Vec3 itemPos = Vec3.atLowerCornerWithOffset(pos, 0.5, 1.01, 0.5).offsetRandomXZ(level.getRandom(), 0.7F); ItemEntity entity = new ItemEntity(level, itemPos.x(), itemPos.y(), itemPos.z(), new ItemStack(Items.BONE_MEAL)); -@@ -315,16 +_,44 @@ +@@ -315,17 +_,45 @@ return newState; } @@ -83,23 +83,24 @@ + if (!willRaiseLevel) { + // Paper end - Add CompostItemEvent and EntityCompostItemEvent return state; - } else { - int newLevel = fillLevel + 1; - BlockState newState = state.setValue(LEVEL, newLevel); -+ // Paper start - move the EntityChangeBlockEvent here to avoid conflict later for the compost events -+ if (sourceEntity != null && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(sourceEntity, pos, newState)) { -+ return null; -+ } -+ // Paper end - level.setBlock(pos, newState, Block.UPDATE_ALL); - level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(sourceEntity, newState)); - if (newLevel == 7) { + } + + int newLevel = fillLevel + 1; + BlockState newState = state.setValue(LEVEL, newLevel); ++ // Paper start - move the EntityChangeBlockEvent here to avoid conflict later for the compost events ++ if (sourceEntity != null && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(sourceEntity, pos, newState)) { ++ return null; ++ } ++ // Paper end + level.setBlock(pos, newState, Block.UPDATE_ALL); + level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(sourceEntity, newState)); + if (newLevel == 7) { @@ -369,13 +_,14 @@ if (contentLevel == 8) { return new ComposterBlock.OutputContainer(state, level, pos, new ItemStack(Items.BONE_MEAL)); } else { -- return (WorldlyContainer)(contentLevel < 7 ? new ComposterBlock.InputContainer(state, level, pos) : new ComposterBlock.EmptyContainer()); -+ return (WorldlyContainer)(contentLevel < 7 ? new ComposterBlock.InputContainer(state, level, pos) : new ComposterBlock.EmptyContainer(level, pos)); // CraftBukkit - empty levelAccessor, blockPos +- return contentLevel < 7 ? new ComposterBlock.InputContainer(state, level, pos) : new ComposterBlock.EmptyContainer(); ++ return contentLevel < 7 ? new ComposterBlock.InputContainer(state, level, pos) : new ComposterBlock.EmptyContainer(level, pos); // CraftBukkit - empty levelAccessor, blockPos } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CopperBulbBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CopperBulbBlock.java.patch index 7f84dabc8180..48ae25be7fc2 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CopperBulbBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CopperBulbBlock.java.patch @@ -11,4 +11,4 @@ + // Paper end - Call BlockRedstoneEvent BlockState newState = state; if (!state.getValue(POWERED)) { - newState = state.cycle(LIT); + newState = newState.cycle(LIT); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/CopperGolemStatueBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/CopperGolemStatueBlock.java.patch index f7127c58613a..e73773c04e7a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/CopperGolemStatueBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/CopperGolemStatueBlock.java.patch @@ -1,13 +1,12 @@ --- a/net/minecraft/world/level/block/CopperGolemStatueBlock.java +++ b/net/minecraft/world/level/block/CopperGolemStatueBlock.java -@@ -111,15 +_,21 @@ - if (itemStack.is(ItemTags.AXES)) { +@@ -112,14 +_,20 @@ return InteractionResult.PASS; - } else { -- this.updatePose(level, state, pos, player); -- return InteractionResult.SUCCESS; -+ return this.updatePose(level, state, pos, player); // Paper - call EntityChangeBlockEvent } + +- this.updatePose(level, state, pos, player); +- return InteractionResult.SUCCESS; ++ return this.updatePose(level, state, pos, player); // Paper - call EntityChangeBlockEvent } - void updatePose(final Level level, final BlockState state, final BlockPos pos, final Player player) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/DoubleBlockCombiner.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/DoubleBlockCombiner.java.patch index cfd5138462c3..3313289a5e9b 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/DoubleBlockCombiner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/DoubleBlockCombiner.java.patch @@ -1,16 +1,16 @@ --- a/net/minecraft/world/level/block/DoubleBlockCombiner.java +++ b/net/minecraft/world/level/block/DoubleBlockCombiner.java -@@ -34,7 +_,12 @@ - return new DoubleBlockCombiner.NeighborCombineResult.Single<>(blockEntity); - } else { - BlockPos neighborPos = pos.relative(connectionResolver.apply(state)); -- BlockState neighbourState = level.getBlockState(neighborPos); -+ // Paper start - Don't load Chunks from Hoppers and other things -+ BlockState neighbourState = level.getBlockStateIfLoaded(neighborPos); -+ if (neighbourState == null) { -+ return new DoubleBlockCombiner.NeighborCombineResult.Single<>(blockEntity); -+ } -+ // Paper end - Don't load Chunks from Hoppers and other things - if (neighbourState.is(state.getBlock())) { - DoubleBlockCombiner.BlockType neighbourType = typeResolver.apply(neighbourState); - if (neighbourType != DoubleBlockCombiner.BlockType.SINGLE +@@ -38,7 +_,12 @@ + } + + BlockPos neighborPos = pos.relative(connectionResolver.apply(state)); +- BlockState neighbourState = level.getBlockState(neighborPos); ++ // Paper start - Don't load Chunks from Hoppers and other things ++ BlockState neighbourState = level.getBlockStateIfLoaded(neighborPos); ++ if (neighbourState == null) { ++ return new DoubleBlockCombiner.NeighborCombineResult.Single<>(blockEntity); ++ } ++ // Paper end - Don't load Chunks from Hoppers and other things + if (neighbourState.is(state.getBlock())) { + DoubleBlockCombiner.BlockType neighbourType = typeResolver.apply(neighbourState); + if (neighbourType != DoubleBlockCombiner.BlockType.SINGLE diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/EndPortalBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/EndPortalBlock.java.patch index 920164481523..f591d40643d1 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/EndPortalBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/EndPortalBlock.java.patch @@ -25,41 +25,41 @@ ResourceKey newDimension = fromEnd ? respawnData.dimension() : Level.END; BlockPos spawnBlockPos = fromEnd ? respawnData.pos() : ServerLevel.END_SPAWN_POINT; ServerLevel newLevel = currentLevel.getServer().getLevel(newDimension); -@@ -91,7 +_,7 @@ - float xRot; - Set relatives; - if (!fromEnd) { -- EndPlatformFeature.createEndPlatform(newLevel, BlockPos.containing(spawnPos).below(), true); -+ EndPlatformFeature.createEndPlatform(newLevel, BlockPos.containing(spawnPos).below(), true, entity); // CraftBukkit - yRot = Direction.WEST.toYRot(); - xRot = 0.0F; - relatives = Relative.union(Relative.DELTA, Set.of(Relative.X_ROT)); -@@ -103,15 +_,26 @@ - xRot = respawnData.pitch(); - relatives = Relative.union(Relative.DELTA, Relative.ROTATION); - if (entity instanceof ServerPlayer serverPlayer) { -- return serverPlayer.findRespawnPositionAndUseSpawnBlock(false, TeleportTransition.DO_NOTHING); -+ return serverPlayer.findRespawnPositionAndUseSpawnBlock(false, TeleportTransition.DO_NOTHING, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason.END_PORTAL); // CraftBukkit - } - - spawnPos = entity.adjustSpawnLocation(newLevel, spawnBlockPos).getBottomCenter(); +@@ -92,7 +_,7 @@ + float xRot; + Set relatives; + if (!fromEnd) { +- EndPlatformFeature.createEndPlatform(newLevel, BlockPos.containing(spawnPos).below(), true); ++ EndPlatformFeature.createEndPlatform(newLevel, BlockPos.containing(spawnPos).below(), true, entity); // CraftBukkit + yRot = Direction.WEST.toYRot(); + xRot = 0.0F; + relatives = Relative.union(Relative.DELTA, Set.of(Relative.X_ROT)); +@@ -104,15 +_,26 @@ + xRot = respawnData.pitch(); + relatives = Relative.union(Relative.DELTA, Relative.ROTATION); + if (entity instanceof ServerPlayer serverPlayer) { +- return serverPlayer.findRespawnPositionAndUseSpawnBlock(false, TeleportTransition.DO_NOTHING); ++ return serverPlayer.findRespawnPositionAndUseSpawnBlock(false, TeleportTransition.DO_NOTHING, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason.END_PORTAL); // CraftBukkit } -+ // CraftBukkit start -+ relatives.removeAll(Relative.ROTATION); // remove relative rotation flags to simplify event mutation -+ float absoluteYaw = !fromEnd ? yRot : entity.getYRot() + yRot; -+ float absolutePitch = entity.getXRot() + xRot; -+ org.bukkit.craftbukkit.event.PortalEventResult result = org.bukkit.craftbukkit.event.CraftEventFactory.handlePortalEvents(entity, org.bukkit.craftbukkit.util.CraftLocation.toBukkit(spawnPos, newLevel, absoluteYaw, absolutePitch), org.bukkit.PortalType.ENDER, 0, 0); -+ if (result == null) { -+ return null; -+ } -+ org.bukkit.Location to = result.to(); -+ - return new TeleportTransition( -- newLevel, spawnPos, Vec3.ZERO, yRot, xRot, relatives, TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET) -+ ((org.bukkit.craftbukkit.CraftWorld) to.getWorld()).getHandle(), org.bukkit.craftbukkit.util.CraftLocation.toVec3(to), Vec3.ZERO, to.getYaw(), to.getPitch(), relatives, TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET), org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_PORTAL - ); -+ // CraftBukkit end + spawnPos = entity.adjustSpawnLocation(newLevel, spawnBlockPos).getBottomCenter(); } + ++ // CraftBukkit start ++ relatives.removeAll(Relative.ROTATION); // remove relative rotation flags to simplify event mutation ++ float absoluteYaw = !fromEnd ? yRot : entity.getYRot() + yRot; ++ float absolutePitch = entity.getXRot() + xRot; ++ org.bukkit.craftbukkit.event.PortalEventResult result = org.bukkit.craftbukkit.event.CraftEventFactory.handlePortalEvents(entity, org.bukkit.craftbukkit.util.CraftLocation.toBukkit(spawnPos, newLevel, absoluteYaw, absolutePitch), org.bukkit.PortalType.ENDER, 0, 0); ++ if (result == null) { ++ return null; ++ } ++ org.bukkit.Location to = result.to(); ++ + return new TeleportTransition( +- newLevel, spawnPos, Vec3.ZERO, yRot, xRot, relatives, TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET) ++ ((org.bukkit.craftbukkit.CraftWorld) to.getWorld()).getHandle(), org.bukkit.craftbukkit.util.CraftLocation.toVec3(to), Vec3.ZERO, to.getYaw(), to.getPitch(), relatives, TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.PLACE_PORTAL_TICKET), org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_PORTAL + ); ++ // CraftBukkit end } + @Override diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/EnderChestBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/EnderChestBlock.java.patch index 80ee1af7526e..6816771d3bc9 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/EnderChestBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/EnderChestBlock.java.patch @@ -1,24 +1,23 @@ --- a/net/minecraft/world/level/block/EnderChestBlock.java +++ b/net/minecraft/world/level/block/EnderChestBlock.java -@@ -82,14 +_,15 @@ +@@ -82,13 +_,16 @@ PlayerEnderChestContainer container = player.getEnderChestInventory(); if (container != null && level.getBlockEntity(pos) instanceof EnderChestBlockEntity enderChest) { BlockPos above = pos.above(); - if (level.getBlockState(above).isRedstoneConductor(level, above)) { + if (level.getBlockState(above).isRedstoneConductor(level, above)) { // Paper - diff on change; make sure that EnderChest#isBlocked uses the same logic return InteractionResult.SUCCESS; - } else { -- if (level instanceof ServerLevel serverLevel) { -- container.setActiveChest(enderChest); -- player.openMenu( -- new SimpleMenuProvider((containerId, inventory, p) -> ChestMenu.threeRows(containerId, inventory, container), CONTAINER_TITLE) -- ); -+ // Paper start - Fix InventoryOpenEvent cancellation - moved up; -+ container.setActiveChest(enderChest); // Needs to happen before ChestMenu.threeRows as it is required for opening animations -+ if (level instanceof ServerLevel serverLevel && player.openMenu( -+ new SimpleMenuProvider((containerId, inventory, p) -> ChestMenu.threeRows(containerId, inventory, container), CONTAINER_TITLE) -+ ).isPresent()) { -+ // Paper end - Fix InventoryOpenEvent cancellation - moved up; - player.awardStat(Stats.OPEN_ENDERCHEST); - PiglinAi.angerNearbyPiglins(serverLevel, player, true); - } + } + +- if (level instanceof ServerLevel serverLevel) { +- container.setActiveChest(enderChest); +- player.openMenu(new SimpleMenuProvider((containerId, inventory, p) -> ChestMenu.threeRows(containerId, inventory, container), CONTAINER_TITLE)); ++ // Paper start - Fix InventoryOpenEvent cancellation - moved up; ++ container.setActiveChest(enderChest); // Needs to happen before ChestMenu.threeRows as it is required for opening animations ++ if (level instanceof ServerLevel serverLevel && player.openMenu( ++ new SimpleMenuProvider((containerId, inventory, p) -> ChestMenu.threeRows(containerId, inventory, container), CONTAINER_TITLE) ++ ).isPresent()) { ++ // Paper end - Fix InventoryOpenEvent cancellation - moved up; + player.awardStat(Stats.OPEN_ENDERCHEST); + PiglinAi.angerNearbyPiglins(serverLevel, player, true); + } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/FlowerPotBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/FlowerPotBlock.java.patch index 34e617023453..7210745f1403 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/FlowerPotBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/FlowerPotBlock.java.patch @@ -1,40 +1,40 @@ --- a/net/minecraft/world/level/block/FlowerPotBlock.java +++ b/net/minecraft/world/level/block/FlowerPotBlock.java -@@ -72,6 +_,18 @@ - } else if (!this.isEmpty()) { +@@ -75,6 +_,18 @@ return InteractionResult.CONSUME; - } else { -+ // Paper start - Add PlayerFlowerPotManipulateEvent -+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); -+ org.bukkit.inventory.ItemStack placedStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemStack); + } + ++ // Paper start - Add PlayerFlowerPotManipulateEvent ++ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); ++ org.bukkit.inventory.ItemStack placedStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemStack); + -+ io.papermc.paper.event.player.PlayerFlowerPotManipulateEvent event = new io.papermc.paper.event.player.PlayerFlowerPotManipulateEvent((org.bukkit.entity.Player) player.getBukkitEntity(), block, placedStack, true); -+ if (!event.callEvent()) { -+ // Update client -+ player.containerMenu.forceHeldSlot(hand); ++ io.papermc.paper.event.player.PlayerFlowerPotManipulateEvent event = new io.papermc.paper.event.player.PlayerFlowerPotManipulateEvent((org.bukkit.entity.Player) player.getBukkitEntity(), block, placedStack, true); ++ if (!event.callEvent()) { ++ // Update client ++ player.containerMenu.forceHeldSlot(hand); + -+ return InteractionResult.CONSUME; -+ } -+ // Paper end - Add PlayerFlowerPotManipulateEvent - level.setBlock(pos, newContents, Block.UPDATE_ALL); - level.gameEvent(player, GameEvent.BLOCK_CHANGE, pos); - player.awardStat(Stats.POT_FLOWER); -@@ -88,6 +_,18 @@ - return InteractionResult.CONSUME; - } else { - ItemStack plant = new ItemStack(this.potted); -+ // Paper start - Add PlayerFlowerPotManipulateEvent -+ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); -+ org.bukkit.inventory.ItemStack pottedStack = new org.bukkit.inventory.ItemStack(org.bukkit.craftbukkit.block.CraftBlockType.minecraftToBukkit(this.potted)); ++ return InteractionResult.CONSUME; ++ } ++ // Paper end - Add PlayerFlowerPotManipulateEvent + level.setBlock(pos, newContents, Block.UPDATE_ALL); + level.gameEvent(player, GameEvent.BLOCK_CHANGE, pos); + player.awardStat(Stats.POT_FLOWER); +@@ -91,6 +_,18 @@ + } + + ItemStack plant = new ItemStack(this.potted); ++ // Paper start - Add PlayerFlowerPotManipulateEvent ++ org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); ++ org.bukkit.inventory.ItemStack pottedStack = new org.bukkit.inventory.ItemStack(org.bukkit.craftbukkit.block.CraftBlockType.minecraftToBukkit(this.potted)); + -+ io.papermc.paper.event.player.PlayerFlowerPotManipulateEvent event = new io.papermc.paper.event.player.PlayerFlowerPotManipulateEvent((org.bukkit.entity.Player) player.getBukkitEntity(), block, pottedStack, false); -+ if (!event.callEvent()) { -+ // Update client -+ player.containerMenu.sendAllDataToRemote(); ++ io.papermc.paper.event.player.PlayerFlowerPotManipulateEvent event = new io.papermc.paper.event.player.PlayerFlowerPotManipulateEvent((org.bukkit.entity.Player) player.getBukkitEntity(), block, pottedStack, false); ++ if (!event.callEvent()) { ++ // Update client ++ player.containerMenu.sendAllDataToRemote(); + -+ return InteractionResult.PASS; -+ } -+ // Paper end - Add PlayerFlowerPotManipulateEvent - if (!player.addItem(plant)) { - player.drop(plant, false); - } ++ return InteractionResult.PASS; ++ } ++ // Paper end - Add PlayerFlowerPotManipulateEvent + if (!player.addItem(plant)) { + player.drop(plant, false); + } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/LecternBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/LecternBlock.java.patch index a87d4990b3e9..b826df878d41 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/LecternBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/LecternBlock.java.patch @@ -40,7 +40,7 @@ level.setBlock(pos, state.setValue(POWERED, isPowered), Block.UPDATE_ALL); updateBelow(level, pos, state); } -@@ -258,8 +_,7 @@ +@@ -256,8 +_,7 @@ private void openScreen(final Level level, final BlockPos pos, final Player player) { BlockEntity blockEntity = level.getBlockEntity(pos); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/MultifaceSpreader.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/MultifaceSpreader.java.patch index cb37ea773907..e9574c2450a9 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/MultifaceSpreader.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/MultifaceSpreader.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/MultifaceSpreader.java +++ b/net/minecraft/world/level/block/MultifaceSpreader.java -@@ -176,14 +_,14 @@ +@@ -178,14 +_,14 @@ level.getChunk(spreadPos.pos()).markPosForPostprocessing(spreadPos.pos()); } @@ -17,7 +17,7 @@ } @FunctionalInterface -@@ -195,19 +_,19 @@ +@@ -197,19 +_,19 @@ SAME_POSITION { @Override public MultifaceSpreader.SpreadPos getSpreadPos(final BlockPos pos, final Direction spreadDirection, final Direction fromFace) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/MushroomBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/MushroomBlock.java.patch index d04287fd33da..534608725b49 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/MushroomBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/MushroomBlock.java.patch @@ -26,11 +26,11 @@ } } } -@@ -92,6 +_,7 @@ - return false; - } else { - level.removeBlock(pos, false); -+ SaplingBlock.treeType = (this == Blocks.BROWN_MUSHROOM) ? org.bukkit.TreeType.BROWN_MUSHROOM : org.bukkit.TreeType.RED_MUSHROOM; // CraftBukkit - if (feature.get().value().place(level, level.getChunkSource().getGenerator(), random, pos)) { - return true; - } else { +@@ -93,6 +_,7 @@ + } + + level.removeBlock(pos, false); ++ SaplingBlock.treeType = (this == Blocks.BROWN_MUSHROOM) ? org.bukkit.TreeType.BROWN_MUSHROOM : org.bukkit.TreeType.RED_MUSHROOM; // CraftBukkit + if (feature.get().value().place(level, level.getChunkSource().getGenerator(), random, pos)) { + return true; + } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/NetherPortalBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/NetherPortalBlock.java.patch index 18b9b33953c2..b71f0beae512 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/NetherPortalBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/NetherPortalBlock.java.patch @@ -38,7 +38,7 @@ entity.setAsInsidePortal(this, pos); } } -@@ -133,16 +_,39 @@ +@@ -133,17 +_,40 @@ @Override public @Nullable TeleportTransition getPortalDestination(final ServerLevel currentLevel, final Entity entity, final BlockPos portalEntryPos) { @@ -55,32 +55,33 @@ + // Paper end - Add EntityPortalReadyEvent if (newLevel == null) { return null; - } else { -- boolean toNether = newLevel.dimension() == Level.NETHER; -+ boolean toNether = newLevel.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER; // CraftBukkit - WorldBorder newWorldBorder = newLevel.getWorldBorder(); - double teleportationScale = DimensionType.getTeleportationScale(currentLevel.dimensionType(), newLevel.dimensionType()); - BlockPos approximateExitPos = newWorldBorder.clampToBounds(entity.getX() * teleportationScale, entity.getY(), entity.getZ() * teleportationScale); -- return this.getExitPortal(newLevel, entity, portalEntryPos, approximateExitPos, toNether, newWorldBorder); -+ // Paper start - Configurable portal search radius -+ int portalSearchRadius = newLevel.paperConfig().environment.portalSearchRadius; -+ if (entity.level().paperConfig().environment.portalSearchVanillaDimensionScaling && toNether) { -+ portalSearchRadius = (int) (portalSearchRadius / newLevel.dimensionType().coordinateScale()); -+ } -+ // Paper end - Configurable portal search radius -+ // CraftBukkit start -+ org.bukkit.craftbukkit.event.PortalEventResult result = org.bukkit.craftbukkit.event.CraftEventFactory.handlePortalEvents(entity, org.bukkit.craftbukkit.util.CraftLocation.toBukkit(approximateExitPos, newLevel), org.bukkit.PortalType.NETHER, portalSearchRadius, newLevel.paperConfig().environment.portalCreateRadius); // Paper - use custom portal search radius -+ if (result == null) { -+ return null; -+ } -+ newLevel = ((org.bukkit.craftbukkit.CraftWorld) result.to().getWorld()).getHandle(); -+ newWorldBorder = newLevel.getWorldBorder(); -+ approximateExitPos = newWorldBorder.clampToBounds(result.to().getX(), result.to().getY(), result.to().getZ()); -+ return this.getExitPortal(newLevel, entity, portalEntryPos, approximateExitPos, toNether, newWorldBorder, result); -+ // CraftBukkit end } + +- boolean toNether = newLevel.dimension() == Level.NETHER; ++ boolean toNether = newLevel.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER; // CraftBukkit + WorldBorder newWorldBorder = newLevel.getWorldBorder(); + double teleportationScale = DimensionType.getTeleportationScale(currentLevel.dimensionType(), newLevel.dimensionType()); + BlockPos approximateExitPos = newWorldBorder.clampToBounds(entity.getX() * teleportationScale, entity.getY(), entity.getZ() * teleportationScale); +- return this.getExitPortal(newLevel, entity, portalEntryPos, approximateExitPos, toNether, newWorldBorder); ++ // Paper start - Configurable portal search radius ++ int portalSearchRadius = newLevel.paperConfig().environment.portalSearchRadius; ++ if (entity.level().paperConfig().environment.portalSearchVanillaDimensionScaling && toNether) { ++ portalSearchRadius = (int) (portalSearchRadius / newLevel.dimensionType().coordinateScale()); ++ } ++ // Paper end - Configurable portal search radius ++ // CraftBukkit start ++ org.bukkit.craftbukkit.event.PortalEventResult result = org.bukkit.craftbukkit.event.CraftEventFactory.handlePortalEvents(entity, org.bukkit.craftbukkit.util.CraftLocation.toBukkit(approximateExitPos, newLevel), org.bukkit.PortalType.NETHER, portalSearchRadius, newLevel.paperConfig().environment.portalCreateRadius); // Paper - use custom portal search radius ++ if (result == null) { ++ return null; ++ } ++ newLevel = ((org.bukkit.craftbukkit.CraftWorld) result.to().getWorld()).getHandle(); ++ newWorldBorder = newLevel.getWorldBorder(); ++ approximateExitPos = newWorldBorder.clampToBounds(result.to().getX(), result.to().getY(), result.to().getZ()); ++ return this.getExitPortal(newLevel, entity, portalEntryPos, approximateExitPos, toNether, newWorldBorder, result); ++ // CraftBukkit end } + private @Nullable TeleportTransition getExitPortal( @@ -153,8 +_,9 @@ final BlockPos approximateExitPos, final boolean toNether, diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/PointedDripstoneBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/PointedDripstoneBlock.java.patch index 84d75864eb4d..5fc931aaec80 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/PointedDripstoneBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/PointedDripstoneBlock.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/PointedDripstoneBlock.java +++ b/net/minecraft/world/level/block/PointedDripstoneBlock.java -@@ -144,6 +_,11 @@ +@@ -146,6 +_,11 @@ && projectile.mayBreak(serverLevel) && projectile instanceof ThrownTrident && projectile.getDeltaMovement().length() > 0.6) { @@ -12,7 +12,7 @@ level.destroyBlock(blockPos, true); } } -@@ -152,7 +_,7 @@ +@@ -154,7 +_,7 @@ @Override public void fallOn(final Level level, final BlockState state, final BlockPos pos, final Entity entity, final double fallDistance) { if (state.getValue(TIP_DIRECTION) == Direction.UP && state.getValue(THICKNESS) == DripstoneThickness.TIP) { @@ -21,7 +21,7 @@ } else { super.fallOn(level, state, pos, entity, fallDistance); } -@@ -210,10 +_,11 @@ +@@ -212,10 +_,11 @@ if (stalactiteTipPos != null) { if (fluidInfo.get().sourceState.is(Blocks.MUD) && fluid == Fluids.WATER) { BlockState newState = Blocks.CLAY.defaultBlockState(); @@ -34,7 +34,7 @@ } else { BlockPos cauldronPos = findFillableCauldronBelowStalactiteTip(level, stalactiteTipPos, fluid); if (cauldronPos != null) { -@@ -359,17 +_,17 @@ +@@ -361,17 +_,17 @@ if (isUnmergedTipWithDirection(existingStateAtTargetPos, growToDirection.getOpposite())) { createMergedTips(existingStateAtTargetPos, level, targetPos); } else if (existingStateAtTargetPos.isAir() || existingStateAtTargetPos.is(Blocks.WATER)) { @@ -55,7 +55,7 @@ } private static void createMergedTips(final BlockState tipState, final LevelAccessor level, final BlockPos tipPos) { -@@ -383,8 +_,8 @@ +@@ -385,8 +_,8 @@ stalagmitePos = tipPos.below(); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/PoweredRailBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/PoweredRailBlock.java.patch index 05f413e5026e..9cd98f8eb36f 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/PoweredRailBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/PoweredRailBlock.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/PoweredRailBlock.java +++ b/net/minecraft/world/level/block/PoweredRailBlock.java -@@ -127,6 +_,11 @@ +@@ -121,6 +_,11 @@ || this.findPoweredRailSignal(level, pos, state, true, 0) || this.findPoweredRailSignal(level, pos, state, false, 0); if (shouldPower != isPowered) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/RailState.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/RailState.java.patch index c5e80cae49a3..25212078a789 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/RailState.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/RailState.java.patch @@ -13,7 +13,7 @@ public RailState(final Level level, final BlockPos pos, final BlockState state) { this.level = level; this.pos = pos; -@@ -140,6 +_,11 @@ +@@ -141,6 +_,11 @@ } private void connectTo(final RailState rail) { @@ -25,7 +25,7 @@ this.connections.add(rail.pos); BlockPos north = this.pos.north(); BlockPos south = this.pos.south(); -@@ -330,10 +_,15 @@ +@@ -331,10 +_,15 @@ this.state = this.state.setValue(this.block.getShapeProperty(), shape); if (first || this.level.getBlockState(this.pos) != this.state) { this.level.setBlock(this.pos, this.state, Block.UPDATE_ALL); @@ -42,7 +42,7 @@ neighbor.removeSoftConnections(); if (neighbor.canConnectTo(this)) { neighbor.connectTo(this); -@@ -346,6 +_,6 @@ +@@ -347,6 +_,6 @@ } public BlockState getState() { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/RedStoneOreBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/RedStoneOreBlock.java.patch index 674f031b2fca..f875da9113c1 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/RedStoneOreBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/RedStoneOreBlock.java.patch @@ -37,9 +37,9 @@ + interact(state, level, pos, player); // CraftBukkit - add player } - return (InteractionResult)(itemStack.getItem() instanceof BlockItem && new BlockPlaceContext(player, hand, itemStack, hitResult).canPlace() + return itemStack.getItem() instanceof BlockItem && new BlockPlaceContext(player, hand, itemStack, hitResult).canPlace() @@ -71,9 +_,14 @@ - : InteractionResult.SUCCESS); + : InteractionResult.SUCCESS; } - private static void interact(final BlockState state, final Level level, final BlockPos pos) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/RespawnAnchorBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/RespawnAnchorBlock.java.patch index a7de8dc2e270..cc22bcf4d953 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/RespawnAnchorBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/RespawnAnchorBlock.java.patch @@ -1,24 +1,19 @@ --- a/net/minecraft/world/level/block/RespawnAnchorBlock.java +++ b/net/minecraft/world/level/block/RespawnAnchorBlock.java -@@ -115,11 +_,16 @@ - LevelData.RespawnData.of(serverLevel.dimension(), pos, 0.0F, 0.0F), false +@@ -115,7 +_,11 @@ + LevelData.RespawnData.of(serverLevel.dimension(), pos, 0.0F, 0.0F), false + ); + if (respawnConfig == null || !respawnConfig.isSamePosition(newRespawnConfig)) { +- serverPlayer.setRespawnPosition(newRespawnConfig, true); ++ // Paper start - Add PlayerSetSpawnEvent ++ if (!serverPlayer.setRespawnPosition(newRespawnConfig, true, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.RESPAWN_ANCHOR)) { ++ return InteractionResult.FAIL; ++ } ++ // Paper end - Add PlayerSetSpawnEvent + serverLevel.playSound( + null, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, SoundEvents.RESPAWN_ANCHOR_SET_SPAWN, SoundSource.BLOCKS, 1.0F, 1.0F ); - if (respawnConfig == null || !respawnConfig.isSamePosition(newRespawnConfig)) { -- serverPlayer.setRespawnPosition(newRespawnConfig, true); -+ if (serverPlayer.setRespawnPosition(newRespawnConfig, true, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.RESPAWN_ANCHOR)) { // Paper - Add PlayerSetSpawnEvent - serverLevel.playSound( - null, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, SoundEvents.RESPAWN_ANCHOR_SET_SPAWN, SoundSource.BLOCKS, 1.0F, 1.0F - ); - return InteractionResult.SUCCESS_SERVER; -+ // Paper start - Add PlayerSetSpawnEvent -+ } else { -+ return InteractionResult.FAIL; -+ } -+ // Paper end - Add PlayerSetSpawnEvent - } - } - -@@ -156,6 +_,7 @@ +@@ -157,6 +_,7 @@ } private void explode(final BlockState state, final ServerLevel level, final BlockPos pos) { @@ -26,7 +21,7 @@ level.removeBlock(pos, false); boolean anyWaterNeighbors = Direction.Plane.HORIZONTAL.stream().map(pos::relative).anyMatch(neighborPos -> isWaterThatWouldFlow(neighborPos, level)); final boolean inWater = anyWaterNeighbors || level.getFluidState(pos.above()).is(FluidTags.WATER); -@@ -174,7 +_,7 @@ +@@ -171,7 +_,7 @@ } }; Vec3 boomPos = pos.getCenter(); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SculkVeinBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SculkVeinBlock.java.patch index 47ecdbed28b0..240f6670469a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/SculkVeinBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/SculkVeinBlock.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/SculkVeinBlock.java +++ b/net/minecraft/world/level/block/SculkVeinBlock.java -@@ -96,14 +_,14 @@ +@@ -95,14 +_,14 @@ final SculkSpreader spreader, final boolean spreadVeins ) { @@ -17,7 +17,7 @@ BlockState state = level.getBlockState(pos); TagKey replaceTag = spreader.replaceableBlocks(); -@@ -113,7 +_,11 @@ +@@ -112,7 +_,11 @@ BlockState supportState = level.getBlockState(supportPos); if (supportState.is(replaceTag)) { BlockState defaultSculk = Blocks.SCULK.defaultBlockState(); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SpreadingSnowyBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SpreadingSnowyBlock.java.patch index 1390b4a5cede..59d1d57ee655 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/SpreadingSnowyBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/SpreadingSnowyBlock.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/SpreadingSnowyBlock.java +++ b/net/minecraft/world/level/block/SpreadingSnowyBlock.java -@@ -46,10 +_,16 @@ +@@ -48,10 +_,16 @@ @Override protected void randomTick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { @@ -17,7 +17,7 @@ level.setBlockAndUpdate(pos, baseBlock.get().defaultBlockState()); } else { if (level.getMaxLocalRawBrightness(pos.above()) >= 9) { -@@ -58,7 +_,7 @@ +@@ -60,7 +_,7 @@ for (int i = 0; i < 4; i++) { BlockPos testPos = pos.offset(random.nextInt(3) - 1, random.nextInt(5) - 3, random.nextInt(3) - 1); if (level.getBlockState(testPos).is(baseBlock.get()) && canPropagate(defaultBlockState, level, testPos)) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/SweetBerryBushBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/SweetBerryBushBlock.java.patch index ff448a23dfea..f218455abdfa 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/SweetBerryBushBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/SweetBerryBushBlock.java.patch @@ -29,7 +29,7 @@ } } } -@@ -125,6 +_,7 @@ +@@ -123,6 +_,7 @@ ) { if (state.getValue(AGE) > 1) { if (level instanceof ServerLevel serverLevel) { @@ -37,7 +37,7 @@ Block.dropFromBlockInteractLootTable( serverLevel, BuiltInLootTables.HARVEST_SWEET_BERRY_BUSH, -@@ -132,8 +_,17 @@ +@@ -130,8 +_,17 @@ level.getBlockEntity(pos), null, player, diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/TntBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/TntBlock.java.patch index a2dbd1b38a0a..80b2aa7bf557 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/TntBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/TntBlock.java.patch @@ -47,15 +47,16 @@ PrimedTnt tnt = new PrimedTnt(level, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, source); level.addFreshEntity(tnt); level.playSound(null, tnt.getX(), tnt.getY(), tnt.getZ(), SoundEvents.TNT_PRIMED, SoundSource.BLOCKS, 1.0F, 1.0F); -@@ -110,7 +_,7 @@ +@@ -110,8 +_,7 @@ if (!itemStack.is(Items.FLINT_AND_STEEL) && !itemStack.is(Items.FIRE_CHARGE)) { return super.useItemOn(itemStack, state, level, pos, player, hand, hitResult); - } else { -- if (prime(level, pos, player)) { -+ if (prime(level, pos, player, () -> org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(level, pos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.PLAYER, player, null))) { // Paper - level.setBlock(pos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL_IMMEDIATE); - Item item = itemStack.getItem(); - if (itemStack.is(Items.FLINT_AND_STEEL)) { + } +- +- if (prime(level, pos, player)) { ++ if (prime(level, pos, player, () -> org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(level, pos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.PLAYER, player, null))) { // Paper + level.setBlock(pos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL_IMMEDIATE); + Item item = itemStack.getItem(); + if (itemStack.is(Items.FLINT_AND_STEEL)) { @@ -136,7 +_,7 @@ Entity owner = projectile.getOwner(); if (projectile.isOnFire() diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/TripWireHookBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/TripWireHookBlock.java.patch index 08c15476b412..31bbdbc5a6b0 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/TripWireHookBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/TripWireHookBlock.java.patch @@ -19,20 +19,20 @@ BlockState newState = block.defaultBlockState().trySetValue(ATTACHED, attached).trySetValue(POWERED, powered); + boolean cancelledEmitterHook = false, cancelledReceiverHook = false; // Paper - Call BlockRedstoneEvent if (receiverPos > 0) { - BlockPos testPosx = pos.relative(direction, receiverPos); + BlockPos testPos = pos.relative(direction, receiverPos); + // Paper start - Call BlockRedstoneEvent + if (wasPowered != powered) { -+ cancelledReceiverHook = !org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, testPosx, powered); ++ cancelledReceiverHook = !org.bukkit.craftbukkit.event.CraftEventFactory.callBinaryRedstoneChange(level, testPos, powered); + } + if (!cancelledReceiverHook) { // always trigger two events even when the first hook current change is cancelled + // Paper end - Call BlockRedstoneEvent Direction opposite = direction.getOpposite(); - level.setBlock(testPosx, newState.setValue(FACING, opposite), Block.UPDATE_ALL); - notifyNeighbors(block, level, testPosx, opposite); + level.setBlock(testPos, newState.setValue(FACING, opposite), Block.UPDATE_ALL); + notifyNeighbors(block, level, testPos, opposite); @@ -169,15 +_,24 @@ } - emitState(level, testPosx, attached, powered, wasAttached, wasPowered); + emitState(level, testPos, attached, powered, wasAttached, wasPowered); - } + } // Paper - Call BlockRedstoneEvent + } @@ -57,10 +57,10 @@ for (int i = 1; i < receiverPos; i++) { @@ -186,7 +_,7 @@ if (wireData != null) { - BlockState testPosState = level.getBlockState(testPosx); + BlockState testPosState = level.getBlockState(testPos); if (testPosState.is(Blocks.TRIPWIRE) || testPosState.is(Blocks.TRIPWIRE_HOOK)) { -- level.setBlock(testPosx, wireData.trySetValue(ATTACHED, attached), Block.UPDATE_ALL); -+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates || !testPosState.is(Blocks.TRIPWIRE)) level.setBlock(testPosx, wireData.trySetValue(ATTACHED, attached), Block.UPDATE_ALL); // Paper - prevent tripwire from updating +- level.setBlock(testPos, wireData.trySetValue(ATTACHED, attached), Block.UPDATE_ALL); ++ if (!io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates || !testPosState.is(Blocks.TRIPWIRE)) level.setBlock(testPos, wireData.trySetValue(ATTACHED, attached), Block.UPDATE_ALL); // Paper - prevent tripwire from updating } } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/VineBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/VineBlock.java.patch index 104fc06cc92d..929b8a555a62 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/VineBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/VineBlock.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/VineBlock.java +++ b/net/minecraft/world/level/block/VineBlock.java -@@ -166,7 +_,7 @@ +@@ -168,7 +_,7 @@ @Override protected void randomTick(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { if (level.getGameRules().get(GameRules.SPREAD_VINES)) { @@ -9,7 +9,7 @@ Direction testDirection = Direction.getRandom(random); BlockPos abovePos = pos.above(); if (testDirection.getAxis().isHorizontal() && !state.getValue(getPropertyForFace(testDirection))) { -@@ -180,30 +_,33 @@ +@@ -182,30 +_,33 @@ boolean ccwHasConnectingFace = state.getValue(getPropertyForFace(ccwDirection)); BlockPos cwTestPos = testPos.relative(cwDirection); BlockPos ccwTestPos = testPos.relative(ccwDirection); @@ -50,7 +50,7 @@ return; } -@@ -221,7 +_,7 @@ +@@ -223,7 +_,7 @@ } if (this.hasHorizontalConnection(aboveState)) { @@ -59,7 +59,7 @@ } return; -@@ -235,7 +_,7 @@ +@@ -237,7 +_,7 @@ BlockState before = belowState.isAir() ? this.defaultBlockState() : belowState; BlockState after = this.copyRandomFaces(state, before, random); if (before != after && this.hasHorizontalConnection(after)) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java.patch index 6157f3afddab..d0b8a8ffef3a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java +++ b/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -@@ -109,13 +_,51 @@ +@@ -104,13 +_,51 @@ }; public final Reference2IntOpenHashMap>> recipesUsed = new Reference2IntOpenHashMap<>(); private final RecipeManager.CachedCheck quickCheck; @@ -53,7 +53,7 @@ @Override protected void loadAdditional(final ValueInput input) { -@@ -128,6 +_,7 @@ +@@ -123,6 +_,7 @@ this.litTotalTime = input.getShortOr("lit_total_time", (short)0); this.recipesUsed.clear(); this.recipesUsed.putAll(input.read("RecipesUsed", RECIPES_USED_CODEC).orElse(Map.of())); @@ -61,7 +61,7 @@ } @Override -@@ -137,6 +_,7 @@ +@@ -132,6 +_,7 @@ output.putShort("cooking_total_time", (short)this.cookingTotalTime); output.putShort("lit_time_remaining", (short)this.litTimeRemaining); output.putShort("lit_total_time", (short)this.litTotalTime); @@ -69,7 +69,7 @@ ContainerHelper.saveAllItems(output, this.items); output.store("RecipesUsed", RECIPES_USED_CODEC, this.recipesUsed); } -@@ -166,24 +_,48 @@ +@@ -161,24 +_,48 @@ int maxStackSize = entity.getMaxStackSize(); ItemStack burnResult = recipe.value().assemble(input); if (!burnResult.isEmpty() && canBurn(entity.items, maxStackSize, burnResult)) { @@ -123,8 +123,8 @@ changed = true; } } else { -@@ -233,28 +_,63 @@ - } +@@ -230,28 +_,63 @@ + return resultCount <= maxResultCount; } - private static void burn(final NonNullList items, final ItemStack inputItemStack, final ItemStack result) { @@ -190,7 +190,7 @@ } @Override -@@ -298,7 +_,7 @@ +@@ -295,7 +_,7 @@ this.items.set(slot, itemStack); itemStack.limitSize(this.getMaxStackSize(itemStack)); if (slot == 0 && !same && this.level instanceof ServerLevel serverLevel) { @@ -199,7 +199,7 @@ this.cookingTimer = 0; this.setChanged(); } -@@ -333,8 +_,8 @@ +@@ -332,8 +_,8 @@ public void awardUsedRecipes(final Player player, final List itemStacks) { } @@ -210,7 +210,7 @@ player.awardRecipes(recipesToAward); for (RecipeHolder recipe : recipesToAward) { -@@ -345,30 +_,60 @@ +@@ -344,30 +_,60 @@ } public List> getRecipesToAwardAndPopExperience(final ServerLevel level, final Vec3 position) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BarrelBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BarrelBlockEntity.java.patch index c0cf3395c308..262672ce2551 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BarrelBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BarrelBlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/BarrelBlockEntity.java +++ b/net/minecraft/world/level/block/entity/BarrelBlockEntity.java -@@ -25,6 +_,40 @@ +@@ -24,6 +_,40 @@ import net.minecraft.world.level.storage.ValueOutput; public class BarrelBlockEntity extends RandomizableContainerBlockEntity { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BeaconBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BeaconBlockEntity.java.patch index e15d7d61fc34..2a9b6fa87339 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BeaconBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BeaconBlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/BeaconBlockEntity.java +++ b/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -@@ -111,6 +_,51 @@ +@@ -107,6 +_,51 @@ return 3; } }; @@ -52,7 +52,7 @@ private static @Nullable Holder filterEffect(final @Nullable Holder effect) { return VALID_EFFECTS.contains(effect) ? effect : null; -@@ -174,10 +_,19 @@ +@@ -170,10 +_,19 @@ } if (entity.levels > 0 && !entity.beamSections.isEmpty()) { @@ -73,7 +73,7 @@ if (entity.lastCheckY >= lastSetBlock) { entity.lastCheckY = level.getMinY() - 1; -@@ -228,7 +_,15 @@ +@@ -224,7 +_,15 @@ @Override public void setRemoved() { @@ -89,7 +89,7 @@ super.setRemoved(); } -@@ -238,29 +_,78 @@ +@@ -234,29 +_,78 @@ final int levels, final @Nullable Holder primaryPower, final @Nullable Holder secondaryPower @@ -186,7 +186,7 @@ public static void playSound(final Level level, final BlockPos worldPosition, final SoundEvent event) { level.playSound(null, worldPosition, event, SoundSource.BLOCKS, 1.0F, 1.0F); -@@ -288,7 +_,7 @@ +@@ -284,7 +_,7 @@ } private static @Nullable Holder loadEffect(final ValueInput input, final String field) { @@ -195,7 +195,7 @@ } @Override -@@ -296,8 +_,10 @@ +@@ -292,8 +_,10 @@ super.loadAdditional(input); this.primaryPower = loadEffect(input, "primary_effect"); this.secondaryPower = loadEffect(input, "secondary_effect"); @@ -206,7 +206,7 @@ } @Override -@@ -308,6 +_,7 @@ +@@ -304,6 +_,7 @@ output.putInt("Levels", this.levels); output.storeNullable("CustomName", ComponentSerialization.CODEC, this.name); this.lockKey.addToTag(output); @@ -214,12 +214,12 @@ } public void setCustomName(final @Nullable Component name) { -@@ -321,7 +_,7 @@ +@@ -317,7 +_,7 @@ @Override public @Nullable AbstractContainerMenu createMenu(final int containerId, final Inventory inventory, final Player player) { - if (this.lockKey.canUnlock(player)) { + if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockLockCheckEvent(this, this.lockKey, this.getDisplayName(), player)) { // Paper - Call BlockLockCheckEvent return new BeaconMenu(containerId, inventory, this.dataAccess, ContainerLevelAccess.create(this.level, this.getBlockPos())); - } else { - BaseContainerBlockEntity.sendChestLockedNotifications(this.getBlockPos().getCenter(), player, this.getDisplayName()); + } + diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java.patch index 64409208f817..b9d27d8405fa 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java.patch @@ -76,7 +76,7 @@ bee.stopRiding(); bee.ejectPassengers(); bee.dropLeash(); -@@ -190,7 +_,7 @@ +@@ -180,7 +_,7 @@ this.level.gameEvent(GameEvent.BLOCK_CHANGE, blockPos, GameEvent.Context.of(bee, this.getBlockState())); } @@ -85,7 +85,7 @@ super.setChanged(); } } -@@ -199,6 +_,12 @@ +@@ -189,6 +_,12 @@ this.stored.add(new BeehiveBlockEntity.BeeData(occupant)); } @@ -98,7 +98,7 @@ private static boolean releaseOccupant( final Level level, final BlockPos blockPos, -@@ -207,8 +_,9 @@ +@@ -197,8 +_,9 @@ final @Nullable List spawned, final BeehiveBlockEntity.BeeReleaseStatus releaseStatus, final @Nullable BlockPos savedFlowerPos @@ -108,62 +108,62 @@ + if (!force && level.environmentAttributes().getValue(EnvironmentAttributes.BEES_STAY_IN_HIVE, blockPos) // CraftBukkit && releaseStatus != BeehiveBlockEntity.BeeReleaseStatus.EMERGENCY) { return false; - } else { -@@ -220,6 +_,17 @@ - } else { - Entity entity = beeData.createEntity(level, blockPos); - if (entity != null) { -+ // CraftBukkit start -+ if (entity instanceof Bee) { -+ float bbWidth = entity.getBbWidth(); -+ double delta = frontBlocked ? 0.0 : 0.55 + bbWidth / 2.0F; -+ double spawnX = blockPos.getX() + 0.5 + delta * facing.getStepX(); -+ double spawnY = blockPos.getY() + 0.5 - entity.getBbHeight() / 2.0F; -+ double spawnZ = blockPos.getZ() + 0.5 + delta * facing.getStepZ(); -+ entity.snapTo(spawnX, spawnY, spawnZ, entity.getYRot(), entity.getXRot()); -+ } -+ if (!level.addFreshEntity(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BEEHIVE)) return false; // CraftBukkit - SpawnReason, moved from below -+ // CraftBukkit end - if (entity instanceof Bee bee) { - RandomSource random = level.getRandom(); - if (savedFlowerPos != null && !bee.hasSavedFlowerPos() && random.nextFloat() < 0.9F) { -@@ -236,7 +_,13 @@ - levelIncrease--; - } - -- level.setBlockAndUpdate(blockPos, state.setValue(BeehiveBlock.HONEY_LEVEL, honeyLevel + levelIncrease)); -+ // Paper start - Fire EntityChangeBlockEvent in more places -+ BlockState newBlockState = state.setValue(BeehiveBlock.HONEY_LEVEL, honeyLevel + levelIncrease); -+ -+ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, blockPos, newBlockState)) { -+ level.setBlockAndUpdate(blockPos, newBlockState); -+ } -+ // Paper end - Fire EntityChangeBlockEvent in more places - } + } +@@ -212,6 +_,17 @@ + + Entity entity = beeData.createEntity(level, blockPos); + if (entity != null) { ++ // CraftBukkit start ++ if (entity instanceof Bee) { ++ float bbWidth = entity.getBbWidth(); ++ double delta = frontBlocked ? 0.0 : 0.55 + bbWidth / 2.0F; ++ double spawnX = blockPos.getX() + 0.5 + delta * facing.getStepX(); ++ double spawnY = blockPos.getY() + 0.5 - entity.getBbHeight() / 2.0F; ++ double spawnZ = blockPos.getZ() + 0.5 + delta * facing.getStepZ(); ++ entity.snapTo(spawnX, spawnY, spawnZ, entity.getYRot(), entity.getXRot()); ++ } ++ if (!level.addFreshEntity(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BEEHIVE)) return false; // CraftBukkit - SpawnReason, moved from below ++ // CraftBukkit end + if (entity instanceof Bee bee) { + RandomSource random = level.getRandom(); + if (savedFlowerPos != null && !bee.hasSavedFlowerPos() && random.nextFloat() < 0.9F) { +@@ -228,7 +_,13 @@ + levelIncrease--; } - } -@@ -245,17 +_,19 @@ - spawned.add(bee); - } -+ /* CraftBukkit start - move up - float bbWidth = entity.getBbWidth(); - double delta = frontBlocked ? 0.0 : 0.55 + bbWidth / 2.0F; - double spawnX = blockPos.getX() + 0.5 + delta * facing.getStepX(); - double spawnY = blockPos.getY() + 0.5 - entity.getBbHeight() / 2.0F; - double spawnZ = blockPos.getZ() + 0.5 + delta * facing.getStepZ(); - entity.snapTo(spawnX, spawnY, spawnZ, entity.getYRot(), entity.getXRot()); -+ */ // CraftBukkit end +- level.setBlockAndUpdate(blockPos, state.setValue(BeehiveBlock.HONEY_LEVEL, honeyLevel + levelIncrease)); ++ // Paper start - Fire EntityChangeBlockEvent in more places ++ BlockState newBlockState = state.setValue(BeehiveBlock.HONEY_LEVEL, honeyLevel + levelIncrease); ++ ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, blockPos, newBlockState)) { ++ level.setBlockAndUpdate(blockPos, newBlockState); ++ } ++ // Paper end - Fire EntityChangeBlockEvent in more places + } } - - level.playSound(null, blockPos, SoundEvents.BEEHIVE_EXIT, SoundSource.BLOCKS, 1.0F, 1.0F); - level.gameEvent(GameEvent.BLOCK_CHANGE, blockPos, GameEvent.Context.of(entity, level.getBlockState(blockPos))); -- return level.addFreshEntity(entity); -+ return true; // CraftBukkit - moved up - } else { - return false; } -@@ -283,6 +_,11 @@ +@@ -237,17 +_,19 @@ + spawned.add(bee); + } + ++ /* CraftBukkit start - move up + float bbWidth = entity.getBbWidth(); + double delta = frontBlocked ? 0.0 : 0.55 + bbWidth / 2.0F; + double spawnX = blockPos.getX() + 0.5 + delta * facing.getStepX(); + double spawnY = blockPos.getY() + 0.5 - entity.getBbHeight() / 2.0F; + double spawnZ = blockPos.getZ() + 0.5 + delta * facing.getStepZ(); + entity.snapTo(spawnX, spawnY, spawnZ, entity.getYRot(), entity.getXRot()); ++ */ // CraftBukkit end + } + + level.playSound(null, blockPos, SoundEvents.BEEHIVE_EXIT, SoundSource.BLOCKS, 1.0F, 1.0F); + level.gameEvent(GameEvent.BLOCK_CHANGE, blockPos, GameEvent.Context.of(entity, level.getBlockState(blockPos))); +- return level.addFreshEntity(entity); ++ return true; // CraftBukkit - moved up + } else { + return false; + } +@@ -273,6 +_,11 @@ changed = true; iterator.remove(); } @@ -175,7 +175,7 @@ } } -@@ -304,9 +_,10 @@ +@@ -294,9 +_,10 @@ @Override protected void loadAdditional(final ValueInput input) { super.loadAdditional(input); @@ -187,7 +187,7 @@ } @Override -@@ -314,12 +_,13 @@ +@@ -304,12 +_,13 @@ super.saveAdditional(output); output.store("bees", BeehiveBlockEntity.Occupant.LIST_CODEC, this.getBees()); output.storeNullable("flower_pos", BlockPos.CODEC, this.savedFlowerPos); @@ -202,7 +202,7 @@ List bees = components.getOrDefault(DataComponents.BEES, Bees.EMPTY).bees(); bees.forEach(this::storeBee); } -@@ -347,15 +_,18 @@ +@@ -337,15 +_,18 @@ private static class BeeData { private final BeehiveBlockEntity.Occupant occupant; diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch index 1d32cbf29e53..f2535a9d05e5 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/BlockEntity.java +++ b/net/minecraft/world/level/block/entity/BlockEntity.java -@@ -40,6 +_,10 @@ +@@ -39,6 +_,10 @@ import org.slf4j.Logger; public abstract class BlockEntity implements DebugValueSource, TypedInstance> { @@ -11,7 +11,7 @@ private static final Codec> TYPE_CODEC = BuiltInRegistries.BLOCK_ENTITY_TYPE.byNameCodec(); private static final Logger LOGGER = LogUtils.getLogger(); private final BlockEntityType type; -@@ -54,6 +_,7 @@ +@@ -53,6 +_,7 @@ this.worldPosition = worldPosition.immutable(); this.validateBlockState(blockState); this.blockState = blockState; @@ -19,7 +19,7 @@ } private void validateBlockState(final BlockState blockState) { -@@ -66,10 +_,11 @@ +@@ -65,10 +_,11 @@ return this.type.isValid(blockState); } @@ -32,7 +32,7 @@ int sectionX = SectionPos.blockToSectionCoord(x); int sectionZ = SectionPos.blockToSectionCoord(z); if (sectionX != base.x() || sectionZ != base.z()) { -@@ -77,6 +_,7 @@ +@@ -76,6 +_,7 @@ x = base.getBlockX(SectionPos.sectionRelative(x)); z = base.getBlockZ(SectionPos.sectionRelative(z)); } @@ -40,7 +40,7 @@ return new BlockPos(x, y, z); } -@@ -94,6 +_,12 @@ +@@ -93,6 +_,12 @@ } protected void loadAdditional(final ValueInput input) { @@ -53,7 +53,7 @@ } public final void loadWithComponents(final ValueInput input) { -@@ -143,6 +_,11 @@ +@@ -136,6 +_,11 @@ public void saveWithoutMetadata(final ValueOutput output) { this.saveAdditional(output); output.store("components", DataComponentMap.CODEC, this.components); @@ -65,7 +65,7 @@ } public final CompoundTag saveCustomOnly(final HolderLookup.Provider registries) { -@@ -158,6 +_,11 @@ +@@ -148,6 +_,11 @@ public void saveCustomOnly(final ValueOutput output) { this.saveAdditional(output); @@ -77,7 +77,7 @@ } public void saveId(final ValueOutput output) { -@@ -293,6 +_,12 @@ +@@ -278,6 +_,12 @@ } public final void applyComponents(final DataComponentMap prototype, final DataComponentPatch patch) { @@ -90,7 +90,7 @@ final Set> implicitComponents = new HashSet<>(); implicitComponents.add(DataComponents.BLOCK_ENTITY_DATA); implicitComponents.add(DataComponents.BLOCK_STATE); -@@ -316,6 +_,10 @@ +@@ -297,6 +_,10 @@ }); DataComponentPatch newPatch = patch.forget(implicitComponents::contains); this.components = newPatch.split().added(); @@ -101,7 +101,7 @@ } protected void collectImplicitComponents(final DataComponentMap.Builder components) { -@@ -351,6 +_,27 @@ +@@ -332,6 +_,27 @@ @Override public void registerDebugValues(final ServerLevel level, final DebugValueSource.Registration registration) { } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java.patch index 266d51acd6f3..dfa24016506b 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java +++ b/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java -@@ -43,6 +_,7 @@ +@@ -42,6 +_,7 @@ private static final Component DEFAULT_NAME = Component.translatable("container.brewing"); private NonNullList items = NonNullList.withSize(5, ItemStack.EMPTY); public int brewTime; @@ -8,7 +8,7 @@ private boolean[] lastPotionCount; private Item ingredient; public int fuel; -@@ -56,6 +_,7 @@ +@@ -51,6 +_,7 @@ return switch (dataId) { case 0 -> BrewingStandBlockEntity.this.brewTime; case 1 -> BrewingStandBlockEntity.this.fuel; @@ -16,7 +16,7 @@ default -> 0; }; } -@@ -68,14 +_,54 @@ +@@ -63,14 +_,54 @@ break; case 1: BrewingStandBlockEntity.this.fuel = value; @@ -72,7 +72,7 @@ public BrewingStandBlockEntity(final BlockPos worldPosition, final BlockState blockState) { super(BlockEntityType.BREWING_STAND, worldPosition, blockState); -@@ -104,8 +_,21 @@ +@@ -99,8 +_,21 @@ public static void serverTick(final Level level, final BlockPos pos, final BlockState selfState, final BrewingStandBlockEntity entity) { ItemStack fuel = entity.items.get(4); if (entity.fuel <= 0 && fuel.is(ItemTags.BREWING_FUEL)) { @@ -96,7 +96,7 @@ setChanged(level, pos, selfState); } -@@ -116,7 +_,7 @@ +@@ -111,7 +_,7 @@ entity.brewTime--; boolean isDoneBrewing = entity.brewTime == 0; if (isDoneBrewing && brewable) { @@ -105,7 +105,7 @@ } else if (!brewable || !ingredient.is(entity.ingredient)) { entity.brewTime = 0; } -@@ -124,7 +_,14 @@ +@@ -119,7 +_,14 @@ setChanged(level, pos, selfState); } else if (brewable && entity.fuel > 0) { entity.fuel--; @@ -121,8 +121,8 @@ entity.ingredient = ingredient.getItem(); setChanged(level, pos, selfState); } -@@ -175,13 +_,37 @@ - } +@@ -172,13 +_,37 @@ + return false; } - private static void doBrew(final Level level, final BlockPos pos, final NonNullList items) { @@ -162,7 +162,7 @@ ingredient.shrink(1); ItemStackTemplate remainder = ingredient.getItem().getCraftingRemainder(); -@@ -220,13 +_,13 @@ +@@ -217,13 +_,13 @@ @Override public boolean canPlaceItem(final int slot, final ItemStack itemStack) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrushableBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrushableBlockEntity.java.patch index d3a465b684db..d378e5992172 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrushableBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BrushableBlockEntity.java.patch @@ -1,42 +1,42 @@ --- a/net/minecraft/world/level/block/entity/BrushableBlockEntity.java +++ b/net/minecraft/world/level/block/entity/BrushableBlockEntity.java -@@ -67,9 +_,26 @@ - return false; - } else { - this.coolDownEndsAtTick = gameTime + 10L; -+ // Paper start - EntityChangeBlockEvent -+ // The vanilla logic here is *so* backwards, we'd be moving basically *all* following calls down. -+ // Instead, compute vanilla ourselves up here and just replace the below usages with our computed values for a free diff-on-change. -+ final int currentCompletionStage = this.getCompletionState(); -+ final boolean enoughBrushesToBreak = ++this.brushCount >= REQUIRED_BRUSHES_TO_BREAK; -+ final int nextCompletionStage = this.getCompletionState(); -+ final boolean differentCompletionStages = currentCompletionStage != nextCompletionStage; -+ final BlockState nextBrokenBlockState = this.getBlockState().setValue(BlockStateProperties.DUSTED, nextCompletionStage); -+ if (enoughBrushesToBreak || differentCompletionStages) { -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent( -+ user, this.worldPosition, enoughBrushesToBreak ? this.computeTurnsTo().defaultBlockState() : nextBrokenBlockState -+ )) { -+ this.brushCount--; -+ return false; -+ } +@@ -68,9 +_,26 @@ + } + + this.coolDownEndsAtTick = gameTime + 10L; ++ // Paper start - EntityChangeBlockEvent ++ // The vanilla logic here is *so* backwards, we'd be moving basically *all* following calls down. ++ // Instead, compute vanilla ourselves up here and just replace the below usages with our computed values for a free diff-on-change. ++ final int currentCompletionStage = this.getCompletionState(); ++ final boolean enoughBrushesToBreak = ++this.brushCount >= REQUIRED_BRUSHES_TO_BREAK; ++ final int nextCompletionStage = this.getCompletionState(); ++ final boolean differentCompletionStages = currentCompletionStage != nextCompletionStage; ++ final BlockState nextBrokenBlockState = this.getBlockState().setValue(BlockStateProperties.DUSTED, nextCompletionStage); ++ if (enoughBrushesToBreak || differentCompletionStages) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent( ++ user, this.worldPosition, enoughBrushesToBreak ? this.computeTurnsTo().defaultBlockState() : nextBrokenBlockState ++ )) { ++ this.brushCount--; ++ return false; + } -+ // Paper end - EntityChangeBlockEvent - this.unpackLootTable(level, user, brush); -- int previousCompletionState = this.getCompletionState(); -- if (++this.brushCount >= 10) { -+ int previousCompletionState = currentCompletionStage; // Paper - EntityChangeBlockEvent - use precomputed - diff on change -+ if (enoughBrushesToBreak) { // Paper - EntityChangeBlockEvent - use precomputed - diff on change - this.brushingCompleted(level, user, brush); - return true; - } else { -@@ -77,7 +_,7 @@ - int completionState = this.getCompletionState(); - if (previousCompletionState != completionState) { - BlockState previousState = this.getBlockState(); -- BlockState state = previousState.setValue(BlockStateProperties.DUSTED, completionState); -+ BlockState state = nextBrokenBlockState; // Paper - EntityChangeBlockEvent - use precomputed - diff on change - level.setBlock(this.getBlockPos(), state, Block.UPDATE_ALL); - } ++ } ++ // Paper end - EntityChangeBlockEvent + this.unpackLootTable(level, user, brush); +- int previousCompletionState = this.getCompletionState(); +- if (++this.brushCount >= 10) { ++ int previousCompletionState = currentCompletionStage; // Paper - EntityChangeBlockEvent - use precomputed - diff on change ++ if (enoughBrushesToBreak) { // Paper - EntityChangeBlockEvent - use precomputed - diff on change + this.brushingCompleted(level, user, brush); + return true; + } +@@ -79,7 +_,7 @@ + int completionState = this.getCompletionState(); + if (previousCompletionState != completionState) { + BlockState previousState = this.getBlockState(); +- BlockState state = previousState.setValue(BlockStateProperties.DUSTED, completionState); ++ BlockState state = nextBrokenBlockState; // Paper - EntityChangeBlockEvent - use precomputed - diff on change + level.setBlock(this.getBlockPos(), state, Block.UPDATE_ALL); + } @@ -118,6 +_,12 @@ this.dropContent(level, user, brush); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java.patch index 991f89beb316..f478236fe4c1 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java +++ b/net/minecraft/world/level/block/entity/CalibratedSculkSensorBlockEntity.java -@@ -21,6 +_,12 @@ +@@ -20,6 +_,12 @@ public VibrationSystem.User createVibrationUser() { return new CalibratedSculkSensorBlockEntity.VibrationUser(this.getBlockPos()); } @@ -13,7 +13,7 @@ protected class VibrationUser extends SculkSensorBlockEntity.VibrationUser { public VibrationUser(final BlockPos blockPos) { -@@ -30,6 +_,7 @@ +@@ -28,6 +_,7 @@ @Override public int getListenerRadius() { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/CampfireBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/CampfireBlockEntity.java.patch index b22ba8ff3bdf..b690fe965c48 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/CampfireBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/CampfireBlockEntity.java.patch @@ -84,7 +84,7 @@ } @Override -@@ -179,7 +_,15 @@ +@@ -176,7 +_,15 @@ return false; } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch index 5a386c38181c..e5c42fe9bcde 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/ChestBlockEntity.java +++ b/net/minecraft/world/level/block/entity/ChestBlockEntity.java -@@ -67,6 +_,40 @@ +@@ -62,6 +_,40 @@ }; private final ChestLidController chestLidController = new ChestLidController(); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/CommandBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/CommandBlockEntity.java.patch index 15397f883fde..24d455c7d017 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/CommandBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/CommandBlockEntity.java.patch @@ -1,9 +1,9 @@ --- a/net/minecraft/world/level/block/entity/CommandBlockEntity.java +++ b/net/minecraft/world/level/block/entity/CommandBlockEntity.java -@@ -32,6 +_,18 @@ - Objects.requireNonNull(CommandBlockEntity.this); - } - +@@ -27,6 +_,18 @@ + private boolean auto = false; + private boolean conditionMet = false; + private final BaseCommandBlock commandBlock = new BaseCommandBlock() { + // CraftBukkit start + @Override + public org.bukkit.command.CommandSender getBukkitSender(CommandSourceStack wrapper) { @@ -11,15 +11,15 @@ + } + + @Override -+ public net.minecraft.server.level.ServerLevel getLevel() { -+ return (net.minecraft.server.level.ServerLevel) CommandBlockEntity.this.getLevel(); ++ public ServerLevel getLevel() { ++ return (ServerLevel) CommandBlockEntity.this.getLevel(); + } + // CraftBukkit end + @Override public void setCommand(final String command) { super.setCommand(command); -@@ -52,7 +_,7 @@ +@@ -47,7 +_,7 @@ Vec3.atCenterOf(CommandBlockEntity.this.worldPosition), new Vec2(0.0F, facing.toYRot()), level, diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ConduitBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ConduitBlockEntity.java.patch index f10559537eed..9b2488d45631 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ConduitBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ConduitBlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/ConduitBlockEntity.java +++ b/net/minecraft/world/level/block/entity/ConduitBlockEntity.java -@@ -164,8 +_,20 @@ +@@ -165,8 +_,20 @@ } private static void applyEffects(final Level level, final BlockPos worldPosition, final List effectBlocks) { @@ -21,7 +21,7 @@ int x = worldPosition.getX(); int y = worldPosition.getY(); int z = worldPosition.getZ(); -@@ -174,7 +_,7 @@ +@@ -175,7 +_,7 @@ if (!players.isEmpty()) { for (Player player : players) { if (worldPosition.closerThan(player.blockPosition(), effectRange) && player.isInWaterOrRain()) { @@ -30,7 +30,7 @@ } } } -@@ -183,13 +_,19 @@ +@@ -184,13 +_,19 @@ private static void updateAndAttackTarget( final ServerLevel level, final BlockPos worldPosition, final BlockState blockState, final ConduitBlockEntity entity, final boolean isActive ) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/CrafterBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/CrafterBlockEntity.java.patch index a312097f3c11..bc4d881c4e5c 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/CrafterBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/CrafterBlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/CrafterBlockEntity.java +++ b/net/minecraft/world/level/block/entity/CrafterBlockEntity.java -@@ -67,6 +_,47 @@ +@@ -60,6 +_,47 @@ } }; diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/HopperBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/HopperBlockEntity.java.patch index bb2bc131a7fc..da4859bb303a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/HopperBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/HopperBlockEntity.java.patch @@ -55,65 +55,64 @@ } } -@@ -120,7 +_,7 @@ - } +@@ -121,7 +_,7 @@ + } - if (changed) { -- entity.setCooldown(8); -+ entity.setCooldown(level.spigotConfig.hopperTransfer); // Spigot - setChanged(level, pos, state); - return true; - } -@@ -153,14 +_,47 @@ - ItemStack itemStack = self.getItem(slot); - if (!itemStack.isEmpty()) { - int originalCount = itemStack.getCount(); -- ItemStack result = addItem(self, container, self.removeItem(slot, 1), direction); -+ // CraftBukkit start - Call event when pushing items into other inventories -+ ItemStack original = itemStack.copy(); -+ org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror( -+ self.removeItem(slot, level.spigotConfig.hopperAmount) -+ ); // Spigot -+ -+ org.bukkit.inventory.Inventory destinationInventory; -+ // Have to special case large chests as they work oddly -+ if (container instanceof final net.minecraft.world.CompoundContainer compoundContainer) { -+ destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer); -+ } else if (container.getOwner() != null) { -+ destinationInventory = container.getOwner().getInventory(); -+ } else { -+ destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(container); -+ } + if (changed) { +- entity.setCooldown(8); ++ entity.setCooldown(level.spigotConfig.hopperTransfer); // Spigot + setChanged(level, pos, state); + return true; + } +@@ -155,14 +_,46 @@ + ItemStack itemStack = self.getItem(slot); + if (!itemStack.isEmpty()) { + int originalCount = itemStack.getCount(); +- ItemStack result = addItem(self, container, self.removeItem(slot, 1), direction); ++ // CraftBukkit start - Call event when pushing items into other inventories ++ ItemStack original = itemStack.copy(); ++ org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror( ++ self.removeItem(slot, level.spigotConfig.hopperAmount) ++ ); // Spigot + -+ org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent( -+ self.getOwner().getInventory(), -+ oitemstack, -+ destinationInventory, -+ true -+ ); -+ if (!event.callEvent()) { -+ self.setItem(slot, original); -+ self.setCooldown(level.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot -+ return false; -+ } -+ int origCount = event.getItem().getAmount(); // Spigot -+ ItemStack result = HopperBlockEntity.addItem(self, container, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), direction); -+ // CraftBukkit end ++ org.bukkit.inventory.Inventory destinationInventory; ++ // Have to special case large chests as they work oddly ++ if (container instanceof final net.minecraft.world.CompoundContainer compoundContainer) { ++ destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer); ++ } else if (container.getOwner() != null) { ++ destinationInventory = container.getOwner().getInventory(); ++ } else { ++ destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(container); ++ } + - if (result.isEmpty()) { - container.setChanged(); - return true; - } ++ org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent( ++ self.getOwner().getInventory(), ++ oitemstack, ++ destinationInventory, ++ true ++ ); ++ if (!event.callEvent()) { ++ self.setItem(slot, original); ++ self.setCooldown(level.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot ++ return false; ++ } ++ int origCount = event.getItem().getAmount(); // Spigot ++ ItemStack result = HopperBlockEntity.addItem(self, container, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), direction); ++ // CraftBukkit end + if (result.isEmpty()) { + container.setChanged(); + return true; + } - itemStack.setCount(originalCount); -- if (originalCount == 1) { -+ // Spigot start -+ itemStack.shrink(origCount - result.getCount()); -+ if (originalCount <= level.spigotConfig.hopperAmount) { -+ // Spigot end - self.setItem(slot, itemStack); - } - } + itemStack.setCount(originalCount); +- if (originalCount == 1) { ++ // Spigot start ++ itemStack.shrink(origCount - result.getCount()); ++ if (originalCount <= level.spigotConfig.hopperAmount) { ++ // Spigot end + self.setItem(slot, itemStack); + } + } @@ -223,7 +_,7 @@ Direction direction = Direction.DOWN; diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/LecternBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/LecternBlockEntity.java.patch index 8715b52b205d..2a4f512c9356 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/LecternBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/LecternBlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/LecternBlockEntity.java +++ b/net/minecraft/world/level/block/entity/LecternBlockEntity.java -@@ -36,11 +_,56 @@ +@@ -35,7 +_,52 @@ public static final int NUM_DATA = 1; public static final int SLOT_BOOK = 0; public static final int NUM_SLOTS = 1; @@ -8,10 +8,6 @@ + // CraftBukkit start - add fields and methods + public final Container bookAccess = new LecternInventory(); + public class LecternInventory implements Container { - { - Objects.requireNonNull(LecternBlockEntity.this); - } - + public java.util.List transaction = new java.util.ArrayList<>(); + private int maxStack = 1; + @@ -58,7 +54,7 @@ @Override public int getContainerSize() { return 1; -@@ -84,11 +_,19 @@ +@@ -79,11 +_,19 @@ @Override public void setItem(final int slot, final ItemStack itemStack) { @@ -79,7 +75,7 @@ } @Override -@@ -170,7 +_,7 @@ +@@ -161,7 +_,7 @@ if (newPage != this.page) { this.page = newPage; this.setChanged(); @@ -88,7 +84,7 @@ } } -@@ -192,6 +_,36 @@ +@@ -183,6 +_,36 @@ return book; } @@ -125,7 +121,7 @@ private CommandSourceStack createCommandSourceStack(final @Nullable Player player, final ServerLevel level) { String textName; Component displayName; -@@ -205,7 +_,7 @@ +@@ -196,7 +_,7 @@ Vec3 pos = Vec3.atCenterOf(this.worldPosition); return new CommandSourceStack( @@ -134,7 +130,7 @@ ); } -@@ -246,7 +_,7 @@ +@@ -237,7 +_,7 @@ @Override public AbstractContainerMenu createMenu(final int containerId, final Inventory inventory, final Player player) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java.patch index cbe5a9a1731f..e8611b4ad6e4 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java +++ b/net/minecraft/world/level/block/entity/SculkSensorBlockEntity.java -@@ -22,6 +_,7 @@ +@@ -21,6 +_,7 @@ private final VibrationSystem.Listener vibrationListener; private final VibrationSystem.User vibrationUser; public int lastVibrationFrequency = 0; @@ -8,7 +8,7 @@ protected SculkSensorBlockEntity(final BlockEntityType type, final BlockPos worldPosition, final BlockState blockState) { super(type, worldPosition, blockState); -@@ -43,14 +_,22 @@ +@@ -42,14 +_,22 @@ super.loadAdditional(input); this.lastVibrationFrequency = input.getIntOr("last_vibration_frequency", 0); this.vibrationData = input.read("listener", VibrationSystem.Data.CODEC).orElseGet(VibrationSystem.Data::new); @@ -32,7 +32,7 @@ @Override public VibrationSystem.Data getVibrationData() { -@@ -89,6 +_,7 @@ +@@ -86,6 +_,7 @@ @Override public int getListenerRadius() { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java.patch index 8bdd7e75a099..c208f2289dd0 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java +++ b/net/minecraft/world/level/block/entity/SculkShriekerBlockEntity.java -@@ -89,6 +_,13 @@ +@@ -88,6 +_,13 @@ } public static @Nullable ServerPlayer tryGetPlayer(final @Nullable Entity sourceEntity) { @@ -14,7 +14,7 @@ if (sourceEntity instanceof ServerPlayer player) { return player; } else if (sourceEntity != null && sourceEntity.getControllingPassenger() instanceof ServerPlayer player) { -@@ -165,7 +_,7 @@ +@@ -164,7 +_,7 @@ private boolean trySummonWarden(final ServerLevel level) { return this.warningLevel >= 4 && SpawnUtil.trySpawnMob( diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/SignBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/SignBlockEntity.java.patch index 719a70f6d376..8265f984dff7 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/SignBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/SignBlockEntity.java.patch @@ -78,9 +78,9 @@ return text; } -@@ -194,7 +_,23 @@ - Style style = message.getStyle(); - switch (style.getClickEvent()) { +@@ -195,7 +_,23 @@ + ClickEvent event = style.getClickEvent(); + switch (event) { case ClickEvent.RunCommand command: - level.getServer().getCommands().performPrefixedCommand(createCommandSourceStack(player, level, pos), command.command()); + // Paper start - Fix commands from signs not firing command events @@ -88,22 +88,22 @@ + if (org.spigotmc.SpigotConfig.logCommands) { + LOGGER.info("{} issued server command: {}", player.getScoreboardName(), commandLine); + } -+ io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent event = new io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent( ++ final io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent bukkitEvent = new io.papermc.paper.event.player.PlayerSignCommandPreprocessEvent( + (org.bukkit.entity.Player) player.getBukkitEntity(), + commandLine, + new org.bukkit.craftbukkit.util.LazyPlayerSet(level.getServer()), + (org.bukkit.block.Sign) org.bukkit.craftbukkit.block.CraftBlock.at(this.level, this.worldPosition).getState(), + isFrontText ? org.bukkit.block.sign.Side.FRONT : org.bukkit.block.sign.Side.BACK + ); -+ if (!event.callEvent()) { ++ if (!bukkitEvent.callEvent()) { + return false; + } -+ level.getServer().getCommands().performPrefixedCommand(createCommandSourceStack(((org.bukkit.craftbukkit.entity.CraftPlayer) event.getPlayer()).getHandle(), level, pos), event.getMessage()); ++ level.getServer().getCommands().performPrefixedCommand(createCommandSourceStack(((org.bukkit.craftbukkit.entity.CraftPlayer) bukkitEvent.getPlayer()).getHandle(), level, pos), bukkitEvent.getMessage()); + // Paper end - Fix commands from signs not firing command events hasAnyClickCommand = true; break; case ClickEvent.ShowDialog dialog: -@@ -213,11 +_,55 @@ +@@ -214,11 +_,55 @@ return hasAnyClickCommand; } @@ -138,7 +138,7 @@ + private CommandSourceStack createCommandSourceStack(final @Nullable Player player, final ServerLevel level, final BlockPos pos) { + // CraftBukkit end String textName = player == null ? "Sign" : player.getPlainTextName(); - Component displayName = (Component)(player == null ? Component.literal("Sign") : player.getDisplayName()); + Component displayName = player == null ? Component.literal("Sign") : player.getDisplayName(); + // Paper start - Fix commands from signs not firing command events + CommandSource commandSource = level.paperConfig().misc.showSignClickCommandFailureMsgsToPlayer ? new io.papermc.paper.commands.DelegatingCommandSource(this.commandSource) { + @Override @@ -161,7 +161,7 @@ ); } -@@ -236,12 +_,17 @@ +@@ -237,12 +_,17 @@ } public @Nullable UUID getPlayerWhoMayEdit() { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java.patch index 97ff70e7bc79..5be334619020 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java +++ b/net/minecraft/world/level/block/entity/trialspawner/TrialSpawner.java -@@ -219,7 +_,14 @@ +@@ -218,7 +_,14 @@ nextSpawnData.getEquipment().ifPresent(mob::equip); } @@ -16,7 +16,7 @@ return Optional.empty(); } -@@ -238,6 +_,20 @@ +@@ -235,6 +_,20 @@ LootParams params = new LootParams.Builder(level).create(LootContextParamSets.EMPTY); ObjectArrayList lootDrops = lootTable.getRandomItems(params); if (!lootDrops.isEmpty()) { @@ -37,7 +37,7 @@ for (ItemStack item : lootDrops) { DefaultDispenseItemBehavior.spawnItem(level, item, 2, Direction.UP, Vec3.atBottomCenterOf(pos).relative(Direction.UP, 1.2)); } -@@ -401,6 +_,35 @@ +@@ -398,6 +_,35 @@ this.requiredPlayerRange ); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/vault/VaultServerData.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/vault/VaultServerData.java.patch index 923e9d99c960..b03601bd1c54 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/vault/VaultServerData.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/vault/VaultServerData.java.patch @@ -24,7 +24,7 @@ public long stateUpdatingResumesAt() { @@ -127,4 +_,15 @@ public float ejectionProgress() { - return this.totalEjectionsNeeded == 1 ? 1.0F : 1.0F - Mth.inverseLerp((float)this.getItemsToEject().size(), 1.0F, (float)this.totalEjectionsNeeded); + return this.totalEjectionsNeeded == 1 ? 1.0F : 1.0F - Mth.inverseLerp(this.getItemsToEject().size(), 1.0F, this.totalEjectionsNeeded); } + + // Paper start - Vault API diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/grower/TreeGrower.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/grower/TreeGrower.java.patch index 19d3e28e7056..7875670c9a27 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/grower/TreeGrower.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/grower/TreeGrower.java.patch @@ -8,17 +8,17 @@ for (int dx = 0; dx >= -1; dx--) { for (int dz = 0; dz >= -1; dz--) { if (isTwoByTwoSapling(state, level, pos, dx, dz)) { -@@ -164,6 +_,7 @@ - if (featureHolder == null) { - return false; - } else { -+ this.setTreeType(featureHolder); // CraftBukkit - ConfiguredFeature feature = featureHolder.value(); - BlockState emptyBlock = level.getFluidState(pos).createLegacyBlock(); - level.setBlock(pos, emptyBlock, Block.UPDATE_NONE); -@@ -210,4 +_,58 @@ - : OptionalInt.empty(); +@@ -166,6 +_,7 @@ + return false; } + ++ this.setTreeType(featureHolder); // CraftBukkit + ConfiguredFeature feature = featureHolder.value(); + BlockState emptyBlock = level.getFluidState(pos).createLegacyBlock(); + level.setBlock(pos, emptyBlock, Block.UPDATE_NONE); +@@ -210,4 +_,58 @@ + ? OptionalInt.of(treeConfig.trunkPlacer.getBaseHeight()) + : OptionalInt.empty(); } + + // CraftBukkit start diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/piston/PistonBaseBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/piston/PistonBaseBlock.java.patch index e0e76a8fab22..8ade0ce1da95 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/piston/PistonBaseBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/piston/PistonBaseBlock.java.patch @@ -68,97 +68,97 @@ - if (pos.getY() < level.getMinY() || pos.getY() > level.getMaxY() || !level.getWorldBorder().isWithinBounds(pos)) { + if (pos.getY() < level.getMinY() || pos.getY() > level.getMaxY() || !level.getWorldBorder().isWithinBounds(pos) || !level.getWorldBorder().isWithinBounds(pos.relative(direction))) { // Paper - Fix piston world border check return false; - } else if (state.isAir()) { - return true; -@@ -289,12 +_,58 @@ - BlockState[] toUpdate = new BlockState[toPush.size() + toDestroy.size()]; - Direction pushDirection = extending ? direction : direction.getOpposite(); - int updateIndex = 0; -+ // CraftBukkit start -+ final org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, pistonPos); -+ -+ final List moved = resolver.getToPush(); -+ final List broken = resolver.getToDestroy(); + } + +@@ -298,12 +_,58 @@ + BlockState[] toUpdate = new BlockState[toPush.size() + toDestroy.size()]; + Direction pushDirection = extending ? direction : direction.getOpposite(); + int updateIndex = 0; ++ // CraftBukkit start ++ final org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, pistonPos); + -+ List blocks = new java.util.AbstractList<>() { ++ final List moved = resolver.getToPush(); ++ final List broken = resolver.getToDestroy(); + -+ @Override -+ public int size() { -+ return moved.size() + broken.size(); -+ } ++ List blocks = new java.util.AbstractList<>() { + -+ @Override -+ public org.bukkit.block.Block get(int index) { -+ if (index >= this.size() || index < 0) { -+ throw new ArrayIndexOutOfBoundsException(index); -+ } ++ @Override ++ public int size() { ++ return moved.size() + broken.size(); ++ } + -+ BlockPos pos = index < moved.size() ? moved.get(index) : broken.get(index - moved.size()); -+ return org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); ++ @Override ++ public org.bukkit.block.Block get(int index) { ++ if (index >= this.size() || index < 0) { ++ throw new ArrayIndexOutOfBoundsException(index); + } -+ }; + -+ final org.bukkit.event.block.BlockPistonEvent event; -+ if (extending) { -+ event = new org.bukkit.event.block.BlockPistonExtendEvent( -+ bukkitBlock, blocks, org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(pushDirection) -+ ); -+ } else { -+ event = new org.bukkit.event.block.BlockPistonRetractEvent( -+ bukkitBlock, blocks, org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(pushDirection) -+ ); ++ BlockPos pos = index < moved.size() ? moved.get(index) : broken.get(index - moved.size()); ++ return org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); + } -+ if (!event.callEvent()) { -+ for (BlockPos brokenPos : broken) { -+ level.sendBlockUpdated(brokenPos, Blocks.AIR.defaultBlockState(), level.getBlockState(brokenPos), Block.UPDATE_ALL); -+ } -+ for (BlockPos movedPos : moved) { -+ level.sendBlockUpdated(movedPos, Blocks.AIR.defaultBlockState(), level.getBlockState(movedPos), Block.UPDATE_ALL); -+ movedPos = movedPos.relative(pushDirection); -+ level.sendBlockUpdated(movedPos, Blocks.AIR.defaultBlockState(), level.getBlockState(movedPos), Block.UPDATE_ALL); -+ } -+ return false; ++ }; ++ ++ final org.bukkit.event.block.BlockPistonEvent event; ++ if (extending) { ++ event = new org.bukkit.event.block.BlockPistonExtendEvent( ++ bukkitBlock, blocks, org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(pushDirection) ++ ); ++ } else { ++ event = new org.bukkit.event.block.BlockPistonRetractEvent( ++ bukkitBlock, blocks, org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(pushDirection) ++ ); ++ } ++ if (!event.callEvent()) { ++ for (BlockPos brokenPos : broken) { ++ level.sendBlockUpdated(brokenPos, Blocks.AIR.defaultBlockState(), level.getBlockState(brokenPos), Block.UPDATE_ALL); ++ } ++ for (BlockPos movedPos : moved) { ++ level.sendBlockUpdated(movedPos, Blocks.AIR.defaultBlockState(), level.getBlockState(movedPos), Block.UPDATE_ALL); ++ movedPos = movedPos.relative(pushDirection); ++ level.sendBlockUpdated(movedPos, Blocks.AIR.defaultBlockState(), level.getBlockState(movedPos), Block.UPDATE_ALL); + } -+ // CraftBukkit end ++ return false; ++ } ++ // CraftBukkit end - for (int i = toDestroy.size() - 1; i >= 0; i--) { - BlockPos pos = toDestroy.get(i); - BlockState state = level.getBlockState(pos); - BlockEntity blockEntity = state.hasBlockEntity() ? level.getBlockEntity(pos) : null; -- dropResources(state, level, pos, blockEntity); -+ dropResources(state, level, pos, blockEntity, pistonPos); // Paper - Add BlockBreakBlockEvent - if (!state.is(BlockTags.FIRE) && level.isClientSide()) { - level.levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, pos, getId(state)); - } -@@ -305,13 +_,28 @@ + for (int i = toDestroy.size() - 1; i >= 0; i--) { + BlockPos pos = toDestroy.get(i); + BlockState state = level.getBlockState(pos); + BlockEntity blockEntity = state.hasBlockEntity() ? level.getBlockEntity(pos) : null; +- dropResources(state, level, pos, blockEntity); ++ dropResources(state, level, pos, blockEntity, pistonPos); // Paper - Add BlockBreakBlockEvent + if (!state.is(BlockTags.FIRE) && level.isClientSide()) { + level.levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, pos, getId(state)); } +@@ -314,13 +_,28 @@ + } - for (int i = toPush.size() - 1; i >= 0; i--) { -- BlockPos pos = toPush.get(i); -- BlockState blockState = level.getBlockState(pos); -+ // Paper start - fix a variety of piston desync dupes -+ boolean allowDesync = io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication; -+ BlockPos oldPos = toPush.get(i); -+ BlockPos pos = oldPos; -+ BlockState blockState = allowDesync ? level.getBlockState(oldPos) : null; -+ // Paper end - fix a variety of piston desync dupes - pos = pos.relative(pushDirection); - deleteAfterMove.remove(pos); - BlockState actualState = Blocks.MOVING_PISTON.defaultBlockState().setValue(FACING, direction); - level.setBlock(pos, actualState, Block.UPDATE_NONE | Block.UPDATE_MOVE_BY_PISTON); -- level.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, actualState, toPushShapes.get(i), direction, extending, false)); -+ // Paper start - fix a variety of piston desync dupes -+ if (!allowDesync) { -+ blockState = level.getBlockState(oldPos); -+ deleteAfterMove.replace(oldPos, blockState); -+ } -+ level.setBlockEntity( -+ MovingPistonBlock.newMovingBlockEntity(pos, actualState, allowDesync ? toPushShapes.get(i) : blockState, direction, extending, false) -+ ); -+ if (!allowDesync) { -+ level.setBlock(oldPos, Blocks.AIR.defaultBlockState(), Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE | Block.UPDATE_MOVE_BY_PISTON | Block.UPDATE_SKIP_ON_PLACE); // set air to prevent later physics updates from seeing this block -+ } -+ // Paper end - fix a variety of piston desync dupes - toUpdate[updateIndex++] = blockState; - } + for (int i = toPush.size() - 1; i >= 0; i--) { +- BlockPos pos = toPush.get(i); +- BlockState blockState = level.getBlockState(pos); ++ // Paper start - fix a variety of piston desync dupes ++ boolean allowDesync = io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication; ++ BlockPos oldPos = toPush.get(i); ++ BlockPos pos = oldPos; ++ BlockState blockState = allowDesync ? level.getBlockState(oldPos) : null; ++ // Paper end - fix a variety of piston desync dupes + pos = pos.relative(pushDirection); + deleteAfterMove.remove(pos); + BlockState actualState = Blocks.MOVING_PISTON.defaultBlockState().setValue(FACING, direction); + level.setBlock(pos, actualState, Block.UPDATE_NONE | Block.UPDATE_MOVE_BY_PISTON); +- level.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(pos, actualState, toPushShapes.get(i), direction, extending, false)); ++ // Paper start - fix a variety of piston desync dupes ++ if (!allowDesync) { ++ blockState = level.getBlockState(oldPos); ++ deleteAfterMove.replace(oldPos, blockState); ++ } ++ level.setBlockEntity( ++ MovingPistonBlock.newMovingBlockEntity(pos, actualState, allowDesync ? toPushShapes.get(i) : blockState, direction, extending, false) ++ ); ++ if (!allowDesync) { ++ level.setBlock(oldPos, Blocks.AIR.defaultBlockState(), Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE | Block.UPDATE_MOVE_BY_PISTON | Block.UPDATE_SKIP_ON_PLACE); // set air to prevent later physics updates from seeing this block ++ } ++ // Paper end - fix a variety of piston desync dupes + toUpdate[updateIndex++] = blockState; + } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/state/BlockBehaviour.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/state/BlockBehaviour.java.patch index ac55e4ac835f..a7ddf93cc18d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/state/BlockBehaviour.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/state/BlockBehaviour.java.patch @@ -62,8 +62,8 @@ private boolean calculateSolid() { if (this.owner.properties.forceSolidOn) { -@@ -503,12 +_,14 @@ - } +@@ -507,12 +_,14 @@ + return bounds.getSize() >= 0.7291666666666666 || bounds.getYsize() >= 1.0; } + protected boolean shapeExceedsCube = true; // Paper - moved from actual method to here @@ -77,7 +77,7 @@ this.legacySolid = this.calculateSolid(); this.occlusionShape = this.canOcclude ? this.owner.getOcclusionShape(this.asState()) : Shapes.empty(); -@@ -548,6 +_,11 @@ +@@ -552,6 +_,11 @@ public boolean isSolid() { return this.legacySolid; } @@ -89,7 +89,7 @@ public boolean isValidSpawn(final BlockGetter level, final BlockPos pos, final EntityType type) { return this.getBlock().properties.isValidSpawn.test(this.asState(), level, pos, type); -@@ -569,19 +_,19 @@ +@@ -573,19 +_,19 @@ return this.occlusionShape; } @@ -114,7 +114,7 @@ return this.isAir; } -@@ -595,7 +_,7 @@ +@@ -599,7 +_,7 @@ } public MapColor getMapColor(final BlockGetter level, final BlockPos pos) { @@ -123,7 +123,7 @@ } public BlockState rotate(final Rotation rotation) { -@@ -651,14 +_,14 @@ +@@ -655,14 +_,14 @@ } public PushReaction getPistonPushReaction() { @@ -140,7 +140,7 @@ return this.canOcclude; } -@@ -749,7 +_,13 @@ +@@ -753,7 +_,13 @@ } public void onPlace(final Level level, final BlockPos pos, final BlockState oldState, final boolean movedByPiston) { @@ -155,7 +155,7 @@ } public void affectNeighborsAfterRemoval(final ServerLevel level, final BlockPos pos, final boolean movedByPiston) { -@@ -776,6 +_,7 @@ +@@ -780,6 +_,7 @@ public void spawnAfterBreak(final ServerLevel level, final BlockPos pos, final ItemStack tool, final boolean dropExperience) { this.getBlock().spawnAfterBreak(this.asState(), level, pos, tool, dropExperience); @@ -163,7 +163,7 @@ } public List getDrops(final LootParams.Builder params) { -@@ -860,11 +_,11 @@ +@@ -864,11 +_,11 @@ return this.getBlock() instanceof EntityBlock ? ((EntityBlock)this.getBlock()).getTicker(level, this.asState(), type) : null; } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/state/StateHolder.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/state/StateHolder.java.patch index 7770ed3eef7b..49ecb7933a4f 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/state/StateHolder.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/state/StateHolder.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/state/StateHolder.java +++ b/net/minecraft/world/level/block/state/StateHolder.java -@@ -142,7 +_,7 @@ +@@ -141,7 +_,7 @@ return length == 0 ? Stream.empty() : IntStream.range(0, length).mapToObj(i -> createValue(this.propertyKeys[i], this.propertyValues[i])); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/state/properties/IntegerProperty.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/state/properties/IntegerProperty.java.patch index 93d336613a43..7265148334e7 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/state/properties/IntegerProperty.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/state/properties/IntegerProperty.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/state/properties/IntegerProperty.java +++ b/net/minecraft/world/level/block/state/properties/IntegerProperty.java -@@ -28,8 +_,7 @@ +@@ -30,8 +_,7 @@ return this.values; } diff --git a/paper-server/patches/sources/net/minecraft/world/level/border/WorldBorder.java.patch b/paper-server/patches/sources/net/minecraft/world/level/border/WorldBorder.java.patch index 6a0b645686f7..3b42c770b6de 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/border/WorldBorder.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/border/WorldBorder.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/border/WorldBorder.java +++ b/net/minecraft/world/level/border/WorldBorder.java -@@ -37,6 +_,8 @@ +@@ -36,6 +_,8 @@ private double centerZ; private int absoluteMaxSize = 29999984; private WorldBorder.BorderExtent extent = new WorldBorder.StaticBorderExtent(5.999997E7F); @@ -9,7 +9,7 @@ public WorldBorder() { this(WorldBorder.Settings.DEFAULT); -@@ -58,6 +_,20 @@ +@@ -57,6 +_,20 @@ return this.isWithinBounds(pos.getMinBlockX(), pos.getMinBlockZ()) && this.isWithinBounds(pos.getMaxBlockX(), pos.getMaxBlockZ()); } @@ -30,7 +30,7 @@ public boolean isWithinBounds(final AABB aabb) { return this.isWithinBounds(aabb.minX, aabb.minZ, aabb.maxX - 1.0E-5F, aabb.maxZ - 1.0E-5F); } -@@ -161,7 +_,15 @@ +@@ -160,7 +_,15 @@ return this.centerZ; } @@ -47,7 +47,7 @@ this.centerX = x; this.centerZ = z; this.extent.onCenterChange(); -@@ -184,7 +_,18 @@ +@@ -183,7 +_,18 @@ return this.extent.getLerpTarget(); } @@ -67,7 +67,7 @@ this.extent = new WorldBorder.StaticBorderExtent(size); this.setDirty(); -@@ -193,7 +_,21 @@ +@@ -192,7 +_,21 @@ } } @@ -87,10 +87,10 @@ + ticks = event.getDurationTicks(); + } + // Paper end - Add worldborder events - this.extent = (WorldBorder.BorderExtent)(from == to - ? new WorldBorder.StaticBorderExtent(to) - : new WorldBorder.MovingBorderExtent(from, to, ticks, gameTime)); -@@ -209,6 +_,7 @@ + this.extent = from == to ? new WorldBorder.StaticBorderExtent(to) : new WorldBorder.MovingBorderExtent(from, to, ticks, gameTime); + this.setDirty(); + +@@ -206,6 +_,7 @@ } public void addListener(final BorderChangeListener listener) { @@ -98,7 +98,7 @@ this.listeners.add(listener); } -@@ -282,6 +_,12 @@ +@@ -279,6 +_,12 @@ } public void tick() { @@ -111,7 +111,7 @@ this.extent = this.extent.update(); } -@@ -302,6 +_,22 @@ +@@ -299,6 +_,22 @@ } } @@ -134,7 +134,7 @@ private interface BorderExtent { double getMinX(final float deltaPartialTick); -@@ -438,6 +_,7 @@ +@@ -433,6 +_,7 @@ this.previousSize = this.size; this.size = this.calculateSize(); if (this.lerpProgress <= 0L) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkGenerator.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkGenerator.java.patch index 44a2ccd05e44..495df6e567bc 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkGenerator.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkGenerator.java.patch @@ -11,7 +11,7 @@ } public Optional getTypeNameForDataFixer() { -@@ -127,11 +_,29 @@ +@@ -127,12 +_,30 @@ ); public @Nullable Pair> findNearestMapStructure( @@ -20,37 +20,38 @@ ) { if (SharedConstants.DEBUG_DISABLE_FEATURES) { return null; - } else { -+ // Paper start - StructuresLocateEvent -+ final org.bukkit.World bukkitWorld = level.getWorld(); -+ final org.bukkit.Location origin = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(pos, level); -+ final List apiStructures = wantedStructures.stream().map(org.bukkit.craftbukkit.generator.structure.CraftStructure::minecraftHolderToBukkit).toList(); -+ if (!apiStructures.isEmpty()) { -+ final io.papermc.paper.event.world.StructuresLocateEvent event = new io.papermc.paper.event.world.StructuresLocateEvent(bukkitWorld, origin, apiStructures, maxSearchRadius, createReference); -+ if (!event.callEvent()) { -+ return null; -+ } -+ if (event.getResult() != null) { -+ return Pair.of(io.papermc.paper.util.MCUtil.toBlockPos(event.getResult().pos()), org.bukkit.craftbukkit.generator.structure.CraftStructure.bukkitToMinecraftHolder(event.getResult().structure())); -+ } -+ pos = org.bukkit.craftbukkit.util.CraftLocation.toBlockPos(event.getOrigin()); -+ maxSearchRadius = event.getRadius(); -+ createReference = event.shouldFindUnexplored(); -+ wantedStructures = HolderSet.direct(org.bukkit.craftbukkit.generator.structure.CraftStructure::bukkitToMinecraftHolder, event.getStructures()); + } + ++ // Paper start - StructuresLocateEvent ++ final org.bukkit.World bukkitWorld = level.getWorld(); ++ final org.bukkit.Location origin = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(pos, level); ++ final List apiStructures = wantedStructures.stream().map(org.bukkit.craftbukkit.generator.structure.CraftStructure::minecraftHolderToBukkit).toList(); ++ if (!apiStructures.isEmpty()) { ++ final io.papermc.paper.event.world.StructuresLocateEvent event = new io.papermc.paper.event.world.StructuresLocateEvent(bukkitWorld, origin, apiStructures, maxSearchRadius, createReference); ++ if (!event.callEvent()) { ++ return null; + } -+ // Paper end - ChunkGeneratorStructureState generatorState = level.getChunkSource().getGeneratorState(); - Map>> placementScans = new Object2ObjectArrayMap<>(); ++ if (event.getResult() != null) { ++ return Pair.of(io.papermc.paper.util.MCUtil.toBlockPos(event.getResult().pos()), org.bukkit.craftbukkit.generator.structure.CraftStructure.bukkitToMinecraftHolder(event.getResult().structure())); ++ } ++ pos = org.bukkit.craftbukkit.util.CraftLocation.toBlockPos(event.getOrigin()); ++ maxSearchRadius = event.getRadius(); ++ createReference = event.shouldFindUnexplored(); ++ wantedStructures = HolderSet.direct(org.bukkit.craftbukkit.generator.structure.CraftStructure::bukkitToMinecraftHolder, event.getStructures()); ++ } ++ // Paper end + ChunkGeneratorStructureState generatorState = level.getChunkSource().getGeneratorState(); + Map>> placementScans = new Object2ObjectArrayMap<>(); -@@ -226,6 +_,7 @@ - BlockPos.MutableBlockPos structurePos = new BlockPos.MutableBlockPos(); +@@ -227,6 +_,7 @@ + BlockPos.MutableBlockPos structurePos = new BlockPos.MutableBlockPos(); - for (ChunkPos chunkPos : positions) { -+ if (!level.paperConfig().environment.locateStructuresOutsideWorldBorder && !level.getWorldBorder().isChunkInBounds(chunkPos.x(), chunkPos.z())) { continue; } // Paper - Bound treasure maps to world border - structurePos.set(SectionPos.sectionToBlockCoord(chunkPos.x(), 8), 32, SectionPos.sectionToBlockCoord(chunkPos.z(), 8)); - double distSqr = structurePos.distSqr(pos); - boolean isClosest = closestPos == null || distSqr < closest; -@@ -260,9 +_,12 @@ + for (ChunkPos chunkPos : positions) { ++ if (!level.paperConfig().environment.locateStructuresOutsideWorldBorder && !level.getWorldBorder().isChunkInBounds(chunkPos.x(), chunkPos.z())) continue; // Paper - Bound treasure maps to world border + structurePos.set(SectionPos.sectionToBlockCoord(chunkPos.x(), 8), 32, SectionPos.sectionToBlockCoord(chunkPos.z(), 8)); + double distSqr = structurePos.distSqr(pos); + boolean isClosest = closestPos == null || distSqr < closest; +@@ -258,9 +_,12 @@ for (int x = -radius; x <= radius; x++) { boolean xEdge = x == -radius || x == radius; @@ -66,7 +67,7 @@ int sectorX = chunkOriginX + spacing * x; int sectorZ = chunkOriginZ + spacing * z; ChunkPos chunkTarget = config.getPotentialStructureChunk(seed, sectorX, sectorZ); -@@ -314,7 +_,7 @@ +@@ -312,7 +_,7 @@ } } @@ -75,7 +76,7 @@ ChunkPos centerPos = chunk.getPos(); if (!SharedConstants.debugVoidTerrain(centerPos)) { SectionPos sectionPos = SectionPos.of(centerPos, level.getMinSectionY()); -@@ -388,7 +_,14 @@ +@@ -386,7 +_,14 @@ Supplier currentlyGenerating = () -> featureRegistry.getResourceKey(feature) .map(Object::toString) .orElseGet(feature::toString); @@ -91,7 +92,7 @@ try { level.setCurrentlyGenerating(currentlyGenerating); -@@ -416,6 +_,34 @@ +@@ -414,6 +_,34 @@ } } } @@ -126,7 +127,7 @@ private static BoundingBox getWritableArea(final ChunkAccess chunk) { ChunkPos chunkPos = chunk.getPos(); -@@ -495,7 +_,7 @@ +@@ -493,7 +_,7 @@ } } @@ -135,7 +136,7 @@ if (structures.size() == 1) { this.tryGenerateStructure( structures.get(0), -@@ -590,6 +_,14 @@ +@@ -588,6 +_,14 @@ biomePredicate ); if (start.isValid()) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java.patch index 7b2700f09563..99a18f95d099 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java.patch @@ -131,20 +131,20 @@ } public List> possibleStructureSets() { -@@ -115,7 +_,13 @@ - int spread = placement.spread(); - HolderSet preferredBiomes = placement.preferredBiomes(); - RandomSource random = RandomSource.create(); -+ // Paper start - Add missing structure set seed configs -+ if (this.conf.strongholdSeed != null && structureSet.is(net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.STRONGHOLDS)) { -+ random.setSeed(this.conf.strongholdSeed); -+ } else { -+ // Paper end - Add missing structure set seed configs - random.setSeed(this.concentricRingsSeed); -+ } // Paper - Add missing structure set seed configs - double angle = random.nextDouble() * Math.PI * 2.0; - int positionInCircle = 0; - int circle = 0; +@@ -116,7 +_,13 @@ + int spread = placement.spread(); + HolderSet preferredBiomes = placement.preferredBiomes(); + RandomSource random = RandomSource.create(); ++ // Paper start - Add missing structure set seed configs ++ if (this.conf.strongholdSeed != null && structureSet.is(net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.STRONGHOLDS)) { ++ random.setSeed(this.conf.strongholdSeed); ++ } else { ++ // Paper end - Add missing structure set seed configs + random.setSeed(this.concentricRingsSeed); ++ } // Paper - Add missing structure set seed configs + double angle = random.nextDouble() * Math.PI * 2.0; + int positionInCircle = 0; + int circle = 0; @@ -193,7 +_,7 @@ for (int testX = sourceX - range; testX <= sourceX + range; testX++) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/LevelChunk.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/LevelChunk.java.patch index 403cc1a43287..f95a91639fe4 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/LevelChunk.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/LevelChunk.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java -@@ -88,13 +_,21 @@ +@@ -87,13 +_,21 @@ }; private final Map tickersInLevel = Maps.newHashMap(); public boolean loaded; @@ -23,7 +23,7 @@ public LevelChunk(final Level level, final ChunkPos pos) { this(level, pos, UpgradeData.EMPTY, new LevelChunkTicks<>(), new LevelChunkTicks<>(), 0L, null, null, null); -@@ -112,7 +_,7 @@ +@@ -111,7 +_,7 @@ final @Nullable BlendingData blendingData ) { super(pos, upgradeData, level, level.palettedContainerFactory(), inhabitedTime, sections, blendingData); @@ -32,7 +32,7 @@ this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap<>(); for (Heightmap.Types type : Heightmap.Types.values()) { -@@ -164,6 +_,10 @@ +@@ -163,6 +_,10 @@ this.skyLightSources = protoChunk.skyLightSources; this.setLightCorrect(protoChunk.isLightCorrect()); this.markUnsaved(); @@ -43,7 +43,7 @@ } public void setUnsavedListener(final LevelChunk.UnsavedListener unsavedListener) { -@@ -172,6 +_,12 @@ +@@ -171,6 +_,12 @@ unsavedListener.setUnsaved(this.chunkPos); } } @@ -56,7 +56,7 @@ @Override public void markUnsaved() { -@@ -205,8 +_,28 @@ +@@ -204,8 +_,28 @@ : super.getListenerRegistry(section); } @@ -85,7 +85,7 @@ int x = pos.getX(); int y = pos.getY(); int z = pos.getZ(); -@@ -241,28 +_,42 @@ +@@ -240,28 +_,42 @@ } } @@ -120,8 +120,8 @@ return Fluids.EMPTY.defaultFluidState(); + /* // Paper - Perf: Optimise Chunk#getFluid - } catch (Throwable var7) { - CrashReport report = CrashReport.forThrowable(var7, "Getting fluid state"); + } catch (Throwable t) { + CrashReport report = CrashReport.forThrowable(t, "Getting fluid state"); CrashReportCategory category = report.addCategory("Block being got"); category.setDetail("Location", () -> CrashReportCategory.formatLocation(this, x, y, z)); throw new ReportedException(report); @@ -130,16 +130,16 @@ } @Override -@@ -323,7 +_,7 @@ - if (!section.getBlockState(localX, localY, localZ).is(newBlock)) { - return null; - } else { -- if (!this.level.isClientSide() && (flags & Block.UPDATE_SKIP_ON_PLACE) == 0) { -+ if (!this.level.isClientSide() && (flags & Block.UPDATE_SKIP_ON_PLACE) == 0 && (!this.level.captureBlockStates || newBlock instanceof net.minecraft.world.level.block.BaseEntityBlock)) { // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled. - state.onPlace(this.level, pos, oldState, movedByPiston); - } +@@ -325,7 +_,7 @@ + return null; + } + +- if (!this.level.isClientSide() && (flags & Block.UPDATE_SKIP_ON_PLACE) == 0) { ++ if (!this.level.isClientSide() && (flags & Block.UPDATE_SKIP_ON_PLACE) == 0 && (!this.level.captureBlockStates || newBlock instanceof net.minecraft.world.level.block.BaseEntityBlock)) { // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled. + state.onPlace(this.level, pos, oldState, movedByPiston); + } -@@ -369,7 +_,12 @@ +@@ -368,7 +_,12 @@ } public @Nullable BlockEntity getBlockEntity(final BlockPos pos, final LevelChunk.EntityCreationType creationType) { @@ -153,7 +153,7 @@ if (blockEntity == null) { CompoundTag tag = this.pendingBlockEntities.remove(pos); if (tag != null) { -@@ -424,7 +_,13 @@ +@@ -423,7 +_,13 @@ BlockPos pos = blockEntity.getBlockPos(); BlockState blockState = this.getBlockState(pos); if (!blockState.hasBlockEntity()) { @@ -168,7 +168,7 @@ } else { BlockState cachedBlockState = blockEntity.getBlockState(); if (blockState != cachedBlockState) { -@@ -471,6 +_,11 @@ +@@ -470,6 +_,11 @@ public void removeBlockEntity(final BlockPos pos) { if (this.isInLevel()) { BlockEntity removeThis = this.blockEntities.remove(pos); @@ -180,7 +180,7 @@ if (removeThis != null) { if (this.level instanceof ServerLevel serverLevel) { this.removeGameEventListener(removeThis, serverLevel); -@@ -514,6 +_,65 @@ +@@ -513,6 +_,65 @@ } } @@ -246,7 +246,7 @@ public boolean isEmpty() { return false; } -@@ -703,6 +_,7 @@ +@@ -702,6 +_,7 @@ } private void updateBlockEntityTicker(final T blockEntity) { @@ -254,39 +254,36 @@ BlockState state = blockEntity.getBlockState(); BlockEntityTicker ticker = state.getTicker(this.level, (BlockEntityType)blockEntity.getType()); if (ticker == null) { -@@ -752,23 +_,24 @@ +@@ -749,7 +_,11 @@ if (this.blockEntity.getType().isValid(blockState)) { this.ticker.tick(LevelChunk.this.level, this.blockEntity.getBlockPos(), blockState, this.blockEntity); this.loggedInvalidBlockState = false; - } else if (!this.loggedInvalidBlockState) { -- this.loggedInvalidBlockState = true; -- LevelChunk.LOGGER -- .warn( -- "Block entity {} @ {} state {} invalid for ticking:", -- LogUtils.defer(this::getType), -- LogUtils.defer(this::getPos), -- blockState -- ); -+ // Paper start - Remove the Block Entity if it's invalid ++ // Paper start - Remove the Block Entity if it's invalid + } else { + LevelChunk.this.removeBlockEntity(this.getPos()); + if (!this.loggedInvalidBlockState) { -+ this.loggedInvalidBlockState = true; -+ LevelChunk.LOGGER.warn("Block entity {} @ {} state {} invalid for ticking:", LogUtils.defer(this::getType), LogUtils.defer(this::getPos), blockState); -+ } + // Paper end - Remove the Block Entity if it's invalid + this.loggedInvalidBlockState = true; + LevelChunk.LOGGER + .warn( +@@ -758,14 +_,17 @@ + LogUtils.defer(this::getPos), + blockState + ); ++ } // Paper - Remove the Block Entity if it's invalid } profiler.pop(); - } catch (Throwable var5) { -- CrashReport report = CrashReport.forThrowable(var5, "Ticking block entity"); + } catch (Throwable t) { +- CrashReport report = CrashReport.forThrowable(t, "Ticking block entity"); - CrashReportCategory category = report.addCategory("Block entity being ticked"); - this.blockEntity.fillCrashReportCategory(category); - throw new ReportedException(report); + // Paper start - Prevent block entity and entity crashes + final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", io.papermc.paper.util.MCUtil.getLevelName(LevelChunk.this.getLevel()), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ()); -+ net.minecraft.server.MinecraftServer.LOGGER.error(msg, var5); -+ net.minecraft.world.level.chunk.LevelChunk.this.level.getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, var5))); // Paper - ServerExceptionEvent ++ LevelChunk.LOGGER.error(msg, t); ++ LevelChunk.this.level.getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, t))); // Paper - ServerExceptionEvent + LevelChunk.this.removeBlockEntity(this.getPos()); + // Paper end - Prevent block entity and entity crashes } diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/LevelChunkSection.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/LevelChunkSection.java.patch index 5d3e1faf88bf..9ee8636b937d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/LevelChunkSection.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/LevelChunkSection.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/chunk/LevelChunkSection.java +++ b/net/minecraft/world/level/chunk/LevelChunkSection.java -@@ -15,12 +_,12 @@ +@@ -14,12 +_,12 @@ public static final int SECTION_HEIGHT = 16; public static final int SECTION_SIZE = 4096; public static final int BIOME_CONTAINER_BITS = 2; @@ -15,7 +15,7 @@ private LevelChunkSection(final LevelChunkSection source) { this.nonEmptyBlockCount = source.nonEmptyBlockCount; -@@ -31,7 +_,7 @@ +@@ -30,7 +_,7 @@ this.biomes = source.biomes.copy(); } @@ -24,7 +24,7 @@ this.states = states; this.biomes = biomes; this.recalcBlockCounts(); -@@ -47,7 +_,7 @@ +@@ -46,7 +_,7 @@ } public FluidState getFluidState(final int sectionX, final int sectionY, final int sectionZ) { @@ -33,7 +33,7 @@ } public void acquire() { -@@ -203,6 +_,12 @@ +@@ -197,6 +_,12 @@ public Holder getNoiseBiome(final int quartX, final int quartY, final int quartZ) { return this.biomes.get(quartX, quartY, quartZ); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/PalettedContainer.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/PalettedContainer.java.patch index 072c43a99a1a..44cc80cd256d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/PalettedContainer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/PalettedContainer.java.patch @@ -35,8 +35,8 @@ + public synchronized T getAndSet(final int x, final int y, final int z, final T value) { // Paper - synchronize this.acquire(); - Object var5; -@@ -125,7 +_,7 @@ + try { +@@ -122,7 +_,7 @@ return this.data.palette.valueFor(oldId); } @@ -45,7 +45,7 @@ this.acquire(); try { -@@ -158,7 +_,7 @@ +@@ -155,7 +_,7 @@ allExistingEntries.forEach(state -> consumer.accept(palette.valueFor(state))); } @@ -54,7 +54,7 @@ this.acquire(); try { -@@ -173,7 +_,7 @@ +@@ -170,7 +_,7 @@ } @Override @@ -63,7 +63,7 @@ this.acquire(); try { -@@ -227,7 +_,7 @@ +@@ -224,7 +_,7 @@ } @Override @@ -71,4 +71,4 @@ + public synchronized PalettedContainerRO.PackedData pack(final Strategy strategy) { // Paper - synchronize this.acquire(); - PalettedContainerRO.PackedData var14; + try { diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/ProtoChunk.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/ProtoChunk.java.patch index 0b28e108703a..54d6c2d0331f 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/ProtoChunk.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/ProtoChunk.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/chunk/ProtoChunk.java +++ b/net/minecraft/world/level/chunk/ProtoChunk.java -@@ -90,14 +_,31 @@ +@@ -90,15 +_,32 @@ return new ChunkAccess.PackedTicks(this.blockTicks.pack(currentTick), this.fluidTicks.pack(currentTick)); } @@ -27,10 +27,11 @@ + // Paper end if (this.isOutsideBuildHeight(y)) { return Blocks.VOID_AIR.defaultBlockState(); - } else { - LevelChunkSection section = this.getSection(this.getSectionIndex(y)); -- return section.hasOnlyAir() ? Blocks.AIR.defaultBlockState() : section.getBlockState(pos.getX() & 15, y & 15, pos.getZ() & 15); -+ return section.hasOnlyAir() ? Blocks.AIR.defaultBlockState() : section.getBlockState(x & 15, y & 15, z & 15); // Paper } + + LevelChunkSection section = this.getSection(this.getSectionIndex(y)); +- return section.hasOnlyAir() ? Blocks.AIR.defaultBlockState() : section.getBlockState(pos.getX() & 15, y & 15, pos.getZ() & 15); ++ return section.hasOnlyAir() ? Blocks.AIR.defaultBlockState() : section.getBlockState(x & 15, y & 15, z & 15); // Paper } + @Override diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/RegionFile.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/RegionFile.java.patch index df53949c1abb..159743d931ed 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/RegionFile.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/RegionFile.java.patch @@ -1,43 +1,43 @@ --- a/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/net/minecraft/world/level/chunk/storage/RegionFile.java @@ -83,6 +_,14 @@ - if (offset != 0) { - int sectorNumber = getSectorNumber(offset); - int numSectors = getNumSectors(offset); -+ // Spigot start -+ if (numSectors == 255) { -+ // We're maxed out, so we need to read the proper length from the section -+ ByteBuffer realLen = ByteBuffer.allocate(4); -+ this.file.read(realLen, sectorNumber * 4096); -+ numSectors = (realLen.getInt(0) + 4) / 4096 + 1; -+ } -+ // Spigot end - if (sectorNumber < 2) { - LOGGER.warn("Region file {} has invalid sector at index: {}; sector {} overlaps with header", path, i, sectorNumber); - this.offsets.put(i, 0); + if (offset != 0) { + int sectorNumber = getSectorNumber(offset); + int numSectors = getNumSectors(offset); ++ // Spigot start ++ if (numSectors == 255) { ++ // We're maxed out, so we need to read the proper length from the section ++ ByteBuffer realLen = ByteBuffer.allocate(4); ++ this.file.read(realLen, sectorNumber * 4096); ++ numSectors = (realLen.getInt(0) + 4) / 4096 + 1; ++ } ++ // Spigot end + if (sectorNumber < 2) { + LOGGER.warn("Region file {} has invalid sector at index: {}; sector {} overlaps with header", path, i, sectorNumber); + this.offsets.put(i, 0); @@ -117,6 +_,13 @@ - } else { - int sectorNumber = getSectorNumber(offset); - int numSectors = getNumSectors(offset); -+ // Spigot start -+ if (numSectors == 255) { -+ ByteBuffer realLen = ByteBuffer.allocate(4); -+ this.file.read(realLen, sectorNumber * 4096); -+ numSectors = (realLen.getInt(0) + 4) / 4096 + 1; -+ } -+ // Spigot end - int sectorsLength = numSectors * 4096; - ByteBuffer buffer = ByteBuffer.allocate(sectorsLength); - this.file.read(buffer, sectorNumber * 4096); + + int sectorNumber = getSectorNumber(offset); + int numSectors = getNumSectors(offset); ++ // Spigot start ++ if (numSectors == 255) { ++ ByteBuffer realLen = ByteBuffer.allocate(4); ++ this.file.read(realLen, sectorNumber * 4096); ++ numSectors = (realLen.getInt(0) + 4) / 4096 + 1; ++ } ++ // Spigot end + int sectorsLength = numSectors * 4096; + ByteBuffer buffer = ByteBuffer.allocate(sectorsLength); + this.file.read(buffer, sectorNumber * 4096); @@ -258,6 +_,7 @@ - return true; - } - } catch (IOException var9) { -+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(var9); // Paper - ServerExceptionEvent - return false; - } + + return true; + } catch (IOException e) { ++ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(e); // Paper - ServerExceptionEvent + return false; } -@@ -329,6 +_,11 @@ + } +@@ -328,6 +_,11 @@ try (FileChannel extFile = FileChannel.open(tmpPath, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) { data.position(5); extFile.write(data); diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/RegionFileStorage.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/RegionFileStorage.java.patch index 1c6ee4a3c21b..da26ce43b89d 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/RegionFileStorage.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/RegionFileStorage.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -@@ -29,18 +_,20 @@ +@@ -29,26 +_,33 @@ this.info = info; } @@ -10,20 +10,20 @@ RegionFile region = this.regionCache.getAndMoveToFirst(key); if (region != null) { return region; - } else { -- if (this.regionCache.size() >= 256) { -+ int cacheSize = io.papermc.paper.configuration.GlobalConfiguration.get() == null ? 256 : io.papermc.paper.configuration.GlobalConfiguration.get().misc.regionFileCacheSize; // Paper - Sanitise RegionFileCache and make configurable - Config not available during initial FileFixerUpper run -+ if (this.regionCache.size() >= cacheSize) { // Paper - Sanitise RegionFileCache and make configurable - this.regionCache.removeLast().close(); - } - - FileUtil.createDirectoriesSafe(this.folder); - Path file = this.folder.resolve("r." + pos.getRegionX() + "." + pos.getRegionZ() + ".mca"); -+ if (existingOnly && !java.nio.file.Files.exists(file)) return null; // CraftBukkit - RegionFile newRegion = new RegionFile(this.info, file, this.folder, this.sync); - this.regionCache.putAndMoveToFirst(key, newRegion); - return newRegion; -@@ -48,7 +_,12 @@ + } + +- if (this.regionCache.size() >= 256) { ++ int cacheSize = io.papermc.paper.configuration.GlobalConfiguration.get() == null ? 256 : io.papermc.paper.configuration.GlobalConfiguration.get().misc.regionFileCacheSize; // Paper - Sanitise RegionFileCache and make configurable - Config not available during initial FileFixerUpper run ++ if (this.regionCache.size() >= cacheSize) { // Paper - Sanitise RegionFileCache and make configurable + this.regionCache.removeLast().close(); + } + + FileUtil.createDirectoriesSafe(this.folder); + Path file = this.folder.resolve("r." + pos.getRegionX() + "." + pos.getRegionZ() + ".mca"); ++ if (existingOnly && !java.nio.file.Files.exists(file)) return null; // CraftBukkit + RegionFile newRegion = new RegionFile(this.info, file, this.folder, this.sync); + this.regionCache.putAndMoveToFirst(key, newRegion); + return newRegion; } public @Nullable CompoundTag read(final ChunkPos pos) throws IOException { @@ -35,9 +35,9 @@ + } + // CraftBukkit end - CompoundTag var4; try (DataInputStream regionChunkInputStream = region.getChunkDataInputStream(pos)) { -@@ -63,7 +_,12 @@ + return regionChunkInputStream == null ? null : NbtIo.read(regionChunkInputStream); +@@ -56,7 +_,12 @@ } public void scanChunk(final ChunkPos pos, final StreamTagVisitor scanner) throws IOException { @@ -51,7 +51,7 @@ try (DataInputStream regionChunkInputStream = region.getChunkDataInputStream(pos)) { if (regionChunkInputStream != null) { -@@ -74,7 +_,7 @@ +@@ -67,7 +_,7 @@ protected void write(final ChunkPos pos, final @Nullable CompoundTag value) throws IOException { if (!SharedConstants.DEBUG_DONT_SAVE_WORLD) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SerializableChunkData.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SerializableChunkData.java.patch index 803a761358c2..16f33d810187 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SerializableChunkData.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SerializableChunkData.java.patch @@ -8,7 +8,7 @@ ) { private static final Codec>> BLOCK_TICKS_CODEC = SavedTick.codec(BuiltInRegistries.BLOCK.byNameCodec()).listOf(); private static final Codec>> FLUID_TICKS_CODEC = SavedTick.codec(BuiltInRegistries.FLUID.byNameCodec()).listOf(); -@@ -107,13 +_,39 @@ +@@ -107,6 +_,24 @@ public static final String BLOCK_LIGHT_TAG = "BlockLight"; public static final String SKY_LIGHT_TAG = "SkyLight"; @@ -33,48 +33,49 @@ public static SerializableChunkData parse( final LevelHeightAccessor levelHeight, final PalettedContainerFactory containerFactory, final CompoundTag chunkData ) { - if (chunkData.getString("Status").isEmpty()) { +@@ -114,7 +_,15 @@ return null; - } else { -- ChunkPos chunkPos = new ChunkPos(chunkData.getIntOr("xPos", 0), chunkData.getIntOr("zPos", 0)); -+ // Paper start - Do not let the server load chunks from newer versions -+ chunkData.getInt("DataVersion").ifPresent(dataVersion -> { -+ if (!JUST_CORRUPT_IT && dataVersion > CURRENT_DATA_VERSION) { -+ new RuntimeException("Server attempted to load chunk saved with newer version of minecraft! " + dataVersion + " > " + CURRENT_DATA_VERSION).printStackTrace(); -+ System.exit(1); -+ } -+ }); -+ // Paper end - Do not let the server load chunks from newer versions -+ ChunkPos chunkPos = new ChunkPos(chunkData.getIntOr("xPos", 0), chunkData.getIntOr("zPos", 0)); // Paper - guard against serializing mismatching coordinates; diff on change, see ChunkSerializer#getChunkCoordinate - long lastUpdateTime = chunkData.getLongOr("LastUpdate", 0L); - long inhabitedTime = chunkData.getLongOr("InhabitedTime", 0L); - ChunkStatus status = chunkData.read("Status", ChunkStatus.CODEC).orElse(ChunkStatus.EMPTY); -@@ -152,7 +_,7 @@ - CompoundTag structureData = chunkData.getCompoundOrEmpty("structures"); - ListTag sectionTags = chunkData.getListOrEmpty("sections"); - List sectionData = new ArrayList<>(sectionTags.size()); -- Codec>> biomesCodec = containerFactory.biomeContainerCodec(); -+ Codec>> biomesCodec = containerFactory.biomeContainerRWCodec(); // CraftBukkit - read/write - Codec> blockStatesCodec = containerFactory.blockStatesContainerCodec(); - - for (int i = 0; i < sectionTags.size(); i++) { -@@ -169,7 +_,7 @@ - .getOrThrow(SerializableChunkData.ChunkReadException::new) - ) - .orElseGet(containerFactory::createForBlockStates); -- PalettedContainerRO> biomes = sectionTag.getCompound("biomes") -+ PalettedContainer> biomes = sectionTag.getCompound("biomes") // CraftBukkit - read/write - .map( - container -> biomesCodec.parse(NbtOps.INSTANCE, container) - .promotePartial(msg -> logErrors(chunkPos, y, msg)) -@@ -206,6 +_,7 @@ - entities, - blockEntities, - structureData -+ , chunkData.get("ChunkBukkitValues") // CraftBukkit - ChunkBukkitValues - ); } + +- ChunkPos chunkPos = new ChunkPos(chunkData.getIntOr("xPos", 0), chunkData.getIntOr("zPos", 0)); ++ // Paper start - Do not let the server load chunks from newer versions ++ chunkData.getInt("DataVersion").ifPresent(dataVersion -> { ++ if (!JUST_CORRUPT_IT && dataVersion > CURRENT_DATA_VERSION) { ++ new RuntimeException("Server attempted to load chunk saved with newer version of minecraft! " + dataVersion + " > " + CURRENT_DATA_VERSION).printStackTrace(); ++ System.exit(1); ++ } ++ }); ++ // Paper end - Do not let the server load chunks from newer versions ++ ChunkPos chunkPos = new ChunkPos(chunkData.getIntOr("xPos", 0), chunkData.getIntOr("zPos", 0)); // Paper - guard against serializing mismatching coordinates; diff on change, see ChunkSerializer#getChunkCoordinate + long lastUpdateTime = chunkData.getLongOr("LastUpdate", 0L); + long inhabitedTime = chunkData.getLongOr("InhabitedTime", 0L); + ChunkStatus status = chunkData.read("Status", ChunkStatus.CODEC).orElse(ChunkStatus.EMPTY); +@@ -153,7 +_,7 @@ + CompoundTag structureData = chunkData.getCompoundOrEmpty("structures"); + ListTag sectionTags = chunkData.getListOrEmpty("sections"); + List sectionData = new ArrayList<>(sectionTags.size()); +- Codec>> biomesCodec = containerFactory.biomeContainerCodec(); ++ Codec>> biomesCodec = containerFactory.biomeContainerRWCodec(); // CraftBukkit - read/write + Codec> blockStatesCodec = containerFactory.blockStatesContainerCodec(); + + for (int i = 0; i < sectionTags.size(); i++) { +@@ -170,7 +_,7 @@ + .getOrThrow(SerializableChunkData.ChunkReadException::new) + ) + .orElseGet(containerFactory::createForBlockStates); +- PalettedContainerRO> biomes = sectionTag.getCompound("biomes") ++ PalettedContainer> biomes = sectionTag.getCompound("biomes") // CraftBukkit - read/write + .map( + container -> biomesCodec.parse(NbtOps.INSTANCE, container) + .promotePartial(msg -> logErrors(chunkPos, y, msg)) +@@ -207,6 +_,7 @@ + entities, + blockEntities, + structureData ++ , chunkData.get("ChunkBukkitValues") // CraftBukkit - ChunkBukkitValues + ); } + @@ -283,6 +_,12 @@ } } @@ -88,28 +89,28 @@ chunk.setLightCorrect(this.lightCorrect); EnumSet toPrime = EnumSet.noneOf(Heightmap.Types.class); -@@ -389,6 +_,12 @@ - CompoundTag structureData = packStructureData( - StructurePieceSerializationContext.fromLevel(level), pos, chunk.getAllStarts(), chunk.getAllReferences() - ); -+ // CraftBukkit start - store chunk persistent data in nbt -+ CompoundTag persistentDataContainer = null; -+ if (!chunk.persistentDataContainer.isEmpty()) { // SPIGOT-6814: Always save PDC to account for 1.17 to 1.18 chunk upgrading. -+ persistentDataContainer = chunk.persistentDataContainer.toTagCompound(); -+ } -+ // CraftBukkit end - return new SerializableChunkData( - level.palettedContainerFactory(), - pos, -@@ -408,6 +_,7 @@ - entities, - blockEntities, - structureData -+ , persistentDataContainer // CraftBukkit - persistentDataContainer - ); - } +@@ -388,6 +_,12 @@ + .map(shorts -> shorts != null && !shorts.isEmpty() ? new ShortArrayList(shorts) : null) + .toArray(ShortList[]::new); + CompoundTag structureData = packStructureData(StructurePieceSerializationContext.fromLevel(level), pos, chunk.getAllStarts(), chunk.getAllReferences()); ++ // CraftBukkit start - store chunk persistent data in nbt ++ CompoundTag persistentDataContainer = null; ++ if (!chunk.persistentDataContainer.isEmpty()) { // SPIGOT-6814: Always save PDC to account for 1.17 to 1.18 chunk upgrading. ++ persistentDataContainer = chunk.persistentDataContainer.toTagCompound(); ++ } ++ // CraftBukkit end + return new SerializableChunkData( + level.palettedContainerFactory(), + pos, +@@ -407,6 +_,7 @@ + entities, + blockEntities, + structureData ++ , persistentDataContainer // CraftBukkit - persistentDataContainer + ); } -@@ -475,6 +_,11 @@ + +@@ -473,6 +_,11 @@ this.heightmaps.forEach((type, data) -> heightmapsTag.put(type.getSerializationKey(), new LongArrayTag(data))); tag.put("Heightmaps", heightmapsTag); tag.put("structures", this.structureData); @@ -121,7 +122,7 @@ return tag; } -@@ -558,6 +_,12 @@ +@@ -556,6 +_,12 @@ } else { StructureStart start = StructureStart.loadStaticStart(context, startsTag.getCompoundOrEmpty(key), seed); if (start != null) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java.patch index 1de77966b738..33a6fe07c51a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/storage/SimpleRegionStorage.java.patch @@ -21,29 +21,29 @@ } public CompoundTag upgradeChunkTag(CompoundTag chunkTag, final int defaultVersion, final @Nullable CompoundTag dataFixContextTag, final int targetVersion) { -@@ -53,8 +_,25 @@ - return chunkTag; - } else { - try { -+ // Spigot start - SPIGOT-6806: Quick and dirty way to prevent below zero generation in old chunks, by setting the status to heightmap instead of empty -+ boolean stopBelowZero = false; -+ final boolean chunkStorage = this.dataFixType == net.minecraft.util.datafix.DataFixTypes.CHUNK; -+ if (chunkStorage) { -+ final boolean belowZeroGenerationInExistingChunks = (this instanceof net.minecraft.server.level.ChunkMap chunkMap) -+ ? chunkMap.level.spigotConfig.belowZeroGenerationInExistingChunks -+ : org.spigotmc.SpigotConfig.belowZeroGenerationInExistingChunks; -+ if (version <= 2730 && !belowZeroGenerationInExistingChunks) { -+ stopBelowZero = "full".equals(chunkTag.getCompound("Level").flatMap(level -> level.getString("Status")).orElse(null)); -+ } -+ } -+ // Spigot end - injectDatafixingContext(chunkTag, dataFixContextTag); - chunkTag = this.dataFixType.update(this.fixerUpper, chunkTag, version, targetVersion); -+ // Spigot start -+ if (stopBelowZero) { -+ chunkTag.putString("Status", net.minecraft.core.registries.BuiltInRegistries.CHUNK_STATUS.getKey(net.minecraft.world.level.chunk.status.ChunkStatus.SPAWN).toString()); +@@ -54,8 +_,25 @@ + } + + try { ++ // Spigot start - SPIGOT-6806: Quick and dirty way to prevent below zero generation in old chunks, by setting the status to heightmap instead of empty ++ boolean stopBelowZero = false; ++ final boolean chunkStorage = this.dataFixType == net.minecraft.util.datafix.DataFixTypes.CHUNK; ++ if (chunkStorage) { ++ final boolean belowZeroGenerationInExistingChunks = (this instanceof net.minecraft.server.level.ChunkMap chunkMap) ++ ? chunkMap.level.spigotConfig.belowZeroGenerationInExistingChunks ++ : org.spigotmc.SpigotConfig.belowZeroGenerationInExistingChunks; ++ if (version <= 2730 && !belowZeroGenerationInExistingChunks) { ++ stopBelowZero = "full".equals(chunkTag.getCompound("Level").flatMap(level -> level.getString("Status")).orElse(null)); + } -+ // Spigot end - removeDatafixingContext(chunkTag); - NbtUtils.addDataVersion(chunkTag, targetVersion); - return chunkTag; ++ } ++ // Spigot end + injectDatafixingContext(chunkTag, dataFixContextTag); + chunkTag = this.dataFixType.update(this.fixerUpper, chunkTag, version, targetVersion); ++ // Spigot start ++ if (stopBelowZero) { ++ chunkTag.putString("Status", net.minecraft.core.registries.BuiltInRegistries.CHUNK_STATUS.getKey(net.minecraft.world.level.chunk.status.ChunkStatus.SPAWN).toString()); ++ } ++ // Spigot end + removeDatafixingContext(chunkTag); + NbtUtils.addDataVersion(chunkTag, targetVersion); + return chunkTag; diff --git a/paper-server/patches/sources/net/minecraft/world/level/entity/PersistentEntitySectionManager.java.patch b/paper-server/patches/sources/net/minecraft/world/level/entity/PersistentEntitySectionManager.java.patch index 1008a9bc4535..c38a5221cf21 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/entity/PersistentEntitySectionManager.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/entity/PersistentEntitySectionManager.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/entity/PersistentEntitySectionManager.java +++ b/net/minecraft/world/level/entity/PersistentEntitySectionManager.java -@@ -53,6 +_,16 @@ +@@ -52,6 +_,16 @@ this.entityGetter = new LevelEntityGetterAdapter<>(this.visibleEntityStorage, this.sectionStorage); } @@ -17,7 +17,7 @@ private void removeSectionIfEmpty(final long sectionPos, final EntitySection section) { if (section.isEmpty()) { this.sectionStorage.remove(sectionPos); -@@ -60,6 +_,7 @@ +@@ -59,6 +_,7 @@ } private boolean addEntityUuid(final T entity) { @@ -25,7 +25,7 @@ if (!this.knownUuids.add(entity.getUUID())) { LOGGER.warn("UUID of added entity already exists: {}", entity); return false; -@@ -73,6 +_,17 @@ +@@ -72,6 +_,17 @@ } private boolean addEntity(final T entity, final boolean loaded) { @@ -42,8 +42,8 @@ + // Paper end - chunk system hooks if (!this.addEntityUuid(entity)) { return false; - } else { -@@ -114,19 +_,23 @@ + } +@@ -113,19 +_,23 @@ } private void startTicking(final T entity) { @@ -67,7 +67,7 @@ this.callbacks.onTrackingEnd(entity); this.visibleEntityStorage.remove(entity); } -@@ -137,6 +_,7 @@ +@@ -136,6 +_,7 @@ } public void updateChunkStatus(final ChunkPos pos, final Visibility chunkStatus) { @@ -75,7 +75,7 @@ long chunkPosKey = pos.pack(); if (chunkStatus == Visibility.HIDDEN) { this.chunkVisibility.remove(chunkPosKey); -@@ -170,6 +_,7 @@ +@@ -169,6 +_,7 @@ } public void ensureChunkQueuedForLoad(final long chunkPos) { @@ -83,7 +83,7 @@ PersistentEntitySectionManager.ChunkLoadStatus chunkLoadStatus = this.chunkLoadStatuses.get(chunkPos); if (chunkLoadStatus == PersistentEntitySectionManager.ChunkLoadStatus.FRESH) { this.requestChunkLoad(chunkPos); -@@ -177,6 +_,11 @@ +@@ -176,6 +_,11 @@ } private boolean storeChunkSections(final long chunkPos, final Consumer savedEntityVisitor) { @@ -96,22 +96,22 @@ if (chunkLoadStatus == PersistentEntitySectionManager.ChunkLoadStatus.PENDING) { return false; @@ -187,6 +_,7 @@ - .collect(Collectors.toList()); - if (rootEntitiesToSave.isEmpty()) { - if (chunkLoadStatus == PersistentEntitySectionManager.ChunkLoadStatus.LOADED) { -+ if (callEvent) org.bukkit.craftbukkit.event.CraftEventFactory.callEntitiesUnloadEvent(((net.minecraft.world.level.chunk.storage.EntityStorage) this.permanentStorage).level, ChunkPos.unpack(chunkPos), ImmutableList.of()); // CraftBukkit - this.permanentStorage.storeEntities(new ChunkEntities<>(ChunkPos.unpack(chunkPos), ImmutableList.of())); - } + .collect(Collectors.toList()); + if (rootEntitiesToSave.isEmpty()) { + if (chunkLoadStatus == PersistentEntitySectionManager.ChunkLoadStatus.LOADED) { ++ if (callEvent) org.bukkit.craftbukkit.event.CraftEventFactory.callEntitiesUnloadEvent(((net.minecraft.world.level.chunk.storage.EntityStorage) this.permanentStorage).level, ChunkPos.unpack(chunkPos), ImmutableList.of()); // CraftBukkit + this.permanentStorage.storeEntities(new ChunkEntities<>(ChunkPos.unpack(chunkPos), ImmutableList.of())); + } @@ -195,6 +_,7 @@ - this.requestChunkLoad(chunkPos); - return false; - } else { -+ if (callEvent) org.bukkit.craftbukkit.event.CraftEventFactory.callEntitiesUnloadEvent(((net.minecraft.world.level.chunk.storage.EntityStorage) this.permanentStorage).level, ChunkPos.unpack(chunkPos), rootEntitiesToSave.stream().map(entity -> (Entity) entity).collect(Collectors.toList())); // CraftBukkit - this.permanentStorage.storeEntities(new ChunkEntities<>(ChunkPos.unpack(chunkPos), rootEntitiesToSave)); - rootEntitiesToSave.forEach(savedEntityVisitor); - return true; -@@ -203,6 +_,7 @@ + this.requestChunkLoad(chunkPos); + return false; + } else { ++ if (callEvent) org.bukkit.craftbukkit.event.CraftEventFactory.callEntitiesUnloadEvent(((net.minecraft.world.level.chunk.storage.EntityStorage) this.permanentStorage).level, ChunkPos.unpack(chunkPos), rootEntitiesToSave.stream().map(entity -> (Entity) entity).collect(Collectors.toList())); // CraftBukkit + this.permanentStorage.storeEntities(new ChunkEntities<>(ChunkPos.unpack(chunkPos), rootEntitiesToSave)); + rootEntitiesToSave.forEach(savedEntityVisitor); + return true; +@@ -202,6 +_,7 @@ } private void requestChunkLoad(final long chunkKey) { @@ -119,7 +119,7 @@ this.chunkLoadStatuses.put(chunkKey, PersistentEntitySectionManager.ChunkLoadStatus.PENDING); ChunkPos pos = ChunkPos.unpack(chunkKey); this.permanentStorage.loadEntities(pos).thenAccept(this.loadingInbox::add).exceptionally(t -> { -@@ -212,7 +_,8 @@ +@@ -211,7 +_,8 @@ } private boolean processChunkUnload(final long chunkKey) { @@ -128,8 +128,8 @@ + boolean storeSuccessful = this.storeChunkSections(chunkKey, entity -> entity.getPassengersAndSelf().forEach(this::unloadEntity), true); // CraftBukkit - add boolean for event call if (!storeSuccessful) { return false; - } else { -@@ -222,7 +_,7 @@ + } +@@ -221,7 +_,7 @@ } private void unloadEntity(final EntityAccess e) { @@ -138,7 +138,7 @@ e.setLevelCallback(EntityInLevelCallback.NULL); } -@@ -231,14 +_,20 @@ +@@ -230,14 +_,20 @@ } public void processPendingLoads() { @@ -159,7 +159,7 @@ this.processPendingLoads(); this.processUnloads(); } -@@ -256,6 +_,7 @@ +@@ -255,6 +_,7 @@ } public void autoSave() { @@ -167,7 +167,7 @@ this.getAllChunksToSave().forEach(chunkKey -> { boolean shouldUnload = this.chunkVisibility.get(chunkKey) == Visibility.HIDDEN; if (shouldUnload) { -@@ -267,6 +_,7 @@ +@@ -266,6 +_,7 @@ } public void saveAll() { @@ -175,7 +175,7 @@ LongSet chunksToSave = this.getAllChunksToSave(); while (!chunksToSave.isEmpty()) { -@@ -283,7 +_,13 @@ +@@ -282,7 +_,13 @@ @Override public void close() throws IOException { @@ -190,7 +190,7 @@ this.permanentStorage.close(); } -@@ -386,6 +_,7 @@ +@@ -383,6 +_,7 @@ BlockPos pos = this.entity.blockPosition(); long newSectionPos = SectionPos.asLong(pos); if (newSectionPos != this.currentSectionKey) { @@ -198,7 +198,7 @@ Visibility previousStatus = this.currentSection.getStatus(); if (!this.currentSection.remove(this.entity)) { PersistentEntitySectionManager.LOGGER -@@ -433,6 +_,7 @@ +@@ -430,6 +_,7 @@ @Override public void onRemove(final Entity.RemovalReason reason) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java.patch b/paper-server/patches/sources/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java.patch index e102937119a9..ed6d7d93e481 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java.patch @@ -9,19 +9,19 @@ ExtraCodecs.NON_NEGATIVE_INT.fieldOf("event_delay").orElse(0).forGetter(VibrationSystem.Data::getTravelTimeInTicks) ) .apply( -@@ -219,7 +_,14 @@ - return false; - } else { - Vec3 destination = listenerSourcePos.get(); -- if (!user.canReceiveVibration(level, BlockPos.containing(sourcePosition), event, context)) { -+ // CraftBukkit start -+ boolean defaultCancel = !user.canReceiveVibration(level, BlockPos.containing(sourcePosition), event, context); -+ Entity entity = context.sourceEntity(); -+ org.bukkit.event.block.BlockReceiveGameEvent event1 = new org.bukkit.event.block.BlockReceiveGameEvent(org.bukkit.craftbukkit.CraftGameEvent.minecraftHolderToBukkit(event), org.bukkit.craftbukkit.block.CraftBlock.at(level, BlockPos.containing(sourcePosition)), (entity == null) ? null : entity.getBukkitEntity()); -+ event1.setCancelled(defaultCancel); -+ level.getCraftServer().getPluginManager().callEvent(event1); -+ if (event1.isCancelled()) { -+ // CraftBukkit end - return false; - } else if (isOccluded(level, sourcePosition, destination)) { - return false; +@@ -223,7 +_,14 @@ + } + + Vec3 destination = listenerSourcePos.get(); +- if (!user.canReceiveVibration(level, BlockPos.containing(sourcePosition), event, context)) { ++ // CraftBukkit start ++ boolean defaultCancel = !user.canReceiveVibration(level, BlockPos.containing(sourcePosition), event, context); ++ Entity entity = context.sourceEntity(); ++ org.bukkit.event.block.BlockReceiveGameEvent event1 = new org.bukkit.event.block.BlockReceiveGameEvent(org.bukkit.craftbukkit.CraftGameEvent.minecraftHolderToBukkit(event), org.bukkit.craftbukkit.block.CraftBlock.at(level, BlockPos.containing(sourcePosition)), (entity == null) ? null : entity.getBukkitEntity()); ++ event1.setCancelled(defaultCancel); ++ level.getCraftServer().getPluginManager().callEvent(event1); ++ if (event1.isCancelled()) { ++ // CraftBukkit end + return false; + } + diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/PatrolSpawner.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/PatrolSpawner.java.patch index 5bbe28c783cf..126c0f28ad40 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/PatrolSpawner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/PatrolSpawner.java.patch @@ -59,12 +59,12 @@ if (!player.isSpectator()) { if (!level.isCloseToVillage(player.blockPosition(), 2)) { int x = (24 + random.nextInt(24)) * (random.nextBoolean() ? -1 : 1); -@@ -80,7 +_,7 @@ +@@ -83,7 +_,7 @@ - mob.setPos(pos.getX(), pos.getY(), pos.getZ()); - mob.finalizeSpawn(level, level.getCurrentDifficultyAt(pos), EntitySpawnReason.PATROL, null); -- level.addFreshEntityWithPassengers(mob); -+ level.addFreshEntityWithPassengers(mob, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.PATROL); // CraftBukkit - return true; - } else { - return false; + mob.setPos(pos.getX(), pos.getY(), pos.getZ()); + mob.finalizeSpawn(level, level.getCurrentDifficultyAt(pos), EntitySpawnReason.PATROL, null); +- level.addFreshEntityWithPassengers(mob); ++ level.addFreshEntityWithPassengers(mob, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.PATROL); // CraftBukkit + return true; + } else { + return false; diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/StructureCheck.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/StructureCheck.java.patch index f3f18c1d4f9d..52b470ddc5e9 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/StructureCheck.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/StructureCheck.java.patch @@ -39,12 +39,12 @@ public StructureCheckResult checkStart(final ChunkPos pos, final Structure structure, final StructurePlacement placement, final boolean requireUnreferenced) { long posKey = pos.pack(); Object2IntMap cachedResult = this.loadedChunks.get(posKey); -@@ -86,7 +_,7 @@ - StructureCheckResult storageCheckResult = this.tryLoadFromStorage(pos, structure, requireUnreferenced, posKey); - if (storageCheckResult != null) { - return storageCheckResult; -- } else if (!placement.applyAdditionalChunkRestrictions(pos.x(), pos.z(), this.seed)) { -+ } else if (!placement.applyAdditionalChunkRestrictions(pos.x(), pos.z(), this.seed, this.getSaltOverride(structure))) { // Paper - add missing structure seed configs - return StructureCheckResult.START_NOT_PRESENT; - } else { - boolean isFeatureChunk = this.featureChecks +@@ -89,7 +_,7 @@ + return storageCheckResult; + } + +- if (!placement.applyAdditionalChunkRestrictions(pos.x(), pos.z(), this.seed)) { ++ if (!placement.applyAdditionalChunkRestrictions(pos.x(), pos.z(), this.seed, this.getSaltOverride(structure))) { // Paper - add missing structure seed configs + return StructureCheckResult.START_NOT_PRESENT; + } + diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java.patch index fa848bf4d8da..d5b22b6c9239 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java.patch @@ -80,7 +80,7 @@ + boolean shouldGenerate(long seed, final int salt, final int sourceX, final int sourceZ, float probability, final @org.jspecify.annotations.Nullable Integer saltOverride); // Paper - Add missing structure set seed configs } - public static enum FrequencyReductionMethod implements StringRepresentable { + public enum FrequencyReductionMethod implements StringRepresentable { @@ -167,8 +_,8 @@ this.reducer = reducer; } diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/EndCityPieces.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/EndCityPieces.java.patch index c687c69a4d8c..087141d8c5ba 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/EndCityPieces.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/EndCityPieces.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/levelgen/structure/structures/EndCityPieces.java +++ b/net/minecraft/world/level/levelgen/structure/structures/EndCityPieces.java -@@ -410,7 +_,10 @@ +@@ -411,7 +_,10 @@ if (markerId.startsWith("Chest")) { BlockPos chestPosition = position.below(); if (chunkBB.isInside(chestPosition)) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java.patch index 07f0395eff24..67381ccb62dc 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java +++ b/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java -@@ -427,10 +_,13 @@ +@@ -429,10 +_,13 @@ BlockPos pos = this.getWorldPos(1, 0, newZ); if (chunkBB.isInside(pos) && this.isInterior(level, 1, 0, newZ, chunkBB)) { this.hasPlacedSpider = true; diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/NetherFortressPieces.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/NetherFortressPieces.java.patch index 0b5accdd428d..760e4631e435 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/NetherFortressPieces.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/NetherFortressPieces.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/levelgen/structure/structures/NetherFortressPieces.java +++ b/net/minecraft/world/level/levelgen/structure/structures/NetherFortressPieces.java -@@ -1194,10 +_,13 @@ +@@ -1174,10 +_,13 @@ BlockPos pos = this.getWorldPos(3, 5, 5); if (chunkBB.isInside(pos)) { this.hasPlacedSpawner = true; diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/StrongholdPieces.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/StrongholdPieces.java.patch index 0c701f0b2de2..5c5114538c68 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/StrongholdPieces.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/structures/StrongholdPieces.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/levelgen/structure/structures/StrongholdPieces.java +++ b/net/minecraft/world/level/levelgen/structure/structures/StrongholdPieces.java -@@ -898,10 +_,13 @@ +@@ -900,10 +_,13 @@ BlockPos pos = this.getWorldPos(5, 3, 6); if (chunkBB.isInside(pos)) { this.hasPlacedSpawner = true; diff --git a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java.patch b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java.patch index 7dda6e8c0a52..6a0fc5b30501 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java.patch @@ -11,7 +11,7 @@ public Vec3i getSize() { return this.size; -@@ -251,7 +_,7 @@ +@@ -249,7 +_,7 @@ } public boolean placeInWorld( @@ -20,79 +20,78 @@ final BlockPos position, final BlockPos referencePos, final StructurePlaceSettings settings, -@@ -261,6 +_,19 @@ - if (this.palettes.isEmpty()) { +@@ -260,6 +_,19 @@ return false; - } else { -+ // CraftBukkit start -+ // We only want the TransformerLevelAccessor at certain locations because in here are many "block update" calls that shouldn't be transformed -+ ServerLevelAccessor wrappedAccessor = level; -+ org.bukkit.craftbukkit.util.CraftStructureTransformer structureTransformer = null; -+ if (wrappedAccessor instanceof org.bukkit.craftbukkit.util.TransformerLevelAccessor transformerAccessor) { -+ level = transformerAccessor.getDelegate(); -+ structureTransformer = transformerAccessor.getStructureTransformer(); -+ // The structureTransformer is not needed if we can not transform blocks therefore we can save a little bit of performance doing this -+ if (structureTransformer != null && !structureTransformer.canTransformBlocks()) { -+ structureTransformer = null; -+ } + } + ++ // CraftBukkit start ++ // We only want the TransformerLevelAccessor at certain locations because in here are many "block update" calls that shouldn't be transformed ++ ServerLevelAccessor wrappedAccessor = level; ++ org.bukkit.craftbukkit.util.CraftStructureTransformer structureTransformer = null; ++ if (wrappedAccessor instanceof org.bukkit.craftbukkit.util.TransformerLevelAccessor transformerAccessor) { ++ level = transformerAccessor.getDelegate(); ++ structureTransformer = transformerAccessor.getStructureTransformer(); ++ // The structureTransformer is not needed if we can not transform blocks therefore we can save a little bit of performance doing this ++ if (structureTransformer != null && !structureTransformer.canTransformBlocks()) { ++ structureTransformer = null; + } -+ // CraftBukkit end - List blockInfoList = settings.getRandomPalette(this.palettes, position).blocks(); - if ((!blockInfoList.isEmpty() || !settings.isIgnoreEntities() && !this.entityInfoList.isEmpty()) - && this.size.getX() >= 1 -@@ -288,6 +_,20 @@ - level.setBlock(blockPos, Blocks.BARRIER.defaultBlockState(), Block.UPDATE_SKIP_ALL_SIDEEFFECTS | Block.UPDATE_NONE); - } ++ } ++ // CraftBukkit end + List blockInfoList = settings.getRandomPalette(this.palettes, position).blocks(); + if ((!blockInfoList.isEmpty() || !settings.isIgnoreEntities() && !this.entityInfoList.isEmpty()) + && this.size.getX() >= 1 +@@ -287,6 +_,20 @@ + level.setBlock(blockPos, Blocks.BARRIER.defaultBlockState(), Block.UPDATE_SKIP_ALL_SIDEEFFECTS | Block.UPDATE_NONE); + } -+ // CraftBukkit start -+ if (structureTransformer != null) { -+ org.bukkit.craftbukkit.block.CraftBlockState craftBlockState = (org.bukkit.craftbukkit.block.CraftBlockState) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(level, blockPos, state, null); -+ if (blockInfo.nbt != null && craftBlockState instanceof org.bukkit.craftbukkit.block.CraftBlockEntityState entityState) { -+ entityState.loadData(blockInfo.nbt); -+ if (craftBlockState instanceof org.bukkit.craftbukkit.block.CraftLootable craftLootable) { -+ craftLootable.setSeed(random.nextLong()); -+ } ++ // CraftBukkit start ++ if (structureTransformer != null) { ++ org.bukkit.craftbukkit.block.CraftBlockState craftBlockState = (org.bukkit.craftbukkit.block.CraftBlockState) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(level, blockPos, state, null); ++ if (blockInfo.nbt != null && craftBlockState instanceof org.bukkit.craftbukkit.block.CraftBlockEntityState entityState) { ++ entityState.loadData(blockInfo.nbt); ++ if (craftBlockState instanceof org.bukkit.craftbukkit.block.CraftLootable craftLootable) { ++ craftLootable.setSeed(random.nextLong()); + } -+ craftBlockState = structureTransformer.transformCraftState(craftBlockState); -+ state = craftBlockState.getHandle(); -+ blockInfo = new StructureTemplate.StructureBlockInfo(blockPos, state, (craftBlockState instanceof org.bukkit.craftbukkit.block.CraftBlockEntityState craftBlockEntityState ? craftBlockEntityState.getSnapshotNBT() : null)); + } -+ // CraftBukkit end - if (level.setBlock(blockPos, state, updateMode)) { - minX = Math.min(minX, blockPos.getX()); - minY = Math.min(minY, blockPos.getY()); -@@ -299,7 +_,7 @@ - if (blockInfo.nbt != null) { - BlockEntity blockEntity = level.getBlockEntity(blockPos); - if (blockEntity != null) { -- if (!SharedConstants.DEBUG_STRUCTURE_EDIT_MODE && blockEntity instanceof RandomizableContainer) { -+ if (structureTransformer == null && !SharedConstants.DEBUG_STRUCTURE_EDIT_MODE && blockEntity instanceof RandomizableContainer) { // CraftBukkit - only process if don't have a transformer access (Was already set above) - SPIGOT-7520: Use structureTransformer as check, so that it is the same as above - blockInfo.nbt.putLong("LootTableSeed", random.nextLong()); - } - -@@ -384,7 +_,11 @@ - if (blockInfox.getSecond() != null) { ++ craftBlockState = structureTransformer.transformCraftState(craftBlockState); ++ state = craftBlockState.getHandle(); ++ blockInfo = new StructureTemplate.StructureBlockInfo(blockPos, state, (craftBlockState instanceof org.bukkit.craftbukkit.block.CraftBlockEntityState craftBlockEntityState ? craftBlockEntityState.getSnapshotNBT() : null)); ++ } ++ // CraftBukkit end + if (level.setBlock(blockPos, state, updateMode)) { + minX = Math.min(minX, blockPos.getX()); + minY = Math.min(minY, blockPos.getY()); +@@ -298,7 +_,7 @@ + if (blockInfo.nbt != null) { BlockEntity blockEntity = level.getBlockEntity(blockPos); if (blockEntity != null) { -- blockEntity.setChanged(); -+ // Paper start - Fix NBT pieces overriding a block entity during worldgen deadlock -+ if (!(level instanceof net.minecraft.world.level.WorldGenLevel)) { -+ blockEntity.setChanged(); -+ } -+ // Paper end - Fix NBT pieces overriding a block entity during worldgen deadlock - } +- if (!SharedConstants.DEBUG_STRUCTURE_EDIT_MODE && blockEntity instanceof RandomizableContainer) { ++ if (structureTransformer == null && !SharedConstants.DEBUG_STRUCTURE_EDIT_MODE && blockEntity instanceof RandomizableContainer) { // CraftBukkit - only process if don't have a transformer access (Was already set above) - SPIGOT-7520: Use structureTransformer as check, so that it is the same as above + blockInfo.nbt.putLong("LootTableSeed", random.nextLong()); + } + +@@ -383,7 +_,11 @@ + if (blockInfo.getSecond() != null) { + BlockEntity blockEntity = level.getBlockEntity(blockPos); + if (blockEntity != null) { ++ // Paper start - Fix NBT pieces overriding a block entity during worldgen deadlock ++ if (!(level instanceof net.minecraft.world.level.WorldGenLevel)) { + blockEntity.setChanged(); ++ } ++ // Paper end - Fix NBT pieces overriding a block entity during worldgen deadlock } } -@@ -392,7 +_,7 @@ + } +@@ -391,7 +_,7 @@ - if (!settings.isIgnoreEntities()) { - this.placeEntities( -- level, -+ wrappedAccessor, // CraftBukkit - position, - settings.getMirror(), - settings.getRotation(), -@@ -512,14 +_,17 @@ + if (!settings.isIgnoreEntities()) { + this.placeEntities( +- level, ++ wrappedAccessor, // CraftBukkit + position, + settings.getMirror(), + settings.getRotation(), +@@ -510,14 +_,17 @@ }); } } @@ -102,20 +101,20 @@ private static Optional createEntityIgnoreException(final ProblemReporter reporter, final ServerLevelAccessor level, final CompoundTag tag) { - try { - return EntityType.create(TagValueInput.create(reporter, level.registryAccess(), tag), level.getLevel(), EntitySpawnReason.STRUCTURE); -- } catch (Exception var4) { +- } catch (Exception ignored) { - return Optional.empty(); - } + // CraftBukkit start + // try { + return EntityType.create(TagValueInput.create(reporter, level.registryAccess(), tag), level.getLevel(), EntitySpawnReason.STRUCTURE, true); // Paper - Don't fire sync event during generation -+ // } catch (Exception var4) { ++ // } catch (Exception ignored) { + // return Optional.empty(); + // } + // CraftBukkit end } public Vec3i getSize(final Rotation rotation) { -@@ -710,6 +_,11 @@ +@@ -708,6 +_,11 @@ tag.put("entities", entityList); tag.put("size", this.newIntegerList(this.size.getX(), this.size.getY(), this.size.getZ())); @@ -127,7 +126,7 @@ return NbtUtils.addCurrentDataVersion(tag); } -@@ -735,6 +_,11 @@ +@@ -733,6 +_,11 @@ BlockPos blockPos = new BlockPos(blockPosTag.getIntOr(0, 0), blockPosTag.getIntOr(1, 0), blockPosTag.getIntOr(2, 0)); entityTag.getCompound("nbt").ifPresent(nbt -> this.entityInfoList.add(new StructureTemplate.StructureEntityInfo(pos, blockPos, nbt))); }); @@ -139,7 +138,7 @@ } private void loadPalette(final HolderGetter blockLookup, final ListTag paletteList, final ListTag blockList) { -@@ -834,7 +_,7 @@ +@@ -832,7 +_,7 @@ public static final class Palette { private final List blocks; diff --git a/paper-server/patches/sources/net/minecraft/world/level/material/FlowingFluid.java.patch b/paper-server/patches/sources/net/minecraft/world/level/material/FlowingFluid.java.patch index adbd1fb3edbd..b6e26231a701 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/material/FlowingFluid.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/material/FlowingFluid.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/material/FlowingFluid.java +++ b/net/minecraft/world/level/material/FlowingFluid.java -@@ -121,6 +_,15 @@ +@@ -120,6 +_,15 @@ Fluid newBelowFluidType = newBelowFluid.getType(); if (belowFluid.canBeReplacedWith(level, belowPos, newBelowFluidType, Direction.DOWN) && canHoldSpecificFluid(level, belowPos, belowState, newBelowFluidType)) { @@ -16,7 +16,7 @@ this.spreadTo(level, belowPos, belowState, Direction.DOWN, newBelowFluid); if (this.sourceNeighborCount(level, pos) >= 3) { this.spreadToSides(level, pos, fluidState, state); -@@ -149,7 +_,18 @@ +@@ -148,7 +_,18 @@ Direction spread = entry.getKey(); FluidState newNeighborFluid = entry.getValue(); BlockPos neighborPos = pos.relative(spread); @@ -36,7 +36,7 @@ } } } -@@ -161,7 +_,8 @@ +@@ -160,7 +_,8 @@ for (Direction direction : Direction.Plane.HORIZONTAL) { BlockPos relativePos = mutablePos.setWithOffset(pos, direction); @@ -46,7 +46,7 @@ FluidState fluidState = blockState.getFluidState(); if (fluidState.getType().isSame(this) && canPassThroughWall(direction, level, pos, state, relativePos, blockState)) { if (fluidState.isSource()) { -@@ -264,13 +_,15 @@ +@@ -265,13 +_,15 @@ container.placeLiquid(level, pos, state, target); } else { if (!state.isAir()) { @@ -63,7 +63,7 @@ protected abstract void beforeDestroyingBlock(LevelAccessor level, BlockPos pos, BlockState state); protected int getSlopeDistance( -@@ -281,7 +_,8 @@ +@@ -282,7 +_,8 @@ for (Direction direction : Direction.Plane.HORIZONTAL) { if (direction != from) { BlockPos testPos = pos.relative(direction); @@ -73,7 +73,7 @@ FluidState testFluidState = testState.getFluidState(); if (this.canPassThrough(level, this.getFlowing(), pos, state, direction, testPos, testState, testFluidState)) { if (context.isHole(testPos)) { -@@ -363,7 +_,8 @@ +@@ -364,7 +_,8 @@ for (Direction direction : Direction.Plane.HORIZONTAL) { BlockPos testPos = pos.relative(direction); @@ -83,7 +83,7 @@ FluidState testFluidState = testState.getFluidState(); if (this.canMaybePassThrough(level, pos, state, direction, testPos, testState, testFluidState)) { FluidState newFluid = this.getNewLiquid(level, testPos, testState); -@@ -434,10 +_,24 @@ +@@ -435,10 +_,24 @@ if (newFluidState.isEmpty()) { fluidState = newFluidState; blockState = Blocks.AIR.defaultBlockState(); @@ -97,7 +97,7 @@ level.setBlock(pos, blockState, Block.UPDATE_ALL); } else if (newFluidState != fluidState) { fluidState = newFluidState; - blockState = newFluidState.createLegacyBlock(); + blockState = fluidState.createLegacyBlock(); + // CraftBukkit start + org.bukkit.event.block.FluidLevelChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callFluidLevelChangeEvent(level, pos, blockState); + if (event.isCancelled()) { @@ -106,9 +106,9 @@ + blockState = ((org.bukkit.craftbukkit.block.data.CraftBlockData) event.getNewData()).getState(); + // CraftBukkit end level.setBlock(pos, blockState, Block.UPDATE_ALL); - level.scheduleTick(pos, newFluidState.getType(), tickDelay); + level.scheduleTick(pos, fluidState.getType(), tickDelay); } -@@ -510,8 +_,27 @@ +@@ -507,8 +_,27 @@ return this.getBlockState(pos, this.getCacheKey(pos)); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java.patch b/paper-server/patches/sources/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java.patch index 14d2fd86288a..599a7aee8a91 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java +++ b/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java -@@ -504,7 +_,12 @@ +@@ -514,7 +_,12 @@ } protected static PathType getPathTypeFromState(final BlockGetter level, final BlockPos pos) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/portal/PortalForcer.java.patch b/paper-server/patches/sources/net/minecraft/world/level/portal/PortalForcer.java.patch index 94746ee3e6ba..ee4f7d6f285e 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/portal/PortalForcer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/portal/PortalForcer.java.patch @@ -79,8 +79,8 @@ } @@ -149,10 +_,20 @@ for (int width = 0; width < 2; width++) { - for (int heightx = 0; heightx < 3; heightx++) { - mutable.setWithOffset(closestFullPosition, width * direction.getStepX(), heightx, width * direction.getStepZ()); + for (int height = 0; height < 3; height++) { + mutable.setWithOffset(closestFullPosition, width * direction.getStepX(), height, width * direction.getStepZ()); - this.level.setBlock(mutable, portalBlockState, Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE); + blockList.setBlock(mutable, portalBlockState, Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE); // CraftBukkit } diff --git a/paper-server/patches/sources/net/minecraft/world/level/portal/PortalShape.java.patch b/paper-server/patches/sources/net/minecraft/world/level/portal/PortalShape.java.patch index 17f9e3ae898f..d1d321acf75b 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/portal/PortalShape.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/portal/PortalShape.java.patch @@ -27,20 +27,20 @@ if (bottomLeft == null) { - return new PortalShape(axis, 0, rightDir, pos, 0, 0); + return new PortalShape(axis, 0, rightDir, pos, 0, 0, blocks); // CraftBukkit - } else { -- int width = calculateWidth(level, bottomLeft, rightDir); -+ int width = calculateWidth(level, bottomLeft, rightDir, blocks); // CraftBukkit - if (width == 0) { -- return new PortalShape(axis, 0, rightDir, bottomLeft, 0, 0); -+ return new PortalShape(axis, 0, rightDir, bottomLeft, 0, 0, blocks); // CraftBukkit - } else { - MutableInt portalBlockCountOutput = new MutableInt(); -- int height = calculateHeight(level, bottomLeft, rightDir, width, portalBlockCountOutput); -- return new PortalShape(axis, portalBlockCountOutput.intValue(), rightDir, bottomLeft, width, height); -+ int height = calculateHeight(level, bottomLeft, rightDir, width, portalBlockCountOutput, blocks); // CraftBukkit -+ return new PortalShape(axis, portalBlockCountOutput.intValue(), rightDir, bottomLeft, width, height, blocks); // CraftBukkit - } } + +- int width = calculateWidth(level, bottomLeft, rightDir); ++ int width = calculateWidth(level, bottomLeft, rightDir, blocks); // CraftBukkit + if (width == 0) { +- return new PortalShape(axis, 0, rightDir, bottomLeft, 0, 0); ++ return new PortalShape(axis, 0, rightDir, bottomLeft, 0, 0, blocks); // CraftBukkit + } + + MutableInt portalBlockCountOutput = new MutableInt(); +- int height = calculateHeight(level, bottomLeft, rightDir, width, portalBlockCountOutput); +- return new PortalShape(axis, portalBlockCountOutput.intValue(), rightDir, bottomLeft, width, height); ++ int height = calculateHeight(level, bottomLeft, rightDir, width, portalBlockCountOutput, blocks); // CraftBukkit ++ return new PortalShape(axis, portalBlockCountOutput.intValue(), rightDir, bottomLeft, width, height, blocks); // CraftBukkit } - private static @Nullable BlockPos calculateBottomLeft(final BlockGetter level, final Direction rightDir, BlockPos pos) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/redstone/NeighborUpdater.java.patch b/paper-server/patches/sources/net/minecraft/world/level/redstone/NeighborUpdater.java.patch index d9bc406db00b..dd5c1d4130ef 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/redstone/NeighborUpdater.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/redstone/NeighborUpdater.java.patch @@ -24,6 +24,6 @@ + } catch (StackOverflowError ex) { + level.lastPhysicsProblem = pos.immutable(); + // Spigot end - } catch (Throwable var9) { - CrashReport report = CrashReport.forThrowable(var9, "Exception while updating neighbours"); + } catch (Throwable t) { + CrashReport report = CrashReport.forThrowable(t, "Exception while updating neighbours"); CrashReportCategory category = report.addCategory("Block being updated"); diff --git a/paper-server/patches/sources/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java.patch b/paper-server/patches/sources/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java.patch index 0a014f3cb6c1..418f1511929b 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java.patch @@ -119,7 +119,7 @@ this.bannerMarkers.put(banner.getId(), banner); this.addDecoration(banner.getDecoration(), level, banner.getId(), xPos, zPos, 180.0, banner.name().orElse(null)); this.setDirty(); -@@ -524,7 +_,7 @@ +@@ -518,7 +_,7 @@ this.player = player; } @@ -128,7 +128,7 @@ int startX = this.minDirtyX; int startY = this.minDirtyY; int width = this.maxDirtyX + 1 - this.minDirtyX; -@@ -533,7 +_,7 @@ +@@ -527,7 +_,7 @@ for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { @@ -137,7 +137,7 @@ } } -@@ -542,17 +_,38 @@ +@@ -536,17 +_,38 @@ private @Nullable Packet nextUpdatePacket(final MapId id) { MapItemSavedData.MapPatch patch; @@ -179,7 +179,7 @@ } else { decorations = null; } -@@ -580,6 +_,23 @@ +@@ -574,6 +_,23 @@ private void markDecorationsDirty() { this.dirtyDecorations = true; } @@ -203,7 +203,7 @@ } private record MapDecorationLocation(Holder type, byte x, byte y, byte rot) { -@@ -624,4 +_,71 @@ +@@ -618,4 +_,71 @@ } } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/LevelStorageSource.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/LevelStorageSource.java.patch index 515c75d42202..92dc79032cc4 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/storage/LevelStorageSource.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/LevelStorageSource.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/storage/LevelStorageSource.java +++ b/net/minecraft/world/level/storage/LevelStorageSource.java -@@ -149,12 +_,13 @@ +@@ -144,13 +_,14 @@ final WorldDataConfiguration dataConfiguration, final Registry datapackDimensions, final HolderLookup.Provider registryAccess @@ -8,14 +8,15 @@ ) { if (DataFixers.getFileFixer().requiresFileFixing(NbtUtils.getDataVersion(levelDataTag))) { throw new IllegalStateException("Cannot get level data without file fixing first"); - } else { - Dynamic dataTag = RegistryOps.injectRegistryContext(levelDataTag, registryAccess); -- WorldGenSettings worldGenSettings = readExistingSavedData(worldAccess, registryAccess, WorldGenSettings.TYPE) -+ WorldGenSettings worldGenSettings = readExistingSavedData(worldAccess, dimension, registryAccess, WorldGenSettings.TYPE) // Paper - pass dimension - .mapOrElse( - Function.identity(), - error -> { -@@ -174,13 +_,13 @@ + } + + Dynamic dataTag = RegistryOps.injectRegistryContext(levelDataTag, registryAccess); +- WorldGenSettings worldGenSettings = readExistingSavedData(worldAccess, registryAccess, WorldGenSettings.TYPE) ++ WorldGenSettings worldGenSettings = readExistingSavedData(worldAccess, dimension, registryAccess, WorldGenSettings.TYPE) // Paper - pass dimension + .mapOrElse( + Function.identity(), + error -> { +@@ -169,13 +_,13 @@ } public static DataResult readExistingSavedData( @@ -28,11 +29,11 @@ CompoundTag fileContents; try { - fileContents = NbtIo.readCompressed(dataLocation, NbtAccounter.defaultQuota()); -+ fileContents = NbtIo.readCompressed(dataLocation, NbtAccounter.create(net.minecraft.nbt.NbtAccounter.DEFAULT_NBT_QUOTA * 50L)); // Paper - raise quota to account for custom data - } catch (IOException var6) { - return DataResult.error(var6::getMessage); ++ fileContents = NbtIo.readCompressed(dataLocation, NbtAccounter.create(NbtAccounter.DEFAULT_NBT_QUOTA * 50L)); // Paper - raise quota to account for custom data + } catch (IOException e) { + return DataResult.error(e::getMessage); } -@@ -396,7 +_,7 @@ +@@ -386,7 +_,7 @@ public LevelStorageSource.LevelStorageAccess validateAndCreateAccess(final String levelId) throws IOException, ContentValidationException { Path levelPath = this.getLevelPath(levelId); diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/PlayerDataStorage.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/PlayerDataStorage.java.patch index 3403b87ebef5..5e0a1748d64b 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/storage/PlayerDataStorage.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/PlayerDataStorage.java.patch @@ -11,9 +11,9 @@ @@ -42,7 +_,7 @@ Path oldFile = playerDirPath.resolve(player.getStringUUID() + ".dat_old"); Util.safeReplaceFile(realFile, tmpFile, oldFile); - } catch (Exception var11) { + } catch (Exception ignored) { - LOGGER.warn("Failed to save player data for {}", player.getPlainTextName()); -+ LOGGER.warn("Failed to save player data for {}", player.getPlainTextName(), var11); // Paper - Print exception ++ LOGGER.warn("Failed to save player data for {}", player.getPlainTextName(), ignored); // Paper - Print exception } } @@ -41,7 +41,7 @@ + } + return optional; + // Spigot end - } catch (Exception var5) { + } catch (Exception ignored) { LOGGER.warn("Failed to load player data for {}", nameAndId.name()); } @@ -84,4 +_,10 @@ diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/PrimaryLevelData.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/PrimaryLevelData.java.patch index 0cf05db6e101..ef7802d8b004 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/storage/PrimaryLevelData.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/PrimaryLevelData.java.patch @@ -74,4 +74,4 @@ + // CraftBukkit end @Deprecated - public static enum SpecialWorldProperty { + public enum SpecialWorldProperty { diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/SavedDataStorage.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/SavedDataStorage.java.patch index ff0ee4e714cc..181dbcff0089 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/storage/SavedDataStorage.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/SavedDataStorage.java.patch @@ -1,20 +1,20 @@ --- a/net/minecraft/world/level/storage/SavedDataStorage.java +++ b/net/minecraft/world/level/storage/SavedDataStorage.java -@@ -156,7 +_,7 @@ - } else { - int threads = Util.maxAllowedExecutorThreads(); - int taskCount = tagsToSave.size(); -- if (taskCount > threads) { -+ if (false && taskCount > threads) { // Paper - Separate dimension data IO pool; just throw them into the fixed pool queue - this.pendingWriteFuture = this.pendingWriteFuture.thenCompose(ignored -> { - List> tasks = new ArrayList<>(threads); - int bucketSize = Mth.positiveCeilDiv(taskCount, threads); -@@ -177,7 +_,7 @@ - ignored -> CompletableFuture.allOf( - tagsToSave.entrySet() - .stream() -- .map(entry -> CompletableFuture.runAsync(() -> this.tryWrite(entry.getKey(), entry.getValue()), Util.ioPool())) -+ .map(entry -> CompletableFuture.runAsync(() -> this.tryWrite(entry.getKey(), entry.getValue()), Util.DIMENSION_DATA_IO_POOL)) // Paper - Separate dimension data IO pool - .toArray(CompletableFuture[]::new) - ) - ); +@@ -155,7 +_,7 @@ + + int threads = Util.maxAllowedExecutorThreads(); + int taskCount = tagsToSave.size(); +- if (taskCount > threads) { ++ if (false && taskCount > threads) { // Paper - Separate dimension data IO pool; just throw them into the fixed pool queue + this.pendingWriteFuture = this.pendingWriteFuture.thenCompose(ignored -> { + List> tasks = new ArrayList<>(threads); + int bucketSize = Mth.positiveCeilDiv(taskCount, threads); +@@ -176,7 +_,7 @@ + ignored -> CompletableFuture.allOf( + tagsToSave.entrySet() + .stream() +- .map(entry -> CompletableFuture.runAsync(() -> this.tryWrite(entry.getKey(), entry.getValue()), Util.ioPool())) ++ .map(entry -> CompletableFuture.runAsync(() -> this.tryWrite(entry.getKey(), entry.getValue()), Util.DIMENSION_DATA_IO_POOL)) // Paper - Separate dimension data IO pool + .toArray(CompletableFuture[]::new) + ) + ); diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java.patch index 6124d48cb417..af31b0db81a6 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java +++ b/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java -@@ -39,6 +_,10 @@ +@@ -34,6 +_,10 @@ ); } }; @@ -11,8 +11,8 @@ protected LootPoolSingletonContainer(final int weight, final int quality, final List conditions, final List functions) { super(conditions); -@@ -135,7 +_,31 @@ - +@@ -125,7 +_,31 @@ + protected abstract class EntryBase implements LootPoolEntry { @Override public int getWeight(final float luck) { - return Math.max(Mth.floor(LootPoolSingletonContainer.this.weight + LootPoolSingletonContainer.this.quality * luck), 0); diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/loot/functions/ExplorationMapFunction.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/loot/functions/ExplorationMapFunction.java.patch index 8862d67128e3..e93e70da8abf 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/storage/loot/functions/ExplorationMapFunction.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/loot/functions/ExplorationMapFunction.java.patch @@ -1,30 +1,29 @@ --- a/net/minecraft/world/level/storage/loot/functions/ExplorationMapFunction.java +++ b/net/minecraft/world/level/storage/loot/functions/ExplorationMapFunction.java -@@ -83,9 +_,25 @@ - Vec3 lootPos = context.getOptionalParameter(LootContextParams.ORIGIN); - if (lootPos != null) { - ServerLevel level = context.getLevel(); -+ // Paper start - Configurable cartographer treasure maps -+ // Simple heuristic for determining if this function is running in the context of a villager selecting -+ // an item for its offers. Technically other callers could satisfiy this but this minimises the diff and -+ // works for all plain vanilla usecases. -+ final boolean runningForVillagerTrade = context.hasParameter(LootContextParams.ADDITIONAL_COST_COMPONENT_ALLOWED) -+ && context.getOptionalParameter(LootContextParams.THIS_ENTITY) instanceof net.minecraft.world.entity.npc.villager.AbstractVillager; -+ if (!level.paperConfig().environment.treasureMaps.enabled) { -+ /* -+ * NOTE: I fear users will just get a plain map as their "treasure" -+ * This is preferable to disrespecting the config. -+ */ -+ return runningForVillagerTrade ? net.minecraft.world.item.ItemStack.EMPTY : itemStack; -+ } -+ final boolean shouldSkipKnownStructures = runningForVillagerTrade -+ ? !level.paperConfig().environment.treasureMaps.findAlreadyDiscoveredVillager -+ : !level.paperConfig().environment.treasureMaps.findAlreadyDiscoveredLootTable.or(!this.skipKnownStructures); -+ // Paper end - Configurable cartographer treasure maps - BlockPos nearestMapStructure = level.findNearestMapStructure( -- this.destination, BlockPos.containing(lootPos), this.searchRadius, this.skipKnownStructures -- ); -+ this.destination, BlockPos.containing(lootPos), this.searchRadius, shouldSkipKnownStructures); // Paper - Configurable cartographer treasure maps - if (nearestMapStructure != null) { - ItemStack map = MapItem.create(level, nearestMapStructure.getX(), nearestMapStructure.getZ(), this.zoom, true, true); - MapItem.renderBiomePreviewMap(level, map); +@@ -84,8 +_,25 @@ + Vec3 lootPos = context.getOptionalParameter(LootContextParams.ORIGIN); + if (lootPos != null) { + ServerLevel level = context.getLevel(); ++ // Paper start - Configurable cartographer treasure maps ++ // Simple heuristic for determining if this function is running in the context of a villager selecting ++ // an item for its offers. Technically other callers could satisfiy this but this minimises the diff and ++ // works for all plain vanilla usecases. ++ final boolean runningForVillagerTrade = context.hasParameter(LootContextParams.ADDITIONAL_COST_COMPONENT_ALLOWED) ++ && context.getOptionalParameter(LootContextParams.THIS_ENTITY) instanceof net.minecraft.world.entity.npc.villager.AbstractVillager; ++ if (!level.paperConfig().environment.treasureMaps.enabled) { ++ /* ++ * NOTE: I fear users will just get a plain map as their "treasure" ++ * This is preferable to disrespecting the config. ++ */ ++ return runningForVillagerTrade ? net.minecraft.world.item.ItemStack.EMPTY : itemStack; ++ } ++ final boolean shouldSkipKnownStructures = runningForVillagerTrade ++ ? !level.paperConfig().environment.treasureMaps.findAlreadyDiscoveredVillager ++ : !level.paperConfig().environment.treasureMaps.findAlreadyDiscoveredLootTable.or(!this.skipKnownStructures); ++ // Paper end - Configurable cartographer treasure maps + BlockPos nearestMapStructure = level.findNearestMapStructure( +- this.destination, BlockPos.containing(lootPos), this.searchRadius, this.skipKnownStructures ++ this.destination, BlockPos.containing(lootPos), this.searchRadius, shouldSkipKnownStructures // Paper - Configurable cartographer treasure maps + ); + if (nearestMapStructure != null) { + ItemStack map = MapItem.create(level, nearestMapStructure.getX(), nearestMapStructure.getZ(), this.zoom, true, true); diff --git a/paper-server/patches/sources/net/minecraft/world/scores/Scoreboard.java.patch b/paper-server/patches/sources/net/minecraft/world/scores/Scoreboard.java.patch index e6118569b330..f2793f732a9b 100644 --- a/paper-server/patches/sources/net/minecraft/world/scores/Scoreboard.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/scores/Scoreboard.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/scores/Scoreboard.java +++ b/net/minecraft/world/scores/Scoreboard.java -@@ -377,7 +_,7 @@ +@@ -373,7 +_,7 @@ } protected List packPlayerTeams() {