diff --git a/patches/server/0001-Mirai-Branding-Changes.patch b/patches/server/0001-Mirai-Branding-Changes.patch index 1c319ef..258d885 100644 --- a/patches/server/0001-Mirai-Branding-Changes.patch +++ b/patches/server/0001-Mirai-Branding-Changes.patch @@ -217,7 +217,7 @@ index b0390eedb507d27426d1e1d73bd4ab63aec89ebe..509a9a5326d94200ca3d7a83ae47c6bb .completer(new ConsoleCommandCompleter(this.server)) .option(LineReader.Option.COMPLETE_IN_WORD, true); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 92f685b1b6015cdd3e6c50fd39a79e2ad187fc91..9b64602e5ce5100dd1d467d404b4a6486ccc2faa 100644 +index 06d31a03ec7d049649e94d013429d2197b697545..02d3584994027d8cfd3c3c70a878404fe6f5fc76 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -913,7 +913,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop optionspec11 = optionparser.accepts("port").withRequiredArg().ofType(Integer.class).defaultsTo(-1, new Integer[0]); OptionSpec optionspec12 = optionparser.accepts("serverId").withRequiredArg(); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 9b64602e5ce5100dd1d467d404b4a6486ccc2faa..e5e88728d2d3b4ac9e266294999af84aee4aeae4 100644 +index 02d3584994027d8cfd3c3c70a878404fe6f5fc76..5b49126a64ea70ea4536a8e511f86f114d5fac1c 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1374,8 +1374,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop= 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 @@ -338,7 +338,7 @@ index 9aab29dd7a09c306d6c0e1e8143daf005d611d65..22c053d0c730e6d82acc556f08eedcd3 } } else { if (elapsedTime >= 15000L) { // 15 seconds -@@ -882,13 +882,13 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -879,13 +879,13 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic // PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel()); // 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 @@ -354,7 +354,7 @@ index 9aab29dd7a09c306d6c0e1e8143daf005d611d65..22c053d0c730e6d82acc556f08eedcd3 return; } // Paper end -@@ -3404,7 +3404,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -3396,7 +3396,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic // Paper start if (!org.bukkit.Bukkit.isPrimaryThread()) { if (recipeSpamPackets.addAndGet(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamIncrement) > io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamLimit) { diff --git a/patches/server/0009-Add-last-tick-time-API.patch b/patches/server/0009-Add-last-tick-time-API.patch index 47fae3d..1893bfc 100644 --- a/patches/server/0009-Add-last-tick-time-API.patch +++ b/patches/server/0009-Add-last-tick-time-API.patch @@ -7,10 +7,10 @@ Original code by YatopiaMC, licensed under MIT You can find the original code on https://github.com/YatopiaMC/Yatopia diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index e5e88728d2d3b4ac9e266294999af84aee4aeae4..98b9b07e24b50e7021546680baf2ddd86ce5bd98 100644 +index 5b49126a64ea70ea4536a8e511f86f114d5fac1c..93ca26908310dca94f063c1820d96b99aa9557a6 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1122,6 +1122,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop= 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 -@@ -3604,6 +3620,16 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -3596,6 +3612,16 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic @Override public void handleKeepAlive(ServerboundKeepAlivePacket packet) { diff --git a/patches/server/0038-Logger-settings-suppressing-pointless-logs.patch b/patches/server/0038-Logger-settings-suppressing-pointless-logs.patch index 1a1147c..42e6d95 100644 --- a/patches/server/0038-Logger-settings-suppressing-pointless-logs.patch +++ b/patches/server/0038-Logger-settings-suppressing-pointless-logs.patch @@ -33,10 +33,10 @@ index 80c1e0e47818486a68e0114b063395290365346b..1194c501a82e0e84d961d4ccb62f0c60 hasSetFarWarned = true; if (this.getServer() != null && this.getServer().isDebugging()) { diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index c3d10b9eaa461f1887785cf47130631b4612b465..58fe8b248f4893cce951931ae8ce447426c4b4b4 100644 +index 1b563829545aebfb1b8f3cea6fa7f99e52a247cc..bc3f0dfe075ea2aeae48df05c66c9045810f7a0b 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -2628,7 +2628,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -2625,7 +2625,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic } if (playerchatmessage.hasExpiredServer(Instant.now())) { diff --git a/patches/server/0039-Add-5-second-tps-average-in-tps.patch b/patches/server/0039-Add-5-second-tps-average-in-tps.patch index 6ca8758..fe24353 100644 --- a/patches/server/0039-Add-5-second-tps-average-in-tps.patch +++ b/patches/server/0039-Add-5-second-tps-average-in-tps.patch @@ -29,7 +29,7 @@ index fa56cd09102a89692b42f1d14257990508c5c720..f9251183df72ddc56662fd3f02acf216 setListData(vector); } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 3cb82a09ff2d588535b60c64bb787e849346e688..5e8a2cd78380727969c771eafa745550f3c5f237 100644 +index 7c0767c12cf01c71db982034e74cf5543ef25997..2a5bd17084238d8073d2f891f4c1af04d33fd09d 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -290,7 +290,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop +Date: Mon, 10 Jan 2022 15:27:58 -0500 +Subject: [PATCH] lithium: chunk.serialization + +Original code by CaffeineMC, licensed under GNU Lesser General Public License v3.0 +You can find the original code on https://github.com/CaffeineMC/lithium-fabric (Yarn mappings) + +diff --git a/src/main/java/me/jellysquid/mods/lithium/common/world/chunk/LithiumHashPalette.java b/src/main/java/me/jellysquid/mods/lithium/common/world/chunk/LithiumHashPalette.java +new file mode 100644 +index 0000000000000000000000000000000000000000..16debe176798f316c122e8e7aef2b50ecb9883a6 +--- /dev/null ++++ b/src/main/java/me/jellysquid/mods/lithium/common/world/chunk/LithiumHashPalette.java +@@ -0,0 +1,189 @@ ++package me.jellysquid.mods.lithium.common.world.chunk; ++ ++import com.google.common.collect.ImmutableList; ++import it.unimi.dsi.fastutil.HashCommon; ++import it.unimi.dsi.fastutil.objects.Reference2IntMap; ++import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; ++import java.util.Arrays; ++import java.util.List; ++import java.util.function.Predicate; ++import net.minecraft.core.IdMap; ++import net.minecraft.network.FriendlyByteBuf; ++import net.minecraft.world.level.chunk.Palette; ++import net.minecraft.world.level.chunk.PaletteResize; ++ ++import static it.unimi.dsi.fastutil.Hash.FAST_LOAD_FACTOR; ++ ++/** ++ * Generally provides better performance over the vanilla {@link net.minecraft.world.level.chunk.HashMapPalette} when calling ++ * {@link LithiumHashPalette#idFor(Object)} through using a faster backing map and reducing pointer chasing. ++ */ ++public class LithiumHashPalette implements Palette { ++ private static final int ABSENT_VALUE = -1; ++ ++ private final IdMap idList; ++ private final PaletteResize resizeHandler; ++ private final int indexBits; ++ ++ private final Reference2IntMap table; ++ private T[] entries; ++ private int size = 0; ++ ++ public LithiumHashPalette(IdMap idList, PaletteResize resizeHandler, int indexBits, T[] entries, Reference2IntMap table, int size) { ++ this.idList = idList; ++ this.resizeHandler = resizeHandler; ++ this.indexBits = indexBits; ++ this.entries = entries; ++ this.table = table; ++ this.size = size; ++ } ++ ++ public LithiumHashPalette(IdMap idList, int bits, PaletteResize resizeHandler, List list) { ++ this(idList, bits, resizeHandler); ++ ++ for (T t : list) { ++ this.addEntry(t); ++ } ++ } ++ ++ @SuppressWarnings("unchecked") ++ public LithiumHashPalette(IdMap idList, int bits, PaletteResize resizeHandler) { ++ this.idList = idList; ++ this.indexBits = bits; ++ this.resizeHandler = resizeHandler; ++ ++ int capacity = 1 << bits; ++ ++ this.entries = (T[]) new Object[capacity]; ++ this.table = new Reference2IntOpenHashMap<>(capacity, FAST_LOAD_FACTOR); ++ this.table.defaultReturnValue(ABSENT_VALUE); ++ } ++ ++ @Override ++ public int idFor(T obj) { ++ int id = this.table.getInt(obj); ++ ++ if (id == ABSENT_VALUE) { ++ id = this.computeEntry(obj); ++ } ++ ++ return id; ++ } ++ ++ @Override ++ public boolean maybeHas(Predicate predicate) { ++ for (int i = 0; i < this.size; ++i) { ++ if (predicate.test(this.entries[i])) { ++ return true; ++ } ++ } ++ ++ return false; ++ } ++ ++ private int computeEntry(T obj) { ++ int id = this.addEntry(obj); ++ ++ if (id >= 1 << this.indexBits) { ++ if (this.resizeHandler == null) { ++ throw new IllegalStateException("Cannot grow"); ++ } else { ++ id = this.resizeHandler.onResize(this.indexBits + 1, obj); ++ } ++ } ++ ++ return id; ++ } ++ ++ private int addEntry(T obj) { ++ int nextId = this.size; ++ ++ if (nextId >= this.entries.length) { ++ this.resize(this.size); ++ } ++ ++ this.table.put(obj, nextId); ++ this.entries[nextId] = obj; ++ ++ this.size++; ++ ++ return nextId; ++ } ++ ++ private void resize(int neededCapacity) { ++ this.entries = Arrays.copyOf(this.entries, HashCommon.nextPowerOfTwo(neededCapacity + 1)); ++ } ++ ++ @Override ++ public T valueFor(int id) { ++ T[] entries = this.entries; ++ ++ if (id >= 0 && id < entries.length) { ++ return entries[id]; ++ } ++ ++ return null; ++ } ++ ++ @Override ++ public void read(FriendlyByteBuf buf) { ++ this.clear(); ++ ++ int entryCount = buf.readVarInt(); ++ ++ for (int i = 0; i < entryCount; ++i) { ++ this.addEntry(this.idList.byId(buf.readVarInt())); ++ } ++ } ++ ++ @Override ++ public void write(FriendlyByteBuf buf) { ++ int size = this.size; ++ buf.writeVarInt(size); ++ ++ for (int i = 0; i < size; ++i) { ++ buf.writeVarInt(this.idList.getId(this.valueFor(i))); ++ } ++ } ++ ++ @Override ++ public int getSerializedSize() { ++ int size = FriendlyByteBuf.getVarIntSize(this.size); ++ ++ for (int i = 0; i < this.size; ++i) { ++ size += FriendlyByteBuf.getVarIntSize(this.idList.getId(this.valueFor(i))); ++ } ++ ++ return size; ++ } ++ ++ @Override ++ public int getSize() { ++ return this.size; ++ } ++ ++ @Override ++ public Palette copy() { ++ return new LithiumHashPalette<>(this.idList, this.resizeHandler, this.indexBits, this.entries.clone(), new Reference2IntOpenHashMap<>(this.table), this.size); ++ } ++ ++ private void clear() { ++ Arrays.fill(this.entries, null); ++ this.table.clear(); ++ this.size = 0; ++ } ++ ++ public List getElements() { ++ ImmutableList.Builder builder = new ImmutableList.Builder<>(); ++ for (T entry : this.entries) { ++ if (entry != null) { ++ builder.add(entry); ++ } ++ } ++ return builder.build(); ++ } ++ ++ public static Palette create(int bits, IdMap idList, PaletteResize listener, List list) { ++ return new LithiumHashPalette<>(idList, bits, listener, list); ++ } ++} +\ No newline at end of file +diff --git a/src/main/java/net/minecraft/util/BitStorage.java b/src/main/java/net/minecraft/util/BitStorage.java +index 106610ccc74b70b557b01c61262d56c4f1147acf..fc986f02290fbe20246022072944980f35dd200c 100644 +--- a/src/main/java/net/minecraft/util/BitStorage.java ++++ b/src/main/java/net/minecraft/util/BitStorage.java +@@ -1,6 +1,7 @@ + package net.minecraft.util; + + import java.util.function.IntConsumer; ++import net.minecraft.world.level.chunk.Palette; // JettPack + + public interface BitStorage { + int getAndSet(int index, int value); +@@ -31,4 +32,6 @@ public interface BitStorage { + + } + // Paper end ++ ++ void compact(Palette srcPalette, Palette dstPalette, short[] out); // JettPack - lithium: chunk.serialization + } +diff --git a/src/main/java/net/minecraft/util/SimpleBitStorage.java b/src/main/java/net/minecraft/util/SimpleBitStorage.java +index 36e33923bf48e56c743ed043bcbc66bc32f0422f..0272dee738e86e066108f5cc3729136335d8197e 100644 +--- a/src/main/java/net/minecraft/util/SimpleBitStorage.java ++++ b/src/main/java/net/minecraft/util/SimpleBitStorage.java +@@ -2,6 +2,7 @@ package net.minecraft.util; + + import java.util.function.IntConsumer; + import javax.annotation.Nullable; ++import net.minecraft.world.level.chunk.Palette; // JettPack + import org.apache.commons.lang3.Validate; + + public class SimpleBitStorage implements BitStorage { +@@ -201,4 +202,44 @@ public class SimpleBitStorage implements BitStorage { + super(message); + } + } ++ ++ // JettPack start - lithium: chunk.serialization ++ @Override ++ public void compact(Palette srcPalette, Palette dstPalette, short[] out) { ++ if (this.size >= Short.MAX_VALUE) { ++ throw new IllegalStateException("Array too large"); ++ } ++ ++ if (this.size != out.length) { ++ throw new IllegalStateException("Array size mismatch"); ++ } ++ ++ short[] mappings = new short[(int) (this.mask + 1)]; ++ ++ int idx = 0; ++ ++ for (long word : this.data) { ++ long bits = word; ++ ++ for (int elementIdx = 0; elementIdx < this.valuesPerLong; ++elementIdx) { ++ int value = (int) (bits & this.mask); ++ int remappedId = mappings[value]; ++ ++ if (remappedId == 0) { ++ remappedId = dstPalette.idFor(srcPalette.valueFor(value)) + 1; ++ mappings[value] = (short) remappedId; ++ } ++ ++ out[idx] = (short) (remappedId - 1); ++ bits >>= this.bits; ++ ++ ++idx; ++ ++ if (idx >= this.size) { ++ return; ++ } ++ } ++ } ++ } ++ // JettPack end + } +diff --git a/src/main/java/net/minecraft/util/ZeroBitStorage.java b/src/main/java/net/minecraft/util/ZeroBitStorage.java +index 97c744508cc535418eba65fa722859c81c22d647..a2ea0a2864b9c4f847f1a14ffc0900e67c18f9ee 100644 +--- a/src/main/java/net/minecraft/util/ZeroBitStorage.java ++++ b/src/main/java/net/minecraft/util/ZeroBitStorage.java +@@ -2,6 +2,7 @@ package net.minecraft.util; + + import java.util.Arrays; + import java.util.function.IntConsumer; ++import net.minecraft.world.level.chunk.Palette; // JettPack + import org.apache.commons.lang3.Validate; + + public class ZeroBitStorage implements BitStorage { +@@ -72,4 +73,6 @@ public class ZeroBitStorage implements BitStorage { + public BitStorage copy() { + return this; + } ++ ++ @Override public void compact(Palette srcPalette, Palette dstPalette, short[] out) {} // JettPack + } +diff --git a/src/main/java/net/minecraft/world/level/chunk/PaletteResize.java b/src/main/java/net/minecraft/world/level/chunk/PaletteResize.java +index acae3eb30e0689048937f479dc3070f0688abdad..9c2b79655f2c63a208c7087d5d897db0fb23f697 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/PaletteResize.java ++++ b/src/main/java/net/minecraft/world/level/chunk/PaletteResize.java +@@ -1,5 +1,5 @@ + package net.minecraft.world.level.chunk; + +-interface PaletteResize { ++public interface PaletteResize { // JettPack - make public + int onResize(int newBits, T object); + } +diff --git a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java +index 7908360dd47937b2cb702e381802b7b278a5198e..f31fd07ce34f798f54d4fae1ccfa22636d4ec2aa 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java ++++ b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java +@@ -22,8 +22,23 @@ import net.minecraft.util.Mth; + import net.minecraft.util.SimpleBitStorage; + import net.minecraft.util.ThreadingDetector; + import net.minecraft.util.ZeroBitStorage; ++import me.jellysquid.mods.lithium.common.world.chunk.LithiumHashPalette; // JettPack + + public class PalettedContainer implements PaletteResize, PalettedContainerRO { ++ // JettPack start - lithium: chunk.serialization ++ private static final ThreadLocal CACHED_ARRAY_4096 = ThreadLocal.withInitial(() -> new short[4096]); ++ private static final ThreadLocal CACHED_ARRAY_64 = ThreadLocal.withInitial(() -> new short[64]); ++ private Optional asOptional(long[] data) { ++ return Optional.of(Arrays.stream(data)); ++ } ++ private short[] getOrCreate(int size) { ++ return switch (size) { ++ case 64 -> CACHED_ARRAY_64.get(); ++ case 4096 -> CACHED_ARRAY_4096.get(); ++ default -> new short[size]; ++ }; ++ } ++ // JettPack end + private static final int MIN_PALETTE_BITS = 0; + private final PaletteResize dummyPaletteResize = (newSize, added) -> { + return 0; +@@ -299,30 +314,54 @@ public class PalettedContainer implements PaletteResize, PalettedContainer + public synchronized PalettedContainerRO.PackedData pack(IdMap idList, PalettedContainer.Strategy paletteProvider) { // Paper - synchronize + this.acquire(); + +- PalettedContainerRO.PackedData var12; ++ // JettPack start - lithium: chunk.serialization ++ Optional data = Optional.empty(); ++ List elements = null; + try { +- HashMapPalette hashMapPalette = new HashMapPalette<>(idList, this.data.storage.getBits(), this.dummyPaletteResize); +- int i = paletteProvider.size(); +- int[] is = new int[i]; +- this.data.storage.unpack(is); +- swapPalette(is, (id) -> { +- return hashMapPalette.idFor(this.data.palette.valueFor(id)); +- }); +- int j = paletteProvider.calculateBitsForSerialization(idList, hashMapPalette.getSize()); +- Optional optional; +- if (j != 0) { +- SimpleBitStorage simpleBitStorage = new SimpleBitStorage(j, i, is); +- optional = Optional.of(Arrays.stream(simpleBitStorage.getRaw())); +- } else { +- optional = Optional.empty(); ++ // The palette that will be serialized ++ LithiumHashPalette hashPalette = null; ++ ++ final Palette palette = this.data.palette(); ++ final BitStorage storage = this.data.storage(); ++ if (storage instanceof ZeroBitStorage || palette.getSize() == 1) { ++ // If the palette only contains one entry, don't attempt to repack it. ++ elements = List.of(palette.valueFor(0)); ++ } else if (palette instanceof LithiumHashPalette lithiumHashPalette) { ++ hashPalette = lithiumHashPalette; + } + +- var12 = new PalettedContainerRO.PackedData<>(hashMapPalette.getEntries(), optional); ++ if (elements == null) { ++ LithiumHashPalette compactedPalette = new LithiumHashPalette<>(idList, storage.getBits(), this.dummyPaletteResize); ++ short[] array = this.getOrCreate(paletteProvider.size()); ++ ++ storage.compact(this.data.palette(), compactedPalette, array); ++ ++ // If the palette didn't change during compaction, do a simple copy of the data array ++ if (hashPalette != null && hashPalette.getSize() == compactedPalette.getSize() && storage.getBits() == paletteProvider.calculateBitsForSerialization(idList, hashPalette.getSize())) { // paletteSize can de-sync from palette - see https://github.com/CaffeineMC/lithium-fabric/issues/279 ++ data = this.asOptional(storage.getRaw().clone()); ++ elements = hashPalette.getElements(); ++ } else { ++ int bits = paletteProvider.calculateBitsForSerialization(idList, compactedPalette.getSize()); ++ if (bits != 0) { ++ // Re-pack the integer array as the palette has changed size ++ SimpleBitStorage copy = new SimpleBitStorage(bits, array.length); ++ for (int i = 0; i < array.length; ++i) { ++ copy.set(i, array[i]); ++ } ++ ++ // We don't need to clone the data array as we are the sole owner of it ++ data = this.asOptional(copy.getRaw()); ++ } ++ ++ elements = compactedPalette.getElements(); ++ } ++ } + } finally { + this.release(); + } + +- return var12; ++ return new PalettedContainerRO.PackedData<>(elements, data); ++ // JettPack end + } + + private static void swapPalette(int[] is, IntUnaryOperator applier) { +@@ -362,17 +401,37 @@ public class PalettedContainer implements PaletteResize, PalettedContainer + + @Override + public void count(PalettedContainer.CountConsumer counter) { +- if (this.data.palette.getSize() == 1) { +- counter.accept(this.data.palette.valueFor(0), this.data.storage.getSize()); +- } else { +- Int2IntOpenHashMap int2IntOpenHashMap = new Int2IntOpenHashMap(); +- this.data.storage.getAll((key) -> { +- int2IntOpenHashMap.addTo(key, 1); +- }); +- int2IntOpenHashMap.int2IntEntrySet().forEach((entry) -> { +- counter.accept(this.data.palette.valueFor(entry.getIntKey()), entry.getIntValue()); +- }); ++ // JettPack start - lithium: chunk.serialization ++ int len = this.data.palette().getSize(); ++ ++ // Do not allocate huge arrays if we're using a large palette ++ if (len > 4096) { ++ // VanillaCopy ++ if (this.data.palette.getSize() == 1) { ++ counter.accept(this.data.palette.valueFor(0), this.data.storage.getSize()); ++ } else { ++ Int2IntOpenHashMap int2IntOpenHashMap = new Int2IntOpenHashMap(); ++ this.data.storage.getAll((key) -> { ++ int2IntOpenHashMap.addTo(key, 1); ++ }); ++ int2IntOpenHashMap.int2IntEntrySet().forEach((entry) -> { ++ counter.accept(this.data.palette.valueFor(entry.getIntKey()), entry.getIntValue()); ++ }); ++ } ++ } ++ ++ short[] counts = new short[len]; ++ ++ this.data.storage().getAll(i -> counts[i]++); ++ ++ for (int i = 0; i < counts.length; i++) { ++ T obj = this.data.palette().valueFor(i); ++ ++ if (obj != null) { ++ counter.accept(obj, counts[i]); ++ } + } ++ // JettPack end + } + + static record Configuration(Palette.Factory factory, int bits) { diff --git a/patches/server/0066-Configurable-criterion-triggers.patch b/patches/server/0067-Configurable-criterion-triggers.patch similarity index 94% rename from patches/server/0066-Configurable-criterion-triggers.patch rename to patches/server/0067-Configurable-criterion-triggers.patch index 02b597a..76bd9d2 100644 --- a/patches/server/0066-Configurable-criterion-triggers.patch +++ b/patches/server/0067-Configurable-criterion-triggers.patch @@ -9,7 +9,7 @@ Original code by YatopiaMC, licensed under MIT You can find the original code on https://github.com/YatopiaMC/Yatopia diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index e52256415e2776f41d107cbf39a73708d6e0d506..4d705dc5294bb07b0ce34c68d1c4bbf33bb84848 100644 +index 666189dae2400decc3d5bf97e073301e2de40472..2392913f2c221882bfdf324b671486a05a87ea76 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -615,7 +615,7 @@ public class ServerPlayer extends Player { @@ -42,7 +42,7 @@ index e52256415e2776f41d107cbf39a73708d6e0d506..4d705dc5294bb07b0ce34c68d1c4bbf3 // CraftBukkit start - initialize oldLevel, fire PlayerLevelChangeEvent, and tick client-sided world border if (this.oldLevel == -1) { diff --git a/src/main/java/wtf/etil/mirai/MiraiConfig.java b/src/main/java/wtf/etil/mirai/MiraiConfig.java -index 7339e70f8182209e6274c7f1f1f3558adcaa2cfa..c12ab155bdd4a1bad7bb428ecddc20a7999f91f5 100644 +index 9bc1e365e0c96907f6fb2b5cd67a12c87d0cf7ed..aa6e4eae07182d74632b7b4ee0844a979a630686 100644 --- a/src/main/java/wtf/etil/mirai/MiraiConfig.java +++ b/src/main/java/wtf/etil/mirai/MiraiConfig.java @@ -209,4 +209,16 @@ public class MiraiConfig { diff --git a/patches/server/0067-Set-item-stuck-sleep-to-15-ticks.patch b/patches/server/0068-Set-item-stuck-sleep-to-15-ticks.patch similarity index 100% rename from patches/server/0067-Set-item-stuck-sleep-to-15-ticks.patch rename to patches/server/0068-Set-item-stuck-sleep-to-15-ticks.patch diff --git a/patches/server/0068-Smarter-statistics-ticking.patch b/patches/server/0069-Smarter-statistics-ticking.patch similarity index 100% rename from patches/server/0068-Smarter-statistics-ticking.patch rename to patches/server/0069-Smarter-statistics-ticking.patch diff --git a/patches/server/0069-some-entity-micro-opts.patch b/patches/server/0070-some-entity-micro-opts.patch similarity index 100% rename from patches/server/0069-some-entity-micro-opts.patch rename to patches/server/0070-some-entity-micro-opts.patch diff --git a/patches/server/0070-Dont-eat-blocks-in-non-ticking-chunks.patch b/patches/server/0071-Dont-eat-blocks-in-non-ticking-chunks.patch similarity index 100% rename from patches/server/0070-Dont-eat-blocks-in-non-ticking-chunks.patch rename to patches/server/0071-Dont-eat-blocks-in-non-ticking-chunks.patch diff --git a/patches/server/0071-Fast-speed-check.patch b/patches/server/0072-Fast-speed-check.patch similarity index 96% rename from patches/server/0071-Fast-speed-check.patch rename to patches/server/0072-Fast-speed-check.patch index 9913551..cc986a6 100644 --- a/patches/server/0071-Fast-speed-check.patch +++ b/patches/server/0072-Fast-speed-check.patch @@ -36,7 +36,7 @@ index 6bc313aa05d572236f05d0960fde0f27b9f93d50..9bdcad2b05367a8dcb519a2db8c4efea this.setDeltaMovement(this.getDeltaMovement().multiply((double) f2, 1.0D, (double) f2)); // Paper start - remove expensive streams from here diff --git a/src/main/java/wtf/etil/mirai/MiraiConfig.java b/src/main/java/wtf/etil/mirai/MiraiConfig.java -index c12ab155bdd4a1bad7bb428ecddc20a7999f91f5..b9351994ac2b9865ca39fdb76625983cf7c63cdb 100644 +index 7a5d000c25af93b60215b3e2867358d7c238c6e4..7658c7743646fb1d3e07a9f91245407a2dd191dd 100644 --- a/src/main/java/wtf/etil/mirai/MiraiConfig.java +++ b/src/main/java/wtf/etil/mirai/MiraiConfig.java @@ -221,4 +221,11 @@ public class MiraiConfig { diff --git a/patches/server/0072-lithium-cache-iterate-outwards.patch b/patches/server/0073-lithium-cache-iterate-outwards.patch similarity index 100% rename from patches/server/0072-lithium-cache-iterate-outwards.patch rename to patches/server/0073-lithium-cache-iterate-outwards.patch diff --git a/patches/server/0073-lithium-ai.raid.patch b/patches/server/0074-lithium-ai.raid.patch similarity index 100% rename from patches/server/0073-lithium-ai.raid.patch rename to patches/server/0074-lithium-ai.raid.patch diff --git a/patches/server/0074-lithium-block.moving_block_shapes.patch b/patches/server/0075-lithium-block.moving_block_shapes.patch similarity index 100% rename from patches/server/0074-lithium-block.moving_block_shapes.patch rename to patches/server/0075-lithium-block.moving_block_shapes.patch diff --git a/patches/server/0075-lithium-shapes.blockstate_cache.patch b/patches/server/0076-lithium-shapes.blockstate_cache.patch similarity index 100% rename from patches/server/0075-lithium-shapes.blockstate_cache.patch rename to patches/server/0076-lithium-shapes.blockstate_cache.patch diff --git a/patches/server/0076-lithium-gen.patch b/patches/server/0077-lithium-gen.patch similarity index 100% rename from patches/server/0076-lithium-gen.patch rename to patches/server/0077-lithium-gen.patch diff --git a/patches/server/0077-PaperPR-Stop-large-look-changes-from-crashing-the-se.patch b/patches/server/0078-PaperPR-Stop-large-look-changes-from-crashing-the-se.patch similarity index 100% rename from patches/server/0077-PaperPR-Stop-large-look-changes-from-crashing-the-se.patch rename to patches/server/0078-PaperPR-Stop-large-look-changes-from-crashing-the-se.patch diff --git a/patches/server/0078-PaperPR-Add-more-collision-code-skipping-logic.patch b/patches/server/0079-PaperPR-Add-more-collision-code-skipping-logic.patch similarity index 100% rename from patches/server/0078-PaperPR-Add-more-collision-code-skipping-logic.patch rename to patches/server/0079-PaperPR-Add-more-collision-code-skipping-logic.patch diff --git a/patches/server/0079-vmp-use-linked-map-for-entity-trackers-for-faster-it.patch b/patches/server/0080-vmp-use-linked-map-for-entity-trackers-for-faster-it.patch similarity index 100% rename from patches/server/0079-vmp-use-linked-map-for-entity-trackers-for-faster-it.patch rename to patches/server/0080-vmp-use-linked-map-for-entity-trackers-for-faster-it.patch diff --git a/patches/server/0080-c2me-reduce_allocs.patch b/patches/server/0081-c2me-reduce_allocs.patch similarity index 100% rename from patches/server/0080-c2me-reduce_allocs.patch rename to patches/server/0081-c2me-reduce_allocs.patch diff --git a/patches/server/0081-lithium-ai.sensor.secondary_poi.patch b/patches/server/0082-lithium-ai.sensor.secondary_poi.patch similarity index 100% rename from patches/server/0081-lithium-ai.sensor.secondary_poi.patch rename to patches/server/0082-lithium-ai.sensor.secondary_poi.patch diff --git a/patches/server/0082-Fix-tick-function-tag-running-before-load.patch b/patches/server/0083-Fix-tick-function-tag-running-before-load.patch similarity index 100% rename from patches/server/0082-Fix-tick-function-tag-running-before-load.patch rename to patches/server/0083-Fix-tick-function-tag-running-before-load.patch diff --git a/patches/server/0084-lithium-suffocation.patch b/patches/server/0084-lithium-suffocation.patch new file mode 100644 index 0000000..e3efa09 --- /dev/null +++ b/patches/server/0084-lithium-suffocation.patch @@ -0,0 +1,100 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: etil2jz +Date: Fri, 8 Apr 2022 22:21:48 +0200 +Subject: [PATCH] lithium: suffocation + +Author: 2No2Name <2No2Name@web.de> + +Original license: GNU Lesser General Public License v3.0 +Original project: https://github.com/CaffeineMC/lithium-fabric (Yarn mappings) + +diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java +index 9bdcad2b05367a8dcb519a2db8c4efea94a4d21c..ae428552912f5a484ecf581b24c0e362c3e2407f 100644 +--- a/src/main/java/net/minecraft/world/entity/Entity.java ++++ b/src/main/java/net/minecraft/world/entity/Entity.java +@@ -2593,39 +2593,64 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { + return !this.isRemoved(); + } + ++ // Mirai start - lithium: suffocation ++ /** ++ * @author 2No2Name ++ * @reason Avoid stream code, use optimized chunk section iteration order ++ */ + public boolean isInWall() { ++ // [VanillaCopy] The whole method functionality including bug below. Cannot use ChunkAwareBlockCollisionSweeper due to ignoring of oversized blocks + if (this.noPhysics) { + return false; +- } else { +- float f = this.dimensions.width * 0.8F; +- AABB axisalignedbb = AABB.ofSize(this.getEyePosition(), (double) f, 1.0E-6D, (double) f); +- +- BlockPos.MutableBlockPos blockposition = new BlockPos.MutableBlockPos(); +- int minX = Mth.floor(axisalignedbb.minX); +- int minY = Mth.floor(axisalignedbb.minY); +- int minZ = Mth.floor(axisalignedbb.minZ); +- int maxX = Mth.floor(axisalignedbb.maxX); +- int maxY = Mth.floor(axisalignedbb.maxY); +- int maxZ = Mth.floor(axisalignedbb.maxZ); +- for (int fz = minZ; fz <= maxZ; ++fz) { +- for (int fx = minX; fx <= maxX; ++fx) { +- for (int fy = minY; fy <= maxY; ++fy) { +- net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk)this.level.getChunkIfLoadedImmediately(fx >> 4, fz >> 4); +- if (chunk == null) { +- continue; ++ } ++ Vec3 position = this.getEyePosition(); ++ double suffocationRadius = Math.abs((double) (this.dimensions.width * 0.8f) / 2.0); ++ ++ double suffocationMinX = position.x - suffocationRadius; ++ double suffocationMinY = position.y - 5.0E-7; ++ double suffocationMinZ = position.z - suffocationRadius; ++ double suffocationMaxX = position.x + suffocationRadius; ++ double suffocationMaxY = position.y + 5.0E-7; ++ double suffocationMaxZ = position.z + suffocationRadius; ++ int minX = Mth.floor(suffocationMinX); ++ int minY = Mth.floor(suffocationMinY); ++ int minZ = Mth.floor(suffocationMinZ); ++ int maxX = Mth.floor(suffocationMaxX); ++ int maxY = Mth.floor(suffocationMaxY); ++ int maxZ = Mth.floor(suffocationMaxZ); ++ ++ Level level = this.level; ++ //skip getting blocks when the entity is outside the world height ++ //also avoids infinite loop with entities below y = Integer.MIN_VALUE (some modded servers do that) ++ if (level.getMinBuildHeight() > maxY || level.getMaxBuildHeight() < minY) { ++ return false; ++ } ++ ++ BlockPos.MutableBlockPos blockposition = new BlockPos.MutableBlockPos(); ++ VoxelShape suffocationShape = null; ++ ++ for (int y = minY; y <= maxY; y++) { ++ for (int z = minZ; z <= maxZ; z++) { ++ for (int x = minX; x <= maxX; x++) { ++ blockposition.set(x, y, z); ++ BlockState iblockdata = level.getBlockState(blockposition); ++ if (!iblockdata.isAir() && iblockdata.isSuffocating(this.level, blockposition)) { ++ if (suffocationShape == null) { ++ suffocationShape = Shapes.create(new AABB(suffocationMinX, suffocationMinY, suffocationMinZ, suffocationMaxX, suffocationMaxY, suffocationMaxZ)); + } + +- BlockState iblockdata = chunk.getBlockStateFinal(fx, fy, fz); +- blockposition.set(fx, fy, fz); +- if (!iblockdata.isAir() && iblockdata.isSuffocating(this.level, blockposition) && Shapes.joinIsNotEmpty(iblockdata.getCollisionShape(this.level, blockposition).move((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ()), Shapes.create(axisalignedbb), BooleanOp.AND)) { ++ if (Shapes.joinIsNotEmpty(iblockdata.getCollisionShape(this.level, blockposition). ++ move(blockposition.getX(), blockposition.getY(), blockposition.getZ()), ++ suffocationShape, BooleanOp.AND)) { + return true; + } + } + } + } +- return false; + } ++ return false; + } ++ // Mirai end + + public InteractionResult interact(Player player, InteractionHand hand) { + return InteractionResult.PASS; diff --git a/patches/server/0083-Optimize-default-values-for-configs.patch b/patches/server/0085-Optimize-default-values-for-configs.patch similarity index 100% rename from patches/server/0083-Optimize-default-values-for-configs.patch rename to patches/server/0085-Optimize-default-values-for-configs.patch diff --git a/patches/server/0084-Configurable-map-update-interval.patch b/patches/server/0086-Configurable-map-update-interval.patch similarity index 96% rename from patches/server/0084-Configurable-map-update-interval.patch rename to patches/server/0086-Configurable-map-update-interval.patch index fe338e2..74e249a 100644 --- a/patches/server/0084-Configurable-map-update-interval.patch +++ b/patches/server/0086-Configurable-map-update-interval.patch @@ -27,7 +27,7 @@ index 67b88da702b780f79c0496cb17f1e6f1f8dd6c2b..712707da510977bfa1ce4b991fd8a8f5 // CraftBukkit start java.util.Collection icons = new java.util.ArrayList(); diff --git a/src/main/java/wtf/etil/mirai/MiraiConfig.java b/src/main/java/wtf/etil/mirai/MiraiConfig.java -index b9351994ac2b9865ca39fdb76625983cf7c63cdb..65eac0889de3dd95a4b850f99b5193bede04358f 100644 +index 7658c7743646fb1d3e07a9f91245407a2dd191dd..23761b89a2fac069e9709db9741afa1ba24ae1d1 100644 --- a/src/main/java/wtf/etil/mirai/MiraiConfig.java +++ b/src/main/java/wtf/etil/mirai/MiraiConfig.java @@ -228,4 +228,11 @@ public class MiraiConfig { diff --git a/patches/server/0085-Fix-hunger-saturation-depleting-on-peaceful.patch b/patches/server/0087-Fix-hunger-saturation-depleting-on-peaceful.patch similarity index 100% rename from patches/server/0085-Fix-hunger-saturation-depleting-on-peaceful.patch rename to patches/server/0087-Fix-hunger-saturation-depleting-on-peaceful.patch diff --git a/patches/server/0086-Fix-mobs-attacking-themselves.patch b/patches/server/0088-Fix-mobs-attacking-themselves.patch similarity index 100% rename from patches/server/0086-Fix-mobs-attacking-themselves.patch rename to patches/server/0088-Fix-mobs-attacking-themselves.patch diff --git a/patches/server/0087-Fix-brewing-stands-resetting-their-brewTime-when-bei.patch b/patches/server/0089-Fix-brewing-stands-resetting-their-brewTime-when-bei.patch similarity index 100% rename from patches/server/0087-Fix-brewing-stands-resetting-their-brewTime-when-bei.patch rename to patches/server/0089-Fix-brewing-stands-resetting-their-brewTime-when-bei.patch diff --git a/patches/server/0090-lithium-world.tick_scheduler.patch b/patches/server/0090-lithium-world.tick_scheduler.patch new file mode 100644 index 0000000..13ccede --- /dev/null +++ b/patches/server/0090-lithium-world.tick_scheduler.patch @@ -0,0 +1,509 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Arthur Blanchot +Date: Fri, 24 Jun 2022 21:17:05 +0200 +Subject: [PATCH] lithium: world.tick_scheduler + +Original license: GPLv3 +Original project: https://github.com/CaffeineMC/lithium-fabric (Yarn mappings) + +diff --git a/src/main/java/me/jellysquid/mods/lithium/common/world/scheduler/OrderedTickQueue.java b/src/main/java/me/jellysquid/mods/lithium/common/world/scheduler/OrderedTickQueue.java +new file mode 100644 +index 0000000000000000000000000000000000000000..52e90ea09b44543af661c214767073cf9d5f3d8f +--- /dev/null ++++ b/src/main/java/me/jellysquid/mods/lithium/common/world/scheduler/OrderedTickQueue.java +@@ -0,0 +1,192 @@ ++package me.jellysquid.mods.lithium.common.world.scheduler; ++ ++import it.unimi.dsi.fastutil.HashCommon; ++import java.util.*; ++import net.minecraft.world.ticks.ScheduledTick; ++ ++/** ++ ++ */ ++public class OrderedTickQueue extends AbstractQueue> { ++ private static final int INITIAL_CAPACITY = 16; ++ private static final Comparator> COMPARATOR = Comparator.comparingLong(ScheduledTick::subTickOrder); ++ ++ private ScheduledTick[] arr; ++ ++ private int lastIndexExclusive; ++ private int firstIndex; ++ ++ private long currentMaxSubTickOrder = Long.MIN_VALUE; ++ private boolean isSorted; ++ private ScheduledTick unsortedPeekResult; ++ ++ @SuppressWarnings("unchecked") ++ public OrderedTickQueue(int capacity) { ++ this.arr = (ScheduledTick[]) new ScheduledTick[capacity]; ++ this.lastIndexExclusive = 0; ++ this.isSorted = true; ++ this.unsortedPeekResult = null; ++ this.firstIndex = 0; ++ } ++ ++ public OrderedTickQueue() { ++ this(INITIAL_CAPACITY); ++ } ++ ++ @Override ++ public void clear() { ++ Arrays.fill(this.arr, null); ++ this.lastIndexExclusive = 0; ++ this.firstIndex = 0; ++ this.currentMaxSubTickOrder = Long.MIN_VALUE; ++ this.isSorted = true; ++ this.unsortedPeekResult = null; ++ } ++ ++ @Override ++ public Iterator> iterator() { ++ if (this.isEmpty()) { ++ return Collections.emptyIterator(); ++ } ++ this.sort(); ++ return new Iterator<>() { ++ int nextIndex = OrderedTickQueue.this.firstIndex; ++ ++ @Override ++ public boolean hasNext() { ++ return this.nextIndex < OrderedTickQueue.this.lastIndexExclusive; ++ } ++ ++ @Override ++ public ScheduledTick next() { ++ return OrderedTickQueue.this.arr[this.nextIndex++]; ++ } ++ }; ++ } ++ ++ @Override ++ public ScheduledTick poll() { ++ if (this.isEmpty()) { ++ return null; ++ } ++ if (!this.isSorted) { ++ this.sort(); ++ } ++ ScheduledTick nextTick; ++ int polledIndex = this.firstIndex++; ++ ScheduledTick[] ticks = this.arr; ++ nextTick = ticks[polledIndex]; ++ ticks[polledIndex] = null; ++ return nextTick; ++ } ++ ++ @Override ++ public ScheduledTick peek() { ++ if (!this.isSorted) { ++ return this.unsortedPeekResult; ++ } else if (this.lastIndexExclusive > this.firstIndex) { ++ return this.getTickAtIndex(this.firstIndex); ++ } ++ return null; ++ } ++ ++ public boolean offer(ScheduledTick tick) { ++ if (this.lastIndexExclusive >= this.arr.length) { ++ //todo remove consumed elements first ++ this.arr = copyArray(this.arr, HashCommon.nextPowerOfTwo(this.arr.length + 1)); ++ } ++ if (tick.subTickOrder() <= this.currentMaxSubTickOrder) { ++ //Set to unsorted instead of slowing down the insertion ++ //This is rare but may happen in bulk ++ //Sorting later needs O(n*log(n)) time, but it only needs to happen when unordered insertion needs to happen ++ //Therefore it is better than n times log(n) time of the PriorityQueue that happens on ordered insertion too ++ this.isSorted = false; ++ ScheduledTick firstTick = this.size() > 0 ? this.arr[this.firstIndex] : null; ++ this.unsortedPeekResult = firstTick == null || tick.subTickOrder() < firstTick.subTickOrder() ? tick : firstTick; ++ } else { ++ this.currentMaxSubTickOrder = tick.subTickOrder(); ++ } ++ this.arr[this.lastIndexExclusive++] = tick; ++ return true; ++ } ++ ++ public int size() { ++ return this.lastIndexExclusive - this.firstIndex; ++ } ++ ++ private void resize(int size) { ++ // Only compact the array if it is completely empty or is less than 50% filled ++ if (size == 0 || size < this.arr.length / 2) { ++ this.arr = copyArray(this.arr, size); ++ } else { ++ // Fill the unused array elements with nulls to release our references to the elements in it ++ for (int i = size; i < this.arr.length; i++) { ++ this.arr[i] = null; ++ } ++ } ++ ++ this.firstIndex = 0; ++ this.lastIndexExclusive = size; ++ ++ if (size == 0 || !this.isSorted) { ++ this.currentMaxSubTickOrder = Long.MIN_VALUE; ++ } else { ++ ScheduledTick tick = this.arr[size - 1]; ++ this.currentMaxSubTickOrder = tick == null ? Long.MIN_VALUE : tick.subTickOrder(); ++ } ++ } ++ ++ public void sort() { ++ if (this.isSorted) { ++ return; ++ } ++ this.removeNullsAndConsumed(); ++ Arrays.sort(this.arr, this.firstIndex, this.lastIndexExclusive, COMPARATOR); ++ this.isSorted = true; ++ this.unsortedPeekResult = null; ++ } ++ ++ public void removeNullsAndConsumed() { ++ int src = this.firstIndex; ++ int dst = 0; ++ while (src < this.lastIndexExclusive) { ++ ScheduledTick orderedTick = this.arr[src]; ++ if (orderedTick != null) { ++ this.arr[dst] = orderedTick; ++ dst++; ++ } ++ src++; ++ } ++ this.resize(dst); ++ } ++ ++ public ScheduledTick getTickAtIndex(int index) { ++ if (!this.isSorted) { ++ throw new IllegalStateException("Unexpected access on unsorted queue!"); ++ } ++ return this.arr[index]; ++ } ++ ++ public void setTickAtIndex(int index, ScheduledTick tick) { ++ if (!this.isSorted) { ++ throw new IllegalStateException("Unexpected access on unsorted queue!"); ++ } ++ this.arr[index] = tick; ++ } ++ ++ @SuppressWarnings("unchecked") ++ private static ScheduledTick[] copyArray(ScheduledTick[] src, int size) { ++ final ScheduledTick[] copy = new ScheduledTick[size]; ++ ++ if (size != 0) { ++ System.arraycopy(src, 0, copy, 0, Math.min(src.length, size)); ++ } ++ ++ return copy; ++ } ++ ++ @Override ++ public boolean isEmpty() { ++ return this.lastIndexExclusive <= this.firstIndex; ++ } ++} +diff --git a/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java b/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java +index 9f6c2e5b5d9e8d714a47c770e255d06c0ef7c190..826ced345c97bd2eb04749f42744a086fafc4ce8 100644 +--- a/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java ++++ b/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java +@@ -16,14 +16,37 @@ import javax.annotation.Nullable; + import net.minecraft.core.BlockPos; + import net.minecraft.nbt.ListTag; + import net.minecraft.world.level.ChunkPos; ++// Mirai start - lithium: world.tick_scheduler ++import it.unimi.dsi.fastutil.ints.IntOpenHashSet; ++import it.unimi.dsi.fastutil.longs.Long2ReferenceAVLTreeMap; ++import it.unimi.dsi.fastutil.objects.ObjectIterator; ++import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; ++import me.jellysquid.mods.lithium.common.world.scheduler.OrderedTickQueue; ++import net.minecraft.world.ticks.SavedTick; ++import net.minecraft.world.ticks.ScheduledTick; ++import net.minecraft.world.ticks.TickPriority; ++import java.util.Collection; ++// Mirai end + + public class LevelChunkTicks implements SerializableTickContainer, TickContainerAccess { +- private final Queue> tickQueue = new PriorityQueue<>(ScheduledTick.DRAIN_ORDER); ++ private Queue> tickQueue = new PriorityQueue<>(ScheduledTick.DRAIN_ORDER); // Mirai - remove final + @Nullable + private List> pendingTicks; +- private final Set> ticksPerPosition = new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH); ++ private Set> ticksPerPosition = new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH); // Mirai - remove final + @Nullable + private BiConsumer, ScheduledTick> onTickAdded; ++ // Mirai start - lithium: world.tick_scheduler ++ private static volatile Reference2IntOpenHashMap TYPE_2_INDEX; ++ ++ static { ++ TYPE_2_INDEX = new Reference2IntOpenHashMap<>(); ++ TYPE_2_INDEX.defaultReturnValue(-1); ++ } ++ ++ private final Long2ReferenceAVLTreeMap> tickQueuesByTimeAndPriority = new Long2ReferenceAVLTreeMap<>(); ++ private OrderedTickQueue nextTickQueue; ++ private final IntOpenHashSet allpendingTicks = new IntOpenHashSet(); ++ // Mirai end + + public LevelChunkTicks() { + } +@@ -35,34 +58,133 @@ public class LevelChunkTicks implements SerializableTickContainer, TickCon + this.ticksPerPosition.add(ScheduledTick.probe(savedTick.type(), savedTick.pos())); + } + ++ // Mirai start - lithium: world.tick_scheduler ++ //Remove replaced collections ++ if (this.pendingTicks != null) { ++ for (SavedTick orderedTick : this.pendingTicks) { ++ this.allpendingTicks.add(tickToInt(orderedTick.pos(), orderedTick.type())); ++ } ++ } ++ this.ticksPerPosition = null; ++ this.tickQueue = null; ++ // Mirai end ++ } ++ ++ // Mirai start - lithium: world.tick_scheduler ++ private static int tickToInt(BlockPos pos, Object type) { ++ //Y coordinate is 12 bits (BlockPos.toLong) ++ //X and Z coordinate is 4 bits each (This scheduler is for a single chunk) ++ //20 bits are in use for pos ++ //12 bits remaining for the type, so up to 4096 different tickable blocks/fluids (not block states) -> can upgrade to long if needed ++ int typeIndex = TYPE_2_INDEX.getInt(type); ++ if (typeIndex == -1) { ++ typeIndex = fixMissingType2Index(type); ++ } ++ ++ int ret = ((pos.getX() & 0xF) << 16) | ((pos.getY() & (0xfff)) << 4) | (pos.getZ() & 0xF); ++ ret |= typeIndex << 20; ++ return ret; + } + ++ //This method must be synchronized, otherwise type->int assignments can be overwritten and therefore change ++ //Uses clone and volatile store to ensure only fully initialized maps are used, all threads share the same mapping ++ private static synchronized int fixMissingType2Index(Object type) { ++ //check again, other thread might have replaced the collection ++ int typeIndex = TYPE_2_INDEX.getInt(type); ++ if (typeIndex == -1) { ++ Reference2IntOpenHashMap clonedType2Index = TYPE_2_INDEX.clone(); ++ clonedType2Index.put(type, typeIndex = clonedType2Index.size()); ++ TYPE_2_INDEX = clonedType2Index; ++ if (typeIndex >= 4096) { ++ throw new IllegalStateException("Lithium Tick Scheduler assumes at most 4096 different block types that receive scheduled pendingTicks exist! Open an issue on GitHub if you see this error!"); ++ } ++ } ++ return typeIndex; ++ } ++ // Mirai end ++ + public void setOnTickAdded(@Nullable BiConsumer, ScheduledTick> tickConsumer) { + this.onTickAdded = tickConsumer; + } + ++ // Mirai start - lithium: world.tick_scheduler ++ /** ++ * @author 2No2Name ++ * @reason use faster collections ++ */ + @Nullable + public ScheduledTick peek() { +- return this.tickQueue.peek(); ++ if (this.nextTickQueue == null) { ++ return null; ++ } ++ return this.nextTickQueue.peek(); + } + ++ /** ++ * @author 2No2Name ++ * @reason use faster collections ++ */ + @Nullable + public ScheduledTick poll() { +- ScheduledTick scheduledTick = this.tickQueue.poll(); +- if (scheduledTick != null) { +- this.ticksPerPosition.remove(scheduledTick); ++ ScheduledTick orderedTick = this.nextTickQueue.poll(); ++ if (orderedTick != null) { ++ if (this.nextTickQueue.isEmpty()) { ++ this.updateNextTickQueue(true); ++ } ++ this.allpendingTicks.remove(tickToInt(orderedTick.pos(), orderedTick.type())); ++ return orderedTick; + } +- +- return scheduledTick; ++ return null; + } + ++ /** ++ * @author 2No2Name ++ * @reason use faster collections ++ */ + @Override + public void schedule(ScheduledTick orderedTick) { +- if (this.ticksPerPosition.add(orderedTick)) { +- this.scheduleUnchecked(orderedTick); ++ int intTick = tickToInt(orderedTick.pos(), orderedTick.type()); ++ if (this.allpendingTicks.add(intTick)) { ++ this.queueTick(orderedTick); ++ } ++ } ++ ++ // Computes a timestamped key including the tick's priority ++ // Keys can be sorted in descending order to find what should be executed first ++ // 60 time bits, 4 priority bits ++ private static long getBucketKey(long time, TickPriority priority) { ++ //using priority.ordinal() as is not negative instead of priority.index ++ return (time << 4L) | (priority.ordinal() & 15); ++ } ++ ++ private void updateNextTickQueue(boolean elementRemoved) { ++ if (elementRemoved && this.nextTickQueue != null && this.nextTickQueue.isEmpty()) { ++ OrderedTickQueue removed = this.tickQueuesByTimeAndPriority.remove(this.tickQueuesByTimeAndPriority.firstLongKey()); ++ if (removed != this.nextTickQueue) { ++ throw new IllegalStateException("Next tick queue doesn't have the lowest key!"); ++ } ++ } ++ if (this.tickQueuesByTimeAndPriority.isEmpty()) { ++ this.nextTickQueue = null; ++ return; + } ++ long firstKey = this.tickQueuesByTimeAndPriority.firstLongKey(); ++ this.nextTickQueue = this.tickQueuesByTimeAndPriority.get(firstKey); ++ } ++ ++ private void queueTick(ScheduledTick orderedTick) { ++ OrderedTickQueue tickQueue = this.tickQueuesByTimeAndPriority.computeIfAbsent(getBucketKey(orderedTick.triggerTick(), orderedTick.priority()), key -> new OrderedTickQueue<>()); ++ if (tickQueue.isEmpty()) { ++ this.updateNextTickQueue(false); ++ } ++ tickQueue.offer(orderedTick); + ++ if (this.onTickAdded != null) { ++ //noinspection unchecked ++ this.onTickAdded.accept((LevelChunkTicks) (Object) this, orderedTick); ++ } + } ++ // Mirai end + + private void scheduleUnchecked(ScheduledTick orderedTick) { + this.tickQueue.add(orderedTick); +@@ -72,60 +194,93 @@ public class LevelChunkTicks implements SerializableTickContainer, TickCon + + } + ++ // Mirai start - lithium: world.tick_scheduler ++ /** ++ * @author 2No2Name ++ * @reason use faster collections ++ */ + @Override + public boolean hasScheduledTick(BlockPos pos, T type) { +- return this.ticksPerPosition.contains(ScheduledTick.probe(type, pos)); ++ return this.allpendingTicks.contains(tickToInt(pos, type)); + } + ++ /** ++ * @author 2No2Name ++ * @reason use faster collections ++ */ + public void removeIf(Predicate> predicate) { +- Iterator> iterator = this.tickQueue.iterator(); +- +- while(iterator.hasNext()) { +- ScheduledTick scheduledTick = iterator.next(); +- if (predicate.test(scheduledTick)) { +- iterator.remove(); +- this.ticksPerPosition.remove(scheduledTick); ++ for (ObjectIterator> tickQueueIterator = this.tickQueuesByTimeAndPriority.values().iterator(); tickQueueIterator.hasNext(); ) { ++ OrderedTickQueue nextTickQueue = tickQueueIterator.next(); ++ nextTickQueue.sort(); ++ boolean removed = false; ++ for (int i = 0; i < nextTickQueue.size(); i++) { ++ ScheduledTick nextTick = nextTickQueue.getTickAtIndex(i); ++ if (predicate.test(nextTick)) { ++ nextTickQueue.setTickAtIndex(i, null); ++ this.allpendingTicks.remove(tickToInt(nextTick.pos(), nextTick.type())); ++ removed = true; ++ } ++ } ++ if (removed) { ++ nextTickQueue.removeNullsAndConsumed(); ++ } ++ if (nextTickQueue.isEmpty()) { ++ tickQueueIterator.remove(); + } + } +- + } + ++ /** ++ * @author 2No2Name ++ * @reason use faster collections ++ */ + public Stream> getAll() { +- return this.tickQueue.stream(); ++ return this.tickQueuesByTimeAndPriority.values().stream().flatMap(Collection::stream); + } + ++ /** ++ * @author 2No2Name ++ * @reason not use unused field ++ */ + @Override + public int count() { +- return this.tickQueue.size() + (this.pendingTicks != null ? this.pendingTicks.size() : 0); ++ return this.allpendingTicks.size(); + } + ++ /** ++ * @author 2No2Name ++ * @reason not use unused field ++ */ + @Override + public ListTag save(long l, Function function) { +- ListTag listTag = new ListTag(); ++ ListTag nbtList = new ListTag(); + if (this.pendingTicks != null) { +- for(SavedTick savedTick : this.pendingTicks) { +- listTag.add(savedTick.save(function)); ++ for (SavedTick tick : this.pendingTicks) { ++ nbtList.add(tick.save(function)); + } + } +- +- for(ScheduledTick scheduledTick : this.tickQueue) { +- listTag.add(SavedTick.saveTick(scheduledTick, function, l)); ++ for (OrderedTickQueue nextTickQueue : this.tickQueuesByTimeAndPriority.values()) { ++ for (ScheduledTick orderedTick : nextTickQueue) { ++ nbtList.add(SavedTick.saveTick(orderedTick, function, l)); ++ } + } +- +- return listTag; ++ return nbtList; + } + ++ /** ++ * @author 2No2Name ++ * @reason use our datastructures ++ */ + public void unpack(long time) { + if (this.pendingTicks != null) { + int i = -this.pendingTicks.size(); +- +- for(SavedTick savedTick : this.pendingTicks) { +- this.scheduleUnchecked(savedTick.unpack(time, (long)(i++))); ++ for (SavedTick tick : this.pendingTicks) { ++ this.queueTick(tick.unpack(time, i++)); + } + } +- + this.pendingTicks = null; + } ++ // Mirai end + + public static LevelChunkTicks load(ListTag tickQueue, Function> nameToTypeFunction, ChunkPos pos) { + ImmutableList.Builder> builder = ImmutableList.builder(); diff --git a/patches/server/0088-Save-Json-list-asynchronously.patch b/patches/server/0091-Save-Json-list-asynchronously.patch similarity index 100% rename from patches/server/0088-Save-Json-list-asynchronously.patch rename to patches/server/0091-Save-Json-list-asynchronously.patch diff --git a/patches/server/0089-Swaps-the-predicate-order-of-collision.patch b/patches/server/0092-Swaps-the-predicate-order-of-collision.patch similarity index 93% rename from patches/server/0089-Swaps-the-predicate-order-of-collision.patch rename to patches/server/0092-Swaps-the-predicate-order-of-collision.patch index 6d2b75b..cdefd08 100644 --- a/patches/server/0089-Swaps-the-predicate-order-of-collision.patch +++ b/patches/server/0092-Swaps-the-predicate-order-of-collision.patch @@ -8,7 +8,7 @@ Original license: GPLv3 Original project: https://github.com/Akarin-project/Akarin diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 9bdcad2b05367a8dcb519a2db8c4efea94a4d21c..6184b54512e795877c7db9a88a0e3324b2858173 100644 +index ae428552912f5a484ecf581b24c0e362c3e2407f..a21f7de5331fc31a291fe177e6e1e843c7895cee 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -1983,8 +1983,9 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { diff --git a/patches/server/0090-Fix-head-rotation-packet-spam.patch b/patches/server/0093-Fix-head-rotation-packet-spam.patch similarity index 100% rename from patches/server/0090-Fix-head-rotation-packet-spam.patch rename to patches/server/0093-Fix-head-rotation-packet-spam.patch diff --git a/patches/server/0091-Cache-block-break-animation-packet.patch b/patches/server/0094-Cache-block-break-animation-packet.patch similarity index 94% rename from patches/server/0091-Cache-block-break-animation-packet.patch rename to patches/server/0094-Cache-block-break-animation-packet.patch index d647d51..fde499c 100644 --- a/patches/server/0091-Cache-block-break-animation-packet.patch +++ b/patches/server/0094-Cache-block-break-animation-packet.patch @@ -7,7 +7,7 @@ Original license: GPLv3 Original project: https://github.com/Electroid/SportPaper diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 789202faad1c9317984b14026bcd585bf7442b26..472d6a86b855cbf9cfab882e9c42b9e17943ddcc 100644 +index 447fa39cf935072178503c3079c74ffe984d01c4..ef932eaedf1dbf4d2a90cab270516b71923d5678 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -1540,6 +1540,7 @@ public class ServerLevel extends Level implements WorldGenLevel { diff --git a/patches/server/0092-Use-more-fastutil-data-structures.patch b/patches/server/0095-Use-more-fastutil-data-structures.patch similarity index 100% rename from patches/server/0092-Use-more-fastutil-data-structures.patch rename to patches/server/0095-Use-more-fastutil-data-structures.patch diff --git a/patches/server/0093-Optimize-Math.round-and-Math.hypot-functions.patch b/patches/server/0096-Optimize-Math.round-and-Math.hypot-functions.patch similarity index 99% rename from patches/server/0093-Optimize-Math.round-and-Math.hypot-functions.patch rename to patches/server/0096-Optimize-Math.round-and-Math.hypot-functions.patch index beef2f7..5107382 100644 --- a/patches/server/0093-Optimize-Math.round-and-Math.hypot-functions.patch +++ b/patches/server/0096-Optimize-Math.round-and-Math.hypot-functions.patch @@ -164,10 +164,10 @@ index e3e80db89c18588322ffdaa0f9fd85e398cb1471..d947011b80ee14e7aaf74af3d9081fc7 throw ERROR_INVALID_TICK_COUNT.create(j); } else { diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 5e8a2cd78380727969c771eafa745550f3c5f237..7e9a837a39553c1c1aaf9c24c9db325392fa434e 100644 +index 2a5bd17084238d8073d2f891f4c1af04d33fd09d..fe8b2de61fdce195210f270e33f508376b60f793 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2790,7 +2790,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop packet) { @@ -92,7 +92,7 @@ index 18c4f2eeb6bb427c1314608fc6a81e4642d92888..b029ae19db2bfde9b08950f41ba8a09e } diff --git a/src/main/java/wtf/etil/mirai/MiraiConfig.java b/src/main/java/wtf/etil/mirai/MiraiConfig.java -index 38c01de9c2edd1b81802bdece037abb38aa3f746..3f879769032d8e01bfae51a604de2daf65e58014 100644 +index f6f88a802c6f1892418fd6bcb8b4bc0b90fb6afb..13884ca2bd4e459498700e2fed1f0b4406538f53 100644 --- a/src/main/java/wtf/etil/mirai/MiraiConfig.java +++ b/src/main/java/wtf/etil/mirai/MiraiConfig.java @@ -244,4 +244,12 @@ public class MiraiConfig { diff --git a/patches/server/0099-PaperPR-Fix-exact-choice-recipe-book-clicks.patch b/patches/server/0102-PaperPR-Fix-exact-choice-recipe-book-clicks.patch similarity index 100% rename from patches/server/0099-PaperPR-Fix-exact-choice-recipe-book-clicks.patch rename to patches/server/0102-PaperPR-Fix-exact-choice-recipe-book-clicks.patch diff --git a/patches/server/0100-Fix-MC-238526.patch b/patches/server/0103-Fix-MC-238526.patch similarity index 100% rename from patches/server/0100-Fix-MC-238526.patch rename to patches/server/0103-Fix-MC-238526.patch diff --git a/patches/server/0101-Lobotomize-stuck-villagers.patch b/patches/server/0104-Lobotomize-stuck-villagers.patch similarity index 98% rename from patches/server/0101-Lobotomize-stuck-villagers.patch rename to patches/server/0104-Lobotomize-stuck-villagers.patch index 121fc7e..ef58ed0 100644 --- a/patches/server/0101-Lobotomize-stuck-villagers.patch +++ b/patches/server/0104-Lobotomize-stuck-villagers.patch @@ -112,7 +112,7 @@ index f0b910df1ee471b4d72d97c6197ab14f2854976e..6ce32a52d621a0c2629568ea07e445f5 + // Purpur end } diff --git a/src/main/java/wtf/etil/mirai/MiraiConfig.java b/src/main/java/wtf/etil/mirai/MiraiConfig.java -index 3f879769032d8e01bfae51a604de2daf65e58014..d45447551a6850e40ae37e9f88c9ba9aa1d3982e 100644 +index 13884ca2bd4e459498700e2fed1f0b4406538f53..b53da92ee9e96d76eada5ce7ed538378b88510c5 100644 --- a/src/main/java/wtf/etil/mirai/MiraiConfig.java +++ b/src/main/java/wtf/etil/mirai/MiraiConfig.java @@ -252,4 +252,11 @@ public class MiraiConfig { diff --git a/patches/server/0102-Fix-a-bunch-of-vanilla-bugs.patch b/patches/server/0105-Fix-a-bunch-of-vanilla-bugs.patch similarity index 100% rename from patches/server/0102-Fix-a-bunch-of-vanilla-bugs.patch rename to patches/server/0105-Fix-a-bunch-of-vanilla-bugs.patch diff --git a/patches/server/0103-Fix-legacy-colors-in-console.patch b/patches/server/0106-Fix-legacy-colors-in-console.patch similarity index 100% rename from patches/server/0103-Fix-legacy-colors-in-console.patch rename to patches/server/0106-Fix-legacy-colors-in-console.patch diff --git a/patches/server/0104-PaperPR-Set-position-before-player-sending-on-dimens.patch b/patches/server/0107-PaperPR-Set-position-before-player-sending-on-dimens.patch similarity index 100% rename from patches/server/0104-PaperPR-Set-position-before-player-sending-on-dimens.patch rename to patches/server/0107-PaperPR-Set-position-before-player-sending-on-dimens.patch diff --git a/patches/server/0105-Set-BlockData-without-light-updates.patch b/patches/server/0108-Set-BlockData-without-light-updates.patch similarity index 100% rename from patches/server/0105-Set-BlockData-without-light-updates.patch rename to patches/server/0108-Set-BlockData-without-light-updates.patch diff --git a/patches/server/0106-Set-multiple-Team-settings-at-once.patch b/patches/server/0109-Set-multiple-Team-settings-at-once.patch similarity index 100% rename from patches/server/0106-Set-multiple-Team-settings-at-once.patch rename to patches/server/0109-Set-multiple-Team-settings-at-once.patch diff --git a/patches/server/0107-Smooth-Teleports.patch b/patches/server/0110-Smooth-Teleports.patch similarity index 100% rename from patches/server/0107-Smooth-Teleports.patch rename to patches/server/0110-Smooth-Teleports.patch diff --git a/patches/server/0108-Unfreeze-MappedRegistry.patch b/patches/server/0111-Unfreeze-MappedRegistry.patch similarity index 100% rename from patches/server/0108-Unfreeze-MappedRegistry.patch rename to patches/server/0111-Unfreeze-MappedRegistry.patch