diff --git a/patches/server/0099-Reduce-array-allocations.patch b/patches/server/0099-Reduce-array-allocations.patch new file mode 100644 index 00000000..1e174a11 --- /dev/null +++ b/patches/server/0099-Reduce-array-allocations.patch @@ -0,0 +1,710 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: violetc <58360096+s-yh-china@users.noreply.github.com> +Date: Thu, 20 Jul 2023 15:03:28 +0800 +Subject: [PATCH] Reduce array allocations + +This patch is Powered by Gale(https://github.com/GaleMC/Gale) + +diff --git a/src/main/java/com/destroystokyo/paper/util/maplist/EntityList.java b/src/main/java/com/destroystokyo/paper/util/maplist/EntityList.java +index 0133ea6feb1ab88f021f66855669f58367e7420b..d5e5463e3054cc06bd6589a864ff2003b1dfb9e3 100644 +--- a/src/main/java/com/destroystokyo/paper/util/maplist/EntityList.java ++++ b/src/main/java/com/destroystokyo/paper/util/maplist/EntityList.java +@@ -5,6 +5,7 @@ import net.minecraft.world.entity.Entity; + import java.util.Arrays; + import java.util.Iterator; + import java.util.NoSuchElementException; ++import top.leavesmc.leaves.util.ArrayConstants; + + // list with O(1) remove & contains + /** +@@ -17,9 +18,7 @@ public final class EntityList implements Iterable { + this.entityToIndex.defaultReturnValue(Integer.MIN_VALUE); + } + +- protected static final Entity[] EMPTY_LIST = new Entity[0]; +- +- protected Entity[] entities = EMPTY_LIST; ++ protected Entity[] entities = ArrayConstants.emptyEntityArray; // Leaves - reduce array allocations + protected int count; + + public int size() { +diff --git a/src/main/java/com/destroystokyo/paper/util/maplist/IBlockDataList.java b/src/main/java/com/destroystokyo/paper/util/maplist/IBlockDataList.java +index 277cfd9d1e8fff5d9b5e534b75c3c5162d58b0b7..19d5f3e167d7c94d33fcedc6c787d86ad5fee770 100644 +--- a/src/main/java/com/destroystokyo/paper/util/maplist/IBlockDataList.java ++++ b/src/main/java/com/destroystokyo/paper/util/maplist/IBlockDataList.java +@@ -6,6 +6,7 @@ import java.util.Arrays; + import net.minecraft.world.level.block.Block; + import net.minecraft.world.level.block.state.BlockState; + import net.minecraft.world.level.chunk.GlobalPalette; ++import top.leavesmc.leaves.util.ArrayConstants; + + /** + * @author Spottedleaf +@@ -20,9 +21,7 @@ public final class IBlockDataList { + this.map.defaultReturnValue(Long.MAX_VALUE); + } + +- private static final long[] EMPTY_LIST = new long[0]; +- +- private long[] byIndex = EMPTY_LIST; ++ private long[] byIndex = ArrayConstants.emptyLongArray; // Leaves - reduce array allocations + private int size; + + public static int getLocationKey(final int x, final int y, final int z) { +diff --git a/src/main/java/io/papermc/paper/command/subcommands/VersionCommand.java b/src/main/java/io/papermc/paper/command/subcommands/VersionCommand.java +index ae60bd96b5284d54676d8e7e4dd5d170b526ec1e..ad33c51ea9f74d2afd39c9139a9114b0f4436400 100644 +--- a/src/main/java/io/papermc/paper/command/subcommands/VersionCommand.java ++++ b/src/main/java/io/papermc/paper/command/subcommands/VersionCommand.java +@@ -7,6 +7,7 @@ import org.bukkit.command.CommandSender; + import org.checkerframework.checker.nullness.qual.NonNull; + import org.checkerframework.checker.nullness.qual.Nullable; + import org.checkerframework.framework.qual.DefaultQualifier; ++import top.leavesmc.leaves.util.ArrayConstants; + + @DefaultQualifier(NonNull.class) + public final class VersionCommand implements PaperSubcommand { +@@ -14,7 +15,7 @@ public final class VersionCommand implements PaperSubcommand { + public boolean execute(final CommandSender sender, final String subCommand, final String[] args) { + final @Nullable Command ver = MinecraftServer.getServer().server.getCommandMap().getCommand("version"); + if (ver != null) { +- ver.execute(sender, "paper", new String[0]); ++ ver.execute(sender, "paper", ArrayConstants.emptyStringArray); // Leaves - reduce array allocations + } + return true; + } +diff --git a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java +index ce449b7b6f615f2c8240e4207f06d4e54ae0083e..454df777262ab969869dd6a651d8113ced4f7c8d 100644 +--- a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java ++++ b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java +@@ -24,6 +24,7 @@ import java.util.Arrays; + import java.util.Iterator; + import java.util.List; + import java.util.function.Predicate; ++import top.leavesmc.leaves.util.ArrayConstants; + + public final class ChunkEntitySlices { + +@@ -82,7 +83,7 @@ public final class ChunkEntitySlices { + } + } + +- return ret.toArray(new org.bukkit.entity.Entity[0]); ++ return ret.toArray(ArrayConstants.emptyBukkitEntityArray); // Leaves - reduce array allocations + } + + public CompoundTag save() { +@@ -299,7 +300,7 @@ public final class ChunkEntitySlices { + + protected static final class BasicEntityList { + +- protected static final Entity[] EMPTY = new Entity[0]; ++ // protected static final Entity[] EMPTY = new Entity[0]; // Leaves - reduce array allocations + protected static final int DEFAULT_CAPACITY = 4; + + protected E[] storage; +@@ -310,7 +311,7 @@ public final class ChunkEntitySlices { + } + + public BasicEntityList(final int cap) { +- this.storage = (E[])(cap <= 0 ? EMPTY : new Entity[cap]); ++ this.storage = (E[])(cap <= 0 ? ArrayConstants.emptyEntityArray : new Entity[cap]); // Leaves - reduce array allocations + } + + public boolean isEmpty() { +@@ -322,7 +323,7 @@ public final class ChunkEntitySlices { + } + + private void resize() { +- if (this.storage == EMPTY) { ++ if (this.storage == ArrayConstants.emptyEntityArray) { // Leaves - reduce array allocations + this.storage = (E[])new Entity[DEFAULT_CAPACITY]; + } else { + this.storage = Arrays.copyOf(this.storage, this.storage.length * 2); +diff --git a/src/main/java/net/minecraft/nbt/ByteArrayTag.java b/src/main/java/net/minecraft/nbt/ByteArrayTag.java +index 163b1895bcbd16e93d36cd60d03e6b21df51cba7..4c56f92e111ad457f9c8cb0694ea01f2a59be3c5 100644 +--- a/src/main/java/net/minecraft/nbt/ByteArrayTag.java ++++ b/src/main/java/net/minecraft/nbt/ByteArrayTag.java +@@ -7,6 +7,7 @@ import java.io.IOException; + import java.util.Arrays; + import java.util.List; + import org.apache.commons.lang3.ArrayUtils; ++import top.leavesmc.leaves.util.ArrayConstants; + + public class ByteArrayTag extends CollectionTag { + +@@ -175,7 +176,7 @@ public class ByteArrayTag extends CollectionTag { + } + + public void clear() { +- this.data = new byte[0]; ++ this.data = ArrayConstants.emptyByteArray; // Leaves - reduce array allocations + } + + @Override +diff --git a/src/main/java/net/minecraft/nbt/CompoundTag.java b/src/main/java/net/minecraft/nbt/CompoundTag.java +index 7e94ebe06fc62293e665d6db19e42d947e7eb30f..b9661ba4b120e378ee1aff1fa1592827e512ec48 100644 +--- a/src/main/java/net/minecraft/nbt/CompoundTag.java ++++ b/src/main/java/net/minecraft/nbt/CompoundTag.java +@@ -17,6 +17,7 @@ import javax.annotation.Nullable; + import net.minecraft.CrashReport; + import net.minecraft.CrashReportCategory; + import net.minecraft.ReportedException; ++import top.leavesmc.leaves.util.ArrayConstants; + + public class CompoundTag implements Tag { + public static final Codec CODEC = Codec.PASSTHROUGH.comapFlatMap((dynamic) -> { +@@ -379,7 +380,7 @@ public class CompoundTag implements Tag { + throw new ReportedException(this.createReport(key, ByteArrayTag.TYPE, var3)); + } + +- return new byte[0]; ++ return ArrayConstants.emptyByteArray; // Leaves - reduce array allocations + } + + public int[] getIntArray(String key) { +@@ -391,7 +392,7 @@ public class CompoundTag implements Tag { + throw new ReportedException(this.createReport(key, IntArrayTag.TYPE, var3)); + } + +- return new int[0]; ++ return ArrayConstants.emptyIntArray; // Leaves - reduce array allocations + } + + public long[] getLongArray(String key) { +@@ -403,7 +404,7 @@ public class CompoundTag implements Tag { + throw new ReportedException(this.createReport(key, LongArrayTag.TYPE, var3)); + } + +- return new long[0]; ++ return ArrayConstants.emptyLongArray; // Leaves - reduce array allocations + } + + public CompoundTag getCompound(String key) { +diff --git a/src/main/java/net/minecraft/nbt/IntArrayTag.java b/src/main/java/net/minecraft/nbt/IntArrayTag.java +index 25ad2c6ff968f4a6b16b4dea3f67341a4261f2a4..478bc2428e133414d13e9a44ad7c2c567c13411e 100644 +--- a/src/main/java/net/minecraft/nbt/IntArrayTag.java ++++ b/src/main/java/net/minecraft/nbt/IntArrayTag.java +@@ -7,6 +7,7 @@ import java.io.IOException; + import java.util.Arrays; + import java.util.List; + import org.apache.commons.lang3.ArrayUtils; ++import top.leavesmc.leaves.util.ArrayConstants; + + public class IntArrayTag extends CollectionTag { + +@@ -189,7 +190,7 @@ public class IntArrayTag extends CollectionTag { + } + + public void clear() { +- this.data = new int[0]; ++ this.data = ArrayConstants.emptyIntArray; // Leaves - reduce array allocations + } + + @Override +diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java +index cf20f0983fc25b26cf92b9d3a28746b1909fc56b..c8d62a76bfa1a54b6ecb23f0d53ba2db15fcb1f7 100644 +--- a/src/main/java/net/minecraft/network/Connection.java ++++ b/src/main/java/net/minecraft/network/Connection.java +@@ -47,6 +47,7 @@ import org.apache.commons.lang3.Validate; + import org.slf4j.Logger; + import org.slf4j.Marker; + import org.slf4j.MarkerFactory; ++import top.leavesmc.leaves.util.ArrayConstants; + + public class Connection extends SimpleChannelInboundHandler> { + +@@ -325,7 +326,7 @@ public class Connection extends SimpleChannelInboundHandler> { + } + + public void setListener(PacketListener listener) { +- Validate.notNull(listener, "packetListener", new Object[0]); ++ Validate.notNull(listener, "packetListener", ArrayConstants.emptyObjectArray); // Leaves - reduce array allocations + this.packetListener = listener; + } + // Paper start +diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java +index 691158e71b06c66ae576c6e9b53caf23d1747330..b840dbdd83eb985615f7de02439ae474dd1afe01 100644 +--- a/src/main/java/net/minecraft/server/level/ServerEntity.java ++++ b/src/main/java/net/minecraft/server/level/ServerEntity.java +@@ -351,7 +351,7 @@ public class ServerEntity { + + if (this.entity instanceof LivingEntity) { + List> list = Lists.newArrayList(); +- EquipmentSlot[] aenumitemslot = EquipmentSlot.values(); ++ EquipmentSlot[] aenumitemslot = EquipmentSlot.VALUES; // Leaves - reduce array allocations + int i = aenumitemslot.length; + + for (int j = 0; j < i; ++j) { +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index c47df8d18be8ac7d32a16e6662dbbd850efc8e8a..709229d6226464d2a0bc773a3916c811f42a69aa 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -177,6 +177,7 @@ import org.bukkit.event.world.GenericGameEvent; + import org.bukkit.event.world.TimeSkipEvent; + // CraftBukkit end + import it.unimi.dsi.fastutil.ints.IntArrayList; // Paper ++import top.leavesmc.leaves.util.ArrayConstants; + + public class ServerLevel extends Level implements WorldGenLevel { + +@@ -1078,7 +1079,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + BlockPos blockposition2 = blockposition.set(j + randomX, randomY, k + randomZ); + BlockState iblockdata = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); + +- iblockdata.randomTick(this, blockposition2, this.randomTickRandom); ++ iblockdata.randomTick(this, blockposition2.immutable(), this.randomTickRandom); // Leaves - reduce array allocations + // We drop the fluid tick since LAVA is ALREADY TICKED by the above method (See LiquidBlock). + // TODO CHECK ON UPDATE (ping the Canadian) + } +@@ -1333,7 +1334,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + + public static List getCurrentlyTickingEntities() { + Entity ticking = currentlyTickingEntity.get(); +- List ret = java.util.Arrays.asList(ticking == null ? new Entity[0] : new Entity[] { ticking }); ++ List ret = java.util.Arrays.asList(ticking == null ? ArrayConstants.emptyEntityArray : new Entity[] { ticking }); // Leaves - reduce array allocations + + return ret; + } +diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index 77f20c1e37ce6c271a7f060bab04324d6b748136..18f6eaefb4db548c08afb053ef7df37890036141 100644 +--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -247,6 +247,7 @@ import org.bukkit.inventory.InventoryView; + import org.bukkit.inventory.SmithingInventory; + import top.leavesmc.leaves.util.ProtocolUtils; + // CraftBukkit end ++import top.leavesmc.leaves.util.ArrayConstants; + + public class ServerGamePacketListenerImpl implements ServerPlayerConnection, TickablePacketListener, ServerGamePacketListener { + +@@ -413,7 +414,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + if (this.keepAlivePending) { + if (!this.processedDisconnect && elapsedTime >= KEEPALIVE_LIMIT) { // check keepalive limit, don't fire if already disconnected + ServerGamePacketListenerImpl.LOGGER.warn("{} was kicked due to keepalive timeout!", this.player.getScoreboardName()); // more info +- this.disconnect(Component.translatable("disconnect.timeout", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause ++ this.disconnect(Component.translatable("disconnect.timeout", ArrayConstants.emptyObjectArray), org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause // Leaves - reduce array allocations + } + } else { + if (elapsedTime >= 15000L) { // 15 seconds +@@ -892,13 +893,13 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + // PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); // Paper - run this async + // CraftBukkit start + if (this.chatSpamTickCount.addAndGet(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamIncrement) > io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamLimit && !this.server.getPlayerList().isOp(this.player.getGameProfile())) { // Paper start - split and make configurable +- server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM)); // Paper - kick event cause ++ server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", ArrayConstants.emptyObjectArray), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM)); // Paper - kick event cause // Leaves - reduce array allocations + return; + } + // Paper start + String str = packet.getCommand(); int index = -1; + if (str.length() > 64 && ((index = str.indexOf(' ')) == -1 || index >= 64)) { +- server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM)); // Paper ++ server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", ArrayConstants.emptyObjectArray), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM)); // Paper - kick event cause // Leaves - reduce array allocations + return; + } + // Paper end +@@ -3327,7 +3328,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic + // Paper start + if (!org.bukkit.Bukkit.isPrimaryThread()) { + if (this.recipeSpamPackets.addAndGet(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamIncrement) > io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamLimit) { +- this.server.scheduleOnMain(() -> this.disconnect(net.minecraft.network.chat.Component.translatable("disconnect.spam", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM)); // Paper - kick event cause ++ this.server.scheduleOnMain(() -> this.disconnect(net.minecraft.network.chat.Component.translatable("disconnect.spam", ArrayConstants.emptyObjectArray), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM)); // Paper - kick event cause // Leaves - reduce array allocations + return; + } + } +diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +index 2ff578e4a953ffcf5176815ba8e3f06f73499989..bf082b9c3947d6037328526e5bfafe2bc3774d03 100644 +--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +@@ -43,6 +43,7 @@ import org.bukkit.craftbukkit.util.Waitable; + import org.bukkit.event.player.AsyncPlayerPreLoginEvent; + import org.bukkit.event.player.PlayerPreLoginEvent; + // CraftBukkit end ++import top.leavesmc.leaves.util.ArrayConstants; + + public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, TickablePacketListener { + +@@ -236,8 +237,10 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + + @Override + public void handleHello(ServerboundHelloPacket packet) { +- Validate.validState(this.state == ServerLoginPacketListenerImpl.State.HELLO, "Unexpected hello packet", new Object[0]); +- Validate.validState(ServerLoginPacketListenerImpl.isValidUsername(packet.name()), "Invalid characters in username", new Object[0]); ++ // Gale start - JettPack - reduce array allocations ++ Validate.validState(this.state == ServerLoginPacketListenerImpl.State.HELLO, "Unexpected hello packet", ArrayConstants.emptyObjectArray); ++ Validate.validState(ServerLoginPacketListenerImpl.isValidUsername(packet.name()), "Invalid characters in username", ArrayConstants.emptyObjectArray); ++ // Gale end - JettPack - reduce array allocations + // Paper start - validate usernames + if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() && io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.performUsernameValidation) { + if (!this.iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation && !validateUsername(packet.name())) { +@@ -296,7 +299,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + + @Override + public void handleKey(ServerboundKeyPacket packet) { +- Validate.validState(this.state == ServerLoginPacketListenerImpl.State.KEY, "Unexpected key packet", new Object[0]); ++ Validate.validState(this.state == ServerLoginPacketListenerImpl.State.KEY, "Unexpected key packet", ArrayConstants.emptyObjectArray); // Leaves - reduce array allocations + + 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 fc9b8f6e9dbef606ade0f2376a8187ae4ca366cb..16670088947fe126674fa9058f4fc8df01546a2c 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -134,6 +134,7 @@ import org.bukkit.event.player.PlayerRespawnEvent.RespawnReason; + import org.bukkit.event.player.PlayerSpawnChangeEvent; + // CraftBukkit end + ++import top.leavesmc.leaves.util.ArrayConstants; + import top.leavesmc.leaves.util.ReturnPortalManager; // Leaves - return portal fix + + public abstract class PlayerList { +@@ -729,7 +730,7 @@ public abstract class PlayerList { + while (iterator.hasNext()) { + entityplayer = (ServerPlayer) iterator.next(); + this.save(entityplayer); // CraftBukkit - Force the player's inventory to be saved +- entityplayer.connection.disconnect(Component.translatable("multiplayer.disconnect.duplicate_login", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.DUPLICATE_LOGIN); // Paper - kick event cause ++ entityplayer.connection.disconnect(Component.translatable("multiplayer.disconnect.duplicate_login", ArrayConstants.emptyObjectArray), org.bukkit.event.player.PlayerKickEvent.Cause.DUPLICATE_LOGIN); // Paper - kick event cause // Leaves - reduce array allocations + } + + // Instead of kicking then returning, we need to store the kick reason +diff --git a/src/main/java/net/minecraft/server/players/StoredUserList.java b/src/main/java/net/minecraft/server/players/StoredUserList.java +index 9e8112fbc40a1d89c0f73ea4452e0fa1bb459bf4..fbca8ae92a91673e1ebc45c7587e0d847698e2d3 100644 +--- a/src/main/java/net/minecraft/server/players/StoredUserList.java ++++ b/src/main/java/net/minecraft/server/players/StoredUserList.java +@@ -27,6 +27,7 @@ import javax.annotation.Nullable; + import net.minecraft.Util; + import net.minecraft.util.GsonHelper; + import org.slf4j.Logger; ++import top.leavesmc.leaves.util.ArrayConstants; + + public abstract class StoredUserList> { + +@@ -96,7 +97,7 @@ public abstract class StoredUserList> { + } + + public String[] getUserList() { +- return (String[]) this.map.keySet().toArray(new String[0]); ++ return (String[]) this.map.keySet().toArray(ArrayConstants.emptyStringArray); // Leaves - reduce array allocations + } + + public boolean isEmpty() { +diff --git a/src/main/java/net/minecraft/util/ZeroBitStorage.java b/src/main/java/net/minecraft/util/ZeroBitStorage.java +index e23995acb97100830079677aab0896487a705416..53e81721507cfc8f88be0ca9565746d78b2a1686 100644 +--- a/src/main/java/net/minecraft/util/ZeroBitStorage.java ++++ b/src/main/java/net/minecraft/util/ZeroBitStorage.java +@@ -4,9 +4,10 @@ import java.util.Arrays; + import java.util.function.IntConsumer; + import org.apache.commons.lang3.Validate; + import net.minecraft.world.level.chunk.Palette; ++import top.leavesmc.leaves.util.ArrayConstants; + + public class ZeroBitStorage implements BitStorage { +- public static final long[] RAW = new long[0]; ++ public static final long[] RAW = ArrayConstants.emptyLongArray; // Leaves - reduce array allocations + private final int size; + + public ZeroBitStorage(int size) { +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index deaba5f2c0f684451d9cac5d1eb73fe7bcc36210..94179dafe22403b4aaa6adcff879b459a073ad09 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -3105,7 +3105,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + @Nullable + private Map collectEquipmentChanges() { + Map map = null; +- EquipmentSlot[] aenumitemslot = EquipmentSlot.values(); ++ EquipmentSlot[] aenumitemslot = EquipmentSlot.VALUES; // Leaves - reduce array allocations + int i = aenumitemslot.length; + + for (int j = 0; j < i; ++j) { +diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java +index e65ce75e2d44843afa6c4a033885a55dcb43c635..a54d43e5172afdb7850b2a52436c9a3d93cccef7 100644 +--- a/src/main/java/net/minecraft/world/entity/Mob.java ++++ b/src/main/java/net/minecraft/world/entity/Mob.java +@@ -1073,7 +1073,7 @@ public abstract class Mob extends LivingEntity implements Targeting { + @Override + protected void dropCustomDeathLoot(DamageSource source, int lootingMultiplier, boolean allowDrops) { + super.dropCustomDeathLoot(source, lootingMultiplier, allowDrops); +- EquipmentSlot[] aenumitemslot = EquipmentSlot.values(); ++ EquipmentSlot[] aenumitemslot = EquipmentSlot.VALUES; // Leaves - reduce array allocations + int j = aenumitemslot.length; + + for (int k = 0; k < j; ++k) { +@@ -1135,7 +1135,7 @@ public abstract class Mob extends LivingEntity implements Targeting { + } + + boolean flag = true; +- EquipmentSlot[] aenumitemslot = EquipmentSlot.values(); ++ EquipmentSlot[] aenumitemslot = EquipmentSlot.VALUES; // Leaves - reduce array allocations + int j = aenumitemslot.length; + + for (int k = 0; k < j; ++k) { +@@ -1222,7 +1222,7 @@ public abstract class Mob extends LivingEntity implements Targeting { + float f = localDifficulty.getSpecialMultiplier(); + + this.enchantSpawnedWeapon(random, f); +- EquipmentSlot[] aenumitemslot = EquipmentSlot.values(); ++ EquipmentSlot[] aenumitemslot = EquipmentSlot.VALUES; // Leaves - reduce array allocations + int i = aenumitemslot.length; + + for (int j = 0; j < i; ++j) { +@@ -1441,7 +1441,7 @@ public abstract class Mob extends LivingEntity implements Targeting { + t0.setInvulnerable(this.isInvulnerable()); + if (flag) { + t0.setCanPickUpLoot(this.canPickUpLoot()); +- EquipmentSlot[] aenumitemslot = EquipmentSlot.values(); ++ EquipmentSlot[] aenumitemslot = EquipmentSlot.VALUES; // Leaves - reduce array allocations + int i = aenumitemslot.length; + + for (int j = 0; j < i; ++j) { +diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java +index 25ed5571b24e590bc95056020d84496492b53298..89d7364bc645a8b9217e87780cdc0ced5318bc2a 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java ++++ b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java +@@ -234,7 +234,7 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { + return; + } + // CraftBukkit end +- EquipmentSlot[] aenumitemslot = EquipmentSlot.values(); ++ EquipmentSlot[] aenumitemslot = EquipmentSlot.VALUES; // Leaves - reduce array allocations + int i = aenumitemslot.length; + + for (int j = 0; j < i; ++j) { +diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java +index 3b8f4c1883a00b4820e8b6fe3e727b5cb2326660..3c2ee97951f88bc1e27de31f30952ae119773858 100644 +--- a/src/main/java/net/minecraft/world/item/ItemStack.java ++++ b/src/main/java/net/minecraft/world/item/ItemStack.java +@@ -1015,7 +1015,7 @@ public final class ItemStack { + int k; + + if (ItemStack.shouldShowInTooltip(i, ItemStack.TooltipPart.MODIFIERS)) { +- EquipmentSlot[] aenumitemslot = EquipmentSlot.values(); ++ EquipmentSlot[] aenumitemslot = EquipmentSlot.VALUES; // Leaves - reduce array allocations + + k = aenumitemslot.length; + +diff --git a/src/main/java/net/minecraft/world/item/crafting/ShapedRecipe.java b/src/main/java/net/minecraft/world/item/crafting/ShapedRecipe.java +index 9c1285e31d947f92e0b00149e342e793898e0d7c..e45d14998e2379ced1d7da9c6583b04469b13798 100644 +--- a/src/main/java/net/minecraft/world/item/crafting/ShapedRecipe.java ++++ b/src/main/java/net/minecraft/world/item/crafting/ShapedRecipe.java +@@ -29,6 +29,7 @@ import org.bukkit.craftbukkit.inventory.CraftRecipe; + import org.bukkit.craftbukkit.inventory.CraftShapedRecipe; + import org.bukkit.inventory.RecipeChoice; + // CraftBukkit end ++import top.leavesmc.leaves.util.ArrayConstants; + + public class ShapedRecipe implements CraftingRecipe { + +@@ -262,7 +263,7 @@ public class ShapedRecipe implements CraftingRecipe { + } + + if (pattern.length == l) { +- return new String[0]; ++ return ArrayConstants.emptyStringArray; // Leaves - reduce array allocations + } else { + String[] astring1 = new String[pattern.length - l - k]; + +diff --git a/src/main/java/net/minecraft/world/item/enchantment/Enchantments.java b/src/main/java/net/minecraft/world/item/enchantment/Enchantments.java +index 2bfbdaeb2b0d99dfd956cd5936403fe8b0eeae64..7ad1545631604aa55f6d4fbdcbaefe6dc647f35c 100644 +--- a/src/main/java/net/minecraft/world/item/enchantment/Enchantments.java ++++ b/src/main/java/net/minecraft/world/item/enchantment/Enchantments.java +@@ -44,8 +44,10 @@ public class Enchantments { + public static final Enchantment MULTISHOT = Enchantments.register("multishot", new MultiShotEnchantment(Enchantment.Rarity.RARE, new EquipmentSlot[]{EquipmentSlot.MAINHAND})); + public static final Enchantment QUICK_CHARGE = Enchantments.register("quick_charge", new QuickChargeEnchantment(Enchantment.Rarity.UNCOMMON, new EquipmentSlot[]{EquipmentSlot.MAINHAND})); + public static final Enchantment PIERCING = Enchantments.register("piercing", new ArrowPiercingEnchantment(Enchantment.Rarity.COMMON, new EquipmentSlot[]{EquipmentSlot.MAINHAND})); +- public static final Enchantment MENDING = Enchantments.register("mending", new MendingEnchantment(Enchantment.Rarity.RARE, EquipmentSlot.values())); +- public static final Enchantment VANISHING_CURSE = Enchantments.register("vanishing_curse", new VanishingCurseEnchantment(Enchantment.Rarity.VERY_RARE, EquipmentSlot.values())); ++ // Leaves start - reduce array allocations ++ public static final Enchantment MENDING = Enchantments.register("mending", new MendingEnchantment(Enchantment.Rarity.RARE, EquipmentSlot.VALUES)); ++ public static final Enchantment VANISHING_CURSE = Enchantments.register("vanishing_curse", new VanishingCurseEnchantment(Enchantment.Rarity.VERY_RARE, EquipmentSlot.VALUES)); ++ // Leaves end - reduce array allocations + + public Enchantments() {} + +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index a1fe9dfda59e65b849955dd04a439cb928488373..772300d2cb8174ea79cacfda90e64bc0581b603a 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -104,6 +104,7 @@ import org.bukkit.entity.SpawnCategory; + import org.bukkit.event.block.BlockPhysicsEvent; + import org.bukkit.event.world.GenericGameEvent; + // CraftBukkit end ++import top.leavesmc.leaves.util.ArrayConstants; + + public abstract class Level implements LevelAccessor, AutoCloseable { + +@@ -1531,7 +1532,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { + public org.bukkit.entity.Entity[] getChunkEntities(int chunkX, int chunkZ) { + io.papermc.paper.world.ChunkEntitySlices slices = ((ServerLevel)this).getEntityLookup().getChunk(chunkX, chunkZ); + if (slices == null) { +- return new org.bukkit.entity.Entity[0]; ++ return ArrayConstants.emptyBukkitEntityArray; // Leaves - reduce array allocations + } + return slices.getChunkEntities(); + } +diff --git a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java +index 10d3912ef043eefdf89105332e29b0d2bf4a5539..3bc33b552743be03c6b895e0d217152a65454807 100644 +--- a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java +@@ -43,6 +43,7 @@ import net.minecraft.world.phys.shapes.VoxelShape; + import org.bukkit.craftbukkit.inventory.CraftBlockInventoryHolder; + import org.bukkit.craftbukkit.util.DummyGeneratorAccess; + // CraftBukkit end ++import top.leavesmc.leaves.util.ArrayConstants; + + public class ComposterBlock extends Block implements WorldlyContainerHolder { + +@@ -415,7 +416,7 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { + + @Override + public int[] getSlotsForFace(Direction side) { +- return side == Direction.DOWN ? new int[]{0} : new int[0]; ++ return side == Direction.DOWN ? ArrayConstants.zeroSingletonIntArray : ArrayConstants.emptyIntArray; // Leaves - reduce array allocations + } + + @Override +@@ -464,7 +465,7 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { + + @Override + public int[] getSlotsForFace(Direction side) { +- return side == Direction.UP ? new int[]{0} : new int[0]; ++ return side == Direction.UP ? ArrayConstants.zeroSingletonIntArray : ArrayConstants.emptyIntArray; // Leaves - reduce array allocations + } + + @Override +@@ -506,7 +507,7 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder { + + @Override + public int[] getSlotsForFace(Direction side) { +- return new int[0]; ++ return ArrayConstants.emptyIntArray; // Leaves - reduce array allocations + } + + @Override +diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java +index 6171f1ec26a822f89c126f64edf3e02a354239df..bbb316b82fa1b1c8e968e9a1c90d47b7612bc2b1 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java +@@ -58,6 +58,7 @@ import org.bukkit.event.inventory.FurnaceSmeltEvent; + import org.bukkit.event.inventory.FurnaceStartSmeltEvent; + import org.bukkit.inventory.CookingRecipe; + // CraftBukkit end ++import top.leavesmc.leaves.util.ArrayConstants; + + public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntity implements WorldlyContainer, RecipeHolder, StackedContentsCompatible { + +@@ -65,7 +66,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit + protected static final int SLOT_FUEL = 1; + protected static final int SLOT_RESULT = 2; + public static final int DATA_LIT_TIME = 0; +- private static final int[] SLOTS_FOR_UP = new int[]{0}; ++ private static final int[] SLOTS_FOR_UP = ArrayConstants.zeroSingletonIntArray; // Leaves - reduce array allocations + private static final int[] SLOTS_FOR_DOWN = new int[]{2, 1}; + private static final int[] SLOTS_FOR_SIDES = new int[]{1}; + public static final int DATA_LIT_DURATION = 1; +diff --git a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java +index 36af81f0957d17e170d229059c66f4eb4539dfeb..487d09aaadd9cf1b239cf9773fa71cbff6e6a77e 100644 +--- a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java ++++ b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java +@@ -9,7 +9,6 @@ import net.minecraft.nbt.CompoundTag; + import net.minecraft.nbt.NbtIo; + import net.minecraft.nbt.NbtUtils; + import net.minecraft.server.level.ServerPlayer; +-import net.minecraft.util.datafix.DataFixTypes; + import net.minecraft.world.entity.player.Player; + import org.slf4j.Logger; + +@@ -18,6 +17,7 @@ import java.io.FileInputStream; + import java.io.InputStream; + import org.bukkit.craftbukkit.entity.CraftPlayer; + // CraftBukkit end ++import top.leavesmc.leaves.util.ArrayConstants; + + public class PlayerDataStorage { + +@@ -119,7 +119,7 @@ public class PlayerDataStorage { + String[] astring = this.playerDir.list(); + + if (astring == null) { +- astring = new String[0]; ++ astring = ArrayConstants.emptyStringArray; // Leaves - reduce array allocations + } + + for (int i = 0; i < astring.length; ++i) { +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftEquipmentSlot.java b/src/main/java/org/bukkit/craftbukkit/CraftEquipmentSlot.java +index 402a238cf502003a232bb95473bd13e59e067fab..6095f5c9298558c77a788c1c9f9ef1f32825b37c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftEquipmentSlot.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftEquipmentSlot.java +@@ -5,8 +5,10 @@ import org.bukkit.inventory.EquipmentSlot; + + public class CraftEquipmentSlot { + +- private static final net.minecraft.world.entity.EquipmentSlot[] slots = new net.minecraft.world.entity.EquipmentSlot[EquipmentSlot.values().length]; +- private static final EquipmentSlot[] enums = new EquipmentSlot[net.minecraft.world.entity.EquipmentSlot.values().length]; ++ // Leaves start - reduce array allocations ++ private static final net.minecraft.world.entity.EquipmentSlot[] slots = net.minecraft.world.entity.EquipmentSlot.VALUES; ++ private static final EquipmentSlot[] enums = new EquipmentSlot[net.minecraft.world.entity.EquipmentSlot.VALUES.length]; ++ // Leaves end - reduce array allocations + + static { + set(EquipmentSlot.HAND, net.minecraft.world.entity.EquipmentSlot.MAINHAND); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftEntityEquipment.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftEntityEquipment.java +index 6827979a5b270ced53b46ecb9eff548727dadb81..1b84078152d0585ec51288e585754be176f2d7c2 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftEntityEquipment.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftEntityEquipment.java +@@ -165,7 +165,7 @@ public class CraftEntityEquipment implements EntityEquipment { + + @Override + public void clear() { +- for (net.minecraft.world.entity.EquipmentSlot slot : net.minecraft.world.entity.EquipmentSlot.values()) { ++ for (net.minecraft.world.entity.EquipmentSlot slot : net.minecraft.world.entity.EquipmentSlot.VALUES) { // Leaves - reduce array allocations + this.setEquipment(slot, null, false); + } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/util/WeakCollection.java b/src/main/java/org/bukkit/craftbukkit/util/WeakCollection.java +index bbacf58740f3faea0d555e4012fe2b15fb46ed50..97afd508898096e5c2e6401cf02b0be587f365d9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/WeakCollection.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/WeakCollection.java +@@ -6,6 +6,7 @@ import java.util.ArrayList; + import java.util.Collection; + import java.util.Iterator; + import java.util.NoSuchElementException; ++import top.leavesmc.leaves.util.ArrayConstants; + + public final class WeakCollection implements Collection { + static final Object NO_VALUE = new Object(); +@@ -164,7 +165,7 @@ public final class WeakCollection implements Collection { + + @Override + public Object[] toArray() { +- return this.toArray(new Object[0]); ++ return this.toArray(ArrayConstants.emptyObjectArray); // Leaves - reduce array allocations + } + + @Override +diff --git a/src/main/java/top/leavesmc/leaves/util/ArrayConstants.java b/src/main/java/top/leavesmc/leaves/util/ArrayConstants.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0523062a825bd36f335f1fa6e1440eaaf400fd58 +--- /dev/null ++++ b/src/main/java/top/leavesmc/leaves/util/ArrayConstants.java +@@ -0,0 +1,21 @@ ++package top.leavesmc.leaves.util; ++ ++import net.minecraft.server.level.ServerLevel; ++ ++// Powered by Gale(https://github.com/GaleMC/Gale) ++ ++public class ArrayConstants { ++ ++ private ArrayConstants() {} ++ ++ public static final Object[] emptyObjectArray = new Object[0]; ++ public static final int[] emptyIntArray = new int[0]; ++ public static final int[] zeroSingletonIntArray = new int[]{0}; ++ public static final byte[] emptyByteArray = new byte[0]; ++ public static final String[] emptyStringArray = new String[0]; ++ public static final long[] emptyLongArray = new long[0]; ++ public static final org.bukkit.entity.Entity[] emptyBukkitEntityArray = new org.bukkit.entity.Entity[0]; ++ public static final net.minecraft.world.entity.Entity[] emptyEntityArray = new net.minecraft.world.entity.Entity[0]; ++ public static final ServerLevel[] emptyServerLevelArray = new ServerLevel[0]; ++ ++}