diff --git a/patches/server/0007-Leaves-Protocol-Core.patch b/patches/server/0007-Leaves-Protocol-Core.patch index 5177fbac..80609aa9 100644 --- a/patches/server/0007-Leaves-Protocol-Core.patch +++ b/patches/server/0007-Leaves-Protocol-Core.patch @@ -33,6 +33,19 @@ index 7655987d061bdb2839b30f926efb034046feaea3..7ae6b2bb868cc3d391bae87fa5e141cf } }; } +diff --git a/src/main/java/net/minecraft/resources/ResourceLocation.java b/src/main/java/net/minecraft/resources/ResourceLocation.java +index 1967c43ee3a12e63365cc40ee6565307e2fd73cf..6e376d0db5321d8e9b6e0b54617ffd171bf4ee73 100644 +--- a/src/main/java/net/minecraft/resources/ResourceLocation.java ++++ b/src/main/java/net/minecraft/resources/ResourceLocation.java +@@ -36,7 +36,7 @@ public final class ResourceLocation implements Comparable { + private final String namespace; + private final String path; + +- private ResourceLocation(String namespace, String path) { ++ public ResourceLocation(String namespace, String path) { // Leaves - private -> public + assert isValidNamespace(namespace); + + assert isValidPath(path); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 1b8f7ff3b0ccef6ce3ac99eecf98622fb13f9269..307c5a0b4b7c68fe2c7d1cf77ff23c766335882d 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java @@ -163,13 +176,14 @@ index 0000000000000000000000000000000000000000..986d2a6641ff8017dddf3e5f2655adfc +} diff --git a/src/main/java/org/leavesmc/leaves/protocol/core/LeavesProtocolManager.java b/src/main/java/org/leavesmc/leaves/protocol/core/LeavesProtocolManager.java new file mode 100644 -index 0000000000000000000000000000000000000000..3a33982b92bfb12ce1284fb9429672a698a7ce4b +index 0000000000000000000000000000000000000000..87fe53e19b66ece66dc0654fb79923418210aa4a --- /dev/null +++ b/src/main/java/org/leavesmc/leaves/protocol/core/LeavesProtocolManager.java -@@ -0,0 +1,365 @@ +@@ -0,0 +1,366 @@ +package org.leavesmc.leaves.protocol.core; + +import net.minecraft.network.FriendlyByteBuf; ++import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import org.apache.commons.lang.ArrayUtils; @@ -333,7 +347,7 @@ index 0000000000000000000000000000000000000000..3a33982b92bfb12ce1284fb9429672a6 + + public static void handlePayload(ServerPlayer player, LeavesCustomPayload payload) { + if (payload instanceof ErrorPayload errorPayload) { -+ player.connection.disconnect("Payload " + Arrays.toString(errorPayload.packetID) + " from " + Arrays.toString(errorPayload.protocolID) + " error", PlayerKickEvent.Cause.INVALID_PAYLOAD); ++ player.connection.disconnect(Component.literal("Payload " + Arrays.toString(errorPayload.packetID) + " from " + Arrays.toString(errorPayload.protocolID) + " error"), PlayerKickEvent.Cause.INVALID_PAYLOAD); + return; + } + diff --git a/patches/server/0010-Fakeplayer-support.patch b/patches/server/0010-Fakeplayer-support.patch index 4c6478af..b53127e2 100644 --- a/patches/server/0010-Fakeplayer-support.patch +++ b/patches/server/0010-Fakeplayer-support.patch @@ -1318,10 +1318,10 @@ index 0000000000000000000000000000000000000000..0db337866c71283464d026a4f230016b +} diff --git a/src/main/java/org/leavesmc/leaves/bot/ServerBot.java b/src/main/java/org/leavesmc/leaves/bot/ServerBot.java new file mode 100644 -index 0000000000000000000000000000000000000000..bba57a2d72ab3051aacd4f4defa3e7377511c36b +index 0000000000000000000000000000000000000000..549fd54c35c8283200562d678fa4bba593878c62 --- /dev/null +++ b/src/main/java/org/leavesmc/leaves/bot/ServerBot.java -@@ -0,0 +1,716 @@ +@@ -0,0 +1,725 @@ +package org.leavesmc.leaves.bot; + +import com.google.common.collect.Lists; @@ -1337,7 +1337,6 @@ index 0000000000000000000000000000000000000000..bba57a2d72ab3051aacd4f4defa3e737 +import net.minecraft.network.PacketSendListener; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketFlow; -+import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket; @@ -1345,6 +1344,7 @@ index 0000000000000000000000000000000000000000..bba57a2d72ab3051aacd4f4defa3e737 +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.EntityDataSerializers; +import net.minecraft.server.MinecraftServer; ++import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; @@ -1365,6 +1365,7 @@ index 0000000000000000000000000000000000000000..bba57a2d72ab3051aacd4f4defa3e737 +import net.minecraft.world.inventory.ChestMenu; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.gameevent.GameEvent; ++import net.minecraft.world.level.portal.DimensionTransition; +import net.minecraft.world.level.storage.LevelResource; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; @@ -1377,7 +1378,9 @@ index 0000000000000000000000000000000000000000..bba57a2d72ab3051aacd4f4defa3e737 +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.LeavesConfig; ++import org.leavesmc.leaves.LeavesLogger; +import org.leavesmc.leaves.bot.agent.BotAction; +import org.leavesmc.leaves.bot.agent.actions.StopAction; +import org.leavesmc.leaves.entity.Bot; @@ -1387,7 +1390,6 @@ index 0000000000000000000000000000000000000000..bba57a2d72ab3051aacd4f4defa3e737 +import org.leavesmc.leaves.event.bot.BotJoinEvent; +import org.leavesmc.leaves.util.MathUtils; + -+import javax.annotation.Nullable; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; @@ -1548,13 +1550,20 @@ index 0000000000000000000000000000000000000000..bba57a2d72ab3051aacd4f4defa3e737 + } + + public void sendFakeData(ServerPlayerConnection playerConnection, boolean login) { -+ playerConnection.send(new ClientboundAddEntityPacket(this)); ++ ChunkMap.TrackedEntity entityTracker = ((ServerLevel) this.level()).getChunkSource().chunkMap.entityMap.get(this.getId()); ++ ++ if (entityTracker == null) { ++ LeavesLogger.LOGGER.warning("Fakeplayer cant get entity tracker for " + this.getId()); ++ return; ++ } ++ ++ playerConnection.send(this.getAddEntityPacket(entityTracker.serverEntity)); + if (login) { + Bukkit.getScheduler().runTaskLater(CraftScheduler.MINECRAFT, () -> { -+ connection.send(new ClientboundRotateHeadPacket(this, (byte) ((getYRot() * 256f) / 360f))); ++ playerConnection.send(new ClientboundRotateHeadPacket(this, (byte) ((getYRot() * 256f) / 360f))); + }, 10); + } else { -+ connection.send(new ClientboundRotateHeadPacket(this, (byte) ((getYRot() * 256f) / 360f))); ++ playerConnection.send(new ClientboundRotateHeadPacket(this, (byte) ((getYRot() * 256f) / 360f))); + } + } + @@ -1597,7 +1606,7 @@ index 0000000000000000000000000000000000000000..bba57a2d72ab3051aacd4f4defa3e737 + + @Nullable + @Override -+ public Entity changeDimension(@NotNull ServerLevel destination) { ++ public Entity changeDimension(@NotNull DimensionTransition teleportTarget) { + return null; // disable dimension change + } + diff --git a/patches/server/0039-Jade-Protocol.patch b/patches/server/0039-Jade-Protocol.patch index 3cd1a92f..b0b0165a 100644 --- a/patches/server/0039-Jade-Protocol.patch +++ b/patches/server/0039-Jade-Protocol.patch @@ -46,7 +46,7 @@ index 055f4b87c01ee7ecf7d2a111b72cc5aa85d9fbe8..5d9030f4787a43c56ae9455180badd56 public Optional nextSpawnData; diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/JadeProtocol.java b/src/main/java/org/leavesmc/leaves/protocol/jade/JadeProtocol.java new file mode 100644 -index 0000000000000000000000000000000000000000..cd5dfd55b6554e47a336c7aa4cb24db3cb4919dd +index 0000000000000000000000000000000000000000..33741d707715619929e5412a786470c5372f5978 --- /dev/null +++ b/src/main/java/org/leavesmc/leaves/protocol/jade/JadeProtocol.java @@ -0,0 +1,343 @@ @@ -160,7 +160,7 @@ index 0000000000000000000000000000000000000000..cd5dfd55b6554e47a336c7aa4cb24db3 + + @Contract("_ -> new") + public static @NotNull ResourceLocation mc_id(String path) { -+ return new ResourceLocation(path); ++ return ResourceLocation.withDefaultNamespace(path); + } + + private static boolean isPrimaryKey(ResourceLocation key) { @@ -824,7 +824,7 @@ index 0000000000000000000000000000000000000000..fd4112ed1911171b3c6b5840b7184b5f +} diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/CampfireProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/CampfireProvider.java new file mode 100644 -index 0000000000000000000000000000000000000000..d22013480b53017db71697af37c0b3daa19c7ac5 +index 0000000000000000000000000000000000000000..a1a479987f2c0b6ff4cfd511cbcac1ea7b1c247b --- /dev/null +++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/CampfireProvider.java @@ -0,0 +1,52 @@ @@ -864,7 +864,7 @@ index 0000000000000000000000000000000000000000..d22013480b53017db71697af37c0b3da + stack = stack.copy(); + + CustomData customData = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY) -+ .update(COOKING_TIME_CODEC, campfire.cookingTime[i] - campfire.cookingProgress[i]) ++ .update(NbtOps.INSTANCE, COOKING_TIME_CODEC, campfire.cookingTime[i] - campfire.cookingProgress[i]) + .getOrThrow(); + stack.set(DataComponents.CUSTOM_DATA, customData); + diff --git a/patches/server/0046-Return-nether-portal-fix.patch b/patches/server/0046-Return-nether-portal-fix.patch index 8f62aeb9..7951eabb 100644 --- a/patches/server/0046-Return-nether-portal-fix.patch +++ b/patches/server/0046-Return-nether-portal-fix.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Return nether portal fix This patch is powered by NetherPortalFix(https://github.com/TwelveIterationMods/NetherPortalFix) diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 636c79ab0bab81812d879301b02eb25f3868eeef..209f1a577d01385f942ed8d2fd48d633cc87e234 100644 +index 636c79ab0bab81812d879301b02eb25f3868eeef..c6905ad01218ce5491fc87d83f80b39c3e25db18 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -17,6 +17,8 @@ import java.util.OptionalInt; @@ -18,15 +18,7 @@ index 636c79ab0bab81812d879301b02eb25f3868eeef..209f1a577d01385f942ed8d2fd48d633 import net.minecraft.ChatFormatting; import net.minecraft.CrashReport; import net.minecraft.CrashReportCategory; -@@ -161,6 +163,7 @@ import net.minecraft.world.phys.Vec3; - import net.minecraft.world.scores.PlayerTeam; - import net.minecraft.world.scores.ScoreAccess; - import net.minecraft.world.scores.ScoreHolder; -+import org.leavesmc.leaves.util.ReturnPortalManager; - import org.slf4j.Logger; - import net.minecraft.world.Container; - import net.minecraft.world.InteractionHand; -@@ -1437,6 +1440,24 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple +@@ -1437,6 +1439,21 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple PlayerChangedWorldEvent changeEvent = new PlayerChangedWorldEvent(this.getBukkitEntity(), worldserver1.getWorld()); this.level().getCraftServer().getPluginManager().callEvent(changeEvent); // CraftBukkit end @@ -37,13 +29,10 @@ index 636c79ab0bab81812d879301b02eb25f3868eeef..209f1a577d01385f942ed8d2fd48d633 + final ResourceKey OVERWORLD = Level.OVERWORLD; + final ResourceKey THE_NETHER = Level.NETHER; + if (!((fromDim != OVERWORLD || toDim != THE_NETHER) && (fromDim != THE_NETHER || toDim != OVERWORLD))) { -+ BlockPos lastPos = this.lastPos; -+ if (lastPos != null) { -+ BlockUtil.FoundRectangle fromPortal = ReturnPortalManager.findPortalAt(this, fromDim, lastPos); -+ BlockPos toPos = this.blockPosition(); -+ if (fromPortal != null) { -+ ReturnPortalManager.storeReturnPortal(this, toDim, toPos, fromPortal); -+ } ++ BlockPos fromPortal = org.leavesmc.leaves.util.ReturnPortalManager.findPortalAt(this, fromDim, lastPos); ++ BlockPos toPos = this.blockPosition(); ++ if (fromPortal != null) { ++ org.leavesmc.leaves.util.ReturnPortalManager.storeReturnPortal(this, toDim, toPos, fromPortal); + } + } + } @@ -52,18 +41,10 @@ index 636c79ab0bab81812d879301b02eb25f3868eeef..209f1a577d01385f942ed8d2fd48d633 if (this.isBlocking()) { this.stopUsingItem(); diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 6720c50a21a3a93267f3ebf21d85db2f1b676d72..64435a682eaa98dc1feb3ba397be209ff0646ce5 100644 +index 6720c50a21a3a93267f3ebf21d85db2f1b676d72..d7dae3b138c30461c498ac7321a5377f62b72e1b 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -26,6 +26,7 @@ import java.util.function.Predicate; - import javax.annotation.Nullable; - import net.minecraft.ChatFormatting; - import net.minecraft.FileUtil; -+import org.leavesmc.leaves.util.ReturnPortalManager; // Leaves - return portal fix - import net.minecraft.commands.CommandSourceStack; - import net.minecraft.core.BlockPos; - import net.minecraft.core.LayeredRegistryAccess; -@@ -939,6 +940,24 @@ public abstract class PlayerList { +@@ -939,6 +939,24 @@ public abstract class PlayerList { if (fromWorld != worldserver) { PlayerChangedWorldEvent event = new PlayerChangedWorldEvent(entityplayer.getBukkitEntity(), fromWorld.getWorld()); this.server.server.getPluginManager().callEvent(event); @@ -101,15 +82,38 @@ index 4c38bfe300fb7da9d2080784b64101f94d77f20c..4f2ce8295977bfb8e9b6e98ca5405ecb private Optional lastClimbablePos; @Nullable private DamageSource lastDamageSource; +diff --git a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java +index a530276b0123dee5680d7e09ad3d2f0414909c91..e9b17c57c7bb8ad70f0e747d43aa0a2999c0c3f5 100644 +--- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java +@@ -171,7 +171,18 @@ public class NetherPortalBlock extends Block implements Portal { + + @Nullable + private DimensionTransition getExitPortal(ServerLevel worldserver, Entity entity, BlockPos blockposition, BlockPos blockposition1, boolean flag, WorldBorder worldborder, int searchRadius, boolean canCreatePortal, int createRadius) { +- Optional optional = worldserver.getPortalForcer().findClosestPortalPosition(blockposition1, worldborder, searchRadius); ++ // Leaves start - fix return portal ++ Optional optional = Optional.empty(); ++ if (org.leavesmc.leaves.LeavesConfig.netherPortalFix && entity instanceof net.minecraft.server.level.ServerPlayer player) { ++ org.leavesmc.leaves.util.ReturnPortalManager.ReturnPortal portal = org.leavesmc.leaves.util.ReturnPortalManager.findReturnPortal(player, entity.level().dimension(), entity.blockPosition()); ++ if (portal != null && worldserver.getBlockState(portal.pos()).is(Blocks.NETHER_PORTAL)) { ++ optional = Optional.of(portal.pos()); ++ } ++ } ++ if (optional.isEmpty()) { ++ optional = worldserver.getPortalForcer().findClosestPortalPosition(blockposition1, worldborder, searchRadius); ++ } ++ // Leaves end - fix return portal + BlockUtil.FoundRectangle blockutil_rectangle; + DimensionTransition.PostDimensionTransition dimensiontransition_a; + diff --git a/src/main/java/org/leavesmc/leaves/util/ReturnPortalManager.java b/src/main/java/org/leavesmc/leaves/util/ReturnPortalManager.java new file mode 100644 -index 0000000000000000000000000000000000000000..d7066d268e7a3b4b2c1b1ef28491078997989d4c +index 0000000000000000000000000000000000000000..67eb48e5b30d1dfa93aacbeb31f1b650b5ecb763 --- /dev/null +++ b/src/main/java/org/leavesmc/leaves/util/ReturnPortalManager.java -@@ -0,0 +1,105 @@ +@@ -0,0 +1,98 @@ +package org.leavesmc.leaves.util; + -+import net.minecraft.BlockUtil; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; @@ -135,17 +139,15 @@ index 0000000000000000000000000000000000000000..d7066d268e7a3b4b2c1b1ef284910789 + private static final String RETURN_PORTAL_UID = "UID"; + private static final String FROM_DIM = "FromDim"; + private static final String FROM_POS = "FromPos"; -+ private static final String TO_MIN_CORNER = "ToMinCorner"; -+ private static final String TO_AXIS_1_SIZE = "ToAxis1Size"; -+ private static final String TO_AXIS_2_SIZE = "ToAxis2Size"; ++ private static final String TO_POS = "ToPos"; + -+ public static BlockUtil.FoundRectangle findPortalAt(Player player, ResourceKey dim, BlockPos pos) { ++ public static BlockPos findPortalAt(Player player, ResourceKey dim, BlockPos pos) { + MinecraftServer server = player.level().getServer(); + if (server != null) { + ServerLevel fromWorld = server.getLevel(dim); + if (fromWorld != null) { + PortalForcer portalForcer = fromWorld.getPortalForcer(); -+ return portalForcer.findPortalAround(pos, false, fromWorld.getWorldBorder()).orElse(null); ++ return portalForcer.findClosestPortalPosition(pos, false, fromWorld.getWorldBorder()).orElse(null); + } + } + @@ -164,15 +166,13 @@ index 0000000000000000000000000000000000000000..d7066d268e7a3b4b2c1b1ef284910789 + ListTag portalList = getPlayerPortalList(player); + for (Tag entry : portalList) { + CompoundTag portal = (CompoundTag) entry; -+ ResourceKey entryFromDim = ResourceKey.create(Registries.DIMENSION, new ResourceLocation(portal.getString(FROM_DIM))); ++ ResourceKey entryFromDim = ResourceKey.create(Registries.DIMENSION, ResourceLocation.parse(portal.getString(FROM_DIM))); + if (entryFromDim == fromDim) { + BlockPos portalTrigger = BlockPos.of(portal.getLong(FROM_POS)); + if (portalTrigger.distSqr(fromPos) <= MAX_PORTAL_DISTANCE_SQ) { -+ UUID uid = portal.hasUUID(RETURN_PORTAL_UID) ? portal.getUUID(RETURN_PORTAL_UID) : UUID.randomUUID(); -+ BlockPos minCorner = BlockPos.of(portal.getLong(TO_MIN_CORNER)); -+ int axis1Size = portal.getInt(TO_AXIS_1_SIZE); -+ int axis2Size = portal.getInt(TO_AXIS_2_SIZE); -+ return new ReturnPortal(uid, new BlockUtil.FoundRectangle(minCorner, axis1Size, axis2Size)); ++ final var uid = portal.hasUUID(RETURN_PORTAL_UID) ? portal.getUUID(RETURN_PORTAL_UID) : UUID.randomUUID(); ++ final var pos = BlockPos.of(portal.getLong(TO_POS)); ++ return new ReturnPortal(uid, pos); + } + } + } @@ -180,7 +180,7 @@ index 0000000000000000000000000000000000000000..d7066d268e7a3b4b2c1b1ef284910789 + return null; + } + -+ public static void storeReturnPortal(ServerPlayer player, ResourceKey fromDim, BlockPos fromPos, BlockUtil.FoundRectangle toPortal) { ++ public static void storeReturnPortal(ServerPlayer player, ResourceKey fromDim, BlockPos fromPos, BlockPos toPos) { + ListTag portalList = getPlayerPortalList(player); + ReturnPortal returnPortal = findReturnPortal(player, fromDim, fromPos); + if (returnPortal != null) { @@ -191,9 +191,7 @@ index 0000000000000000000000000000000000000000..d7066d268e7a3b4b2c1b1ef284910789 + portalCompound.putUUID(RETURN_PORTAL_UID, UUID.randomUUID()); + portalCompound.putString(FROM_DIM, String.valueOf(fromDim.location())); + portalCompound.putLong(FROM_POS, fromPos.asLong()); -+ portalCompound.putLong(TO_MIN_CORNER, toPortal.minCorner.asLong()); -+ portalCompound.putInt(TO_AXIS_1_SIZE, toPortal.axis1Size); -+ portalCompound.putInt(TO_AXIS_2_SIZE, toPortal.axis2Size); ++ portalCompound.putLong(TO_POS, toPos.asLong()); + portalList.add(portalCompound); + } + @@ -202,13 +200,13 @@ index 0000000000000000000000000000000000000000..d7066d268e7a3b4b2c1b1ef284910789 + ListTag portalList = getPlayerPortalList(player); + for (int i = 0; i < portalList.size(); i++) { + CompoundTag entry = (CompoundTag) portalList.get(i); -+ if (entry.hasUUID(RETURN_PORTAL_UID) && entry.getUUID(RETURN_PORTAL_UID).equals(portal.uid())) { ++ if (entry.hasUUID(RETURN_PORTAL_UID) && entry.getUUID(RETURN_PORTAL_UID).equals(portal.uid)) { + portalList.remove(i); + break; + } + } + } + -+ public record ReturnPortal(UUID uid, BlockUtil.FoundRectangle rectangle) { ++ public record ReturnPortal(UUID uid, BlockPos pos) { + } +} diff --git a/patches/server/0048-Xaero-Map-Protocol.patch b/patches/server/0048-Xaero-Map-Protocol.patch index 31864f8e..7e19eb28 100644 --- a/patches/server/0048-Xaero-Map-Protocol.patch +++ b/patches/server/0048-Xaero-Map-Protocol.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Xaero Map Protocol diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 64435a682eaa98dc1feb3ba397be209ff0646ce5..b4e163ca4b582a3e803a0764f4f4be6092038cbb 100644 +index d7dae3b138c30461c498ac7321a5377f62b72e1b..d89089a9236b6d647894ac7cc19aaa399162024c 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -1262,6 +1262,7 @@ public abstract class PlayerList { +@@ -1261,6 +1261,7 @@ public abstract class PlayerList { player.connection.send(new ClientboundInitializeBorderPacket(worldborder)); player.connection.send(new ClientboundSetTimePacket(world.getGameTime(), world.getDayTime(), world.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT))); player.connection.send(new ClientboundSetDefaultSpawnPositionPacket(world.getSharedSpawnPos(), world.getSharedSpawnAngle())); diff --git a/patches/server/0056-No-feather-falling-trample.patch b/patches/server/0056-No-feather-falling-trample.patch index 9b6ef741..43d00b55 100644 --- a/patches/server/0056-No-feather-falling-trample.patch +++ b/patches/server/0056-No-feather-falling-trample.patch @@ -5,24 +5,16 @@ Subject: [PATCH] No feather falling trample diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -index d59e33e7326489c6d55d316d0130f22235f4c63c..79ef9b8bd2905d4ca3562971823a9bf48e60a038 100644 +index d59e33e7326489c6d55d316d0130f22235f4c63c..e48b1b7dbfb5d6914420bce0565108c34342922b 100644 --- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java +++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -@@ -14,6 +14,7 @@ import net.minecraft.world.entity.Entity; - import net.minecraft.world.entity.LivingEntity; - import net.minecraft.world.entity.player.Player; - import net.minecraft.world.item.context.BlockPlaceContext; -+import net.minecraft.world.item.enchantment.Enchantments; - import net.minecraft.world.level.BlockGetter; - import net.minecraft.world.level.GameRules; - import net.minecraft.world.level.Level; -@@ -112,6 +113,13 @@ public class FarmBlock extends Block { +@@ -112,6 +112,13 @@ public class FarmBlock extends Block { public void fallOn(Level world, BlockState state, BlockPos pos, Entity entity, float fallDistance) { super.fallOn(world, state, pos, entity, fallDistance); // CraftBukkit - moved here as game rules / events shouldn't affect fall damage. if (!world.isClientSide && world.random.nextFloat() < fallDistance - 0.5F && entity instanceof LivingEntity && (entity instanceof Player || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) && entity.getBbWidth() * entity.getBbWidth() * entity.getBbHeight() > 0.512F) { + // Leaves start - noFeatherFallingTrample + if (org.leavesmc.leaves.LeavesConfig.noFeatherFallingTrample) { -+ if (net.minecraft.world.item.enchantment.EnchantmentHelper.getEnchantmentLevel(Enchantments.FEATHER_FALLING, (LivingEntity) entity) > 0) { ++ if (net.minecraft.world.item.enchantment.EnchantmentHelper.getEnchantmentLevel(world.registryAccess().registryOrThrow(net.minecraft.core.registries.Registries.ENCHANTMENT).getHolder(net.minecraft.world.item.enchantment.Enchantments.FEATHER_FALLING).get(), (LivingEntity) entity) > 0) { + return; + } + } diff --git a/patches/server/0065-Shave-snow-layers.patch b/patches/server/0065-Shave-snow-layers.patch index 1c4bcf6d..08abe683 100644 --- a/patches/server/0065-Shave-snow-layers.patch +++ b/patches/server/0065-Shave-snow-layers.patch @@ -5,52 +5,28 @@ Subject: [PATCH] Shave snow layers diff --git a/src/main/java/net/minecraft/world/item/ShovelItem.java b/src/main/java/net/minecraft/world/item/ShovelItem.java -index 24f6a158e4759aac3be8da4cf5e0d40bd295355b..8c15f74cc5f3c4dfc499e6bdab75f10f66ea36b1 100644 +index 24f6a158e4759aac3be8da4cf5e0d40bd295355b..97c3a9281ef10c88947febf152a005b0cd05cc64 100644 --- a/src/main/java/net/minecraft/world/item/ShovelItem.java +++ b/src/main/java/net/minecraft/world/item/ShovelItem.java -@@ -2,20 +2,25 @@ package net.minecraft.world.item; - - import com.google.common.collect.Maps; - import com.google.common.collect.ImmutableMap.Builder; -+ - import java.util.Map; -+ - import net.minecraft.core.BlockPos; - import net.minecraft.core.Direction; - import net.minecraft.sounds.SoundEvents; - import net.minecraft.sounds.SoundSource; - import net.minecraft.tags.BlockTags; - import net.minecraft.world.InteractionResult; -+import net.minecraft.world.entity.EquipmentSlot; - import net.minecraft.world.entity.LivingEntity; - import net.minecraft.world.entity.player.Player; - import net.minecraft.world.item.context.UseOnContext; -+import net.minecraft.world.item.enchantment.EnchantmentHelper; - import net.minecraft.world.level.Level; - import net.minecraft.world.level.block.Block; - import net.minecraft.world.level.block.Blocks; - import net.minecraft.world.level.block.CampfireBlock; -+import net.minecraft.world.level.block.SnowLayerBlock; - import net.minecraft.world.level.block.state.BlockState; - import net.minecraft.world.level.gameevent.GameEvent; - -@@ -44,6 +49,24 @@ public class ShovelItem extends DiggerItem { +@@ -44,6 +44,26 @@ public class ShovelItem extends DiggerItem { return InteractionResult.PASS; } else { Player player = context.getPlayer(); + // Leaves start - shaveSnowLayers + if (org.leavesmc.leaves.LeavesConfig.shaveSnowLayers && blockState.is(Blocks.SNOW)) { -+ int layers = blockState.getValue(SnowLayerBlock.LAYERS); -+ level.setBlock(blockPos, layers > 1 ? blockState.setValue(SnowLayerBlock.LAYERS, layers - 1) : Blocks.AIR.defaultBlockState(), 11); -+ Block.popResource(level, blockPos, new ItemStack(EnchantmentHelper.hasSilkTouch(context.getItemInHand()) ? Items.SNOW : Items.SNOWBALL)); ++ int layers = blockState.getValue(net.minecraft.world.level.block.SnowLayerBlock.LAYERS); ++ ItemStack tool = context.getItemInHand(); ++ boolean hasSilkTouch = net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(level.registryAccess().registryOrThrow(net.minecraft.core.registries.Registries.ENCHANTMENT).getHolder(net.minecraft.world.item.enchantment.Enchantments.SILK_TOUCH).get(), tool) > 0; ++ BlockState shavedBlockState = layers > 1 ? blockState.setValue(net.minecraft.world.level.block.SnowLayerBlock.LAYERS, layers - 1) : Blocks.AIR.defaultBlockState(); ++ ++ level.setBlock(blockPos, shavedBlockState, Block.UPDATE_ALL_IMMEDIATE); ++ level.gameEvent(GameEvent.BLOCK_CHANGE, blockPos, GameEvent.Context.of(player, shavedBlockState)); ++ ++ Block.popResource(level, blockPos, new ItemStack(hasSilkTouch ? Items.SNOW : Items.SNOWBALL)); + level.playSound(player, blockPos, SoundEvents.SNOW_BREAK, SoundSource.BLOCKS, 1.0F, 1.0F); + + if (player != null) { -+ context.getItemInHand().hurtAndBreak(1, player.getRandom(), player, () -> -+ player.broadcastBreakEvent(switch (context.getHand()) { -+ case MAIN_HAND -> EquipmentSlot.MAINHAND; -+ case OFF_HAND -> EquipmentSlot.OFFHAND; -+ })); ++ tool.hurtAndBreak(1, player, LivingEntity.getSlotForHand(context.getHand())); + } + + return InteractionResult.SUCCESS; @@ -59,7 +35,7 @@ index 24f6a158e4759aac3be8da4cf5e0d40bd295355b..8c15f74cc5f3c4dfc499e6bdab75f10f BlockState blockState2 = FLATTENABLES.get(blockState.getBlock()); BlockState blockState3 = null; Runnable afterAction = null; // Paper -@@ -52,11 +75,11 @@ public class ShovelItem extends DiggerItem { +@@ -52,11 +72,11 @@ public class ShovelItem extends DiggerItem { blockState3 = blockState2; } else if (blockState.getBlock() instanceof CampfireBlock && blockState.getValue(CampfireBlock.LIT)) { afterAction = () -> { // Paper diff --git a/patches/server/0086-Reduce-array-allocations.patch b/patches/server/0086-Reduce-array-allocations.patch index b2d42636..17ad3979 100644 --- a/patches/server/0086-Reduce-array-allocations.patch +++ b/patches/server/0086-Reduce-array-allocations.patch @@ -287,17 +287,26 @@ index b0f7a378f19b9837c060c891002cd5db756cdae1..8b13bd7aec76f30c5b59207583930665 final String s; diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index b4e163ca4b582a3e803a0764f4f4be6092038cbb..2d599babb305d69dfeff5427eae0b51faf1eac0c 100644 +index d89089a9236b6d647894ac7cc19aaa399162024c..fbd14c119bd028fdde5470ab8dd7357bf2268909 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -27,6 +27,7 @@ import javax.annotation.Nullable; - import net.minecraft.ChatFormatting; - import net.minecraft.FileUtil; - import org.leavesmc.leaves.util.ReturnPortalManager; // Leaves - return portal fix -+import org.leavesmc.leaves.util.ArrayConstants; - import net.minecraft.commands.CommandSourceStack; - import net.minecraft.core.BlockPos; - import net.minecraft.core.LayeredRegistryAccess; +@@ -946,13 +946,9 @@ public abstract class PlayerList { + final ResourceKey OVERWORLD = Level.OVERWORLD; + final ResourceKey THE_NETHER = Level.NETHER; + if (!((fromDim != OVERWORLD || toDim != THE_NETHER) && (fromDim != THE_NETHER || toDim != OVERWORLD))) { +- BlockPos lastPos = entityplayer1.lastPos; +- if (lastPos != null) { +- net.minecraft.BlockUtil.FoundRectangle fromPortal = ReturnPortalManager.findPortalAt(entityplayer1, fromDim, lastPos); +- BlockPos toPos = entityplayer1.blockPosition(); +- if (fromPortal != null) { +- ReturnPortalManager.storeReturnPortal(entityplayer1, toDim, toPos, fromPortal); +- } ++ BlockPos fromPortal = org.leavesmc.leaves.util.ReturnPortalManager.findPortalAt(entityplayer1, fromDim, entityplayer1.lastPos); ++ if (fromPortal != null) { ++ org.leavesmc.leaves.util.ReturnPortalManager.storeReturnPortal(entityplayer1, toDim, entityplayer1.blockPosition(), fromPortal); + } + } + } diff --git a/src/main/java/net/minecraft/server/players/StoredUserList.java b/src/main/java/net/minecraft/server/players/StoredUserList.java index c038da20b76c0b7b1c18471b20be01e849d29f3a..603007a376dc76c46d34f265283dda693cbf6c88 100644 --- a/src/main/java/net/minecraft/server/players/StoredUserList.java diff --git a/patches/server/0095-Fix-villagers-dont-release-memory.patch b/patches/server/0095-Fix-villagers-dont-release-memory.patch index 70e47439..b0b38955 100644 --- a/patches/server/0095-Fix-villagers-dont-release-memory.patch +++ b/patches/server/0095-Fix-villagers-dont-release-memory.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Fix villagers dont release memory diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index 7e1871401ec5e3e9a85232053490259f132aec0a..caeaea4fb858cb569e555743cbfd0f1672204b91 100644 +index 7e1871401ec5e3e9a85232053490259f132aec0a..18642b4e43d0725690be44b53bbddb6d4486e5f1 100644 --- a/src/main/java/net/minecraft/world/entity/npc/Villager.java +++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java @@ -1071,4 +1071,20 @@ public class Villager extends AbstractVillager implements ReputationEventHandler @@ -16,14 +16,14 @@ index 7e1871401ec5e3e9a85232053490259f132aec0a..caeaea4fb858cb569e555743cbfd0f16 + // Leaves start - fixes a memory leak when villagers get moved to another world + @Nullable + @Override -+ public Entity changeDimension(ServerLevel destination) { ++ public Entity changeDimension(net.minecraft.world.level.portal.DimensionTransition destination) { + if (org.leavesmc.leaves.LeavesConfig.villagersDontReleaseMemoryFix) { + this.releaseAllPois(); + this.getBrain().eraseMemory(MemoryModuleType.HOME); + this.getBrain().eraseMemory(MemoryModuleType.JOB_SITE); + this.getBrain().eraseMemory(MemoryModuleType.POTENTIAL_JOB_SITE); + this.getBrain().eraseMemory(MemoryModuleType.MEETING_POINT); -+ this.refreshBrain(destination); ++ this.refreshBrain(destination.newLevel()); + } + return super.changeDimension(destination); + } diff --git a/patches/server/0097-Bow-infinity-fix.patch b/patches/server/0097-Bow-infinity-fix.patch index 9427d0b2..1fbf9215 100644 --- a/patches/server/0097-Bow-infinity-fix.patch +++ b/patches/server/0097-Bow-infinity-fix.patch @@ -5,16 +5,25 @@ Subject: [PATCH] Bow infinity fix diff --git a/src/main/java/net/minecraft/world/item/BowItem.java b/src/main/java/net/minecraft/world/item/BowItem.java -index 6eb5c0f23d9dc61e69ad5ad493c89602a9dcd4b5..be3e02e90e2370f103b41b26eae705b12722a3fa 100644 +index 6eb5c0f23d9dc61e69ad5ad493c89602a9dcd4b5..0b8a1c4ba8df45b0a162a468ff58357e048d43ca 100644 --- a/src/main/java/net/minecraft/world/item/BowItem.java +++ b/src/main/java/net/minecraft/world/item/BowItem.java -@@ -81,7 +81,8 @@ public class BowItem extends ProjectileWeaponItem { +@@ -18,6 +18,8 @@ public class BowItem extends ProjectileWeaponItem { + public static final int MAX_DRAW_DURATION = 20; + public static final int DEFAULT_RANGE = 15; + ++ private static final ItemStack EMPTY_ARROW = new ItemStack(Items.ARROW); // Leaves - Bow infinity fix ++ + public BowItem(Item.Properties settings) { + super(settings); + } +@@ -81,7 +83,8 @@ public class BowItem extends ProjectileWeaponItem { @Override public InteractionResultHolder use(Level world, Player user, InteractionHand hand) { ItemStack itemStack = user.getItemInHand(hand); - boolean bl = !user.getProjectile(itemStack).isEmpty(); + boolean bl = !user.getProjectile(itemStack).isEmpty() -+ || (org.leavesmc.leaves.LeavesConfig.bowInfinityFix && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.INFINITY, itemStack) > 0); ++ || (org.leavesmc.leaves.LeavesConfig.bowInfinityFix && net.minecraft.world.item.enchantment.EnchantmentHelper.processAmmoUse((ServerLevel) world, itemStack, EMPTY_ARROW, 1) <= 0); // Leaves - Bow infinity fix if (!user.hasInfiniteMaterials() && !bl) { return InteractionResultHolder.fail(itemStack); } else { diff --git a/patches/server/0102-Replay-Mod-API.patch b/patches/server/0102-Replay-Mod-API.patch index fcc58815..f43180c5 100644 --- a/patches/server/0102-Replay-Mod-API.patch +++ b/patches/server/0102-Replay-Mod-API.patch @@ -134,10 +134,10 @@ index e7b444a10b244828827b3c66c53465206ea8e0ec..030601fdfde2232a933b2ad7022e9909 .filter(player -> !playerList.isOp(player.getGameProfile())) .map(player -> player.getGameProfile().getName()), diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 2d599babb305d69dfeff5427eae0b51faf1eac0c..8bddc03875884489b0246fe211438c556f195374 100644 +index fbd14c119bd028fdde5470ab8dd7357bf2268909..2ea690d26eacc4d5d5cceae71511be04de748a5d 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -126,6 +126,7 @@ import org.bukkit.event.player.PlayerSpawnChangeEvent; +@@ -124,6 +124,7 @@ import org.bukkit.event.player.PlayerSpawnChangeEvent; // CraftBukkit end import org.leavesmc.leaves.bot.ServerBot; @@ -145,7 +145,7 @@ index 2d599babb305d69dfeff5427eae0b51faf1eac0c..8bddc03875884489b0246fe211438c55 public abstract class PlayerList { -@@ -158,6 +159,7 @@ public abstract class PlayerList { +@@ -156,6 +157,7 @@ public abstract class PlayerList { private boolean allowCommandsForAllPlayers; private static final boolean ALLOW_LOGOUTIVATOR = false; private int sendAllPlayerInfoIn; @@ -153,7 +153,7 @@ index 2d599babb305d69dfeff5427eae0b51faf1eac0c..8bddc03875884489b0246fe211438c55 // CraftBukkit start private CraftServer cserver; -@@ -184,6 +186,120 @@ public abstract class PlayerList { +@@ -182,6 +184,120 @@ public abstract class PlayerList { } abstract public void loadAndSaveFiles(); // Paper - fix converting txt to json file; moved from DedicatedPlayerList constructor @@ -274,7 +274,7 @@ index 2d599babb305d69dfeff5427eae0b51faf1eac0c..8bddc03875884489b0246fe211438c55 public void placeNewPlayer(Connection connection, ServerPlayer player, CommonListenerCookie clientData) { player.isRealPlayer = true; // Paper player.loginTime = System.currentTimeMillis(); // Paper - Replace OfflinePlayer#getLastPlayed -@@ -330,6 +446,7 @@ public abstract class PlayerList { +@@ -328,6 +444,7 @@ public abstract class PlayerList { // entityplayer.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(this.players)); // CraftBukkit - replaced with loop below this.players.add(player); @@ -282,7 +282,7 @@ index 2d599babb305d69dfeff5427eae0b51faf1eac0c..8bddc03875884489b0246fe211438c55 this.playersByName.put(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT), player); // Spigot this.playersByUUID.put(player.getUUID(), player); // this.broadcastAll(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityplayer))); // CraftBukkit - replaced with loop below -@@ -401,6 +518,12 @@ public abstract class PlayerList { +@@ -399,6 +516,12 @@ public abstract class PlayerList { continue; } @@ -295,7 +295,7 @@ index 2d599babb305d69dfeff5427eae0b51faf1eac0c..8bddc03875884489b0246fe211438c55 onlinePlayers.add(entityplayer1); // Paper - Use single player info update packet on join } // Paper start - Use single player info update packet on join -@@ -604,6 +727,43 @@ public abstract class PlayerList { +@@ -602,6 +725,43 @@ public abstract class PlayerList { } @@ -339,7 +339,7 @@ index 2d599babb305d69dfeff5427eae0b51faf1eac0c..8bddc03875884489b0246fe211438c55 public net.kyori.adventure.text.Component remove(ServerPlayer entityplayer) { // CraftBukkit - return string // Paper - return Component // Paper start - Fix kick event leave message not being sent return this.remove(entityplayer, net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(entityplayer.getDisplayName()))); -@@ -672,6 +832,7 @@ public abstract class PlayerList { +@@ -670,6 +830,7 @@ public abstract class PlayerList { entityplayer.retireScheduler(); // Paper - Folia schedulers entityplayer.getAdvancements().stopListening(); this.players.remove(entityplayer); @@ -347,7 +347,7 @@ index 2d599babb305d69dfeff5427eae0b51faf1eac0c..8bddc03875884489b0246fe211438c55 this.playersByName.remove(entityplayer.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot this.server.getCustomBossEvents().onPlayerDisconnect(entityplayer); UUID uuid = entityplayer.getUUID(); -@@ -766,7 +927,7 @@ public abstract class PlayerList { +@@ -764,7 +925,7 @@ public abstract class PlayerList { event.disallow(PlayerLoginEvent.Result.KICK_BANNED, io.papermc.paper.adventure.PaperAdventure.asAdventure(ichatmutablecomponent)); // Paper - Adventure } else { // return this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(gameprofile) ? IChatBaseComponent.translatable("multiplayer.disconnect.server_full") : null; @@ -1032,7 +1032,7 @@ index 0000000000000000000000000000000000000000..8978fe0c7ed092334618e27892f940ee +} diff --git a/src/main/java/org/leavesmc/leaves/replay/ReplayFile.java b/src/main/java/org/leavesmc/leaves/replay/ReplayFile.java new file mode 100644 -index 0000000000000000000000000000000000000000..5076b552816d7eae3a1c89fff488de63414eb5ee +index 0000000000000000000000000000000000000000..331ced8677b28827c277c64ae0b31d4d9ecd1d9b --- /dev/null +++ b/src/main/java/org/leavesmc/leaves/replay/ReplayFile.java @@ -0,0 +1,199 @@ @@ -1119,7 +1119,7 @@ index 0000000000000000000000000000000000000000..5076b552816d7eae3a1c89fff488de63 + ConnectionProtocol.STATUS, StatusProtocols.CLIENTBOUND, + ConnectionProtocol.LOGIN, LoginProtocols.CLIENTBOUND, + ConnectionProtocol.CONFIGURATION, ConfigurationProtocols.CLIENTBOUND, -+ ConnectionProtocol.PLAY, GameProtocols.CLIENTBOUND.bind(RegistryFriendlyByteBuf.decorator(MinecraftServer.getServer().registryAccess())) ++ ConnectionProtocol.PLAY, GameProtocols.CLIENTBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(MinecraftServer.getServer().registryAccess())) + ); + } + diff --git a/patches/server/0119-Linear-region-file-format.patch b/patches/server/0119-Linear-region-file-format.patch index 8d2a410e..85f20d08 100644 --- a/patches/server/0119-Linear-region-file-format.patch +++ b/patches/server/0119-Linear-region-file-format.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Linear region file format This patch is Powered by LinearPurpur(https://github.com/StupidCraft/LinearPurpur) diff --git a/build.gradle.kts b/build.gradle.kts -index 369d3cf80e4f86a7d30c45befd0e10a594236dd5..ec0e49de0fe578c2bdbf9594ab44c39d64774741 100644 +index 369d3cf80e4f86a7d30c45befd0e10a594236dd5..9a6ed88e2c117dee378dfe8b20c8548a6b56c22c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,6 +30,10 @@ dependencies { @@ -14,12 +14,27 @@ index 369d3cf80e4f86a7d30c45befd0e10a594236dd5..ec0e49de0fe578c2bdbf9594ab44c39d implementation("io.netty:netty-codec-haproxy:4.1.97.Final") // Paper - Add support for proxy protocol // Paper end + // Leaves start - Linear format -+ implementation("com.github.luben:zstd-jni:1.5.5-11") ++ implementation("com.github.luben:zstd-jni:1.5.6-3") + implementation("org.lz4:lz4-java:1.8.0") + // Leaves end - Linear format implementation("org.apache.logging.log4j:log4j-iostreams:2.22.1") // Paper - remove exclusion implementation("org.ow2.asm:asm-commons:9.7") implementation("org.spongepowered:configurate-yaml:4.2.0-SNAPSHOT") // Paper - config files +diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java +index 73df26b27146bbad2106d57b22dd3c792ed3dd1d..f3bd1488da34ea796c8205088e83d4c5dbd9f6bc 100644 +--- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java ++++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java +@@ -7,8 +7,8 @@ public interface ChunkSystemRegionFileStorage { + + public boolean moonrise$doesRegionFileNotExistNoIO(final int chunkX, final int chunkZ); + +- public RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ); ++ public org.leavesmc.leaves.region.AbstractRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ); + +- public RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException; ++ public org.leavesmc.leaves.region.AbstractRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException; + + } diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/io/RegionFileIOThread.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/io/RegionFileIOThread.java index c833f78d083b8f661087471c35bc90f65af1b525..8a00fd8c05df53ac99f214254e4dd9bd71858162 100644 --- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/io/RegionFileIOThread.java @@ -49,7 +64,7 @@ index c833f78d083b8f661087471c35bc90f65af1b525..8a00fd8c05df53ac99f214254e4dd9bd synchronized (cache) { regionFile = ((ChunkSystemRegionFileStorage)(Object)cache).moonrise$getRegionFileIfLoaded(chunkX, chunkZ); diff --git a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java -index 0382b6597a130d746f8954a93a756a9d1ac81d50..a382c2ba675256ff1ee5962596e9705e2ae649b5 100644 +index 0382b6597a130d746f8954a93a756a9d1ac81d50..256d0541394e24a039f1f670e3d894ac039e212d 100644 --- a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java +++ b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java @@ -76,7 +76,7 @@ public class WorldUpgrader { @@ -70,8 +85,35 @@ index 0382b6597a130d746f8954a93a756a9d1ac81d50..a382c2ba675256ff1ee5962596e9705e }); if (afile == null) { +@@ -414,7 +414,7 @@ public class WorldUpgrader { + List list1 = Lists.newArrayList(); + + try { +- RegionFile regionfile = new RegionFile(key, file.toPath(), regionDirectory, true); ++ org.leavesmc.leaves.region.AbstractRegionFile regionfile = org.leavesmc.leaves.region.AbstractRegionFileFactory.getAbstractRegionFile(key, file.toPath(), regionDirectory, true); // Leaves + + try { + for (int i1 = 0; i1 < 32; ++i1) { +@@ -477,7 +477,7 @@ public class WorldUpgrader { + + protected abstract boolean tryProcessOnePosition(T storage, ChunkPos chunkPos, ResourceKey worldKey); + +- private void onFileFinished(RegionFile regionFile) { ++ private void onFileFinished(org.leavesmc.leaves.region.AbstractRegionFile regionFile) { // Leaves + if (WorldUpgrader.this.recreateRegionFiles) { + if (this.previousWriteFuture != null) { + this.previousWriteFuture.join(); +@@ -502,7 +502,7 @@ public class WorldUpgrader { + } + } + +- static record FileToUpgrade(RegionFile file, List chunksToUpgrade) { ++ static record FileToUpgrade(org.leavesmc.leaves.region.AbstractRegionFile file, List chunksToUpgrade) { // Leaves + + } + diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -index e761b63eebc1e76b2bb1cb887d83d0b63ad6ec90..75695153e9620b2f3db0a2ef34e4cc3fc53ce97a 100644 +index e761b63eebc1e76b2bb1cb887d83d0b63ad6ec90..2fefc69cc1df01a5ede2e5f2642adec6238e6368 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java @@ -28,7 +28,7 @@ import net.minecraft.nbt.NbtIo; // Paper @@ -83,24 +125,7 @@ index e761b63eebc1e76b2bb1cb887d83d0b63ad6ec90..75695153e9620b2f3db0a2ef34e4cc3f private static final Logger LOGGER = LogUtils.getLogger(); private static final int SECTOR_BYTES = 4096; -@@ -52,6 +52,16 @@ public class RegionFile implements AutoCloseable { - @VisibleForTesting - protected final RegionBitmap usedSectors; - -+ // Leaves start - Abstract getters -+ public Path getRegionFile() { -+ return this.path; -+ } -+ -+ public java.util.concurrent.locks.ReentrantLock getFileLock() { -+ return this.fileLock; -+ } -+ // Leaves end -+ - public RegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync) throws IOException { - this(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync); // Paper - Configurable region compression format - } -@@ -465,10 +475,10 @@ public class RegionFile implements AutoCloseable { +@@ -465,10 +465,10 @@ public class RegionFile implements AutoCloseable { private static int getChunkIndex(int x, int z) { return (x & 31) + (z & 31) * 32; } @@ -113,7 +138,7 @@ index e761b63eebc1e76b2bb1cb887d83d0b63ad6ec90..75695153e9620b2f3db0a2ef34e4cc3f final int offset = getChunkIndex(x, z); boolean previous = this.oversized[offset] == 1; this.oversized[offset] = (byte) (oversized ? 1 : 0); -@@ -507,7 +517,7 @@ public class RegionFile implements AutoCloseable { +@@ -507,7 +507,7 @@ public class RegionFile implements AutoCloseable { return this.path.getParent().resolve(this.path.getFileName().toString().replaceAll("\\.mca$", "") + "_oversized_" + x + "_" + z + ".nbt"); } @@ -123,10 +148,10 @@ index e761b63eebc1e76b2bb1cb887d83d0b63ad6ec90..75695153e9620b2f3db0a2ef34e4cc3f try (DataInputStream out = new DataInputStream(new java.io.BufferedInputStream(new InflaterInputStream(Files.newInputStream(file))))) { return NbtIo.read((java.io.DataInput) out); diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index 0615fd82b71efb9a397de01615050e6d906c2844..90affc33e40cc9e07b3ee5e18ded356f85bf43c9 100644 +index 0615fd82b71efb9a397de01615050e6d906c2844..fd46492faadcccaaf5256ce37230ff07c22d682f 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -@@ -21,10 +21,14 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -21,7 +21,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise public static final String ANVIL_EXTENSION = ".mca"; private static final int MAX_CACHE_SIZE = 256; @@ -135,25 +160,53 @@ index 0615fd82b71efb9a397de01615050e6d906c2844..90affc33e40cc9e07b3ee5e18ded356f private final RegionStorageInfo info; private final Path folder; private final boolean sync; -+ // Leaves start - region format -+ public final org.leavesmc.leaves.region.RegionFileFormat format; -+ public final int linearCompression; -+ // Leaves end +@@ -31,7 +31,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise + private static final int MAX_NON_EXISTING_CACHE = 1024 * 64; + private final it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet nonExistingRegionFiles = new it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet(MAX_NON_EXISTING_CACHE+1); + private static String getRegionFileName(final int chunkX, final int chunkZ) { +- return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + ".mca"; ++ return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + (org.leavesmc.leaves.LeavesConfig.regionFormatName != org.leavesmc.leaves.region.RegionFileFormat.LINEAR ? ".mca" : ".linear"); // Leaves + } + + private boolean doesRegionFilePossiblyExist(final long position) { +@@ -66,15 +66,15 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise + } - // Paper start - rewrite chunk system - private static final int REGION_SHIFT = 5; -@@ -110,6 +114,10 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - this.folder = directory; - this.sync = dsync; + @Override +- public synchronized final RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) { ++ public synchronized final org.leavesmc.leaves.region.AbstractRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) { // Leaves + return this.regionCache.getAndMoveToFirst(ChunkPos.asLong(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT)); + } + + @Override +- public synchronized final RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException { ++ public synchronized final org.leavesmc.leaves.region.AbstractRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException { // Leaves + final long key = ChunkPos.asLong(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT); + +- RegionFile ret = this.regionCache.getAndMoveToFirst(key); ++ org.leavesmc.leaves.region.AbstractRegionFile ret = this.regionCache.getAndMoveToFirst(key); // Leaves + if (ret != null) { + return ret; + } +@@ -112,7 +112,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise this.info = storageKey; -+ // Leaves start -+ this.format = org.leavesmc.leaves.LeavesConfig.regionFormatName; -+ this.linearCompression = org.leavesmc.leaves.LeavesConfig.linearCompressionLevel; -+ // Leaves end } - public RegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit // Paper - public -@@ -149,7 +157,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +- public RegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit // Paper - public ++ public org.leavesmc.leaves.region.AbstractRegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit // Paper - public // Leaves + // Paper start - rewrite chunk system + if (existingOnly) { + return this.moonrise$getRegionFileIfExists(chunkcoordintpair.x, chunkcoordintpair.z); +@@ -120,7 +120,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise + synchronized (this) { + final long key = ChunkPos.asLong(chunkcoordintpair.x >> REGION_SHIFT, chunkcoordintpair.z >> REGION_SHIFT); + +- RegionFile ret = this.regionCache.getAndMoveToFirst(key); ++ org.leavesmc.leaves.region.AbstractRegionFile ret = this.regionCache.getAndMoveToFirst(key); // Leaves + if (ret != null) { + return ret; + } +@@ -149,7 +149,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise org.apache.logging.log4j.LogManager.getLogger().fatal(msg + " (" + file.toString().replaceAll(".+[\\\\/]", "") + " - " + x + "," + z + ") Go clean it up to remove this message. /minecraft:tp " + (x<<4)+" 128 "+(z<<4) + " - DO NOT REPORT THIS TO PAPER - You may ask for help on Discord, but do not file an issue. These error messages can not be removed."); } @@ -162,7 +215,7 @@ index 0615fd82b71efb9a397de01615050e6d906c2844..90affc33e40cc9e07b3ee5e18ded356f synchronized (regionfile) { try (DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkCoordinate)) { CompoundTag oversizedData = regionfile.getOversizedData(chunkCoordinate.x, chunkCoordinate.z); -@@ -184,7 +192,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -184,7 +184,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise @Nullable public CompoundTag read(ChunkPos pos) throws IOException { // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing @@ -171,16 +224,7 @@ index 0615fd82b71efb9a397de01615050e6d906c2844..90affc33e40cc9e07b3ee5e18ded356f if (regionfile == null) { return null; } -@@ -193,7 +201,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - - // Paper start - if (regionfile.isOversized(pos.x, pos.z)) { -- printOversizedLog("Loading Oversized Chunk!", regionfile.getPath(), pos.x, pos.z); -+ printOversizedLog("Loading Oversized Chunk!", regionfile.getRegionFile(), pos.x, pos.z); // Leaves - return readOversizedChunk(regionfile, pos); - } - // Paper end -@@ -235,7 +243,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -235,7 +235,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise public void scanChunk(ChunkPos chunkPos, StreamTagVisitor scanner) throws IOException { // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing @@ -189,16 +233,16 @@ index 0615fd82b71efb9a397de01615050e6d906c2844..90affc33e40cc9e07b3ee5e18ded356f if (regionfile == null) { return; } -@@ -265,7 +273,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -265,7 +265,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise } public void write(ChunkPos pos, @Nullable CompoundTag nbt) throws IOException { // Paper - public - RegionFile regionfile = this.getRegionFile(pos, nbt == null); // CraftBukkit // Paper - rewrite chunk system -+ org.leavesmc.leaves.region.AbstractRegionFile regionfile = this.getRegionFile(pos, nbt == null); // CraftBukkit // Paper - rewrite chunk system ++ org.leavesmc.leaves.region.AbstractRegionFile regionfile = this.getRegionFile(pos, nbt == null); // CraftBukkit // Paper - rewrite chunk system // Leaves // Paper start - rewrite chunk system if (regionfile == null) { // if the RegionFile doesn't exist, no point in deleting from it -@@ -281,8 +289,33 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -281,8 +281,33 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise if (nbt == null) { regionfile.clear(pos); } else { @@ -206,8 +250,8 @@ index 0615fd82b71efb9a397de01615050e6d906c2844..90affc33e40cc9e07b3ee5e18ded356f + // Leaves start - auto convert anvil to linear + DataOutputStream dataoutputstream; + -+ if(regionfile instanceof RegionFile && org.leavesmc.leaves.LeavesConfig.regionFormatName == org.leavesmc.leaves.region.RegionFileFormat.LINEAR && org.leavesmc.leaves.LeavesConfig.autoConvertAnvilToLinear) { -+ Path linearFilePath = Path.of(regionfile.getRegionFile().toString().replaceAll(".mca", ".linear")); ++ if (regionfile instanceof RegionFile && org.leavesmc.leaves.LeavesConfig.regionFormatName == org.leavesmc.leaves.region.RegionFileFormat.LINEAR && org.leavesmc.leaves.LeavesConfig.autoConvertAnvilToLinear) { ++ Path linearFilePath = Path.of(regionfile.getPath().toString().replaceAll(".mca", ".linear")); + try (org.leavesmc.leaves.region.LinearRegionFile linearRegionFile = new org.leavesmc.leaves.region.LinearRegionFile(linearFilePath, org.leavesmc.leaves.LeavesConfig.linearCompressionLevel)) { + DataInputStream regionDataInputStream = regionfile.getChunkDataInputStream(pos); + if (regionDataInputStream == null) { @@ -218,12 +262,12 @@ index 0615fd82b71efb9a397de01615050e6d906c2844..90affc33e40cc9e07b3ee5e18ded356f + try (DataOutputStream linearDataOutputStream = linearRegionFile.getChunkDataOutputStream(pos)) { + NbtIo.write(compoundTag, linearDataOutputStream); + } -+ + + linearRegionFile.flush(); -+ if(java.nio.file.Files.isRegularFile(regionfile.getRegionFile())) { -+ java.nio.file.Files.delete(regionfile.getRegionFile()); ++ if(java.nio.file.Files.isRegularFile(regionfile.getPath())) { ++ java.nio.file.Files.delete(regionfile.getPath()); + } - ++ + dataoutputstream = linearRegionFile.getChunkDataOutputStream(pos); + } + } else { @@ -233,21 +277,30 @@ index 0615fd82b71efb9a397de01615050e6d906c2844..90affc33e40cc9e07b3ee5e18ded356f try { NbtIo.write(nbt, (DataOutput) dataoutputstream); regionfile.setOversized(pos.x, pos.z, false); // Paper - We don't do this anymore, mojang stores differently, but clear old meta flag if it exists to get rid of our own meta file once last oversized is gone -@@ -341,7 +374,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise +@@ -324,7 +349,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise + // Paper start - rewrite chunk system + synchronized (this) { + final ExceptionCollector exceptionCollector = new ExceptionCollector<>(); +- for (final RegionFile regionFile : this.regionCache.values()) { ++ for (final org.leavesmc.leaves.region.AbstractRegionFile regionFile : this.regionCache.values()) { // Leaves + try { + regionFile.close(); + } catch (final IOException ex) { +@@ -341,7 +366,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise // Paper start - rewrite chunk system synchronized (this) { final ExceptionCollector exceptionCollector = new ExceptionCollector<>(); - for (final RegionFile regionFile : this.regionCache.values()) { -+ for (final org.leavesmc.leaves.region.AbstractRegionFile regionFile : this.regionCache.values()) { ++ for (final org.leavesmc.leaves.region.AbstractRegionFile regionFile : this.regionCache.values()) { // Leaves try { regionFile.flush(); } catch (final IOException ex) { diff --git a/src/main/java/org/leavesmc/leaves/region/AbstractRegionFile.java b/src/main/java/org/leavesmc/leaves/region/AbstractRegionFile.java new file mode 100644 -index 0000000000000000000000000000000000000000..2116a2e7e10e64aad1373171c6efde65de6ca198 +index 0000000000000000000000000000000000000000..e5439ece2a33a8d88df6423eca22a895129fdbf4 --- /dev/null +++ b/src/main/java/org/leavesmc/leaves/region/AbstractRegionFile.java -@@ -0,0 +1,45 @@ +@@ -0,0 +1,37 @@ +package org.leavesmc.leaves.region; + +import net.minecraft.nbt.CompoundTag; @@ -262,95 +315,81 @@ index 0000000000000000000000000000000000000000..2116a2e7e10e64aad1373171c6efde65 + +public interface AbstractRegionFile { + -+ void flush() throws IOException; -+ -+ void clear(ChunkPos pos) throws IOException; ++ Path getPath(); + -+ void close() throws IOException; ++ DataInputStream getChunkDataInputStream(ChunkPos pos) throws IOException; + -+ void setStatus(int x, int z, ChunkStatus status); ++ DataOutputStream getChunkDataOutputStream(ChunkPos pos) throws IOException; + -+ void setOversized(int x, int z, boolean b) throws IOException; ++ CompoundTag getOversizedData(int x, int z) throws IOException; + + boolean hasChunk(ChunkPos pos); + -+ boolean doesChunkExist(ChunkPos pos) throws Exception; ++ boolean doesChunkExist(ChunkPos pos); + + boolean isOversized(int x, int z); + -+ boolean recalculateHeader() throws IOException; -+ -+ DataOutputStream getChunkDataOutputStream(ChunkPos pos) throws IOException; -+ -+ DataInputStream getChunkDataInputStream(ChunkPos pos) throws IOException; -+ -+ CompoundTag getOversizedData(int x, int z) throws IOException; ++ void flush() throws IOException; + -+ ChunkStatus getStatusIfCached(int x, int z); ++ void close() throws IOException; + -+ ReentrantLock getFileLock(); ++ void clear(ChunkPos pos) throws IOException; + -+ Path getRegionFile(); ++ void setOversized(int x, int z, boolean oversized) throws IOException; +} + diff --git a/src/main/java/org/leavesmc/leaves/region/AbstractRegionFileFactory.java b/src/main/java/org/leavesmc/leaves/region/AbstractRegionFileFactory.java new file mode 100644 -index 0000000000000000000000000000000000000000..8050b23fd624d2462200b621a6d711b144b2b46b +index 0000000000000000000000000000000000000000..72f4507aa10f2ecad545199ccb88038fd49dbe35 --- /dev/null +++ b/src/main/java/org/leavesmc/leaves/region/AbstractRegionFileFactory.java -@@ -0,0 +1,31 @@ +@@ -0,0 +1,24 @@ +package org.leavesmc.leaves.region; + +import net.minecraft.world.level.chunk.storage.RegionFile; +import net.minecraft.world.level.chunk.storage.RegionFileVersion; +import net.minecraft.world.level.chunk.storage.RegionStorageInfo; ++import org.leavesmc.leaves.LeavesConfig; + +import java.io.IOException; +import java.nio.file.Path; + +public class AbstractRegionFileFactory { + -+ public static AbstractRegionFile getAbstractRegionFile(int linearCompression, RegionStorageInfo storageKey, Path file, Path directory, boolean dsync) throws IOException { -+ return getAbstractRegionFile(linearCompression, storageKey, file, directory, RegionFileVersion.VERSION_DEFLATE, dsync); -+ } -+ -+ public static AbstractRegionFile getAbstractRegionFile(int linearCompression, RegionStorageInfo storageKey, Path file, Path directory, boolean dsync, boolean canRecalcHeader) throws IOException { -+ return getAbstractRegionFile(linearCompression, storageKey, file, directory, RegionFileVersion.VERSION_DEFLATE, dsync, canRecalcHeader); -+ } -+ -+ public static AbstractRegionFile getAbstractRegionFile(int linearCompression, RegionStorageInfo storageKey, Path file, Path directory, RegionFileVersion outputChunkStreamVersion, boolean dsync) throws IOException { -+ return getAbstractRegionFile(linearCompression, storageKey, file, directory, outputChunkStreamVersion, dsync, false); ++ public static AbstractRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync) throws IOException { ++ return getAbstractRegionFile(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync); + } + -+ public static AbstractRegionFile getAbstractRegionFile(int linearCompression, RegionStorageInfo storageKey, Path file, Path directory, RegionFileVersion outputChunkStreamVersion, boolean dsync, boolean canRecalcHeader) throws IOException { -+ if (file.toString().endsWith(".linear")) { -+ return new LinearRegionFile(file, linearCompression); ++ public static AbstractRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync) throws IOException { ++ if (path.toString().endsWith(".linear")) { ++ return new LinearRegionFile(path, LeavesConfig.linearCompressionLevel); + } else { -+ return new RegionFile(storageKey, file, directory, outputChunkStreamVersion, dsync, canRecalcHeader); ++ return new RegionFile(storageKey, path, directory, compressionFormat, dsync); + } + } +} diff --git a/src/main/java/org/leavesmc/leaves/region/LinearRegionFile.java b/src/main/java/org/leavesmc/leaves/region/LinearRegionFile.java new file mode 100644 -index 0000000000000000000000000000000000000000..dd57eea25d8a52b298c49e47f06108cbf8150160 +index 0000000000000000000000000000000000000000..0c0ccc4d1848ee3c440fbe4b924aead09c9947dc --- /dev/null +++ b/src/main/java/org/leavesmc/leaves/region/LinearRegionFile.java -@@ -0,0 +1,330 @@ +@@ -0,0 +1,314 @@ +package org.leavesmc.leaves.region; + +import com.github.luben.zstd.ZstdInputStream; +import com.github.luben.zstd.ZstdOutputStream; +import com.mojang.logging.LogUtils; -+import net.jpountz.lz4.LZ4Compressor; -+import net.jpountz.lz4.LZ4Factory; -+import net.jpountz.lz4.LZ4FastDecompressor; -+import net.minecraft.nbt.CompoundTag; -+import net.minecraft.world.level.ChunkPos; -+import net.minecraft.world.level.chunk.status.ChunkStatus; -+import org.slf4j.Logger; + -+import javax.annotation.Nullable; -+import java.io.*; ++import java.io.BufferedOutputStream; ++import java.io.ByteArrayInputStream; ++import java.io.ByteArrayOutputStream; ++import java.io.DataInputStream; ++import java.io.DataOutputStream; ++import java.io.File; ++import java.io.FileInputStream; ++import java.io.FileOutputStream; ++import java.io.IOException; ++import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; @@ -359,7 +398,14 @@ index 0000000000000000000000000000000000000000..dd57eea25d8a52b298c49e47f06108cb +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; -+import java.util.concurrent.locks.ReentrantLock; ++import javax.annotation.Nullable; ++ ++import net.jpountz.lz4.LZ4Compressor; ++import net.jpountz.lz4.LZ4Factory; ++import net.jpountz.lz4.LZ4FastDecompressor; ++import net.minecraft.nbt.CompoundTag; ++import net.minecraft.world.level.ChunkPos; ++import org.slf4j.Logger; + +// Powered by LinearPurpur(https://github.com/StupidCraft/LinearPurpur) +public class LinearRegionFile implements AbstractRegionFile, AutoCloseable { @@ -371,19 +417,12 @@ index 0000000000000000000000000000000000000000..dd57eea25d8a52b298c49e47f06108cb + private static final Logger LOGGER = LogUtils.getLogger(); + private static final List SUPPORTED_VERSIONS = Arrays.asList((byte) 1, (byte) 2); + private static final LinearRegionFileFlusher linearRegionFileFlusher = new LinearRegionFileFlusher(); -+ + private final byte[][] buffer = new byte[1024][]; + private final int[] bufferUncompressedSize = new int[1024]; -+ + private final int[] chunkTimestamps = new int[1024]; -+ private final ChunkStatus[] statuses = new ChunkStatus[1024]; -+ + private final LZ4Compressor compressor; + private final LZ4FastDecompressor decompressor; -+ -+ public final ReentrantLock fileLock = new ReentrantLock(true); + private final int compressionLevel; -+ + private final AtomicBoolean markedToSave = new AtomicBoolean(false); + public boolean closed = false; + public Path path; @@ -462,12 +501,16 @@ index 0000000000000000000000000000000000000000..dd57eea25d8a52b298c49e47f06108cb + } + } + -+ public Path getRegionFile() { -+ return this.path; ++ private static int getChunkIndex(int x, int z) { ++ return (x & 31) + ((z & 31) << 5); + } + -+ public ReentrantLock getFileLock() { -+ return this.fileLock; ++ private static int getTimestamp() { ++ return (int) (System.currentTimeMillis() / 1000L); ++ } ++ ++ public Path getPath() { ++ return this.path; + } + + public void flush() throws IOException { @@ -487,12 +530,12 @@ index 0000000000000000000000000000000000000000..dd57eea25d8a52b298c49e47f06108cb + try { + save(); + } catch (IOException e) { -+ LOGGER.error("Failed to flush region file " + path.toAbsolutePath(), e); ++ LOGGER.error("Failed to flush region file {}", path.toAbsolutePath(), e); + } + } + -+ public boolean doesChunkExist(ChunkPos pos) throws Exception { -+ throw new Exception("doesChunkExist is a stub"); ++ public boolean doesChunkExist(ChunkPos pos) { ++ return false; + } + + private synchronized void save() throws IOException { @@ -552,11 +595,6 @@ index 0000000000000000000000000000000000000000..dd57eea25d8a52b298c49e47f06108cb + Files.move(tempFile.toPath(), this.path, StandardCopyOption.REPLACE_EXISTING); + } + -+ -+ public void setStatus(int x, int z, ChunkStatus status) { -+ this.statuses[getChunkIndex(x, z)] = status; -+ } -+ + public synchronized void write(ChunkPos pos, ByteBuffer buffer) { + try { + byte[] b = toByteArray(new ByteArrayInputStream(buffer.array())); @@ -573,7 +611,7 @@ index 0000000000000000000000000000000000000000..dd57eea25d8a52b298c49e47f06108cb + this.chunkTimestamps[index] = getTimestamp(); + this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] = uncompressedSize; + } catch (IOException e) { -+ LOGGER.error("Chunk write IOException " + e + " " + this.path); ++ LOGGER.error("Chunk write IOException {} {}", e, this.path); + } + markToSave(); + } @@ -582,21 +620,6 @@ index 0000000000000000000000000000000000000000..dd57eea25d8a52b298c49e47f06108cb + return new DataOutputStream(new BufferedOutputStream(new ChunkBuffer(pos))); + } + -+ private class ChunkBuffer extends ByteArrayOutputStream { -+ -+ private final ChunkPos pos; -+ -+ public ChunkBuffer(ChunkPos chunkcoordintpair) { -+ super(); -+ this.pos = chunkcoordintpair; -+ } -+ -+ public void close() { -+ ByteBuffer bytebuffer = ByteBuffer.wrap(this.buf, 0, this.count); -+ LinearRegionFile.this.write(this.pos, bytebuffer); -+ } -+ } -+ + private byte[] toByteArray(InputStream in) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] tempBuffer = new byte[4096]; @@ -619,10 +642,6 @@ index 0000000000000000000000000000000000000000..dd57eea25d8a52b298c49e47f06108cb + return null; + } + -+ public ChunkStatus getStatusIfCached(int x, int z) { -+ return this.statuses[getChunkIndex(x, z)]; -+ } -+ + public void clear(ChunkPos pos) { + int i = getChunkIndex(pos.x, pos.z); + this.buffer[i] = null; @@ -639,22 +658,11 @@ index 0000000000000000000000000000000000000000..dd57eea25d8a52b298c49e47f06108cb + if (closed) { + return; + } ++ + closed = true; + flush(); // sync + } + -+ private static int getChunkIndex(int x, int z) { -+ return (x & 31) + ((z & 31) << 5); -+ } -+ -+ private static int getTimestamp() { -+ return (int) (System.currentTimeMillis() / 1000L); -+ } -+ -+ public boolean recalculateHeader() { -+ return false; -+ } -+ + public void setOversized(int x, int z, boolean something) { + } + @@ -665,26 +673,44 @@ index 0000000000000000000000000000000000000000..dd57eea25d8a52b298c49e47f06108cb + public boolean isOversized(int x, int z) { + return false; + } ++ ++ private class ChunkBuffer extends ByteArrayOutputStream { ++ private final ChunkPos pos; ++ ++ public ChunkBuffer(ChunkPos chunkcoordintpair) { ++ super(); ++ this.pos = chunkcoordintpair; ++ } ++ ++ public void close() { ++ ByteBuffer bytebuffer = ByteBuffer.wrap(this.buf, 0, this.count); ++ LinearRegionFile.this.write(this.pos, bytebuffer); ++ } ++ } +} diff --git a/src/main/java/org/leavesmc/leaves/region/LinearRegionFileFlusher.java b/src/main/java/org/leavesmc/leaves/region/LinearRegionFileFlusher.java new file mode 100644 -index 0000000000000000000000000000000000000000..d452d704c54b211be6becd41d12862ba33553c1f +index 0000000000000000000000000000000000000000..93a1f8594dd02e012c1e8ffbe6e819927bd47389 --- /dev/null +++ b/src/main/java/org/leavesmc/leaves/region/LinearRegionFileFlusher.java -@@ -0,0 +1,53 @@ +@@ -0,0 +1,56 @@ +package org.leavesmc.leaves.region; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +import java.util.Queue; -+import java.util.concurrent.*; ++import java.util.concurrent.ExecutorService; ++import java.util.concurrent.Executors; ++import java.util.concurrent.LinkedBlockingQueue; ++import java.util.concurrent.ScheduledExecutorService; ++import java.util.concurrent.TimeUnit; + -+import org.bukkit.Bukkit; +import org.leavesmc.leaves.LeavesConfig; +import org.leavesmc.leaves.LeavesLogger; + +// Powered by LinearPurpur(https://github.com/StupidCraft/LinearPurpur) +public class LinearRegionFileFlusher { ++ + private final Queue savingQueue = new LinkedBlockingQueue<>(); + private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor( + new ThreadFactoryBuilder() @@ -692,14 +718,14 @@ index 0000000000000000000000000000000000000000..d452d704c54b211be6becd41d12862ba + .build() + ); + private final ExecutorService executor = Executors.newFixedThreadPool( -+ LeavesConfig.getLinearFlushThreads(), ++ LeavesConfig.linearFlushThreads, + new ThreadFactoryBuilder() + .setNameFormat("linear-flusher-%d") + .build() + ); + + public LinearRegionFileFlusher() { -+ LeavesLogger.LOGGER.info("Using " + LeavesConfig.getLinearFlushThreads() + " threads for linear region flushing."); ++ LeavesLogger.LOGGER.info("Using " + LeavesConfig.linearFlushThreads + " threads for linear region flushing."); + scheduler.scheduleAtFixedRate(this::pollAndFlush, 0L, LeavesConfig.linearFlushFrequency, TimeUnit.SECONDS); + } + @@ -724,7 +750,6 @@ index 0000000000000000000000000000000000000000..d452d704c54b211be6becd41d12862ba + scheduler.shutdown(); + } +} -+ diff --git a/src/main/java/org/leavesmc/leaves/region/RegionFileFormat.java b/src/main/java/org/leavesmc/leaves/region/RegionFileFormat.java new file mode 100644 index 0000000000000000000000000000000000000000..3651246acf3dd786eb6a85c7a846a248962cdd7f diff --git a/patches/server/0131-Bytebuf-API.patch b/patches/server/0131-Bytebuf-API.patch index a8bb5b4b..779105d3 100644 --- a/patches/server/0131-Bytebuf-API.patch +++ b/patches/server/0131-Bytebuf-API.patch @@ -18,10 +18,10 @@ index 2de8da4dbe2f7b9da740a90829f18bff0b3d5b8c..a8af45393b4733ea3b6639ad7d890896 } diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 8bddc03875884489b0246fe211438c556f195374..4a349d64aba156cdf5e109fe02afb210b0145fd7 100644 +index 2ea690d26eacc4d5d5cceae71511be04de748a5d..cd56f9c00e3d5b72247588c797ee345d84db8f8c 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -470,6 +470,12 @@ public abstract class PlayerList { +@@ -468,6 +468,12 @@ public abstract class PlayerList { return; }