From 82216a59fef17863c86192c2754417480baa71c1 Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Sat, 21 Dec 2024 13:21:47 +0100 Subject: [PATCH] Apply some feature patches to files instead They're small and/or really shouldn't be left unapplied --- ...ldBounds-and-getBlockState-for-inlin.patch | 98 ------- ...item-frames-performance-and-bug-fixe.patch | 135 --------- ...heck-distance-in-entity-interactions.patch | 68 ----- .../moonrise/paper/PaperHooks.java.patch | 244 +++++++++++++++++ .../util/BaseChunkSystemHooks.java.patch} | 258 +----------------- .../sources/net/minecraft/Util.java.patch | 8 + .../net/minecraft/core/Vec3i.java.patch | 11 + .../server/level/ServerLevel.java.patch | 9 +- .../server/level/ServerPlayer.java.patch | 15 +- .../world/entity/LivingEntity.java.patch | 21 +- .../entity/vehicle/AbstractBoat.java.patch | 9 + .../minecraft/world/level/Level.java.patch | 9 +- .../world/level/chunk/ChunkAccess.java.patch | 8 + .../level/chunk/ImposterProtoChunk.java.patch | 15 + .../world/level/chunk/ProtoChunk.java.patch | 21 +- .../maps/MapItemSavedData.java.patch | 73 ++++- 16 files changed, 424 insertions(+), 578 deletions(-) delete mode 100644 paper-server/patches/features/0002-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch delete mode 100644 paper-server/patches/features/0003-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch delete mode 100644 paper-server/patches/features/0014-Check-distance-in-entity-interactions.patch create mode 100644 paper-server/patches/sources/ca/spottedleaf/moonrise/paper/PaperHooks.java.patch rename paper-server/patches/{features/0001-Add-PaperHooks.patch => sources/ca/spottedleaf/moonrise/paper/util/BaseChunkSystemHooks.java.patch} (59%) create mode 100644 paper-server/patches/sources/net/minecraft/world/level/chunk/ImposterProtoChunk.java.patch diff --git a/paper-server/patches/features/0002-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch b/paper-server/patches/features/0002-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch deleted file mode 100644 index 4f1d53e0e3..0000000000 --- a/paper-server/patches/features/0002-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Thu, 3 Mar 2016 02:07:55 -0600 -Subject: [PATCH] Optimize isInWorldBounds and getBlockState for inlining - -Hot methods, so reduce # of instructions for the method. - -Move is valid location test to the BlockPosition class so that it can access local variables. - -Replace all calls to the new place to the unnecessary forward. - -Optimize getType and getBlockData to manually inline and optimize the calls - -diff --git a/net/minecraft/core/Vec3i.java b/net/minecraft/core/Vec3i.java -index 03e2178430849d26c9826517e34ad069c94fc00a..11555ce7159ca6c8ddfe9691f86d3720c07cb086 100644 ---- a/net/minecraft/core/Vec3i.java -+++ b/net/minecraft/core/Vec3i.java -@@ -28,6 +28,12 @@ public class Vec3i implements Comparable { - ); - } - -+ // Paper start -+ public final boolean isInsideBuildHeightAndWorldBoundsHorizontal(net.minecraft.world.level.LevelHeightAccessor levelHeightAccessor) { -+ return getX() >= -30000000 && getZ() >= -30000000 && getX() < 30000000 && getZ() < 30000000 && !levelHeightAccessor.isOutsideBuildHeight(getY()); -+ } -+ // Paper end -+ - public Vec3i(int x, int y, int z) { - this.x = x; - this.y = y; -diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index e0239091729f6be138c037951fd5c138497ee358..691fee2e2097244126f4fac0f5d00bf6916b9766 100644 ---- a/net/minecraft/world/level/Level.java -+++ b/net/minecraft/world/level/Level.java -@@ -350,7 +350,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - // Paper end - - public boolean isInWorldBounds(BlockPos pos) { -- return !this.isOutsideBuildHeight(pos) && isInWorldBoundsHorizontal(pos); -+ return pos.isInsideBuildHeightAndWorldBoundsHorizontal(this); // Paper - use better/optimized check - } - - public static boolean isInSpawnableBounds(BlockPos pos) { -diff --git a/net/minecraft/world/level/chunk/ChunkAccess.java b/net/minecraft/world/level/chunk/ChunkAccess.java -index f68f3f5e8ef39a0dc371e75110227a39791c04c8..12d9b532e466ec4e46920d409b5f1b3ae60b80f8 100644 ---- a/net/minecraft/world/level/chunk/ChunkAccess.java -+++ b/net/minecraft/world/level/chunk/ChunkAccess.java -@@ -130,6 +130,7 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh - return GameEventListenerRegistry.NOOP; - } - -+ public abstract BlockState getBlockState(final int x, final int y, final int z); // Paper - @Nullable - public abstract BlockState setBlockState(BlockPos pos, BlockState state, boolean isMoving); - -diff --git a/net/minecraft/world/level/chunk/ImposterProtoChunk.java b/net/minecraft/world/level/chunk/ImposterProtoChunk.java -index 6c43e5e685871289968db8171342fd84189edcba..e7c0f4da8508fbca467326f475668d66454d7b77 100644 ---- a/net/minecraft/world/level/chunk/ImposterProtoChunk.java -+++ b/net/minecraft/world/level/chunk/ImposterProtoChunk.java -@@ -56,6 +56,12 @@ public class ImposterProtoChunk extends ProtoChunk { - public BlockState getBlockState(BlockPos pos) { - return this.wrapped.getBlockState(pos); - } -+ // Paper start -+ @Override -+ public final BlockState getBlockState(final int x, final int y, final int z) { -+ return this.wrapped.getBlockStateFinal(x, y, z); -+ } -+ // Paper end - - @Override - public FluidState getFluidState(BlockPos pos) { -diff --git a/net/minecraft/world/level/chunk/ProtoChunk.java b/net/minecraft/world/level/chunk/ProtoChunk.java -index e359b5f694210f05e5675a995dbfc1a95cec76db..8c333d7f390d823a7c7f303e2f444f52ec16f799 100644 ---- a/net/minecraft/world/level/chunk/ProtoChunk.java -+++ b/net/minecraft/world/level/chunk/ProtoChunk.java -@@ -99,12 +99,18 @@ public class ProtoChunk extends ChunkAccess { - - @Override - public BlockState getBlockState(BlockPos pos) { -- int y = pos.getY(); -+ // Paper start -+ return getBlockState(pos.getX(), pos.getY(), pos.getZ()); -+ } -+ public BlockState getBlockState(final int x, final int y, final int z) { -+ // 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); -+ // Paper start -+ LevelChunkSection section = this.getSections()[this.getSectionIndex(y)]; -+ return section.hasOnlyAir() ? Blocks.AIR.defaultBlockState() : section.getBlockState(x & 15, y & 15, z & 15); -+ // Paper end - } - } - diff --git a/paper-server/patches/features/0003-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch b/paper-server/patches/features/0003-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch deleted file mode 100644 index a547df5f1b..0000000000 --- a/paper-server/patches/features/0003-Improve-Maps-in-item-frames-performance-and-bug-fixe.patch +++ /dev/null @@ -1,135 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Fri, 29 Apr 2016 20:02:00 -0400 -Subject: [PATCH] Improve Maps (in item frames) performance and bug fixes - -Maps used a modified version of rendering to support plugin controlled -imaging on maps. The Craft Map Renderer is much slower than Vanilla, -causing maps in item frames to cause a noticeable hit on server performance. - -This updates the map system to not use the Craft system if we detect that no -custom renderers are in use, defaulting to the much simpler Vanilla system. - -Additionally, numerous issues to player position tracking on maps has been fixed. - -diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 1f66adcd70aae7eac3d9f9539163905695581631..34a53bf34d10c56e6f53ce9aab2fc2780509f2f1 100644 ---- a/net/minecraft/server/level/ServerLevel.java -+++ b/net/minecraft/server/level/ServerLevel.java -@@ -2282,7 +2282,9 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - } - - map.carriedByPlayers.remove(player); -- map.carriedBy.removeIf(holdingPlayer -> holdingPlayer.player == player); -+ if (map.carriedBy.removeIf(holdingPlayer -> holdingPlayer.player == player)) { -+ map.decorations.remove(player.getName().getString()); // Paper -+ } - } - } - } -diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index 36e0d3f225a71b75ece7bf3fceeba47af948a6df..ff5889f8fed0707a6654d9d21862e32e2ebc866d 100644 ---- a/net/minecraft/server/level/ServerPlayer.java -+++ b/net/minecraft/server/level/ServerPlayer.java -@@ -2594,6 +2594,14 @@ public class ServerPlayer extends Player { - this.awardStat(Stats.DROP); - } - -+ // Paper start - remove player from map on drop -+ if (item.getItem() == net.minecraft.world.item.Items.FILLED_MAP) { -+ final MapItemSavedData mapData = MapItem.getSavedData(item, this.level()); -+ if (mapData != null) { -+ mapData.tickCarriedBy(this, item); -+ } -+ } -+ // Paper end - remove player from map on drop - return itemEntity; - } - } -diff --git a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -index fd50bd77e4dc7b18240afe5505c6e6f0f869c127..f60c2f3a3dfc69f50225b6ee7333ada5e9dfd090 100644 ---- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -+++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -@@ -67,6 +67,7 @@ public class MapItemSavedData extends SavedData { - public final Map decorations = Maps.newLinkedHashMap(); - private final Map frameMarkers = Maps.newHashMap(); - private int trackedDecorationCount; -+ private org.bukkit.craftbukkit.map.RenderData vanillaRender = new org.bukkit.craftbukkit.map.RenderData(); // Paper - - // CraftBukkit start - public final org.bukkit.craftbukkit.map.CraftMapView mapView; -@@ -92,6 +93,7 @@ public class MapItemSavedData extends SavedData { - // CraftBukkit start - this.mapView = new org.bukkit.craftbukkit.map.CraftMapView(this); - this.server = (org.bukkit.craftbukkit.CraftServer) org.bukkit.Bukkit.getServer(); -+ this.vanillaRender.buffer = colors; // Paper - // CraftBukkit end - } - -@@ -163,6 +165,7 @@ public class MapItemSavedData extends SavedData { - if (byteArray.length == 16384) { - mapItemSavedData.colors = byteArray; - } -+ mapItemSavedData.vanillaRender.buffer = byteArray; // Paper - - RegistryOps registryOps = levelRegistry.createSerializationContext(NbtOps.INSTANCE); - -@@ -337,7 +340,7 @@ public class MapItemSavedData extends SavedData { - this.trackedDecorationCount--; - } - -- this.setDecorationsDirty(); -+ if (mapDecoration != null) this.setDecorationsDirty(); // Paper - only mark dirty if a change occurs - } - - public static void addTargetDecoration(ItemStack stack, BlockPos pos, String type, Holder mapDecorationType) { -@@ -610,7 +613,16 @@ public class MapItemSavedData extends SavedData { - @Nullable - Packet nextUpdatePacket(MapId mapId) { - MapItemSavedData.MapPatch mapPatch; -- org.bukkit.craftbukkit.map.RenderData render = MapItemSavedData.this.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) this.player.getBukkitEntity()); // CraftBukkit -+ // Paper start -+ if (!this.dirtyData && this.tick % 5 != 0) { -+ // this won't end up sending, so don't render it! -+ this.tick++; -+ return null; -+ } -+ -+ final boolean vanillaMaps = this.shouldUseVanillaMap(); -+ org.bukkit.craftbukkit.map.RenderData render = !vanillaMaps ? MapItemSavedData.this.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) this.player.getBukkitEntity()) : MapItemSavedData.this.vanillaRender; // CraftBukkit // Paper -+ // Paper end - if (this.dirtyData) { - this.dirtyData = false; - mapPatch = this.createPatch(render.buffer); // CraftBukkit -@@ -623,6 +635,7 @@ public class MapItemSavedData extends SavedData { - this.dirtyDecorations = false; - // CraftBukkit start - java.util.Collection icons = new java.util.ArrayList(); -+ if (vanillaMaps) this.addSeenPlayers(icons); // Paper - - for (org.bukkit.map.MapCursor cursor : render.cursors) { - if (cursor.isVisible()) { -@@ -658,6 +671,23 @@ public class MapItemSavedData extends SavedData { - private void markDecorationsDirty() { - this.dirtyDecorations = true; - } -+ -+ // Paper start -+ private void addSeenPlayers(java.util.Collection icons) { -+ org.bukkit.entity.Player player = (org.bukkit.entity.Player) this.player.getBukkitEntity(); -+ MapItemSavedData.this.decorations.forEach((name, mapIcon) -> { -+ // If this cursor is for a player check visibility with vanish system -+ org.bukkit.entity.Player other = org.bukkit.Bukkit.getPlayerExact(name); // Spigot -+ if (other == null || player.canSee(other)) { -+ icons.add(mapIcon); -+ } -+ }); -+ } -+ -+ private boolean shouldUseVanillaMap() { -+ return mapView.getRenderers().size() == 1 && mapView.getRenderers().getFirst().getClass() == org.bukkit.craftbukkit.map.CraftMapRenderer.class; -+ } -+ // Paper end - } - - record MapDecorationLocation(Holder type, byte x, byte y, byte rot) { diff --git a/paper-server/patches/features/0014-Check-distance-in-entity-interactions.patch b/paper-server/patches/features/0014-Check-distance-in-entity-interactions.patch deleted file mode 100644 index 39272633a7..0000000000 --- a/paper-server/patches/features/0014-Check-distance-in-entity-interactions.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Mon, 2 Aug 2021 10:10:40 +0200 -Subject: [PATCH] Check distance in entity interactions - - -diff --git a/net/minecraft/Util.java b/net/minecraft/Util.java -index ae1d53cefb9cede1c93cb8b22122a4a2d2d9a40c..80a7a85e1a03a1ca406259207e1ae3b909b3284f 100644 ---- a/net/minecraft/Util.java -+++ b/net/minecraft/Util.java -@@ -130,6 +130,7 @@ public class Util { - .findFirst() - .orElseThrow(() -> new IllegalStateException("No jar file system provider found")); - private static Consumer thePauser = string -> {}; -+ public static final double COLLISION_EPSILON = 1.0E-7; // Paper - Check distance in entity interactions - - public static Collector, ?, Map> toMap() { - return Collectors.toMap(Entry::getKey, Entry::getValue); -diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java -index 9bf5addb07f40cc50e80a46c0ee7944e938620fb..635e6e49483194c43b0ab47b5e1bacfe84613c3a 100644 ---- a/net/minecraft/world/entity/LivingEntity.java -+++ b/net/minecraft/world/entity/LivingEntity.java -@@ -1385,7 +1385,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.hurtCurrentlyUsedShield(amount); - f1 = amount; - amount = 0.0F; -- if (!damageSource.is(DamageTypeTags.IS_PROJECTILE) && damageSource.getDirectEntity() instanceof LivingEntity livingEntity) { -+ if (!damageSource.is(DamageTypeTags.IS_PROJECTILE) && damageSource.getDirectEntity() instanceof LivingEntity livingEntity && livingEntity.distanceToSqr(this) <= (200.0D * 200.0D)) { // Paper - Check distance in entity interactions - this.blockUsingShield(livingEntity); - } - -@@ -1470,6 +1470,14 @@ public abstract class LivingEntity extends Entity implements Attackable { - d = damageSource.getSourcePosition().x() - this.getX(); - d1 = damageSource.getSourcePosition().z() - this.getZ(); - } -+ // Paper start - Check distance in entity interactions; see for loop in knockback method -+ if (Math.abs(d) > 200) { -+ d = Math.random() - Math.random(); -+ } -+ if (Math.abs(d1) > 200) { -+ d1 = Math.random() - Math.random(); -+ } -+ // Paper end - Check distance in entity interactions - - this.knockback(0.4F, d, d1, damageSource.getDirectEntity(), damageSource.getDirectEntity() == null ? io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.DAMAGE : io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events - if (!flag) { -@@ -2342,7 +2350,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.hurtCurrentlyUsedShield((float) -event.getDamage(DamageModifier.BLOCKING)); - Entity entity = damageSource.getDirectEntity(); - -- if (!damageSource.is(DamageTypeTags.IS_PROJECTILE) && entity instanceof LivingEntity) { // Paper - Fix shield disable inconsistency -+ if (!damageSource.is(DamageTypeTags.IS_PROJECTILE) && entity instanceof LivingEntity && entity.distanceToSqr(this) <= (200.0D * 200.0D)) { // Paper - Fix shield disable inconsistency & Check distance in entity interactions - this.blockUsingShield((LivingEntity) entity); - } - } -diff --git a/net/minecraft/world/entity/vehicle/AbstractBoat.java b/net/minecraft/world/entity/vehicle/AbstractBoat.java -index 3bdb3b0984d0fee21b2c094e1d4c1f917ab68f92..54a4bf2f7df87b4a694187ade81ba158f83f0246 100644 ---- a/net/minecraft/world/entity/vehicle/AbstractBoat.java -+++ b/net/minecraft/world/entity/vehicle/AbstractBoat.java -@@ -638,7 +638,7 @@ public abstract class AbstractBoat extends VehicleEntity implements Leashable { - this.waterLevel = this.getY(1.0); - double d2 = this.getWaterLevelAbove() - this.getBbHeight() + 0.101; - if (this.level().noCollision(this, this.getBoundingBox().move(0.0, d2 - this.getY(), 0.0))) { -- this.setPos(this.getX(), d2, this.getZ()); -+ this.move(MoverType.SELF, new Vec3(0.0D, d2 - this.getY(), 0.0D)); // Paper - Check distance in entity interactions // TODO Still needed?? - this.setDeltaMovement(this.getDeltaMovement().multiply(1.0, 0.0, 1.0)); - this.lastYd = 0.0; - } diff --git a/paper-server/patches/sources/ca/spottedleaf/moonrise/paper/PaperHooks.java.patch b/paper-server/patches/sources/ca/spottedleaf/moonrise/paper/PaperHooks.java.patch new file mode 100644 index 0000000000..d736409b62 --- /dev/null +++ b/paper-server/patches/sources/ca/spottedleaf/moonrise/paper/PaperHooks.java.patch @@ -0,0 +1,244 @@ +--- /dev/null ++++ b/ca/spottedleaf/moonrise/paper/PaperHooks.java +@@ -1,0 +_,241 @@ ++package ca.spottedleaf.moonrise.paper; ++ ++import ca.spottedleaf.moonrise.common.PlatformHooks; ++import ca.spottedleaf.moonrise.paper.util.BaseChunkSystemHooks; ++import com.mojang.datafixers.DSL; ++import com.mojang.datafixers.DataFixer; ++import com.mojang.serialization.Dynamic; ++import java.util.Collection; ++import net.minecraft.core.BlockPos; ++import net.minecraft.nbt.CompoundTag; ++import net.minecraft.nbt.NbtOps; ++import net.minecraft.server.level.ChunkHolder; ++import net.minecraft.server.level.GenerationChunkHolder; ++import net.minecraft.server.level.ServerLevel; ++import net.minecraft.server.level.ServerPlayer; ++import net.minecraft.world.entity.Entity; ++import net.minecraft.world.entity.boss.EnderDragonPart; ++import net.minecraft.world.level.BlockGetter; ++import net.minecraft.world.level.ChunkPos; ++import net.minecraft.world.level.Level; ++import net.minecraft.world.level.block.state.BlockState; ++import net.minecraft.world.level.chunk.ChunkAccess; ++import net.minecraft.world.level.chunk.LevelChunk; ++import net.minecraft.world.level.chunk.ProtoChunk; ++import net.minecraft.world.level.chunk.storage.SerializableChunkData; ++import net.minecraft.world.level.entity.EntityTypeTest; ++import net.minecraft.world.phys.AABB; ++import java.util.List; ++import java.util.function.Predicate; ++ ++public final class PaperHooks extends BaseChunkSystemHooks implements PlatformHooks { ++ ++ @Override ++ public String getBrand() { ++ return "Paper"; ++ } ++ ++ @Override ++ public int getLightEmission(final BlockState blockState, final BlockGetter world, final BlockPos pos) { ++ return blockState.getLightEmission(); ++ } ++ ++ @Override ++ public Predicate maybeHasLightEmission() { ++ return (final BlockState state) -> { ++ return state.getLightEmission() != 0; ++ }; ++ } ++ ++ @Override ++ public boolean hasCurrentlyLoadingChunk() { ++ return false; ++ } ++ ++ @Override ++ public LevelChunk getCurrentlyLoadingChunk(final GenerationChunkHolder holder) { ++ return null; ++ } ++ ++ @Override ++ public void setCurrentlyLoading(final GenerationChunkHolder holder, final LevelChunk levelChunk) { ++ ++ } ++ ++ @Override ++ public void chunkFullStatusComplete(final LevelChunk newChunk, final ProtoChunk original) { ++ ++ } ++ ++ @Override ++ public boolean allowAsyncTicketUpdates() { ++ return true; ++ } ++ ++ @Override ++ public void onChunkHolderTicketChange(final ServerLevel world, final ChunkHolder holder, final int oldLevel, final int newLevel) { ++ ++ } ++ ++ @Override ++ public void chunkUnloadFromWorld(final LevelChunk chunk) { ++ ++ } ++ ++ @Override ++ public void chunkSyncSave(final ServerLevel world, final ChunkAccess chunk, final SerializableChunkData data) { ++ ++ } ++ ++ @Override ++ public void onChunkWatch(final ServerLevel world, final LevelChunk chunk, final ServerPlayer player) { ++ ++ } ++ ++ @Override ++ public void onChunkUnWatch(final ServerLevel world, final ChunkPos chunk, final ServerPlayer player) { ++ ++ } ++ ++ @Override ++ public void addToGetEntities(final Level world, final Entity entity, final AABB boundingBox, final Predicate predicate, final List into) { ++ final Collection parts = world.dragonParts(); ++ if (parts.isEmpty()) { ++ return; ++ } ++ ++ for (final EnderDragonPart part : parts) { ++ if (part != entity && part.getBoundingBox().intersects(boundingBox) && (predicate == null || predicate.test(part))) { ++ into.add(part); ++ } ++ } ++ } ++ ++ @Override ++ public void addToGetEntities(final Level world, final EntityTypeTest entityTypeTest, final AABB boundingBox, final Predicate predicate, final List into, final int maxCount) { ++ if (into.size() >= maxCount) { ++ // fix neoforge issue: do not add if list is already full ++ return; ++ } ++ ++ final Collection parts = world.dragonParts(); ++ if (parts.isEmpty()) { ++ return; ++ } ++ for (final EnderDragonPart part : parts) { ++ if (!part.getBoundingBox().intersects(boundingBox)) { ++ continue; ++ } ++ final T casted = (T)entityTypeTest.tryCast(part); ++ if (casted != null && (predicate == null || predicate.test(casted))) { ++ into.add(casted); ++ if (into.size() >= maxCount) { ++ break; ++ } ++ } ++ } ++ } ++ ++ @Override ++ public void entityMove(final Entity entity, final long oldSection, final long newSection) { ++ ++ } ++ ++ @Override ++ public boolean screenEntity(final ServerLevel world, final Entity entity, final boolean fromDisk, final boolean event) { ++ return true; ++ } ++ ++ @Override ++ public boolean configFixMC224294() { ++ return true; ++ } ++ ++ @Override ++ public boolean configAutoConfigSendDistance() { ++ return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingAdvanced.autoConfigSendDistance; ++ } ++ ++ @Override ++ public double configPlayerMaxLoadRate() { ++ return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkLoadRate; ++ } ++ ++ @Override ++ public double configPlayerMaxGenRate() { ++ return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkGenerateRate; ++ } ++ ++ @Override ++ public double configPlayerMaxSendRate() { ++ return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkSendRate; ++ } ++ ++ @Override ++ public int configPlayerMaxConcurrentLoads() { ++ return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingAdvanced.playerMaxConcurrentChunkLoads; ++ } ++ ++ @Override ++ public int configPlayerMaxConcurrentGens() { ++ return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingAdvanced.playerMaxConcurrentChunkGenerates; ++ } ++ ++ @Override ++ public long configAutoSaveInterval(final ServerLevel world) { ++ return world.paperConfig().chunks.autoSaveInterval.value(); ++ } ++ ++ @Override ++ public int configMaxAutoSavePerTick(final ServerLevel world) { ++ return world.paperConfig().chunks.maxAutoSaveChunksPerTick; ++ } ++ ++ @Override ++ public boolean configFixMC159283() { ++ return true; ++ } ++ ++ @Override ++ public boolean forceNoSave(final ChunkAccess chunk) { ++ return chunk instanceof LevelChunk levelChunk && levelChunk.mustNotSave; ++ } ++ ++ @Override ++ public CompoundTag convertNBT(final DSL.TypeReference type, final DataFixer dataFixer, final CompoundTag nbt, ++ final int fromVersion, final int toVersion) { ++ return (CompoundTag)dataFixer.update( ++ type, new Dynamic<>(NbtOps.INSTANCE, nbt), fromVersion, toVersion ++ ).getValue(); ++ } ++ ++ @Override ++ public boolean hasMainChunkLoadHook() { ++ return false; ++ } ++ ++ @Override ++ public void mainChunkLoad(final ChunkAccess chunk, final SerializableChunkData chunkData) { ++ ++ } ++ ++ @Override ++ public List modifySavedEntities(final ServerLevel world, final int chunkX, final int chunkZ, final List entities) { ++ return entities; ++ } ++ ++ @Override ++ public void unloadEntity(final Entity entity) { ++ entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK, org.bukkit.event.entity.EntityRemoveEvent.Cause.UNLOAD); ++ } ++ ++ @Override ++ public void postLoadProtoChunk(final ServerLevel world, final ProtoChunk chunk) { ++ net.minecraft.world.level.chunk.status.ChunkStatusTasks.postLoadProtoChunk(world, chunk.getEntities()); ++ } ++ ++ @Override ++ public int modifyEntityTrackingRange(final Entity entity, final int currentRange) { ++ return org.spigotmc.TrackingRange.getEntityTrackingRange(entity, currentRange); ++ } ++} diff --git a/paper-server/patches/features/0001-Add-PaperHooks.patch b/paper-server/patches/sources/ca/spottedleaf/moonrise/paper/util/BaseChunkSystemHooks.java.patch similarity index 59% rename from paper-server/patches/features/0001-Add-PaperHooks.patch rename to paper-server/patches/sources/ca/spottedleaf/moonrise/paper/util/BaseChunkSystemHooks.java.patch index 5df4d535a5..1835941481 100644 --- a/paper-server/patches/features/0001-Add-PaperHooks.patch +++ b/paper-server/patches/sources/ca/spottedleaf/moonrise/paper/util/BaseChunkSystemHooks.java.patch @@ -1,262 +1,6 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Spottedleaf -Date: Mon, 16 Dec 2024 09:03:35 -0800 -Subject: [PATCH] Add PaperHooks - - -diff --git a/ca/spottedleaf/moonrise/paper/PaperHooks.java b/ca/spottedleaf/moonrise/paper/PaperHooks.java -new file mode 100644 -index 0000000000000000000000000000000000000000..2988c418b34d6f699a9c24406cfd6949465b64f0 ---- /dev/null -+++ b/ca/spottedleaf/moonrise/paper/PaperHooks.java -@@ -0,0 +1,241 @@ -+package ca.spottedleaf.moonrise.paper; -+ -+import ca.spottedleaf.moonrise.common.PlatformHooks; -+import ca.spottedleaf.moonrise.paper.util.BaseChunkSystemHooks; -+import com.mojang.datafixers.DSL; -+import com.mojang.datafixers.DataFixer; -+import com.mojang.serialization.Dynamic; -+import java.util.Collection; -+import net.minecraft.core.BlockPos; -+import net.minecraft.nbt.CompoundTag; -+import net.minecraft.nbt.NbtOps; -+import net.minecraft.server.level.ChunkHolder; -+import net.minecraft.server.level.GenerationChunkHolder; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.entity.boss.EnderDragonPart; -+import net.minecraft.world.level.BlockGetter; -+import net.minecraft.world.level.ChunkPos; -+import net.minecraft.world.level.Level; -+import net.minecraft.world.level.block.state.BlockState; -+import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.LevelChunk; -+import net.minecraft.world.level.chunk.ProtoChunk; -+import net.minecraft.world.level.chunk.storage.SerializableChunkData; -+import net.minecraft.world.level.entity.EntityTypeTest; -+import net.minecraft.world.phys.AABB; -+import java.util.List; -+import java.util.function.Predicate; -+ -+public final class PaperHooks extends BaseChunkSystemHooks implements PlatformHooks { -+ -+ @Override -+ public String getBrand() { -+ return "Paper"; -+ } -+ -+ @Override -+ public int getLightEmission(final BlockState blockState, final BlockGetter world, final BlockPos pos) { -+ return blockState.getLightEmission(); -+ } -+ -+ @Override -+ public Predicate maybeHasLightEmission() { -+ return (final BlockState state) -> { -+ return state.getLightEmission() != 0; -+ }; -+ } -+ -+ @Override -+ public boolean hasCurrentlyLoadingChunk() { -+ return false; -+ } -+ -+ @Override -+ public LevelChunk getCurrentlyLoadingChunk(final GenerationChunkHolder holder) { -+ return null; -+ } -+ -+ @Override -+ public void setCurrentlyLoading(final GenerationChunkHolder holder, final LevelChunk levelChunk) { -+ -+ } -+ -+ @Override -+ public void chunkFullStatusComplete(final LevelChunk newChunk, final ProtoChunk original) { -+ -+ } -+ -+ @Override -+ public boolean allowAsyncTicketUpdates() { -+ return true; -+ } -+ -+ @Override -+ public void onChunkHolderTicketChange(final ServerLevel world, final ChunkHolder holder, final int oldLevel, final int newLevel) { -+ -+ } -+ -+ @Override -+ public void chunkUnloadFromWorld(final LevelChunk chunk) { -+ -+ } -+ -+ @Override -+ public void chunkSyncSave(final ServerLevel world, final ChunkAccess chunk, final SerializableChunkData data) { -+ -+ } -+ -+ @Override -+ public void onChunkWatch(final ServerLevel world, final LevelChunk chunk, final ServerPlayer player) { -+ -+ } -+ -+ @Override -+ public void onChunkUnWatch(final ServerLevel world, final ChunkPos chunk, final ServerPlayer player) { -+ -+ } -+ -+ @Override -+ public void addToGetEntities(final Level world, final Entity entity, final AABB boundingBox, final Predicate predicate, final List into) { -+ final Collection parts = world.dragonParts(); -+ if (parts.isEmpty()) { -+ return; -+ } -+ -+ for (final EnderDragonPart part : parts) { -+ if (part != entity && part.getBoundingBox().intersects(boundingBox) && (predicate == null || predicate.test(part))) { -+ into.add(part); -+ } -+ } -+ } -+ -+ @Override -+ public void addToGetEntities(final Level world, final EntityTypeTest entityTypeTest, final AABB boundingBox, final Predicate predicate, final List into, final int maxCount) { -+ if (into.size() >= maxCount) { -+ // fix neoforge issue: do not add if list is already full -+ return; -+ } -+ -+ final Collection parts = world.dragonParts(); -+ if (parts.isEmpty()) { -+ return; -+ } -+ for (final EnderDragonPart part : parts) { -+ if (!part.getBoundingBox().intersects(boundingBox)) { -+ continue; -+ } -+ final T casted = (T)entityTypeTest.tryCast(part); -+ if (casted != null && (predicate == null || predicate.test(casted))) { -+ into.add(casted); -+ if (into.size() >= maxCount) { -+ break; -+ } -+ } -+ } -+ } -+ -+ @Override -+ public void entityMove(final Entity entity, final long oldSection, final long newSection) { -+ -+ } -+ -+ @Override -+ public boolean screenEntity(final ServerLevel world, final Entity entity, final boolean fromDisk, final boolean event) { -+ return true; -+ } -+ -+ @Override -+ public boolean configFixMC224294() { -+ return true; -+ } -+ -+ @Override -+ public boolean configAutoConfigSendDistance() { -+ return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingAdvanced.autoConfigSendDistance; -+ } -+ -+ @Override -+ public double configPlayerMaxLoadRate() { -+ return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkLoadRate; -+ } -+ -+ @Override -+ public double configPlayerMaxGenRate() { -+ return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkGenerateRate; -+ } -+ -+ @Override -+ public double configPlayerMaxSendRate() { -+ return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingBasic.playerMaxChunkSendRate; -+ } -+ -+ @Override -+ public int configPlayerMaxConcurrentLoads() { -+ return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingAdvanced.playerMaxConcurrentChunkLoads; -+ } -+ -+ @Override -+ public int configPlayerMaxConcurrentGens() { -+ return io.papermc.paper.configuration.GlobalConfiguration.get().chunkLoadingAdvanced.playerMaxConcurrentChunkGenerates; -+ } -+ -+ @Override -+ public long configAutoSaveInterval(final ServerLevel world) { -+ return world.paperConfig().chunks.autoSaveInterval.value(); -+ } -+ -+ @Override -+ public int configMaxAutoSavePerTick(final ServerLevel world) { -+ return world.paperConfig().chunks.maxAutoSaveChunksPerTick; -+ } -+ -+ @Override -+ public boolean configFixMC159283() { -+ return true; -+ } -+ -+ @Override -+ public boolean forceNoSave(final ChunkAccess chunk) { -+ return chunk instanceof LevelChunk levelChunk && levelChunk.mustNotSave; -+ } -+ -+ @Override -+ public CompoundTag convertNBT(final DSL.TypeReference type, final DataFixer dataFixer, final CompoundTag nbt, -+ final int fromVersion, final int toVersion) { -+ return (CompoundTag)dataFixer.update( -+ type, new Dynamic<>(NbtOps.INSTANCE, nbt), fromVersion, toVersion -+ ).getValue(); -+ } -+ -+ @Override -+ public boolean hasMainChunkLoadHook() { -+ return false; -+ } -+ -+ @Override -+ public void mainChunkLoad(final ChunkAccess chunk, final SerializableChunkData chunkData) { -+ -+ } -+ -+ @Override -+ public List modifySavedEntities(final ServerLevel world, final int chunkX, final int chunkZ, final List entities) { -+ return entities; -+ } -+ -+ @Override -+ public void unloadEntity(final Entity entity) { -+ entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK, org.bukkit.event.entity.EntityRemoveEvent.Cause.UNLOAD); -+ } -+ -+ @Override -+ public void postLoadProtoChunk(final ServerLevel world, final ProtoChunk chunk) { -+ net.minecraft.world.level.chunk.status.ChunkStatusTasks.postLoadProtoChunk(world, chunk.getEntities()); -+ } -+ -+ @Override -+ public int modifyEntityTrackingRange(final Entity entity, final int currentRange) { -+ return org.spigotmc.TrackingRange.getEntityTrackingRange(entity, currentRange); -+ } -+} -diff --git a/ca/spottedleaf/moonrise/paper/util/BaseChunkSystemHooks.java b/ca/spottedleaf/moonrise/paper/util/BaseChunkSystemHooks.java -new file mode 100644 -index 0000000000000000000000000000000000000000..34b45bc11124efb22f0f3ae5b2ad8f445c719476 --- /dev/null +++ b/ca/spottedleaf/moonrise/paper/util/BaseChunkSystemHooks.java -@@ -0,0 +1,332 @@ +@@ -1,0 +_,332 @@ +package ca.spottedleaf.moonrise.paper.util; + +import ca.spottedleaf.concurrentutil.util.Priority; diff --git a/paper-server/patches/sources/net/minecraft/Util.java.patch b/paper-server/patches/sources/net/minecraft/Util.java.patch index 946139d552..ebf86ad6c2 100644 --- a/paper-server/patches/sources/net/minecraft/Util.java.patch +++ b/paper-server/patches/sources/net/minecraft/Util.java.patch @@ -28,6 +28,14 @@ private static final DateTimeFormatter FILENAME_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss", Locale.ROOT); public static final int LINEAR_LOOKUP_THRESHOLD = 8; private static final Set ALLOWED_UNTRUSTED_LINK_PROTOCOLS = Set.of("http", "https"); +@@ -113,6 +_,7 @@ + .findFirst() + .orElseThrow(() -> new IllegalStateException("No jar file system provider found")); + private static Consumer thePauser = string -> {}; ++ public static final double COLLISION_EPSILON = 1.0E-7; // Paper - Check distance in entity interactions + + public static Collector, ?, Map> toMap() { + return Collectors.toMap(Entry::getKey, Entry::getValue); @@ -135,7 +_,7 @@ } diff --git a/paper-server/patches/sources/net/minecraft/core/Vec3i.java.patch b/paper-server/patches/sources/net/minecraft/core/Vec3i.java.patch index cd374686c0..09caa51586 100644 --- a/paper-server/patches/sources/net/minecraft/core/Vec3i.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/Vec3i.java.patch @@ -47,3 +47,14 @@ return this.z; } +@@ -235,4 +_,10 @@ + public String toShortString() { + return this.getX() + ", " + this.getY() + ", " + this.getZ(); + } ++ ++ // Paper start - Perf: Optimize isInWorldBounds ++ public final boolean isInsideBuildHeightAndWorldBoundsHorizontal(final net.minecraft.world.level.LevelHeightAccessor levelHeightAccessor) { ++ return this.getX() >= -30000000 && this.getZ() >= -30000000 && this.getX() < 30000000 && this.getZ() < 30000000 && !levelHeightAccessor.isOutsideBuildHeight(this.getY()); ++ } ++ // Paper end - Perf: Optimize isInWorldBounds + } 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 b8d9ca742e..6bb71f81a0 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 @@ -1059,7 +1059,7 @@ String string = "onTrackingStart called during navigation iteration"; Util.logAndPauseIfInIde( "onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration") -@@ -1757,10 +_,51 @@ +@@ -1757,10 +_,52 @@ } entity.updateDynamicGameEventListener(DynamicGameEventListener::add); @@ -1081,8 +1081,7 @@ @Override public void onTrackingEnd(Entity entity) { + org.spigotmc.AsyncCatcher.catchOp("entity unregister"); // Spigot -+ // Spigot start -+ // TODO I don't think this is needed anymore ++ // Spigot start // TODO I don't think this is needed anymore + if (entity instanceof Player player) { + for (final ServerLevel level : ServerLevel.this.getServer().getAllLevels()) { + for (final Optional savedData : level.getDataStorage().cache.values()) { @@ -1091,7 +1090,9 @@ + } + + map.carriedByPlayers.remove(player); -+ map.carriedBy.removeIf(holdingPlayer -> holdingPlayer.player == player); ++ if (map.carriedBy.removeIf(holdingPlayer -> holdingPlayer.player == player)) { ++ map.decorations.remove(player.getName().getString()); ++ } + } + } + } 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 7c69b49dd9..c32e052b23 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 @@ -1342,7 +1342,7 @@ } public SectionPos getLastSectionPos() { -@@ -1930,16 +_,41 @@ +@@ -1930,21 +_,54 @@ } @Override @@ -1386,6 +1386,19 @@ } this.awardStat(Stats.DROP); + } + ++ // Paper start - remove player from map on drop ++ if (item.getItem() == net.minecraft.world.item.Items.FILLED_MAP) { ++ final MapItemSavedData mapData = MapItem.getSavedData(item, this.level()); ++ if (mapData != null) { ++ mapData.tickCarriedBy(this, item); ++ } ++ } ++ // Paper end - remove player from map on drop + return itemEntity; + } + } @@ -1955,6 +_,11 @@ return null; } else { 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 df1aedb289..84c9704c87 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 @@ -497,7 +497,7 @@ return false; } else if (damageSource.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) { return false; -@@ -1116,10 +_,11 @@ +@@ -1116,47 +_,71 @@ amount = 0.0F; } @@ -512,7 +512,11 @@ this.hurtCurrentlyUsedShield(amount); f1 = amount; amount = 0.0F; -@@ -1130,33 +_,56 @@ +- if (!damageSource.is(DamageTypeTags.IS_PROJECTILE) && damageSource.getDirectEntity() instanceof LivingEntity livingEntity) { ++ if (!damageSource.is(DamageTypeTags.IS_PROJECTILE) && damageSource.getDirectEntity() instanceof LivingEntity livingEntity && livingEntity.distanceToSqr(this) <= (200.0D * 200.0D)) { // Paper - Check distance in entity interactions + this.blockUsingShield(livingEntity); + } + flag = true; } @@ -584,9 +588,18 @@ this.markHurt(); } -@@ -1186,7 +_,7 @@ +@@ -1185,8 +_,16 @@ + d = damageSource.getSourcePosition().x() - this.getX(); d1 = damageSource.getSourcePosition().z() - this.getZ(); } ++ // Paper start - Check distance in entity interactions; see for loop in knockback method ++ if (Math.abs(d) > 200) { ++ d = Math.random() - Math.random(); ++ } ++ if (Math.abs(d1) > 200) { ++ d1 = Math.random() - Math.random(); ++ } ++ // Paper end - Check distance in entity interactions - this.knockback(0.4F, d, d1); + this.knockback(0.4F, d, d1, damageSource.getDirectEntity(), damageSource.getDirectEntity() == null ? io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.DAMAGE : io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events @@ -1110,7 +1123,7 @@ + this.hurtCurrentlyUsedShield((float) -event.getDamage(DamageModifier.BLOCKING)); + Entity entity = damageSource.getDirectEntity(); + -+ if (!damageSource.is(DamageTypeTags.IS_PROJECTILE) && entity instanceof LivingEntity) { // Paper - Fix shield disable inconsistency ++ if (!damageSource.is(DamageTypeTags.IS_PROJECTILE) && entity instanceof LivingEntity && entity.distanceToSqr(this) <= (200.0D * 200.0D)) { // Paper - Fix shield disable inconsistency & Check distance in entity interactions + this.blockUsingShield((LivingEntity) entity); + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/AbstractBoat.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/AbstractBoat.java.patch index a5d91baad1..3d61d83b48 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/vehicle/AbstractBoat.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/vehicle/AbstractBoat.java.patch @@ -75,6 +75,15 @@ this.applyEffectsFromBlocks(); this.applyEffectsFromBlocks(); this.tickBubbleColumn(); +@@ -598,7 +_,7 @@ + this.waterLevel = this.getY(1.0); + double d2 = this.getWaterLevelAbove() - this.getBbHeight() + 0.101; + if (this.level().noCollision(this, this.getBoundingBox().move(0.0, d2 - this.getY(), 0.0))) { +- this.setPos(this.getX(), d2, this.getZ()); ++ this.move(MoverType.SELF, new Vec3(0.0D, d2 - this.getY(), 0.0D)); // Paper - Fix some exploit with boats // TODO Still needed? + this.setDeltaMovement(this.getDeltaMovement().multiply(1.0, 0.0, 1.0)); + this.lastYd = 0.0; + } @@ -762,11 +_,18 @@ @Override 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 66f1c0a2ed..9958bd72b6 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 @@ -241,7 +241,7 @@ @Override public boolean isClientSide() { -@@ -167,6 +_,13 @@ +@@ -167,8 +_,15 @@ return null; } @@ -253,14 +253,17 @@ + // Paper end + public boolean isInWorldBounds(BlockPos pos) { - return !this.isOutsideBuildHeight(pos) && isInWorldBoundsHorizontal(pos); +- return !this.isOutsideBuildHeight(pos) && isInWorldBoundsHorizontal(pos); ++ return pos.isInsideBuildHeightAndWorldBoundsHorizontal(this); // Paper - Perf: Optimize isInWorldBounds } + + public static boolean isInSpawnableBounds(BlockPos pos) { @@ -176,21 +_,84 @@ } private static boolean isInWorldBoundsHorizontal(BlockPos pos) { - return pos.getX() >= -30000000 && pos.getZ() >= -30000000 && pos.getX() < 30000000 && pos.getZ() < 30000000; -+ return pos.getX() >= -30000000 && pos.getZ() >= -30000000 && pos.getX() < 30000000 && pos.getZ() < 30000000; // Diff on change warnUnsafeChunk() ++ return pos.getX() >= -30000000 && pos.getZ() >= -30000000 && pos.getX() < 30000000 && pos.getZ() < 30000000; // Diff on change warnUnsafeChunk() and isInsideBuildHeightAndWorldBoundsHorizontal } private static boolean isOutsideSpawnableHeight(int y) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkAccess.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkAccess.java.patch index baf2047d7c..d1b5769824 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkAccess.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/ChunkAccess.java.patch @@ -39,6 +39,14 @@ } private static void replaceMissingSections(Registry biomeRegistry, LevelChunkSection[] sections) { +@@ -123,6 +_,7 @@ + return GameEventListenerRegistry.NOOP; + } + ++ public abstract BlockState getBlockState(final int x, final int y, final int z); // Paper + @Nullable + public abstract BlockState setBlockState(BlockPos pos, BlockState state, boolean isMoving); + @@ -273,6 +_,7 @@ public boolean tryMarkSaved() { if (this.unsaved) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/chunk/ImposterProtoChunk.java.patch b/paper-server/patches/sources/net/minecraft/world/level/chunk/ImposterProtoChunk.java.patch new file mode 100644 index 0000000000..da521db813 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/chunk/ImposterProtoChunk.java.patch @@ -0,0 +1,15 @@ +--- a/net/minecraft/world/level/chunk/ImposterProtoChunk.java ++++ b/net/minecraft/world/level/chunk/ImposterProtoChunk.java +@@ -56,6 +_,12 @@ + public BlockState getBlockState(BlockPos pos) { + return this.wrapped.getBlockState(pos); + } ++ // Paper start ++ @Override ++ public final BlockState getBlockState(final int x, final int y, final int z) { ++ return this.wrapped.getBlockStateFinal(x, y, z); ++ } ++ // Paper end + + @Override + public FluidState getFluidState(BlockPos pos) { 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 9988645334..d0111479a1 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 -@@ -85,6 +_,18 @@ +@@ -85,14 +_,32 @@ return new ChunkAccess.PackedTicks(this.blockTicks.pack(gametime), this.fluidTicks.pack(gametime)); } @@ -18,4 +18,21 @@ + @Override public BlockState getBlockState(BlockPos pos) { - int y = pos.getY(); +- int y = pos.getY(); ++ // Paper start ++ return getBlockState(pos.getX(), pos.getY(), pos.getZ()); ++ } ++ public BlockState getBlockState(final int x, final int y, final int z) { ++ // 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); ++ // Paper start ++ LevelChunkSection section = this.getSections()[this.getSectionIndex(y)]; ++ return section.hasOnlyAir() ? Blocks.AIR.defaultBlockState() : section.getBlockState(x & 15, y & 15, z & 15); ++ // Paper end + } + } + 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 b03e362a20..9aa3e55368 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 @@ -1,26 +1,35 @@ --- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java +++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java +@@ -61,6 +_,7 @@ + public byte scale; + public byte[] colors = new byte[16384]; + public boolean locked; ++ private final org.bukkit.craftbukkit.map.RenderData vanillaRender = new org.bukkit.craftbukkit.map.RenderData(); // Paper - Use Vanilla map renderer when possible + public final List carriedBy = Lists.newArrayList(); + public final Map carriedByPlayers = Maps.newHashMap(); + private final Map bannerMarkers = Maps.newHashMap(); @@ -68,6 +_,13 @@ private final Map frameMarkers = Maps.newHashMap(); private int trackedDecorationCount; + // CraftBukkit start + public final org.bukkit.craftbukkit.map.CraftMapView mapView; -+ private org.bukkit.craftbukkit.CraftServer server; -+ public java.util.UUID uniqueId = null; ++ private final org.bukkit.craftbukkit.CraftServer server; ++ public java.util.UUID uniqueId; + public MapId id; + // CraftBukkit end + public static SavedData.Factory factory() { return new SavedData.Factory<>(() -> { throw new IllegalStateException("Should never create an empty map saved data"); -@@ -82,6 +_,10 @@ +@@ -82,6 +_,11 @@ this.trackingPosition = trackingPosition; this.unlimitedTracking = unlimitedTracking; this.locked = locked; + // CraftBukkit start + this.mapView = new org.bukkit.craftbukkit.map.CraftMapView(this); + this.server = (org.bukkit.craftbukkit.CraftServer) org.bukkit.Bukkit.getServer(); ++ this.vanillaRender.buffer = colors; // Paper - Use Vanilla map renderer when possible + // CraftBukkit end } @@ -76,6 +85,14 @@ int _int = tag.getInt("xCenter"); int _int1 = tag.getInt("zCenter"); byte b = (byte)Mth.clamp(tag.getByte("scale"), 0, 4); +@@ -114,6 +_,7 @@ + if (byteArray.length == 16384) { + mapItemSavedData.colors = byteArray; + } ++ mapItemSavedData.vanillaRender.buffer = byteArray; // Paper - Use Vanilla map renderer when possible + + RegistryOps registryOps = levelRegistry.createSerializationContext(NbtOps.INSTANCE); + @@ -154,6 +_,25 @@ .encodeStart(NbtOps.INSTANCE, this.dimension.location()) .resultOrPartial(LOGGER::error) @@ -115,6 +132,15 @@ } MapDecorations mapDecorations = mapStack.getOrDefault(DataComponents.MAP_DECORATIONS, MapDecorations.EMPTY); +@@ -267,7 +_,7 @@ + this.trackedDecorationCount--; + } + +- this.setDecorationsDirty(); ++ if (mapDecoration != null) this.setDecorationsDirty(); // Paper - only mark dirty if a change occurs + } + + public static void addTargetDecoration(ItemStack stack, BlockPos pos, String type, Holder mapDecorationType) { @@ -421,7 +_,7 @@ return true; } @@ -142,11 +168,21 @@ } } -@@ -540,17 +_,27 @@ +@@ -540,17 +_,38 @@ @Nullable Packet nextUpdatePacket(MapId mapId) { MapItemSavedData.MapPatch mapPatch; -+ org.bukkit.craftbukkit.map.RenderData render = MapItemSavedData.this.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) this.player.getBukkitEntity()); // CraftBukkit ++ // Paper start ++ if (!this.dirtyData && this.tick % 5 != 0) { ++ // this won't end up sending, so don't render it! ++ this.tick++; ++ return null; ++ } ++ ++ final boolean vanillaMaps = this.shouldUseVanillaMap(); ++ // Use Vanilla map renderer when possible - much simpler/faster than the CB rendering ++ org.bukkit.craftbukkit.map.RenderData render = !vanillaMaps ? MapItemSavedData.this.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) this.player.getBukkitEntity()) : MapItemSavedData.this.vanillaRender; ++ // Paper end if (this.dirtyData) { this.dirtyData = false; - mapPatch = this.createPatch(); @@ -157,11 +193,12 @@ Collection collection; - if (this.dirtyDecorations && this.tick++ % 5 == 0) { -+ if ((true || this.dirtyDecorations) && this.tick++ % 5 == 0) { // CraftBukkit - custom maps don't update this yet ++ if ((true || this.dirtyDecorations) && this.tick++ % 5 == 0) { // CraftBukkit - custom maps don't update this yet // TODO fix this this.dirtyDecorations = false; - collection = MapItemSavedData.this.decorations.values(); + // CraftBukkit start + java.util.Collection icons = new java.util.ArrayList(); ++ if (vanillaMaps) this.addSeenPlayers(icons); // Paper + + for (org.bukkit.map.MapCursor cursor : render.cursors) { + if (cursor.isVisible()) { @@ -173,3 +210,27 @@ } else { collection = null; } +@@ -578,6 +_,23 @@ + private void markDecorationsDirty() { + this.dirtyDecorations = true; + } ++ ++ // Paper start ++ private void addSeenPlayers(java.util.Collection icons) { ++ org.bukkit.entity.Player player = (org.bukkit.entity.Player) this.player.getBukkitEntity(); ++ MapItemSavedData.this.decorations.forEach((name, mapIcon) -> { ++ // If this cursor is for a player check visibility with vanish system ++ org.bukkit.entity.Player other = org.bukkit.Bukkit.getPlayerExact(name); // Spigot ++ if (other == null || player.canSee(other)) { ++ icons.add(mapIcon); ++ } ++ }); ++ } ++ ++ private boolean shouldUseVanillaMap() { ++ return mapView.getRenderers().size() == 1 && mapView.getRenderers().getFirst().getClass() == org.bukkit.craftbukkit.map.CraftMapRenderer.class; ++ } ++ // Paper end + } + + record MapDecorationLocation(Holder type, byte x, byte y, byte rot) {