+Date: Fri, 21 Jan 2022 10:19:06 -0500
+Subject: [PATCH] lithium: shapes.blockstate_cache
+
+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/util/collections/Object2BooleanCacheTable.java b/src/main/java/me/jellysquid/mods/lithium/common/util/collections/Object2BooleanCacheTable.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..a833ec84b2053c805dd33821cc08939c1cb79e96
+--- /dev/null
++++ b/src/main/java/me/jellysquid/mods/lithium/common/util/collections/Object2BooleanCacheTable.java
+@@ -0,0 +1,59 @@
++package me.jellysquid.mods.lithium.common.util.collections;
++
++import it.unimi.dsi.fastutil.HashCommon;
++import java.util.function.Predicate;
++import net.minecraft.util.Mth;
++
++/**
++ * A lossy hashtable implementation that stores a mapping between an object and a boolean.
++ *
++ * Any hash collisions will result in an overwrite: this is safe because the correct value can always be recomputed,
++ * given that the given operator is deterministic.
++ *
++ * This implementation is safe to use from multiple threads
++ */
++public final class Object2BooleanCacheTable {
++ private final int mask;
++
++ private final Node[] nodes;
++
++ private final Predicate operator;
++
++ @SuppressWarnings("unchecked")
++ public Object2BooleanCacheTable(int capacity, Predicate operator) {
++ int capacity1 = Mth.smallestEncompassingPowerOfTwo(capacity);
++ this.mask = capacity1 - 1;
++
++ this.nodes = (Node[]) new Node[capacity1];
++
++ this.operator = operator;
++ }
++
++ private static int hash(T key) {
++ return HashCommon.mix(key.hashCode());
++ }
++
++ public boolean get(T key) {
++ int idx = hash(key) & this.mask;
++
++ Node node = this.nodes[idx];
++ if (node != null && key.equals(node.key)) {
++ return node.value;
++ }
++
++ boolean test = this.operator.test(key);
++ this.nodes[idx] = new Node<>(key, test);
++
++ return test;
++ }
++
++ static class Node {
++ final T key;
++ final boolean value;
++
++ Node(T key, boolean value) {
++ this.key = key;
++ this.value = value;
++ }
++ }
++}
+\ No newline at end of file
+diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java
+index dfe1e522a747b894d43124b97eaceb0ab196ac44..1834470b549d8352317cf081173ff542c9faac1e 100644
+--- a/src/main/java/net/minecraft/world/level/block/Block.java
++++ b/src/main/java/net/minecraft/world/level/block/Block.java
+@@ -64,17 +64,19 @@ import net.minecraft.world.phys.shapes.BooleanOp;
+ import net.minecraft.world.phys.shapes.Shapes;
+ import net.minecraft.world.phys.shapes.VoxelShape;
+ import org.slf4j.Logger;
++import me.jellysquid.mods.lithium.common.util.collections.Object2BooleanCacheTable; // JettPack
+
+ public class Block extends BlockBehaviour implements ItemLike {
+
+ private static final Logger LOGGER = LogUtils.getLogger();
+ private final Holder.Reference builtInRegistryHolder;
+ public static final IdMapper BLOCK_STATE_REGISTRY = new IdMapper<>();
+- private static final LoadingCache SHAPE_FULL_BLOCK_CACHE = CacheBuilder.newBuilder().maximumSize(512L).weakKeys().build(new CacheLoader() {
+- public Boolean load(VoxelShape voxelshape) {
+- return !Shapes.joinIsNotEmpty(Shapes.block(), voxelshape, BooleanOp.NOT_SAME);
+- }
+- });
++ // JettPack start - lithium: shapes.blockstate_cache
++ private static final Object2BooleanCacheTable FULL_CUBE_CACHE = new Object2BooleanCacheTable<>(
++ 512,
++ shape -> !Shapes.joinIsNotEmpty(Shapes.block(), shape, BooleanOp.NOT_SAME)
++ );
++ // JettPack end
+ public static final int UPDATE_NEIGHBORS = 1;
+ public static final int UPDATE_CLIENTS = 2;
+ public static final int UPDATE_INVISIBLE = 4;
+@@ -281,7 +283,7 @@ public class Block extends BlockBehaviour implements ItemLike {
+ }
+
+ public static boolean isShapeFullBlock(VoxelShape shape) {
+- return (Boolean) Block.SHAPE_FULL_BLOCK_CACHE.getUnchecked(shape);
++ return FULL_CUBE_CACHE.get(shape); // JettPack - lithium: shapes.blockstate_cache
+ }
+
+ public boolean propagatesSkylightDown(BlockState state, BlockGetter world, BlockPos pos) {
diff --git a/DivineMC/patches/server/0011-lithium-ai.raid.patch b/DivineMC/patches/server/0011-lithium-ai.raid.patch
new file mode 100644
index 0000000..fb88c6e
--- /dev/null
+++ b/DivineMC/patches/server/0011-lithium-ai.raid.patch
@@ -0,0 +1,79 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: jellysquid3
+Date: Tue, 18 Jan 2022 10:37:18 -0500
+Subject: [PATCH] lithium: ai.raid
+
+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/net/minecraft/world/entity/raid/Raid.java b/src/main/java/net/minecraft/world/entity/raid/Raid.java
+index 6a0a1731fd6804eb69d3641213712d31bce085b2..5f4bb589474ce7d4f214e32ab0bc4b9cb71638d0 100644
+--- a/src/main/java/net/minecraft/world/entity/raid/Raid.java
++++ b/src/main/java/net/minecraft/world/entity/raid/Raid.java
+@@ -269,7 +269,16 @@ public class Raid {
+ this.status = Raid.RaidStatus.STOPPED;
+ }
+
++ private boolean isBarDirty; // JettPack
+ public void tick() {
++ // JettPack start - lithium: ai.raid
++ if (this.isBarDirty) {
++ this.raidEvent.setProgress(Mth.clamp(this.getHealthOfLivingRaiders() / this.totalHealth, 0.0F, 1.0F));
++
++ this.isBarDirty = false;
++ }
++ // JettPack end
++
+ if (!this.isStopped()) {
+ if (this.status == Raid.RaidStatus.ONGOING) {
+ boolean flag = this.active;
+@@ -626,7 +635,7 @@ public class Raid {
+ }
+
+ public void updateBossbar() {
+- this.raidEvent.setProgress(Mth.clamp(this.getHealthOfLivingRaiders() / this.totalHealth, 0.0F, 1.0F));
++ this.isBarDirty = true; // JettPack - lithium: ai.raid
+ }
+
+ public float getHealthOfLivingRaiders() {
+diff --git a/src/main/java/net/minecraft/world/entity/raid/Raider.java b/src/main/java/net/minecraft/world/entity/raid/Raider.java
+index 8877423a99e387c18d1d994518bf15d8d9ba64af..a65e82c8e2975244d725ff2f4931df183f25b63f 100644
+--- a/src/main/java/net/minecraft/world/entity/raid/Raider.java
++++ b/src/main/java/net/minecraft/world/entity/raid/Raider.java
+@@ -46,8 +46,9 @@ import net.minecraft.world.phys.Vec3;
+ public abstract class Raider extends PatrollingMonster {
+
+ protected static final EntityDataAccessor IS_CELEBRATING = SynchedEntityData.defineId(Raider.class, EntityDataSerializers.BOOLEAN);
++ public static final ItemStack CACHED_OMINOUS_BANNER = Raid.getLeaderBannerInstance(); // JettPack - lithium: ai.raid
+ static final Predicate ALLOWED_ITEMS = (entityitem) -> {
+- return !entityitem.hasPickUpDelay() && entityitem.isAlive() && ItemStack.matches(entityitem.getItem(), Raid.getLeaderBannerInstance());
++ return !entityitem.hasPickUpDelay() && entityitem.isAlive() && ItemStack.matches(entityitem.getItem(), CACHED_OMINOUS_BANNER); // JettPack - lithium: ai.raid
+ };
+ @Nullable
+ protected Raid raid;
+@@ -149,7 +150,7 @@ public abstract class Raider extends PatrollingMonster {
+ }
+ }
+
+- if (!itemstack.isEmpty() && ItemStack.matches(itemstack, Raid.getLeaderBannerInstance()) && entityhuman != null) {
++ if (!itemstack.isEmpty() && ItemStack.matches(itemstack, CACHED_OMINOUS_BANNER) && entityhuman != null) { // JettPack - lithium: ai.raid
+ MobEffectInstance mobeffect = entityhuman.getEffect(MobEffects.BAD_OMEN);
+ byte b0 = 1;
+ int i;
+@@ -309,6 +310,7 @@ public abstract class Raider extends PatrollingMonster {
+ public class ObtainRaidLeaderBannerGoal extends Goal {
+
+ private final T mob;
++ private static final ItemStack CACHED_OMINOUS_BANNER = Raid.getLeaderBannerInstance(); // JettPack
+
+ public ObtainRaidLeaderBannerGoal(T entityraider) { // CraftBukkit - decompile error
+ this.mob = entityraider;
+@@ -320,7 +322,7 @@ public abstract class Raider extends PatrollingMonster {
+ if (!this.mob.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) || !this.mob.canPickUpLoot()) return false; // Paper - respect game and entity rules for picking up items
+ Raid raid = this.mob.getCurrentRaid();
+
+- if (this.mob.hasActiveRaid() && !this.mob.getCurrentRaid().isOver() && this.mob.canBeLeader() && !ItemStack.matches(this.mob.getItemBySlot(EquipmentSlot.HEAD), Raid.getLeaderBannerInstance())) {
++ if (this.mob.hasActiveRaid() && !this.mob.getCurrentRaid().isOver() && this.mob.canBeLeader() && !ItemStack.matches(this.mob.getItemBySlot(EquipmentSlot.HEAD), CACHED_OMINOUS_BANNER)) { // JettPack - lithium: ai.raid
+ Raider entityraider = raid.getLeader(this.mob.getWave());
+
+ if (entityraider == null || !entityraider.isAlive()) {
diff --git a/DivineMC/patches/server/0012-Stop-wasting-resources-on-JsonList-get.patch b/DivineMC/patches/server/0012-Stop-wasting-resources-on-JsonList-get.patch
new file mode 100644
index 0000000..6d96bd1
--- /dev/null
+++ b/DivineMC/patches/server/0012-Stop-wasting-resources-on-JsonList-get.patch
@@ -0,0 +1,82 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Ivan Pekov
+Date: Fri, 4 Sep 2020 10:07:42 +0300
+Subject: [PATCH] Stop wasting resources on JsonList#get
+
+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/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
+index 3fc95b7d7b41e078e1d219e29ada27aeab1320bf..faaf13f46bc7bf0ffc1fe61f45e9f11cb9c8b4d5 100644
+--- a/src/main/java/net/minecraft/server/players/PlayerList.java
++++ b/src/main/java/net/minecraft/server/players/PlayerList.java
+@@ -758,13 +758,19 @@ public abstract class PlayerList {
+ if (getBans().isBanned(gameprofile) && (gameprofilebanentry = getBans().get(gameprofile)) != null) {
+ // Paper end
+
+- ichatmutablecomponent = Component.translatable("multiplayer.disconnect.banned.reason", gameprofilebanentry.getReason());
+- if (gameprofilebanentry.getExpires() != null) {
+- ichatmutablecomponent.append((Component) Component.translatable("multiplayer.disconnect.banned.expiration", PlayerList.BAN_DATE_FORMAT.format(gameprofilebanentry.getExpires())));
+- }
++ // Yatopia start - Stop wasting resources on JsonList#get
++ if (!gameprofilebanentry.hasExpired()) {
++ ichatmutablecomponent = Component.translatable("multiplayer.disconnect.banned.reason", gameprofilebanentry.getReason());
++ if (gameprofilebanentry.getExpires() != null) {
++ ichatmutablecomponent.append((Component) Component.translatable("multiplayer.disconnect.banned.expiration", PlayerList.BAN_DATE_FORMAT.format(gameprofilebanentry.getExpires())));
++ }
+
+- // return chatmessage;
+- event.disallow(PlayerLoginEvent.Result.KICK_BANNED, PaperAdventure.asAdventure(ichatmutablecomponent)); // Paper - Adventure
++ // return chatmessage;
++ event.disallow(PlayerLoginEvent.Result.KICK_BANNED, PaperAdventure.asAdventure(ichatmutablecomponent)); // Paper - Adventure
++ } else {
++ getBans().remove(gameprofile);
++ }
++ // Yatopia end
+ } else if (!this.isWhiteListed(gameprofile, event)) { // Paper
+ //ichatmutablecomponent = Component.translatable("multiplayer.disconnect.not_whitelisted"); // Paper
+ //event.disallow(PlayerLoginEvent.Result.KICK_WHITELIST, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(org.spigotmc.SpigotConfig.whitelistMessage)); // Spigot // Paper - Adventure - moved to isWhitelisted
+diff --git a/src/main/java/net/minecraft/server/players/StoredUserList.java b/src/main/java/net/minecraft/server/players/StoredUserList.java
+index 63c0fe30ff035b6b5c1b4b35d3ad6c649d94e421..109e08e098a6c1ca1ba3dc2a9a293eaf9d5d7cb7 100644
+--- a/src/main/java/net/minecraft/server/players/StoredUserList.java
++++ b/src/main/java/net/minecraft/server/players/StoredUserList.java
+@@ -73,9 +73,12 @@ public abstract class StoredUserList> {
+ // Paper start
+ // this.g();
+ // return (V) this.d.get(this.a(k0)); // CraftBukkit - fix decompile error
+- return (V) this.map.computeIfPresent(this.getKeyForUser(key), (k, v) -> {
++ // Yatopia start - Stop wasting resources on JsonList#get
++ return this.map.get(this.getKeyForUser(key));
++ /*return (V) this.map.computeIfPresent(this.getKeyForUser(key), (k, v) -> {
+ return v.hasExpired() ? null : v;
+- });
++ });*/
++ // Yatopia end
+ // Paper end
+ }
+
+@@ -150,7 +153,8 @@ public abstract class StoredUserList> {
+ public void save() throws IOException {
+ this.removeExpired(); // Paper - remove expired values before saving
+ JsonArray jsonarray = new JsonArray();
+- Stream stream = this.map.values().stream().map((jsonlistentry) -> { // CraftBukkit - decompile error
++ // Yatopia start - Stop wasting resources on JsonList#get
++ /*Stream stream = this.map.values().stream().map((jsonlistentry) -> { // CraftBukkit - decompile error
+ JsonObject jsonobject = new JsonObject();
+
+ Objects.requireNonNull(jsonlistentry);
+@@ -158,7 +162,13 @@ public abstract class StoredUserList> {
+ });
+
+ Objects.requireNonNull(jsonarray);
+- stream.forEach(jsonarray::add);
++ stream.forEach(jsonarray::add);*/
++ for (V value : this.map.values()) {
++ JsonObject obj = new JsonObject();
++ value.serialize(obj);
++ jsonarray.add(obj);
++ }
++ // Yatopia end
+ BufferedWriter bufferedwriter = Files.newWriter(this.file, StandardCharsets.UTF_8);
+
+ try {
diff --git a/DivineMC/patches/server/0013-Fix-outdated-server-showing-in-ping-before-server-fu.patch b/DivineMC/patches/server/0013-Fix-outdated-server-showing-in-ping-before-server-fu.patch
new file mode 100644
index 0000000..2a52723
--- /dev/null
+++ b/DivineMC/patches/server/0013-Fix-outdated-server-showing-in-ping-before-server-fu.patch
@@ -0,0 +1,21 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: William Blake Galbreath
+Date: Tue, 4 Jun 2019 15:50:08 -0500
+Subject: [PATCH] Fix 'outdated server' showing in ping before server fully
+ boots
+
+Original code by PurpurMC, licensed under MIT
+You can find the original code on https://github.com/PurpurMC/Purpur
+
+diff --git a/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
+index 29a22da1b94d51300481c071aa16bfd8cd02178f..f67cbb1badc007987e62872bb0160ad6d05e3d97 100644
+--- a/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
++++ b/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
+@@ -153,6 +153,7 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListene
+ this.connection.send(new ClientboundStatusResponsePacket(ping));
+ // CraftBukkit end
+ */
++ if (this.server.getStatus().getVersion() == null) return; // Purpur - do not respond to pings before we know the protocol version
+ com.destroystokyo.paper.network.StandardPaperServerListPingEventImpl.processRequest(this.server, this.connection);
+ // Paper end
+ }
diff --git a/DivineMC/patches/server/0014-Remove-TickTask.patch b/DivineMC/patches/server/0014-Remove-TickTask.patch
new file mode 100644
index 0000000..1128a2e
--- /dev/null
+++ b/DivineMC/patches/server/0014-Remove-TickTask.patch
@@ -0,0 +1,97 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: foss-mc <69294560+foss-mc@users.noreply.github.com>
+Date: Thu, 1 Jul 2021 11:59:11 +0000
+Subject: [PATCH] Remove TickTask
+
+Original code by PatinaMC, licensed under GNU General Public License v3.0
+You can find the original code on https://github.com/PatinaMC/Patina
+
+diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
+index 3378298b0c465c0df9618804c390930e875bcce3..904ce75db06d3a50025bf758279e84346912ef6c 100644
+--- a/src/main/java/net/minecraft/server/MinecraftServer.java
++++ b/src/main/java/net/minecraft/server/MinecraftServer.java
+@@ -182,7 +182,7 @@ import org.bukkit.event.server.ServerLoadEvent;
+
+ import co.aikar.timings.MinecraftTimings; // Paper
+
+-public abstract class MinecraftServer extends ReentrantBlockableEventLoop implements CommandSource, AutoCloseable {
++public abstract class MinecraftServer extends ReentrantBlockableEventLoop implements CommandSource, AutoCloseable { // Patina
+
+ private static MinecraftServer SERVER; // Paper
+ public static final Logger LOGGER = LogUtils.getLogger();
+@@ -1297,19 +1297,21 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop {};
+ }
+ // Paper end
+- return new TickTask(this.tickCount, runnable);
++ return runnable; // Patina
+ }
+
++ /* // Patina
+ protected boolean shouldRun(TickTask ticktask) {
+ return ticktask.getTick() + 3 < this.tickCount || this.haveTime();
+ }
++ */
+
+ @Override
+ public boolean pollTask() {
+@@ -1341,10 +1343,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop optional = Optional.of(this.getFile("server-icon.png")).filter(File::isFile);
+diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+index 7266e6703d5cd0fea90ec88c74a7d4567f2420ae..16ee24bef4eb2184d821565665f3c1ddf0f3bb39 100644
+--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
++++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+@@ -1007,10 +1007,12 @@ public class ServerChunkCache extends ChunkSource {
+ return runnable;
+ }
+
++ /* // Patina
+ @Override
+ protected boolean shouldRun(Runnable task) {
+ return true;
+ }
++ */
+
+ @Override
+ protected boolean scheduleExecutables() {
+diff --git a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
+index 7a4ade1a4190bf4fbb048919ae2be230f7b80fff..8bf10c68c233a445902a143eaeb5252247c74a75 100644
+--- a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
++++ b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java
+@@ -29,7 +29,7 @@ public abstract class BlockableEventLoop implements Profiler
+
+ protected abstract R wrapRunnable(Runnable runnable);
+
+- protected abstract boolean shouldRun(R task);
++ //protected abstract boolean shouldRun(R task); // Patina
+
+ public boolean isSameThread() {
+ return Thread.currentThread() == this.getRunningThread();
+@@ -120,7 +120,7 @@ public abstract class BlockableEventLoop implements Profiler
+ R runnable = this.pendingRunnables.peek();
+ if (runnable == null) {
+ return false;
+- } else if (this.blockingCount == 0 && !this.shouldRun(runnable)) {
++ } else if (this.blockingCount == 0 && !true/*this.shouldRun(runnable)*/) { // Patina
+ return false;
+ } else {
+ this.doRunTask(this.pendingRunnables.remove());
diff --git a/DivineMC/patches/server/0015-Make-a-field-final.patch b/DivineMC/patches/server/0015-Make-a-field-final.patch
new file mode 100644
index 0000000..04cfb33
--- /dev/null
+++ b/DivineMC/patches/server/0015-Make-a-field-final.patch
@@ -0,0 +1,21 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: foss-mc <69294560+foss-mc@users.noreply.github.com>
+Date: Thu, 1 Jul 2021 12:11:49 +0000
+Subject: [PATCH] Make a field final
+
+Original code by PatinaMC, licensed under GNU General Public License v3.0
+You can find the original code on https://github.com/PatinaMC/Patina
+
+diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java
+index e0dd0fc1638377f4d4226d4b2976b901d635dff0..e75a428ff261a52b8d5f72d5c46437feef5b8ac4 100644
+--- a/src/main/java/net/minecraft/commands/CommandSourceStack.java
++++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java
+@@ -59,7 +59,7 @@ public class CommandSourceStack implements SharedSuggestionProvider, com.destroy
+ private final Vec2 rotation;
+ private final CommandSigningContext signingContext;
+ private final TaskChainer chatMessageChainer;
+- public java.util.Map currentCommand = new java.util.concurrent.ConcurrentHashMap<>(); // CraftBukkit // Paper
++ public final java.util.Map currentCommand = new java.util.concurrent.ConcurrentHashMap<>(); // CraftBukkit // Paper // Patina - make a field final
+
+ public CommandSourceStack(CommandSource output, Vec3 pos, Vec2 rot, ServerLevel world, int level, String name, Component displayName, MinecraftServer server, @Nullable Entity entity) {
+ this(output, pos, rot, world, level, name, displayName, server, entity, false, (commandcontext, flag, j) -> {
diff --git a/DivineMC/patches/server/0016-Don-t-create-new-random-instance.patch b/DivineMC/patches/server/0016-Don-t-create-new-random-instance.patch
new file mode 100644
index 0000000..2ced06c
--- /dev/null
+++ b/DivineMC/patches/server/0016-Don-t-create-new-random-instance.patch
@@ -0,0 +1,43 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: foss-mc <69294560+foss-mc@users.noreply.github.com>
+Date: Thu, 1 Jul 2021 12:17:44 +0000
+Subject: [PATCH] Don't create new random instance
+
+Original code by PatinaMC, licensed under GNU General Public License v3.0
+You can find the original code on https://github.com/PatinaMC/Patina
+
+diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
+index e5af7ef4ada68922a70f593ccec555ecb50627a9..eb634c540842a06bfea196bc9fe4bfbd73012bf1 100644
+--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
+@@ -380,7 +380,7 @@ public class ServerPlayer extends Player {
+ long l = k * k;
+ int i1 = l > 2147483647L ? Integer.MAX_VALUE : (int) l;
+ int j1 = this.getCoprime(i1);
+- int k1 = RandomSource.create().nextInt(i1);
++ int k1 = worldserver.random.nextInt(i1); // Patina - don't create new random instance
+
+ for (int l1 = 0; l1 < i1; ++l1) {
+ int i2 = (k1 + j1 * l1) % i1;
+@@ -417,7 +417,7 @@ public class ServerPlayer extends Player {
+ long l = k * k;
+ int i1 = l > 2147483647L ? Integer.MAX_VALUE : (int) l;
+ int j1 = this.getCoprime(i1);
+- int k1 = RandomSource.create().nextInt(i1);
++ int k1 = world.random.nextInt(i1); // Patina - don't create new random instance
+
+ for (int l1 = 0; l1 < i1; ++l1) {
+ int i2 = (k1 + j1 * l1) % i1;
+diff --git a/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java b/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java
+index 1ef089dbf83de35d875c00efdf468c397be56978..c345f10cbf7f3451edc604f97cdf959d70639e17 100644
+--- a/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java
++++ b/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java
+@@ -349,7 +349,7 @@ public class QueryThreadGs4 extends GenericThread {
+ this.identBytes[2] = bs[5];
+ this.identBytes[3] = bs[6];
+ this.ident = new String(this.identBytes, StandardCharsets.UTF_8);
+- this.challenge = RandomSource.create().nextInt(16777216);
++ this.challenge = java.util.concurrent.ThreadLocalRandom.current().nextInt(16777216); // Patina - don't create new random instance
+ this.challengeBytes = String.format(Locale.ROOT, "\t%s%d\u0000", this.ident, this.challenge).getBytes(StandardCharsets.UTF_8);
+ }
+
diff --git a/DivineMC/patches/server/0017-Completely-remove-bootstrapExecutor.patch b/DivineMC/patches/server/0017-Completely-remove-bootstrapExecutor.patch
new file mode 100644
index 0000000..95fd7a9
--- /dev/null
+++ b/DivineMC/patches/server/0017-Completely-remove-bootstrapExecutor.patch
@@ -0,0 +1,30 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: foss-mc <69294560+foss-mc@users.noreply.github.com>
+Date: Thu, 1 Jul 2021 12:26:15 +0000
+Subject: [PATCH] Completely remove bootstrapExecutor
+
+Original code by PatinaMC, licensed under GNU General Public License v3.0
+You can find the original code on https://github.com/PatinaMC/Patina
+
+diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
+index cdb7aea969b56f59d88f60bc3744e4932228c50a..59ecf5ff33617a6b9d2a3ae317315484235da804 100644
+--- a/src/main/java/net/minecraft/Util.java
++++ b/src/main/java/net/minecraft/Util.java
+@@ -79,7 +79,7 @@ public class Util {
+ private static final int DEFAULT_MAX_THREADS = 255;
+ private static final String MAX_THREADS_SYSTEM_PROPERTY = "max.bg.threads";
+ private static final AtomicInteger WORKER_COUNT = new AtomicInteger(1);
+- private static final ExecutorService BOOTSTRAP_EXECUTOR = makeExecutor("Bootstrap", -2); // Paper - add -2 priority
++ //private static final ExecutorService BOOTSTRAP_EXECUTOR = makeExecutor("Bootstrap", -2); // Paper - add -2 priority // Patina
+ private static final ExecutorService BACKGROUND_EXECUTOR = makeExecutor("Main", -1); // Paper - add -1 priority
+ // Paper start - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread
+ public static final ExecutorService PROFILE_EXECUTOR = Executors.newFixedThreadPool(2, new java.util.concurrent.ThreadFactory() {
+@@ -207,7 +207,7 @@ public class Util {
+ }
+
+ public static ExecutorService bootstrapExecutor() {
+- return BOOTSTRAP_EXECUTOR;
++ return BACKGROUND_EXECUTOR; // Patina
+ }
+
+ public static ExecutorService backgroundExecutor() {
diff --git a/DivineMC/patches/server/0018-Fix-rotating-UP-DOWN-CW-and-CCW.patch b/DivineMC/patches/server/0018-Fix-rotating-UP-DOWN-CW-and-CCW.patch
new file mode 100644
index 0000000..27fc4c6
--- /dev/null
+++ b/DivineMC/patches/server/0018-Fix-rotating-UP-DOWN-CW-and-CCW.patch
@@ -0,0 +1,38 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: William Blake Galbreath
+Date: Wed, 6 Jan 2021 02:19:29 -0600
+Subject: [PATCH] Fix rotating UP/DOWN CW and CCW
+
+Original code by PurpurMC, licensed under MIT
+You can find the original code on https://github.com/PurpurMC/Purpur
+
+diff --git a/src/main/java/net/minecraft/core/Direction.java b/src/main/java/net/minecraft/core/Direction.java
+index ee725b972d3d5fb22538aaff9c72e47c6bad0cea..2217968eb5ecac0a2063cf1eae7d754d760e9f28 100644
+--- a/src/main/java/net/minecraft/core/Direction.java
++++ b/src/main/java/net/minecraft/core/Direction.java
+@@ -252,6 +252,12 @@ public enum Direction implements StringRepresentable {
+ case EAST:
+ var10000 = SOUTH;
+ break;
++ // Purpur start
++ case UP:
++ return UP;
++ case DOWN:
++ return DOWN;
++ // Purpur end
+ default:
+ throw new IllegalStateException("Unable to get Y-rotated facing of " + this);
+ }
+@@ -364,6 +370,12 @@ public enum Direction implements StringRepresentable {
+ case EAST:
+ var10000 = NORTH;
+ break;
++ // Purpur start
++ case UP:
++ return UP;
++ case DOWN:
++ return DOWN;
++ // Purpur end
+ default:
+ throw new IllegalStateException("Unable to get CCW facing of " + this);
+ }
diff --git a/DivineMC/patches/server/0019-Fix-vanilla-command-permission-handler.patch b/DivineMC/patches/server/0019-Fix-vanilla-command-permission-handler.patch
new file mode 100644
index 0000000..9352e63
--- /dev/null
+++ b/DivineMC/patches/server/0019-Fix-vanilla-command-permission-handler.patch
@@ -0,0 +1,32 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: William Blake Galbreath
+Date: Sat, 28 Mar 2020 01:51:32 -0500
+Subject: [PATCH] Fix vanilla command permission handler
+
+Original code by PurpurMC, licensed under MIT
+You can find the original code on https://github.com/PurpurMC/Purpur
+
+diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java
+index 39844531b03eb8a6c70700b4ecbf0ff1a557424d..632ae75cb3bbc7a3955872d14ad0fbc2459f32e8 100644
+--- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java
++++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java
+@@ -35,6 +35,7 @@ public abstract class CommandNode implements Comparable> {
+ private final boolean forks;
+ private Command command;
+ public LiteralCommandNode clientNode = null; // Paper
++ private String permission = null; public String getPermission() { return permission; } public void setPermission(String permission) { this.permission = permission; } // Purpur
+ // CraftBukkit start
+ public void removeCommand(String name) {
+ this.children.remove(name);
+diff --git a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
+index 6035af2cf08353b3d3801220d8116d8611a0cd37..7774ab6a2e553a40def4bb4dceea9e5f58d31c1e 100644
+--- a/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
++++ b/src/main/java/org/bukkit/craftbukkit/command/VanillaCommandWrapper.java
+@@ -94,6 +94,7 @@ public final class VanillaCommandWrapper extends BukkitCommand {
+ }
+
+ public static String getPermission(CommandNode vanillaCommand) {
++ if (vanillaCommand.getPermission() != null) return vanillaCommand.getPermission(); // Purpur
+ // Paper start
+ final String commandName;
+ if (vanillaCommand.getRedirect() == null) {
diff --git a/DivineMC/patches/server/0020-Remove-sync-chunk-writes-in-server.properties.patch b/DivineMC/patches/server/0020-Remove-sync-chunk-writes-in-server.properties.patch
new file mode 100644
index 0000000..dc3fd38
--- /dev/null
+++ b/DivineMC/patches/server/0020-Remove-sync-chunk-writes-in-server.properties.patch
@@ -0,0 +1,34 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Simon Gardling
+Date: Mon, 6 Dec 2021 10:27:12 -0500
+Subject: [PATCH] Remove 'sync-chunk-writes' in server.properties
+
+Original code by Titaniumtown, licensed under GNU General Public License v3.0
+You can find the original code on https://gitlab.com/Titaniumtown/JettPack
+
+diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+index d4efadbc87ee0b6cb8564c57fc9dcbb48367a767..300e61a9ebaece1f337031b27181f270f90e7a52 100644
+--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+@@ -392,7 +392,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
+ BufferedWriter bufferedwriter = Files.newBufferedWriter(file);
+
+ try {
+- bufferedwriter.write(String.format(Locale.ROOT, "sync-chunk-writes=%s%n", dedicatedserverproperties.syncChunkWrites));
++ //bufferedwriter.write(String.format(Locale.ROOT, "sync-chunk-writes=%s%n", dedicatedserverproperties.syncChunkWrites)); // JettPack - remove 'sync-chunk-writes' in server.properties
+ bufferedwriter.write(String.format(Locale.ROOT, "gamemode=%s%n", dedicatedserverproperties.gamemode));
+ bufferedwriter.write(String.format(Locale.ROOT, "spawn-monsters=%s%n", dedicatedserverproperties.spawnMonsters));
+ bufferedwriter.write(String.format(Locale.ROOT, "entity-broadcast-range-percentage=%d%n", dedicatedserverproperties.entityBroadcastRangePercentage));
+diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
+index a32cfa75a9bea896f558bab646d0868391b069a9..3e4a3915cdf29fc964e0314ce01d156dd2f4f873 100644
+--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
+@@ -136,7 +136,7 @@ public class DedicatedServerProperties extends Settings {
+ return Mth.clamp(integer, (int) 1, 29999984);
+ }, 29999984);
+- this.syncChunkWrites = this.get("sync-chunk-writes", true) && Boolean.getBoolean("Paper.enable-sync-chunk-writes"); // Paper - hide behind flag
++ this.syncChunkWrites = Boolean.getBoolean("Paper.enable-sync-chunk-writes"); // Paper - hide behind flag // JettPack - remove 'sync-chunk-writes' in server.properties
+ this.enableJmxMonitoring = this.get("enable-jmx-monitoring", false);
+ this.enableStatus = this.get("enable-status", true);
+ this.hideOnlinePlayers = this.get("hide-online-players", false);
diff --git a/DivineMC/patches/server/0021-Remove-Spigot-tick-limiter.patch b/DivineMC/patches/server/0021-Remove-Spigot-tick-limiter.patch
new file mode 100644
index 0000000..f68db39
--- /dev/null
+++ b/DivineMC/patches/server/0021-Remove-Spigot-tick-limiter.patch
@@ -0,0 +1,80 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Simon Gardling
+Date: Mon, 6 Dec 2021 10:34:33 -0500
+Subject: [PATCH] Remove Spigot tick limiter
+
+Original code by Titaniumtown, licensed under GNU General Public License v3.0
+You can find the original code on https://gitlab.com/Titaniumtown/JettPack
+
+diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
+index 13aee2a785b3ddb481744277a25c1ab95e036d4a..7fc3c9892d69d14de694d5328fe17a971019cc54 100644
+--- a/src/main/java/net/minecraft/world/level/Level.java
++++ b/src/main/java/net/minecraft/world/level/Level.java
+@@ -176,8 +176,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+ public final com.destroystokyo.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
+ public final co.aikar.timings.WorldTimingsHandler timings; // Paper
+ public static BlockPos lastPhysicsProblem; // Spigot
+- private org.spigotmc.TickLimiter entityLimiter;
+- private org.spigotmc.TickLimiter tileLimiter;
++ //private org.spigotmc.TickLimiter entityLimiter; // JettPack - remove tick limiter
++ //private org.spigotmc.TickLimiter tileLimiter; // JettPack - remove tick limiter
+ private int tileTickPosition;
+ public final Map explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
+ public java.util.ArrayDeque redstoneUpdateInfos; // Paper - Move from Map in BlockRedstoneTorch to here
+@@ -371,8 +371,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
+ // CraftBukkit end
+ timings = new co.aikar.timings.WorldTimingsHandler(this); // Paper - code below can generate new world and access timings
+ this.keepSpawnInMemory = this.paperConfig().spawn.keepSpawnLoaded; // Paper
+- this.entityLimiter = new org.spigotmc.TickLimiter(spigotConfig.entityMaxTickTime);
+- this.tileLimiter = new org.spigotmc.TickLimiter(spigotConfig.tileMaxTickTime);
++ //this.entityLimiter = new org.spigotmc.TickLimiter(spigotConfig.entityMaxTickTime); // JettPack - remove tick limiter
++ //this.tileLimiter = new org.spigotmc.TickLimiter(spigotConfig.tileMaxTickTime); // JettPack - remove tick limiter
+ this.chunkPacketBlockController = this.paperConfig().anticheat.antiXray.enabled ? new com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray(this, executor) : com.destroystokyo.paper.antixray.ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray
+ }
+
+diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java
+index 46ef3400605cc420bd88f13838df7d1f1106235e..a5a2e497eb3e651f3e715f995a80161d919ebab9 100644
+--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java
++++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java
+@@ -446,6 +446,7 @@ public class SpigotWorldConfig
+ this.hangingTickFrequency = this.getInt( "hanging-tick-frequency", 100 );
+ }
+
++ /* JettPack - remove tick limiter
+ public int tileMaxTickTime;
+ public int entityMaxTickTime;
+ private void maxTickTimes()
+@@ -454,6 +455,7 @@ public class SpigotWorldConfig
+ this.entityMaxTickTime = this.getInt("max-tick-time.entity", 50);
+ this.log("Tile Max Tick Time: " + this.tileMaxTickTime + "ms Entity max Tick Time: " + this.entityMaxTickTime + "ms");
+ }
++ */
+
+ public int thunderChance;
+ private void thunderChance()
+diff --git a/src/main/java/org/spigotmc/TickLimiter.java b/src/main/java/org/spigotmc/TickLimiter.java
+deleted file mode 100644
+index 4074538ea6090bf99d8ab04b1e98c2832a0e9a98..0000000000000000000000000000000000000000
+--- a/src/main/java/org/spigotmc/TickLimiter.java
++++ /dev/null
+@@ -1,20 +0,0 @@
+-package org.spigotmc;
+-
+-public class TickLimiter {
+-
+- private final int maxTime;
+- private long startTime;
+-
+- public TickLimiter(int maxtime) {
+- this.maxTime = maxtime;
+- }
+-
+- public void initTick() {
+- this.startTime = System.currentTimeMillis();
+- }
+-
+- public boolean shouldContinue() {
+- long remaining = System.currentTimeMillis() - this.startTime;
+- return remaining < this.maxTime;
+- }
+-}
diff --git a/DivineMC/patches/server/0022-Spread-out-and-optimise-player-list-ticksSpread-out-.patch b/DivineMC/patches/server/0022-Spread-out-and-optimise-player-list-ticksSpread-out-.patch
new file mode 100644
index 0000000..9225aad
--- /dev/null
+++ b/DivineMC/patches/server/0022-Spread-out-and-optimise-player-list-ticksSpread-out-.patch
@@ -0,0 +1,68 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: James Lyne
+Date: Mon, 7 Dec 2020 17:52:36 +0000
+Subject: [PATCH] Spread out and optimise player list ticksSpread out and
+ optimise player list ticks
+
+Original code by PurpurMC, licensed under MIT
+You can find the original code on https://github.com/PurpurMC/Purpur
+
+diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
+index faaf13f46bc7bf0ffc1fe61f45e9f11cb9c8b4d5..f4b554da231ed968c6fa7d71380da361d463d6c5 100644
+--- a/src/main/java/net/minecraft/server/players/PlayerList.java
++++ b/src/main/java/net/minecraft/server/players/PlayerList.java
+@@ -1032,22 +1032,22 @@ public abstract class PlayerList {
+ }
+
+ public void tick() {
+- if (++this.sendAllPlayerInfoIn > 600) {
+- // CraftBukkit start
+- for (int i = 0; i < this.players.size(); ++i) {
+- final ServerPlayer target = (ServerPlayer) this.players.get(i);
+-
+- target.connection.send(new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.UPDATE_LATENCY, this.players.stream().filter(new Predicate() {
+- @Override
+- public boolean test(ServerPlayer input) {
+- return target.getBukkitEntity().canSee(input.getBukkitEntity());
+- }
+- }).collect(Collectors.toList())));
++ // Purpur start
++ if (this.sendAllPlayerInfoIn < this.players.size()) {
++ final org.bukkit.craftbukkit.entity.CraftPlayer target = this.players.get(this.sendAllPlayerInfoIn).getBukkitEntity();
++ final List list = new java.util.ArrayList<>();
++ for (ServerPlayer player : this.players) {
++ if (target.canSee(player.getUUID())) {
++ list.add(player);
++ }
+ }
+- // CraftBukkit end
+- this.sendAllPlayerInfoIn = 0;
++ target.getHandle().connection.send(new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.UPDATE_LATENCY, list));
+ }
+
++ if (++this.sendAllPlayerInfoIn > 600) {
++ this.sendAllPlayerInfoIn = 0;
++ }
++ // Purpur end
+ }
+
+ public void broadcastAll(Packet> packet) {
+diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+index b1136b9c39b16cbb9dfe460f88000f74ccd4f571..cfbabdcade291b2fcdbe83206b060b8762f50f41 100644
+--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+@@ -1883,7 +1883,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
+
+ @Override
+ public boolean canSee(org.bukkit.entity.Entity entity) {
+- return !this.hiddenEntities.containsKey(entity.getUniqueId());
++ // Purpur start
++ return this.canSee(entity.getUniqueId());
++ }
++
++ public boolean canSee(UUID uuid) {
++ return !this.hiddenEntities.containsKey(uuid);
++ // Purpur end
+ }
+
+ @Override
diff --git a/DivineMC/patches/server/0023-Don-t-save-Fireworks.patch b/DivineMC/patches/server/0023-Don-t-save-Fireworks.patch
new file mode 100644
index 0000000..b2c6986
--- /dev/null
+++ b/DivineMC/patches/server/0023-Don-t-save-Fireworks.patch
@@ -0,0 +1,24 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Aikar
+Date: Sat, 28 Dec 2013 21:25:06 -0500
+Subject: [PATCH] Don't save Fireworks
+
+Original code by Starlis, licensed under GNU General Public License v3.0
+You can find the original code on https://github.com/starlis/empirecraft
+
+diff --git a/src/main/java/net/minecraft/world/entity/projectile/FireworkRocketEntity.java b/src/main/java/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
+index 61252ef8a79bac0ea2d3d231ec6b12166f39d072..d01654155b200b53d7822f6695d1ab94aabb8a52 100644
+--- a/src/main/java/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
++++ b/src/main/java/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
+@@ -358,4 +358,11 @@ public class FireworkRocketEntity extends Projectile implements ItemSupplier {
+ public boolean isAttackable() {
+ return false;
+ }
++
++ // EMC start
++ @Override
++ public boolean shouldBeSaved() {
++ return false;
++ }
++ // EMC end
+ }
diff --git a/DivineMC/patches/server/0024-Do-not-drop-items-from-Give-command.patch b/DivineMC/patches/server/0024-Do-not-drop-items-from-Give-command.patch
new file mode 100644
index 0000000..53a6cb7
--- /dev/null
+++ b/DivineMC/patches/server/0024-Do-not-drop-items-from-Give-command.patch
@@ -0,0 +1,20 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Aikar
+Date: Thu, 14 Jan 2016 00:49:14 -0500
+Subject: [PATCH] Do not drop items from Give command
+
+Original code by Starlis, licensed under GNU General Public License v3.0
+You can find the original code on https://github.com/starlis/empirecraft
+
+diff --git a/src/main/java/net/minecraft/server/commands/GiveCommand.java b/src/main/java/net/minecraft/server/commands/GiveCommand.java
+index 06e3a868e922f1b7a586d0ca28f64a67ae463b68..00c481ebf012efa5424e32521e7aecf4b36f24c0 100644
+--- a/src/main/java/net/minecraft/server/commands/GiveCommand.java
++++ b/src/main/java/net/minecraft/server/commands/GiveCommand.java
+@@ -58,6 +58,7 @@ public class GiveCommand {
+ boolean flag = entityplayer.getInventory().add(itemstack);
+ ItemEntity entityitem;
+
++ if (true) { continue; } // EMC - never drop items
+ if (flag && itemstack.isEmpty()) {
+ itemstack.setCount(1);
+ entityitem = entityplayer.drop(itemstack, false, false, false); // SPIGOT-2942: Add boolean to call event
diff --git a/DivineMC/patches/server/0025-Do-not-process-chat-commands-before-player-has-joine.patch b/DivineMC/patches/server/0025-Do-not-process-chat-commands-before-player-has-joine.patch
new file mode 100644
index 0000000..2fc441d
--- /dev/null
+++ b/DivineMC/patches/server/0025-Do-not-process-chat-commands-before-player-has-joine.patch
@@ -0,0 +1,20 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: chickeneer
+Date: Tue, 3 Aug 2021 10:39:44 -0500
+Subject: [PATCH] Do not process chat/commands before player has joined
+
+Original code by Starlis, licensed under GNU General Public License v3.0
+You can find the original code on https://github.com/starlis/empirecraft
+
+diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+index 65362a582d19ab690bcdd68533319f70a7e585f1..ca245019669591a5468de2df6dedc3080b61282e 100644
+--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
++++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+@@ -2346,6 +2346,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
+ } else if (this.player.isRemoved() || this.player.getChatVisibility() == ChatVisiblity.HIDDEN) { // CraftBukkit - dead men tell no tales
+ this.send(new ClientboundSystemChatPacket(Component.translatable("chat.disabled.options").withStyle(ChatFormatting.RED), false));
+ return false;
++ } else if (!player.didPlayerJoinEvent) { return false; // EMC - do not handle chat messages before they joined
+ } else {
+ LastSeenMessagesValidator lastseenmessagesvalidator = this.lastSeenMessagesValidator;
+ Set set;
diff --git a/DivineMC/patches/server/0026-Fix-cow-rotation-when-shearing-mooshroom.patch b/DivineMC/patches/server/0026-Fix-cow-rotation-when-shearing-mooshroom.patch
new file mode 100644
index 0000000..3815c53
--- /dev/null
+++ b/DivineMC/patches/server/0026-Fix-cow-rotation-when-shearing-mooshroom.patch
@@ -0,0 +1,26 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: William Blake Galbreath
+Date: Fri, 3 May 2019 23:53:16 -0500
+Subject: [PATCH] Fix cow rotation when shearing mooshroom
+
+Original code by PurpurMC, licensed under MIT
+You can find the original code on https://github.com/PurpurMC/Purpur
+
+diff --git a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java
+index e84d4ecc1fd8e196743a37b18306a4769abbcb77..a715465611be53dc94770feee0f13381f7d82e24 100644
+--- a/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java
++++ b/src/main/java/net/minecraft/world/entity/animal/MushroomCow.java
+@@ -180,7 +180,13 @@ public class MushroomCow extends Cow implements Shearable {
+
+ entitycow.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
+ entitycow.setHealth(this.getHealth());
++ // Purpur start
++ entitycow.copyPosition(this);
+ entitycow.yBodyRot = this.yBodyRot;
++ entitycow.setYHeadRot(this.getYHeadRot());
++ entitycow.yRotO = this.yRotO;
++ entitycow.xRotO = this.xRotO;
++ // Purpur end
+ if (this.hasCustomName()) {
+ entitycow.setCustomName(this.getCustomName());
+ entitycow.setCustomNameVisible(this.isCustomNameVisible());
diff --git a/DivineMC/patches/server/0027-End-gateway-should-check-if-entity-can-use-portal.patch b/DivineMC/patches/server/0027-End-gateway-should-check-if-entity-can-use-portal.patch
new file mode 100644
index 0000000..fe2b31d
--- /dev/null
+++ b/DivineMC/patches/server/0027-End-gateway-should-check-if-entity-can-use-portal.patch
@@ -0,0 +1,20 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: William Blake Galbreath
+Date: Sat, 21 Mar 2020 18:33:05 -0500
+Subject: [PATCH] End gateway should check if entity can use portal
+
+Original code by PurpurMC, licensed under MIT
+You can find the original code on https://github.com/PurpurMC/Purpur
+
+diff --git a/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java
+index 56d68b87287f0bb2c79ce0bed02fa333b85c4287..5c7e30eb5e8a2a1ab18750a2cd2ec7364e8c52e0 100644
+--- a/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java
++++ b/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java
+@@ -177,6 +177,7 @@ public class TheEndGatewayBlockEntity extends TheEndPortalBlockEntity {
+
+ public static void teleportEntity(Level world, BlockPos pos, BlockState state, Entity entity, TheEndGatewayBlockEntity blockEntity) {
+ if (world instanceof ServerLevel && !blockEntity.isCoolingDown()) {
++ if (!entity.canChangeDimensions()) return; // Purpur
+ ServerLevel worldserver = (ServerLevel) world;
+
+ blockEntity.teleportCooldown = 100;
diff --git a/DivineMC/patches/server/0028-Arrows-should-not-reset-despawn-counter.patch b/DivineMC/patches/server/0028-Arrows-should-not-reset-despawn-counter.patch
new file mode 100644
index 0000000..693b1fb
--- /dev/null
+++ b/DivineMC/patches/server/0028-Arrows-should-not-reset-despawn-counter.patch
@@ -0,0 +1,24 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: William Blake Galbreath
+Date: Wed, 4 Nov 2020 13:12:50 -0600
+Subject: [PATCH] Arrows should not reset despawn counter
+
+This prevents keeping arrows alive indefinitely (such as when the block
+the arrow is stuck in gets removed, like a piston head going up/down)
+
+Original code by PurpurMC, licensed under MIT
+You can find the original code on https://github.com/PurpurMC/Purpur
+
+diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
+index bc01e5014e1355a225bdf5c47f2965290b45e2d2..49f093b21aa1268d40aa54ebfce06976bd79ae81 100644
+--- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
++++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
+@@ -322,7 +322,7 @@ public abstract class AbstractArrow extends Projectile {
+ Vec3 vec3d = this.getDeltaMovement();
+
+ this.setDeltaMovement(vec3d.multiply((double) (this.random.nextFloat() * 0.2F), (double) (this.random.nextFloat() * 0.2F), (double) (this.random.nextFloat() * 0.2F)));
+- this.life = 0;
++ // this.life = 0; // Purpur - do not reset despawn counter
+ }
+
+ @Override
diff --git a/DivineMC/patches/server/0029-PaperPR-Use-DataConverter-for-itemstack-entity-deser.patch b/DivineMC/patches/server/0029-PaperPR-Use-DataConverter-for-itemstack-entity-deser.patch
new file mode 100644
index 0000000..07237fc
--- /dev/null
+++ b/DivineMC/patches/server/0029-PaperPR-Use-DataConverter-for-itemstack-entity-deser.patch
@@ -0,0 +1,32 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jake Potrebic <15055071+Machine-Maker@users.noreply.github.com>
+Date: Fri, 10 Dec 2021 08:15:36 -0500
+Subject: [PATCH] PaperPR Use DataConverter for itemstack/entity
+ deserialization
+
+
+diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+index eff5dda2232fec841e5a5ba393f09475b0ce2861..26402ccd5dfc4713df5514354e2f8baa6c767530 100644
+--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+@@ -453,8 +453,8 @@ public final class CraftMagicNumbers implements UnsafeValues {
+
+ CompoundTag compound = deserializeNbtFromBytes(data);
+ int dataVersion = compound.getInt("DataVersion");
+- Dynamic converted = DataFixers.getDataFixer().update(References.ITEM_STACK, new Dynamic(NbtOps.INSTANCE, compound), dataVersion, getDataVersion());
+- return CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.of((CompoundTag) converted.getValue()));
++ compound = ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.ITEM_STACK, compound, dataVersion, getDataVersion()); // Paper - rewrite dataconverter
++ return CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.of(compound));
+ }
+
+ @Override
+@@ -474,8 +474,7 @@ public final class CraftMagicNumbers implements UnsafeValues {
+
+ CompoundTag compound = deserializeNbtFromBytes(data);
+ int dataVersion = compound.getInt("DataVersion");
+- Dynamic converted = DataFixers.getDataFixer().update(References.ENTITY_TREE, new Dynamic<>(NbtOps.INSTANCE, compound), dataVersion, getDataVersion());
+- compound = (CompoundTag) converted.getValue();
++ compound = ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.ENTITY, compound, dataVersion, getDataVersion()); // Paper - rewrite dataconverter
+ if (!preserveUUID) compound.remove("UUID"); // Generate a new UUID so we don't have to worry about deserializing the same entity twice
+ return net.minecraft.world.entity.EntityType.create(compound, ((org.bukkit.craftbukkit.CraftWorld) world).getHandle())
+ .orElseThrow(() -> new IllegalArgumentException("An ID was not found for the data. Did you downgrade?")).getBukkitEntity();
diff --git a/DivineMC/patches/server/0030-Dont-eat-blocks-in-non-ticking-chunks.patch b/DivineMC/patches/server/0030-Dont-eat-blocks-in-non-ticking-chunks.patch
new file mode 100644
index 0000000..2c7240d
--- /dev/null
+++ b/DivineMC/patches/server/0030-Dont-eat-blocks-in-non-ticking-chunks.patch
@@ -0,0 +1,38 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: BillyGalbreath
+Date: Sat, 15 Jan 2022 06:23:04 -0600
+Subject: [PATCH] Dont eat blocks in non ticking chunks
+
+Original code by PurpurMC, licensed under MIT
+You can find the original code on https://github.com/PurpurMC/Purpur
+
+diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
+index 9ce60dd72dee4d3ceef38f425b13aed18fd5e002..9976630fad886392057f642e84f919f0b95cc040 100644
+--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
+@@ -983,7 +983,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
+ return this.anyPlayerCloseEnoughForSpawning(this.getUpdatingChunkIfPresent(chunkcoordintpair.toLong()), chunkcoordintpair, reducedRange);
+ }
+
+- final boolean anyPlayerCloseEnoughForSpawning(ChunkHolder playerchunk, ChunkPos chunkcoordintpair, boolean reducedRange) {
++ public final boolean anyPlayerCloseEnoughForSpawning(ChunkHolder playerchunk, ChunkPos chunkcoordintpair, boolean reducedRange) { // Purpur - package -> public
+ // this function is so hot that removing the map lookup call can have an order of magnitude impact on its performance
+ // tested and confirmed via System.nanoTime()
+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet playersInRange = reducedRange ? playerchunk.playersInMobSpawnRange : playerchunk.playersInChunkTickRange;
+diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java
+index 80aa539f7c6a6ee44338de084cdcdf5fb4ef996a..9c2c2b3557f4a70c6c965f159a57682e1827d1ad 100644
+--- a/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java
++++ b/src/main/java/net/minecraft/world/entity/ai/goal/EatBlockGoal.java
+@@ -31,6 +31,12 @@ public class EatBlockGoal extends Goal {
+
+ @Override
+ public boolean canUse() {
++ // Purpur start
++ net.minecraft.world.level.chunk.LevelChunk chunk = this.mob.level.getChunkIfLoaded(this.mob.blockPosition);
++ if (chunk == null || chunk.playerChunk == null || !((net.minecraft.server.level.ServerLevel) this.mob.level).getChunkSource().chunkMap.anyPlayerCloseEnoughForSpawning(chunk.playerChunk, this.mob.chunkPosition(), false)) {
++ return false;
++ }
++ // Purpur end
+ if (this.mob.getRandom().nextInt(this.mob.isBaby() ? 50 : 1000) != 0) {
+ return false;
+ } else {
diff --git a/DivineMC/patches/server/0031-carpetfixes-BiomeAccess-prediction.patch b/DivineMC/patches/server/0031-carpetfixes-BiomeAccess-prediction.patch
new file mode 100644
index 0000000..710d7e3
--- /dev/null
+++ b/DivineMC/patches/server/0031-carpetfixes-BiomeAccess-prediction.patch
@@ -0,0 +1,119 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: etil2jz <81570777+etil2jz@users.noreply.github.com>
+Date: Fri, 22 Apr 2022 22:44:56 +0200
+Subject: [PATCH] carpetfixes: BiomeAccess prediction
+
+Author: fxmorin
+
+Original license: MIT
+Original project: https://github.com/fxmorin/carpet-fixes (Yarn mappings)
+
+Copyright (c) 2020 Fx Morin
+
+diff --git a/src/main/java/net/minecraft/world/level/biome/BiomeManager.java b/src/main/java/net/minecraft/world/level/biome/BiomeManager.java
+index 5695c5116c8a338b2e41aafcb2dc9f2146856970..6ee0a42dd048352c3df5d4788ea09170010a95b5 100644
+--- a/src/main/java/net/minecraft/world/level/biome/BiomeManager.java
++++ b/src/main/java/net/minecraft/world/level/biome/BiomeManager.java
+@@ -28,41 +28,72 @@ public class BiomeManager {
+ return new BiomeManager(storage, this.biomeZoomSeed);
+ }
+
++ // DivineMC start - carpetfixes: BiomeAccess prediction
++ private static final double maxOffset = 0.4500000001D; // DivineMC - carpetfixes: BiomeAccess prediction
+ public Holder getBiome(BlockPos pos) {
+- int i = pos.getX() - 2;
+- int j = pos.getY() - 2;
+- int k = pos.getZ() - 2;
+- int l = i >> 2;
+- int m = j >> 2;
+- int n = k >> 2;
+- double d = (double)(i & 3) / 4.0D;
+- double e = (double)(j & 3) / 4.0D;
+- double f = (double)(k & 3) / 4.0D;
+- int o = 0;
+- double g = Double.POSITIVE_INFINITY;
+-
+- for(int p = 0; p < 8; ++p) {
+- boolean bl = (p & 4) == 0;
+- boolean bl2 = (p & 2) == 0;
+- boolean bl3 = (p & 1) == 0;
+- int q = bl ? l : l + 1;
+- int r = bl2 ? m : m + 1;
+- int s = bl3 ? n : n + 1;
+- double h = bl ? d : d - 1.0D;
+- double t = bl2 ? e : e - 1.0D;
+- double u = bl3 ? f : f - 1.0D;
+- double v = getFiddledDistance(this.biomeZoomSeed, q, r, s, h, t, u);
+- if (g > v) {
+- o = p;
+- g = v;
++ int xMinus2 = pos.getX() - 2;
++ int yMinus2 = pos.getY() - 2;
++ int zMinus2 = pos.getZ() - 2;
++ int x = xMinus2 >> 2; // BlockPos to BiomePos
++ int y = yMinus2 >> 2;
++ int z = zMinus2 >> 2;
++ double quartX = (double) (xMinus2 & 3) / 4.0D; // quartLocal divided by 4
++ double quartY = (double) (yMinus2 & 3) / 4.0D; // 0/4, 1/4, 2/4, 3/4
++ double quartZ = (double) (zMinus2 & 3) / 4.0D; // [0, 0.25, 0.5, 0.75]
++ int smallestX = 0;
++ double smallestDist = Double.POSITIVE_INFINITY;
++ for (int biomeX = 0; biomeX < 8; ++biomeX) {
++ boolean everyOtherQuad = (biomeX & 4) == 0; // 1 1 1 1 0 0 0 0
++ boolean everyOtherPair = (biomeX & 2) == 0; // 1 1 0 0 1 1 0 0
++ boolean everyOther = (biomeX & 1) == 0; // 1 0 1 0 1 0 1 0
++ double quartXX = everyOtherQuad ? quartX : quartX - 1.0D; //[-1.0,-0.75,-0.5,-0.25,0.0,0.25,0.5,0.75]
++ double quartYY = everyOtherPair ? quartY : quartY - 1.0D;
++ double quartZZ = everyOther ? quartZ : quartZ - 1.0D;
++
++ //This code block is new
++ double maxQuartYY = 0.0D, maxQuartZZ = 0.0D;
++ if (biomeX != 0) {
++ maxQuartYY = Mth.square(Math.max(quartYY + maxOffset, Math.abs(quartYY - maxOffset)));
++ maxQuartZZ = Mth.square(Math.max(quartZZ + maxOffset, Math.abs(quartZZ - maxOffset)));
++ double maxQuartXX = Mth.square(Math.max(quartXX + maxOffset,Math.abs(quartXX - maxOffset)));
++ if (smallestDist < maxQuartXX + maxQuartYY + maxQuartZZ) continue;
++ }
++
++ int xx = everyOtherQuad ? x : x + 1;
++ int yy = everyOtherPair ? y : y + 1;
++ int zz = everyOther ? z : z + 1;
++
++ //I transferred the code from method_38106 to here, so I could call continue halfway through
++ long seed = LinearCongruentialGenerator.next(this.biomeZoomSeed, xx);
++ seed = LinearCongruentialGenerator.next(seed, yy);
++ seed = LinearCongruentialGenerator.next(seed, zz);
++ seed = LinearCongruentialGenerator.next(seed, xx);
++ seed = LinearCongruentialGenerator.next(seed, yy);
++ seed = LinearCongruentialGenerator.next(seed, zz);
++ double offsetX = getFiddle(seed);
++ double sqrX = Mth.square(quartXX + offsetX);
++ if (biomeX != 0 && smallestDist < sqrX + maxQuartYY + maxQuartZZ) continue; //skip the rest of the loop
++ seed = LinearCongruentialGenerator.next(seed, this.biomeZoomSeed);
++ double offsetY = getFiddle(seed);
++ double sqrY = Mth.square(quartYY + offsetY);
++ if (biomeX != 0 && smallestDist < sqrX + sqrY + maxQuartZZ) continue; // skip the rest of the loop
++ seed = LinearCongruentialGenerator.next(seed, this.biomeZoomSeed);
++ double offsetZ = getFiddle(seed);
++ double biomeDist = sqrX + sqrY + Mth.square(quartZZ + offsetZ);
++
++ if (smallestDist > biomeDist) {
++ smallestX = biomeX;
++ smallestDist = biomeDist;
+ }
+ }
+
+- int w = (o & 4) == 0 ? l : l + 1;
+- int x = (o & 2) == 0 ? m : m + 1;
+- int y = (o & 1) == 0 ? n : n + 1;
+- return this.noiseBiomeSource.getNoiseBiome(w, x, y);
++ return(this.noiseBiomeSource.getNoiseBiome(
++ (smallestX & 4) == 0 ? x : x + 1,
++ (smallestX & 2) == 0 ? y : y + 1,
++ (smallestX & 1) == 0 ? z : z + 1
++ ));
+ }
++ // DivineMC end
+
+ public Holder getNoiseBiomeAtPosition(double x, double y, double z) {
+ int i = QuartPos.fromBlock(Mth.floor(x));
diff --git a/DivineMC/patches/server/0032-Fix-MC-121706.patch b/DivineMC/patches/server/0032-Fix-MC-121706.patch
new file mode 100644
index 0000000..179f8b4
--- /dev/null
+++ b/DivineMC/patches/server/0032-Fix-MC-121706.patch
@@ -0,0 +1,23 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Etil <81570777+etil2jz@users.noreply.github.com>
+Date: Sun, 2 Jan 2022 20:37:30 +0100
+Subject: [PATCH] Fix MC-121706
+
+
+diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/RangedBowAttackGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/RangedBowAttackGoal.java
+index 6558b0d4bea99948fdc2b51751f3cfdc239d4b67..edb296ceaebfc296cf76682beeeda95d6ac2d93a 100644
+--- a/src/main/java/net/minecraft/world/entity/ai/goal/RangedBowAttackGoal.java
++++ b/src/main/java/net/minecraft/world/entity/ai/goal/RangedBowAttackGoal.java
+@@ -111,10 +111,10 @@ public class RangedBowAttackGoal extends Go
+
+ this.mob.getMoveControl().strafe(this.strafingBackwards ? -0.5F : 0.5F, this.strafingClockwise ? 0.5F : -0.5F);
+ this.mob.lookAt(livingEntity, 30.0F, 30.0F);
+- } else {
+- this.mob.getLookControl().setLookAt(livingEntity, 30.0F, 30.0F);
+ }
+
++ this.mob.getLookControl().setLookAt(livingEntity, 30.0F, 30.0F); // DivineMC - fix MC-121706
++
+ if (this.mob.isUsingItem()) {
+ if (!bl && this.seeTime < -60) {
+ this.mob.stopUsingItem();
diff --git a/DivineMC/patches/server/0033-PaperPR-Add-more-collision-code-skipping-logic.patch b/DivineMC/patches/server/0033-PaperPR-Add-more-collision-code-skipping-logic.patch
new file mode 100644
index 0000000..c1b3a8c
--- /dev/null
+++ b/DivineMC/patches/server/0033-PaperPR-Add-more-collision-code-skipping-logic.patch
@@ -0,0 +1,22 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: etil2jz <81570777+etil2jz@users.noreply.github.com>
+Date: Sat, 19 Mar 2022 16:27:30 +0100
+Subject: [PATCH] PaperPR Add more collision code skipping logic
+
+Taken from https://github.com/PaperMC/Paper/pull/7581
+
+diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
+index c0e316582e085873c05a76c16e612eabd2e8cf2a..dd881ca1460ad3d1f17b40969a872c3226d9d0c9 100644
+--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
+@@ -3466,6 +3466,10 @@ public abstract class LivingEntity extends Entity {
+
+ protected void pushEntities() {
+ // Paper start - don't run getEntities if we're not going to use its result
++ if (!isCollidable(level.paperConfig().collisions.fixClimbingBypassingCrammingRule)) return;
++ net.minecraft.world.scores.Team team = getTeam();
++ if (team != null && team.getCollisionRule() == net.minecraft.world.scores.Team.CollisionRule.NEVER) return;
++
+ int i = this.level.getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING);
+ if (i <= 0 && level.paperConfig().collisions.maxEntityCollisions <= 0) {
+ return;
diff --git a/DivineMC/patches/server/0034-Fix-tick-function-tag-running-before-load.patch b/DivineMC/patches/server/0034-Fix-tick-function-tag-running-before-load.patch
new file mode 100644
index 0000000..737ef16
--- /dev/null
+++ b/DivineMC/patches/server/0034-Fix-tick-function-tag-running-before-load.patch
@@ -0,0 +1,26 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: etil2jz <81570777+etil2jz@users.noreply.github.com>
+Date: Fri, 8 Apr 2022 21:20:50 +0200
+Subject: [PATCH] Fix tick function tag running before load
+
+
+diff --git a/src/main/java/net/minecraft/server/ServerFunctionManager.java b/src/main/java/net/minecraft/server/ServerFunctionManager.java
+index 00a50196f6a4768d84acfbbeec79a0753308f091..3452ff5d378a2703fb0959c8163ee0274236e839 100644
+--- a/src/main/java/net/minecraft/server/ServerFunctionManager.java
++++ b/src/main/java/net/minecraft/server/ServerFunctionManager.java
+@@ -46,13 +46,14 @@ public class ServerFunctionManager {
+ }
+
+ public void tick() {
+- this.executeTagFunctions(this.ticking, ServerFunctionManager.TICK_FUNCTION_TAG);
++ //this.executeTagFunctions(this.ticking, ServerFunctionManager.TICK_FUNCTION_TAG); // DivineMC - moved down
+ if (this.postReload) {
+ this.postReload = false;
+ Collection collection = this.library.getTag(ServerFunctionManager.LOAD_FUNCTION_TAG);
+
+ this.executeTagFunctions(collection, ServerFunctionManager.LOAD_FUNCTION_TAG);
+ }
++ this.executeTagFunctions(this.ticking, ServerFunctionManager.TICK_FUNCTION_TAG); // DivineMC - fix tick function tag running before load
+
+ }
+
diff --git a/DivineMC/patches/server/0035-Optimize-default-values-for-configs.patch b/DivineMC/patches/server/0035-Optimize-default-values-for-configs.patch
new file mode 100644
index 0000000..3264577
--- /dev/null
+++ b/DivineMC/patches/server/0035-Optimize-default-values-for-configs.patch
@@ -0,0 +1,379 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: etil2jz <81570777+etil2jz@users.noreply.github.com>
+Date: Sun, 8 May 2022 13:13:02 +0200
+Subject: [PATCH] Optimize default values for configs
+
+
+diff --git a/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java b/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java
+index 34eb43ca2bf446504c372f98dfbe6dbfd0a81369..40d61b50ad783a6d68fc7b43ae0d3fa9cc579ecb 100644
+--- a/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java
++++ b/src/main/java/gg/pufferfish/pufferfish/PufferfishConfig.java
+@@ -217,7 +217,7 @@ public class PufferfishConfig {
+ public static int maxProjectileLoadsPerProjectile;
+ private static void projectileLoading() {
+ maxProjectileLoadsPerTick = getInt("projectile.max-loads-per-tick", 10, "Controls how many chunks are allowed", "to be sync loaded by projectiles in a tick.");
+- maxProjectileLoadsPerProjectile = getInt("projectile.max-loads-per-projectile", 10, "Controls how many chunks a projectile", "can load in its lifetime before it gets", "automatically removed.");
++ maxProjectileLoadsPerProjectile = getInt("projectile.max-loads-per-projectile", 8, "Controls how many chunks a projectile", "can load in its lifetime before it gets", "automatically removed."); // DivineMC - optimize default values for configs
+
+ setComment("projectile", "Optimizes projectile settings");
+ }
+diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java
+index 54bca103347e89f116fb7fbf37449a32ac094286..4c6ce35aa6f0ccdcbbf66e0e53a1cc8421b04ef0 100644
+--- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java
++++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java
+@@ -55,7 +55,7 @@ public class GlobalConfiguration extends ConfigurationPart {
+ public boolean enabled = true;
+ public boolean reallyEnabled = false;
+ public boolean verbose = true;
+- public String url = "https://timings.aikar.co/";
++ public String url = "https://timin.gs/"; // DivineMC - optimize default values for configs
+ public boolean serverNamePrivacy = false;
+ public List hiddenConfigEntries = List.of(
+ "database",
+@@ -289,9 +289,9 @@ public class GlobalConfiguration extends ConfigurationPart {
+ public boolean fixEntityPositionDesync = true;
+ public boolean loadPermissionsYmlBeforePlugins = true;
+ @Constraints.Min(4)
+- public int regionFileCacheSize = 256;
++ public int regionFileCacheSize = 512; // DivineMC - optimize default values for configs
+ @Comment("See https://luckformula.emc.gs")
+- public boolean useAlternativeLuckFormula = false;
++ public boolean useAlternativeLuckFormula = true; // DivineMC - optimize default values for configs
+ public boolean lagCompensateBlockBreaking = true;
+ public boolean useDimensionTypeForCustomSpawners = false;
+ public boolean strictAdvancementDimensionCheck = false;
+diff --git a/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java b/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java
+index 3d2e67dc559ee3910b17ca86a46030ec05232250..71ef6082b459bb9812f362141d8fadfc162c88ea 100644
+--- a/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java
++++ b/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java
+@@ -113,8 +113,8 @@ public class WorldConfiguration extends ConfigurationPart {
+ public ArmorStands armorStands;
+
+ public class ArmorStands extends ConfigurationPart {
+- public boolean doCollisionEntityLookups = true;
+- public boolean tick = true;
++ public boolean doCollisionEntityLookups = false; // DivineMC - optimize default values for configs
++ public boolean tick = false; // DivineMC - optimize default values for configs
+ }
+
+ public Spawning spawning;
+@@ -197,8 +197,8 @@ public class WorldConfiguration extends ConfigurationPart {
+ public Behavior behavior;
+
+ public class Behavior extends ConfigurationPart {
+- public boolean disableChestCatDetection = false;
+- public boolean spawnerNerfedMobsShouldJump = false;
++ public boolean disableChestCatDetection = true; // DivineMC - optimize default values for configs
++ public boolean spawnerNerfedMobsShouldJump = true; // DivineMC - optimize default values for configs
+ public int experienceMergeMaxValue = -1;
+ public boolean shouldRemoveDragon = false;
+ public boolean zombiesTargetTurtleEggs = true;
+@@ -241,7 +241,7 @@ public class WorldConfiguration extends ConfigurationPart {
+ public boolean enderDragonsDeathAlwaysPlacesDragonEgg = false;
+ public boolean phantomsDoNotSpawnOnCreativePlayers = true;
+ public boolean phantomsOnlyAttackInsomniacs = true;
+- public boolean parrotsAreUnaffectedByPlayerMovement = false;
++ public boolean parrotsAreUnaffectedByPlayerMovement = true; // DivineMC - optimize default values for configs
+ public double zombieVillagerInfectionChance = -1.0;
+ public MobsCanAlwaysPickUpLoot mobsCanAlwaysPickUpLoot;
+
+@@ -251,7 +251,7 @@ public class WorldConfiguration extends ConfigurationPart {
+ }
+
+ public boolean disablePlayerCrits = false;
+- public boolean nerfPigmenFromNetherPortals = false;
++ public boolean nerfPigmenFromNetherPortals = true; // DivineMC - optimize default values for configs
+ public PillagerPatrols pillagerPatrols;
+
+ public class PillagerPatrols extends ConfigurationPart {
+@@ -309,7 +309,7 @@ public class WorldConfiguration extends ConfigurationPart {
+ public class Environment extends ConfigurationPart {
+ public boolean disableThunder = false;
+ public boolean disableIceAndSnow = false;
+- public boolean optimizeExplosions = false;
++ public boolean optimizeExplosions = true; // DivineMC - optimize default values for configs
+ public boolean disableExplosionKnockback = false;
+ public boolean generateFlatBedrock = false;
+ public FrostedIce frostedIce;
+@@ -354,7 +354,7 @@ public class WorldConfiguration extends ConfigurationPart {
+
+ public class Maps extends ConfigurationPart {
+ public int itemFrameCursorLimit = 128;
+- public int itemFrameCursorUpdateInterval = 10;
++ public int itemFrameCursorUpdateInterval = 20; // DivineMC - optimize default values for configs
+ }
+
+ public Fixes fixes;
+@@ -380,7 +380,7 @@ public class WorldConfiguration extends ConfigurationPart {
+ public class Hopper extends ConfigurationPart {
+ public boolean cooldownWhenFull = true;
+ public boolean disableMoveEvent = false;
+- public boolean ignoreOccludingBlocks = false;
++ public boolean ignoreOccludingBlocks = true; // DivineMC - optimize default values for configs
+ }
+
+ public Collisions collisions;
+@@ -388,9 +388,9 @@ public class WorldConfiguration extends ConfigurationPart {
+ public class Collisions extends ConfigurationPart {
+ public boolean onlyPlayersCollide = false;
+ public boolean allowVehicleCollisions = true;
+- public boolean fixClimbingBypassingCrammingRule = false;
++ public boolean fixClimbingBypassingCrammingRule = true; // DivineMC - optimize default values for configs
+ @RequiresSpigotInitialization(MaxEntityCollisionsInitializer.class)
+- public int maxEntityCollisions = 8;
++ public int maxEntityCollisions = 2; // DivineMC - optimize default values for configs
+ public boolean allowPlayerCrammingDamage = false;
+ }
+
+@@ -398,18 +398,32 @@ public class WorldConfiguration extends ConfigurationPart {
+
+ public class Chunks extends ConfigurationPart {
+ public AutosavePeriod autoSaveInterval = AutosavePeriod.def();
+- public int maxAutoSaveChunksPerTick = 24;
++ public int maxAutoSaveChunksPerTick = 12; // DivineMC - optimize default values for configs
+ public int fixedChunkInhabitedTime = -1;
+- public boolean preventMovingIntoUnloadedChunks = false;
+- public Duration delayChunkUnloadsBy = Duration.of("10s");
++ public boolean preventMovingIntoUnloadedChunks = true; // DivineMC - optimize default values for configs
++ public Duration delayChunkUnloadsBy = Duration.of("5s"); // DivineMC - optimize default values for configs
+ public Reference2IntMap> entityPerChunkSaveLimit = Util.make(new Reference2IntOpenHashMap<>(Registry.ENTITY_TYPE.size()), map -> {
+ map.defaultReturnValue(-1);
+- map.put(EntityType.EXPERIENCE_ORB, -1);
+- map.put(EntityType.SNOWBALL, -1);
+- map.put(EntityType.ENDER_PEARL, -1);
+- map.put(EntityType.ARROW, -1);
+- map.put(EntityType.FIREBALL, -1);
+- map.put(EntityType.SMALL_FIREBALL, -1);
++ // DivineMC start - optimize default values for configs
++ map.put(EntityType.EXPERIENCE_ORB, 16);
++ map.put(EntityType.SNOWBALL, 8);
++ map.put(EntityType.ENDER_PEARL, 8);
++ map.put(EntityType.ARROW, 16);
++ map.put(EntityType.FIREBALL, 8);
++ map.put(EntityType.SMALL_FIREBALL, 8);
++ map.put(EntityType.DRAGON_FIREBALL, 3);
++ map.put(EntityType.EGG, 8);
++ map.put(EntityType.EYE_OF_ENDER, 8);
++ map.put(EntityType.FIREWORK_ROCKET, 8);
++ map.put(EntityType.POTION, 8);
++ map.put(EntityType.LLAMA_SPIT, 3);
++ map.put(EntityType.SHULKER_BULLET, 8);
++ map.put(EntityType.SPECTRAL_ARROW, 16);
++ map.put(EntityType.EXPERIENCE_BOTTLE, 3);
++ map.put(EntityType.TRIDENT, 16);
++ map.put(EntityType.WITHER_SKULL, 4);
++ map.put(EntityType.AREA_EFFECT_CLOUD, 8);
++ // DivineMC end
+ });
+ }
+
+@@ -423,11 +437,22 @@ public class WorldConfiguration extends ConfigurationPart {
+ public TickRates tickRates;
+
+ public class TickRates extends ConfigurationPart {
+- public int grassSpread = 1;
+- public int containerUpdate = 1;
+- public int mobSpawner = 1;
+- public Table, String, Integer> sensor = Util.make(HashBasedTable.create(), table -> table.put(EntityType.VILLAGER, "secondarypoisensor", 40));
+- public Table, String, Integer> behavior = Util.make(HashBasedTable.create(), table -> table.put(EntityType.VILLAGER, "validatenearbypoi", -1));
++ // DivineMC start - optimize default values for configs
++ public int grassSpread = 4;
++ public int containerUpdate = 3;
++ public int mobSpawner = 2;
++ public Table, String, Integer> sensor = Util.make(HashBasedTable.create(), table -> {
++ table.put(EntityType.VILLAGER, "secondarypoisensor", 80);
++ table.put(EntityType.VILLAGER, "nearestbedsensor", 80);
++ table.put(EntityType.VILLAGER, "villagerbabiessensor", 40);
++ table.put(EntityType.VILLAGER, "playersensor", 40);
++ table.put(EntityType.VILLAGER, "nearestlivingentitysensor", 40);
++ });
++ public Table, String, Integer> behavior = Util.make(HashBasedTable.create(), table -> {
++ table.put(EntityType.VILLAGER, "validatenearbypoi", 60);
++ table.put(EntityType.VILLAGER, "acquirepoi", 120);
++ });
++ // DivineMC end
+ }
+
+ @Setting(FeatureSeedsGeneration.FEATURE_SEEDS_KEY)
+@@ -435,7 +460,7 @@ public class WorldConfiguration extends ConfigurationPart {
+
+ public class FeatureSeeds extends ConfigurationPart.Post {
+ @Setting(FeatureSeedsGeneration.GENERATE_KEY)
+- public boolean generateRandomSeedsForAll = false;
++ public boolean generateRandomSeedsForAll = true; // DivineMC - optimize default values for configs
+ @Setting(FeatureSeedsGeneration.FEATURES_KEY)
+ public Reference2LongMap>> features = new Reference2LongOpenHashMap<>();
+
+@@ -449,9 +474,9 @@ public class WorldConfiguration extends ConfigurationPart {
+
+ public class Misc extends ConfigurationPart {
+ public int lightQueueSize = 20;
+- public boolean updatePathfindingOnBlockUpdate = true;
++ public boolean updatePathfindingOnBlockUpdate = false; // DivineMC - optimize default values for configs
+ public boolean showSignClickCommandFailureMsgsToPlayer = false;
+- public RedstoneImplementation redstoneImplementation = RedstoneImplementation.VANILLA;
++ public RedstoneImplementation redstoneImplementation = RedstoneImplementation.ALTERNATE_CURRENT; // DivineMC - optimize default values for configs
+ public boolean disableEndCredits = false;
+ public float maxLeashDistance = 10f;
+ public boolean disableSprintInterruptionOnAttack = false;
+diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java
+index a5a2e497eb3e651f3e715f995a80161d919ebab9..b88bda3a9a8b3d4e77569f7e3b405bc4b0fbf0df 100644
+--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java
++++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java
+@@ -150,14 +150,14 @@ public class SpigotWorldConfig
+ public double itemMerge;
+ private void itemMerge()
+ {
+- this.itemMerge = this.getDouble("merge-radius.item", 2.5 );
++ this.itemMerge = this.getDouble("merge-radius.item", 3.5 ); // DivineMC - optimize default values for configs
+ this.log( "Item Merge Radius: " + this.itemMerge );
+ }
+
+ public double expMerge;
+ private void expMerge()
+ {
+- this.expMerge = this.getDouble("merge-radius.exp", 3.0 );
++ this.expMerge = this.getDouble("merge-radius.exp", 4.0 ); // DivineMC - optimize default values for configs
+ this.log( "Experience Merge Radius: " + this.expMerge );
+ }
+
+@@ -196,7 +196,7 @@ public class SpigotWorldConfig
+ public byte mobSpawnRange;
+ private void mobSpawnRange()
+ {
+- this.mobSpawnRange = (byte) getInt( "mob-spawn-range", 8 ); // Paper - Vanilla
++ this.mobSpawnRange = (byte) getInt( "mob-spawn-range", 2 ); // Paper - Vanilla // DivineMC - optimize default values for configs
+ this.log( "Mob Spawn Range: " + this.mobSpawnRange );
+ }
+
+@@ -207,14 +207,14 @@ public class SpigotWorldConfig
+ this.log( "Item Despawn Rate: " + this.itemDespawnRate );
+ }
+
+- public int animalActivationRange = 32;
+- public int monsterActivationRange = 32;
++ public int animalActivationRange = 16; // DivineMC - optimize default values for configs
++ public int monsterActivationRange = 24; // DivineMC - optimize default values for configs
+ public int raiderActivationRange = 48;
+- public int miscActivationRange = 16;
++ public int miscActivationRange = 8; // DivineMC - optimize default values for configs
+ // Paper start
+ public int flyingMonsterActivationRange = 32;
+- public int waterActivationRange = 16;
+- public int villagerActivationRange = 32;
++ public int waterActivationRange = 8; // DivineMC - optimize default values for configs
++ public int villagerActivationRange = 16; // DivineMC - optimize default values for configs
+ public int wakeUpInactiveAnimals = 4;
+ public int wakeUpInactiveAnimalsEvery = 60*20;
+ public int wakeUpInactiveAnimalsFor = 5*20;
+@@ -231,7 +231,7 @@ public class SpigotWorldConfig
+ public int villagersWorkImmunityFor = 20;
+ public boolean villagersActiveForPanic = true;
+ // Paper end
+- public boolean tickInactiveVillagers = true;
++ public boolean tickInactiveVillagers = false; // DivineMC - optimize default values for configs
+ public boolean ignoreSpectatorActivation = false;
+ private void activationRange()
+ {
+@@ -297,7 +297,7 @@ public class SpigotWorldConfig
+ {
+ this.set( "ticks-per.hopper-check", 1 );
+ }
+- this.hopperCheck = this.getInt( "ticks-per.hopper-check", 1 );
++ this.hopperCheck = this.getInt( "ticks-per.hopper-check", 8 ); // DivineMC - optimize default values for configs
+ this.hopperAmount = this.getInt( "hopper-amount", 1 );
+ this.hopperCanLoadChunks = this.getBoolean( "hopper-can-load-chunks", false );
+ this.log( "Hopper Transfer: " + this.hopperTransfer + " Hopper Check: " + this.hopperCheck + " Hopper Amount: " + this.hopperAmount + " Hopper Can Load Chunks: " + this.hopperCanLoadChunks );
+@@ -307,7 +307,7 @@ public class SpigotWorldConfig
+ public int tridentDespawnRate;
+ private void arrowDespawnRate()
+ {
+- this.arrowDespawnRate = this.getInt( "arrow-despawn-rate", 1200 );
++ this.arrowDespawnRate = this.getInt( "arrow-despawn-rate", 300 ); // DivineMC - optimize default values for configs
+ this.tridentDespawnRate = this.getInt( "trident-despawn-rate", this.arrowDespawnRate );
+ this.log( "Arrow Despawn Rate: " + this.arrowDespawnRate + " Trident Respawn Rate:" + this.tridentDespawnRate );
+ }
+@@ -322,14 +322,14 @@ public class SpigotWorldConfig
+ public boolean nerfSpawnerMobs;
+ private void nerfSpawnerMobs()
+ {
+- this.nerfSpawnerMobs = this.getBoolean( "nerf-spawner-mobs", false );
++ this.nerfSpawnerMobs = this.getBoolean( "nerf-spawner-mobs", true ); // DivineMC - optimize default values for configs
+ this.log( "Nerfing mobs spawned from spawners: " + this.nerfSpawnerMobs );
+ }
+
+ public boolean enableZombiePigmenPortalSpawns;
+ private void enableZombiePigmenPortalSpawns()
+ {
+- this.enableZombiePigmenPortalSpawns = this.getBoolean( "enable-zombie-pigmen-portal-spawns", true );
++ this.enableZombiePigmenPortalSpawns = this.getBoolean( "enable-zombie-pigmen-portal-spawns", false ); // DivineMC - optimize default values for configs
+ this.log( "Allow Zombie Pigmen to spawn from portal blocks: " + this.enableZombiePigmenPortalSpawns );
+ }
+
+@@ -443,7 +443,7 @@ public class SpigotWorldConfig
+ public int hangingTickFrequency;
+ private void hangingTickFrequency()
+ {
+- this.hangingTickFrequency = this.getInt( "hanging-tick-frequency", 100 );
++ this.hangingTickFrequency = this.getInt( "hanging-tick-frequency", 200 ); // DivineMC - optimize default values for configs
+ }
+
+ /* JettPack - remove tick limiter
+diff --git a/src/main/resources/configurations/bukkit.yml b/src/main/resources/configurations/bukkit.yml
+index eef7c125b2689f29cae5464659eacdf33f5695b2..c6b04acb5371a0ac454c5e377bccad5b0972aed8 100644
+--- a/src/main/resources/configurations/bukkit.yml
++++ b/src/main/resources/configurations/bukkit.yml
+@@ -18,28 +18,28 @@ settings:
+ update-folder: update
+ plugin-profiling: false
+ connection-throttle: 4000
+- query-plugins: true
++ query-plugins: false
+ deprecated-verbose: default
+ shutdown-message: Server closed
+ minimum-api: none
+ use-map-color-cache: true
+ spawn-limits:
+- monsters: 70
+- animals: 10
+- water-animals: 5
+- water-ambient: 20
+- water-underground-creature: 5
+- axolotls: 5
+- ambient: 15
++ monsters: 20
++ animals: 5
++ water-animals: 2
++ water-ambient: 2
++ water-underground-creature: 3
++ axolotls: 3
++ ambient: 1
+ chunk-gc:
+- period-in-ticks: 600
++ period-in-ticks: 400
+ ticks-per:
+ animal-spawns: 400
+- monster-spawns: 1
+- water-spawns: 1
+- water-ambient-spawns: 1
+- water-underground-creature-spawns: 1
+- axolotl-spawns: 1
+- ambient-spawns: 1
++ monster-spawns: 10
++ water-spawns: 400
++ water-ambient-spawns: 400
++ water-underground-creature-spawns: 400
++ axolotl-spawns: 400
++ ambient-spawns: 400
+ autosave: 6000
+ aliases: now-in-commands.yml
+diff --git a/src/main/resources/configurations/commands.yml b/src/main/resources/configurations/commands.yml
+index 18f54571200e2eca09a39b88f170fe7b99d8618f..1b57d51d92c5c69286800d10baeaa936fa208cae 100644
+--- a/src/main/resources/configurations/commands.yml
++++ b/src/main/resources/configurations/commands.yml
+@@ -12,5 +12,3 @@
+ command-block-overrides: []
+ ignore-vanilla-permissions: false
+ aliases:
+- icanhasbukkit:
+- - "version $1-"
diff --git a/DivineMC/patches/server/0036-Fix-hunger-saturation-depleting-on-peaceful.patch b/DivineMC/patches/server/0036-Fix-hunger-saturation-depleting-on-peaceful.patch
new file mode 100644
index 0000000..60230f6
--- /dev/null
+++ b/DivineMC/patches/server/0036-Fix-hunger-saturation-depleting-on-peaceful.patch
@@ -0,0 +1,21 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: etil2jz <81570777+etil2jz@users.noreply.github.com>
+Date: Fri, 22 Apr 2022 18:50:49 +0200
+Subject: [PATCH] Fix hunger saturation depleting on peaceful
+
+The food saturation value is depleted on peaceful, even though
+the displayed hunger bar never goes down. Hunger (or any related value, including saturation)
+should not go down on peaceful. See https://bugs.mojang.com/browse/MC-31819.
+
+diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
+index 9b131f0a827413e9f5d6d0f7491c5481576cb8b1..3ec10c8f6cdf98cbf3789845a0d87572e8687ba9 100644
+--- a/src/main/java/net/minecraft/world/entity/player/Player.java
++++ b/src/main/java/net/minecraft/world/entity/player/Player.java
+@@ -1919,6 +1919,7 @@ public abstract class Player extends LivingEntity {
+ }
+
+ public void causeFoodExhaustion(float f, EntityExhaustionEvent.ExhaustionReason reason) {
++ if (this.level.getDifficulty() == Difficulty.PEACEFUL) return; // DivineMC - fix hunger saturation depleting on peaceful
+ // CraftBukkit end
+ if (!this.abilities.invulnerable) {
+ if (!this.level.isClientSide) {
diff --git a/DivineMC/patches/server/0037-Fix-mobs-attacking-themselves.patch b/DivineMC/patches/server/0037-Fix-mobs-attacking-themselves.patch
new file mode 100644
index 0000000..e0f5cc5
--- /dev/null
+++ b/DivineMC/patches/server/0037-Fix-mobs-attacking-themselves.patch
@@ -0,0 +1,21 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: etil2jz <81570777+etil2jz@users.noreply.github.com>
+Date: Fri, 29 Apr 2022 12:08:22 +0200
+Subject: [PATCH] Fix mobs attacking themselves
+
+If an entity is provoked by a second one using commands,
+the second will join in the fight against itself,
+causing it to attack itself repeatedly. See https://bugs.mojang.com/browse/MC-110386.
+
+diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java
+index 39ea15c7577af186d93d4ad9a48034d746a86fc8..1de734820a5a4b1580c123a8e4a2513d52c42a4b 100644
+--- a/src/main/java/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java
++++ b/src/main/java/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java
+@@ -114,6 +114,7 @@ public class HurtByTargetGoal extends TargetGoal {
+ }
+
+ protected void alertOther(Mob mob, LivingEntity target) {
++ if (mob == target) return; // DivineMC - avoid entities with suicidal thoughts /s
+ mob.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY, true); // CraftBukkit - reason
+ }
+ }
diff --git a/DivineMC/patches/server/0038-Fix-brewing-stands-resetting-their-brewTime-when-bei.patch b/DivineMC/patches/server/0038-Fix-brewing-stands-resetting-their-brewTime-when-bei.patch
new file mode 100644
index 0000000..5473fa3
--- /dev/null
+++ b/DivineMC/patches/server/0038-Fix-brewing-stands-resetting-their-brewTime-when-bei.patch
@@ -0,0 +1,27 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: etil2jz <81570777+etil2jz@users.noreply.github.com>
+Date: Sun, 8 May 2022 16:34:27 +0200
+Subject: [PATCH] Fix brewing stands resetting their brewTime when being
+ unloaded
+
+
+diff --git a/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java
+index 55006724ccec9f3de828ec18693728e9741ff65f..694dfd4e5d77f94b17c5c3927e09e962a566b4ed 100644
+--- a/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java
++++ b/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java
+@@ -295,6 +295,7 @@ public class BrewingStandBlockEntity extends BaseContainerBlockEntity implements
+ ContainerHelper.loadAllItems(nbt, this.items);
+ this.brewTime = nbt.getShort("BrewTime");
+ this.fuel = nbt.getByte("Fuel");
++ this.ingredient = net.minecraft.core.Registry.ITEM.get(new net.minecraft.resources.ResourceLocation(nbt.getString("DivineMC.ingredient"))); // DivineMC - fix brewing stands resetting their brewTime when being unloaded
+ }
+
+ @Override
+@@ -303,6 +304,7 @@ public class BrewingStandBlockEntity extends BaseContainerBlockEntity implements
+ nbt.putShort("BrewTime", (short) this.brewTime);
+ ContainerHelper.saveAllItems(nbt, this.items);
+ nbt.putByte("Fuel", (byte) this.fuel);
++ nbt.putString("DivineMC.ingredient", net.minecraft.core.Registry.ITEM.getKey(this.ingredient).toString()); // DivineMC - fix brewing stands resetting their brewTime when being unloaded
+ }
+
+ @Override
diff --git a/DivineMC/patches/server/0039-PaperPR-Optimize-VarInts.patch b/DivineMC/patches/server/0039-PaperPR-Optimize-VarInts.patch
new file mode 100644
index 0000000..2a77b65
--- /dev/null
+++ b/DivineMC/patches/server/0039-PaperPR-Optimize-VarInts.patch
@@ -0,0 +1,62 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: astei
+Date: Sat, 1 Oct 2022 09:56:47 +0200
+Subject: [PATCH] PaperPR Optimize VarInts
+
+Original license: GPLv3
+Original project: https://github.com/PaperMC/Velocity
+Paper pull request: https://github.com/PaperMC/Paper/pull/8418
+
+diff --git a/src/main/java/net/minecraft/network/FriendlyByteBuf.java b/src/main/java/net/minecraft/network/FriendlyByteBuf.java
+index 35377576ed182814051c11f902e02e8e921e84e3..4b4a3c0da7a512e16d9a5758ed7312dc9ddc1e28 100644
+--- a/src/main/java/net/minecraft/network/FriendlyByteBuf.java
++++ b/src/main/java/net/minecraft/network/FriendlyByteBuf.java
+@@ -87,15 +87,18 @@ public class FriendlyByteBuf extends ByteBuf {
+ this.source = parent;
+ }
+
+- public static int getVarIntSize(int value) {
+- for (int j = 1; j < 5; ++j) {
+- if ((value & -1 << j * 7) == 0) {
+- return j;
+- }
++ //Paper start - Optimize VarInts
++ private static final int[] VARINT_EXACT_BYTE_LENGTHS = new int[33];
++ static {
++ for (int i = 0; i <= 32; ++i) {
++ VARINT_EXACT_BYTE_LENGTHS[i] = (int) Math.ceil((31d - (i - 1)) / 7d);
+ }
+-
+- return 5;
++ VARINT_EXACT_BYTE_LENGTHS[32] = 1; // Special case for the number 0.
++ }
++ public static int getVarIntSize(int value) {
++ return VARINT_EXACT_BYTE_LENGTHS[Integer.numberOfLeadingZeros(value)]; // Paper - Optimize VarInts
+ }
++ //Paper end - Optimize VarInts
+
+ public static int getVarLongSize(long value) {
+ for (int j = 1; j < 10; ++j) {
+@@ -503,7 +506,22 @@ public class FriendlyByteBuf extends ByteBuf {
+ return new UUID(this.readLong(), this.readLong());
+ }
+
++ // Paper start - Optimize VarInts
+ public FriendlyByteBuf writeVarInt(int value) {
++ // Peel the one and two byte count cases explicitly as they are the most common VarInt sizes
++ // that the proxy will write, to improve inlining.
++ if ((value & (0xFFFFFFFF << 7)) == 0) {
++ writeByte(value);
++ } else if ((value & (0xFFFFFFFF << 14)) == 0) {
++ int w = (value & 0x7F | 0x80) << 8 | (value >>> 7);
++ writeShort(w);
++ } else {
++ writeVarInt_(value);
++ }
++ return this;
++ }
++ public FriendlyByteBuf writeVarInt_(int value) {
++ // Paper end - Optimize VarInts
+ while ((value & -128) != 0) {
+ this.writeByte(value & 127 | 128);
+ value >>>= 7;
diff --git a/DivineMC/patches/server/0040-PaperPR-Fix-exact-choice-recipe-book-clicks.patch b/DivineMC/patches/server/0040-PaperPR-Fix-exact-choice-recipe-book-clicks.patch
new file mode 100644
index 0000000..020cc11
--- /dev/null
+++ b/DivineMC/patches/server/0040-PaperPR-Fix-exact-choice-recipe-book-clicks.patch
@@ -0,0 +1,130 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jake Potrebic
+Date: Sat, 14 May 2022 15:42:34 -0700
+Subject: [PATCH] PaperPR Fix exact choice recipe book clicks
+
+Taken from https://github.com/PaperMC/Paper/pull/7822
+
+diff --git a/src/main/java/net/minecraft/world/entity/player/StackedContents.java b/src/main/java/net/minecraft/world/entity/player/StackedContents.java
+index efee1a8e0e3ad566cd550e51d3e559c5a495889a..f75ff62be1630e3a86f917e18432769eb6d61abc 100644
+--- a/src/main/java/net/minecraft/world/entity/player/StackedContents.java
++++ b/src/main/java/net/minecraft/world/entity/player/StackedContents.java
+@@ -37,8 +37,62 @@ public class StackedContents {
+ int i = getStackingIndex(stack);
+ int j = Math.min(maxCount, stack.getCount());
+ this.put(i, j);
++ // Paper start
++ if (stack.hasTag()) {
++ this.put(getExactStackingIndex(stack), j);
++ }
++ }
++
++ }
++ private static final net.minecraft.core.IdMap EXACT_MATCHES_ID_MAP = new net.minecraft.core.IdMap<>() {
++ private final java.util.concurrent.atomic.AtomicInteger idCounter = new java.util.concurrent.atomic.AtomicInteger(Registry.ITEM.size());
++ private final it.unimi.dsi.fastutil.objects.Object2IntMap itemstackToId = new it.unimi.dsi.fastutil.objects.Object2IntOpenCustomHashMap<>(new it.unimi.dsi.fastutil.Hash.Strategy<>() {
++ @Override
++ public int hashCode(ItemStack o) {
++ return java.util.Objects.hash(o.getItem(), o.getTag());
++ }
++
++ @Override
++ public boolean equals(@Nullable ItemStack a, @Nullable ItemStack b) {
++ if (a == null || b == null) {
++ return false;
++ }
++ return ItemStack.isSameItemSameTags(a, b);
++ }
++ });
++ private final it.unimi.dsi.fastutil.ints.Int2ObjectMap idToItemstack = new it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap<>();
++
++ @Override
++ public int getId(ItemStack value) {
++ if (!this.itemstackToId.containsKey(value)) {
++ final int id = this.idCounter.incrementAndGet();
++ final ItemStack copy = value.copy();
++ this.itemstackToId.put(copy, id);
++ this.idToItemstack.put(id, copy);
++ return id;
++ }
++ return this.itemstackToId.getInt(value);
++ }
++
++ @Override
++ public @Nullable ItemStack byId(int index) {
++ return this.idToItemstack.get(index);
++ }
++
++ @Override
++ public int size() {
++ return this.itemstackToId.size();
++ }
++
++ @Override
++ public java.util.Iterator iterator() {
++ return this.idToItemstack.values().iterator();
+ }
++ };
+
++ public static int getExactStackingIndex(ItemStack stack) {
++ return EXACT_MATCHES_ID_MAP.getId(stack);
++ // Paper end
+ }
+
+ public static int getStackingIndex(ItemStack stack) {
+@@ -80,6 +134,12 @@ public class StackedContents {
+ }
+
+ public static ItemStack fromStackingIndex(int itemId) {
++ // Paper start
++ if (itemId > Registry.ITEM.size()) {
++ final ItemStack stack = EXACT_MATCHES_ID_MAP.byId(itemId);
++ return stack == null ? ItemStack.EMPTY : stack.copy();
++ }
++ // Paper end
+ return itemId == 0 ? ItemStack.EMPTY : new ItemStack(Item.byId(itemId));
+ }
+
+diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
+index 4fea1c9873b4dd9c9f21722adbb02200487caf3c..cd47b6882509888f7d34e95b4687ca7a9eab6caf 100644
+--- a/src/main/java/net/minecraft/world/item/ItemStack.java
++++ b/src/main/java/net/minecraft/world/item/ItemStack.java
+@@ -105,6 +105,7 @@ import org.bukkit.event.world.StructureGrowEvent;
+
+ public final class ItemStack {
+
++ public boolean isExactRecipeIngredient = false; // Paper
+ public static final Codec CODEC = RecordCodecBuilder.create((instance) -> {
+ return instance.group(Registry.ITEM.byNameCodec().fieldOf("id").forGetter((itemstack) -> {
+ return itemstack.item;
+diff --git a/src/main/java/net/minecraft/world/item/crafting/Ingredient.java b/src/main/java/net/minecraft/world/item/crafting/Ingredient.java
+index 895c0f1600139e340aa22a7c398978add56fa706..d5ced4c4ad354bbe6e6d256853de659923044299 100644
+--- a/src/main/java/net/minecraft/world/item/crafting/Ingredient.java
++++ b/src/main/java/net/minecraft/world/item/crafting/Ingredient.java
+@@ -54,7 +54,11 @@ public final class Ingredient implements Predicate {
+ if (this.itemStacks == null) {
+ this.itemStacks = (ItemStack[]) Arrays.stream(this.values).flatMap((recipeitemstack_provider) -> {
+ return recipeitemstack_provider.getItems().stream();
+- }).distinct().toArray((i) -> {
++ // Paper start
++ }).distinct().peek(stack -> {
++ stack.isExactRecipeIngredient = this.exact;
++ }).toArray((i) -> {
++ // Paper end
+ return new ItemStack[i];
+ });
+ }
+@@ -104,7 +108,13 @@ public final class Ingredient implements Predicate {
+ for (int j = 0; j < i; ++j) {
+ ItemStack itemstack = aitemstack[j];
+
++ // Paper start
++ if (itemstack.isExactRecipeIngredient) {
++ this.stackingIds.add(StackedContents.getExactStackingIndex(itemstack));
++ } else {
++ // Paper end
+ this.stackingIds.add(StackedContents.getStackingIndex(itemstack));
++ } // Paper
+ }
+
+ this.stackingIds.sort(IntComparators.NATURAL_COMPARATOR);
diff --git a/DivineMC/patches/server/0041-Fix-MC-238526.patch b/DivineMC/patches/server/0041-Fix-MC-238526.patch
new file mode 100644
index 0000000..ebd211e
--- /dev/null
+++ b/DivineMC/patches/server/0041-Fix-MC-238526.patch
@@ -0,0 +1,18 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: etil2jz <81570777+etil2jz@users.noreply.github.com>
+Date: Mon, 8 Aug 2022 11:21:49 +0200
+Subject: [PATCH] Fix MC-238526
+
+
+diff --git a/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java b/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java
+index 18389f46902bb9879ac6d734723e9a720724dc48..a50dff923743c9f916747abbf5c7d8c729ac8efe 100644
+--- a/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java
++++ b/src/main/java/net/minecraft/world/entity/animal/WaterAnimal.java
+@@ -83,6 +83,6 @@ public abstract class WaterAnimal extends PathfinderMob {
+ i = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.maximum.or(i);
+ j = world.getMinecraftWorld().paperConfig().entities.spawning.wateranimalSpawnHeight.minimum.or(j);
+ // Paper end
+- return pos.getY() >= j && pos.getY() <= i && world.getFluidState(pos.below()).is(FluidTags.WATER) && world.getBlockState(pos.above()).is(Blocks.WATER);
++ return ((reason == MobSpawnType.SPAWNER) || (pos.getY() >= j && pos.getY() <= i)) && world.getFluidState(pos.below()).is(FluidTags.WATER) && world.getBlockState(pos.above()).is(Blocks.WATER); // DivineMC
+ }
+ }
diff --git a/DivineMC/patches/server/0042-lithium-replace-AI-goal-set-with-optimized-collectio.patch b/DivineMC/patches/server/0042-lithium-replace-AI-goal-set-with-optimized-collectio.patch
new file mode 100644
index 0000000..270f64b
--- /dev/null
+++ b/DivineMC/patches/server/0042-lithium-replace-AI-goal-set-with-optimized-collectio.patch
@@ -0,0 +1,29 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: 2No2Name <2No2Name@web.de>
+Date: Sun, 12 Dec 2021 16:41:06 -0500
+Subject: [PATCH] lithium: replace AI goal set with optimized collection
+
+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/net/minecraft/world/entity/ai/goal/GoalSelector.java b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
+index 0cc0d719e95e108263683b7a40f4ce3a8ca9465b..abc27a60986602e84eb556436a65b997617852a1 100644
+--- a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
++++ b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
+@@ -12,6 +12,7 @@ import java.util.function.Supplier;
+ import java.util.stream.Stream;
+ import net.minecraft.util.profiling.ProfilerFiller;
+ import org.slf4j.Logger;
++import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet; // Lithium
+
+ public class GoalSelector {
+ private static final Logger LOGGER = LogUtils.getLogger();
+@@ -27,7 +28,7 @@ public class GoalSelector {
+ }
+ };
+ private final Map lockedFlags = new EnumMap<>(Goal.Flag.class);
+- public final Set availableGoals = Sets.newLinkedHashSet();
++ public final Set availableGoals = new ObjectLinkedOpenHashSet<>(); // Lithium - replace AI goal set with optimized collection
+ private final Supplier profiler;
+ private final EnumSet disabledFlags = EnumSet.noneOf(Goal.Flag.class); // Paper unused, but dummy to prevent plugins from crashing as hard. Theyll need to support paper in a special case if this is super important, but really doesn't seem like it would be.
+ private final com.destroystokyo.paper.util.set.OptimizedSmallEnumSet goalTypes = new com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from pathfindergoalselector
diff --git a/DivineMC/patches/server/0043-lithium-cached-hashcode.patch b/DivineMC/patches/server/0043-lithium-cached-hashcode.patch
new file mode 100644
index 0000000..70a534f
--- /dev/null
+++ b/DivineMC/patches/server/0043-lithium-cached-hashcode.patch
@@ -0,0 +1,44 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: jellysquid3
+Date: Wed, 15 Dec 2021 11:30:23 -0500
+Subject: [PATCH] lithium: cached hashcode
+
+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/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java
+index 9aa3aca48d443f81201e93402ec413a26bd92cf4..1834470b549d8352317cf081173ff542c9faac1e 100644
+--- a/src/main/java/net/minecraft/world/level/block/Block.java
++++ b/src/main/java/net/minecraft/world/level/block/Block.java
+@@ -614,11 +614,18 @@ public class Block extends BlockBehaviour implements ItemLike {
+ private final BlockState first;
+ private final BlockState second;
+ private final Direction direction;
++ private int hash; // JettPack
+
+ public BlockStatePairKey(BlockState self, BlockState other, Direction facing) {
+ this.first = self;
+ this.second = other;
+ this.direction = facing;
++ // JettPack start - lithium: cached_hashcode
++ int hash = this.first.hashCode();
++ hash = 31 * hash + this.second.hashCode();
++ hash = 31 * hash + this.direction.hashCode();
++ this.hash = hash;
++ // JettPack end
+ }
+
+ public boolean equals(Object object) {
+@@ -634,11 +641,7 @@ public class Block extends BlockBehaviour implements ItemLike {
+ }
+
+ public int hashCode() {
+- int i = this.first.hashCode();
+-
+- i = 31 * i + this.second.hashCode();
+- i = 31 * i + this.direction.hashCode();
+- return i;
++ return this.hash; // JettPack
+ }
+ }
+ }
diff --git a/DivineMC/patches/server/0044-vmp-skip-entity-move-if-movement-is-zero.patch b/DivineMC/patches/server/0044-vmp-skip-entity-move-if-movement-is-zero.patch
new file mode 100644
index 0000000..893fbe0
--- /dev/null
+++ b/DivineMC/patches/server/0044-vmp-skip-entity-move-if-movement-is-zero.patch
@@ -0,0 +1,43 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: ishland
+Date: Sun, 12 Dec 2021 17:19:00 -0500
+Subject: [PATCH] vmp: skip entity move if movement is zero
+
+Copyright (c) 2021-2022 ishland
+
+Original code by RelativityMC, licensed under MIT
+You can find the original code on https://github.com/RelativityMC/VMP-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 d96422f871c18303ce7ff7a182c685b0ddbfa04d..8a614fd335810b38c95f9f8b71f98b378893b985 100644
+--- a/src/main/java/net/minecraft/world/entity/Entity.java
++++ b/src/main/java/net/minecraft/world/entity/Entity.java
+@@ -299,6 +299,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
+ public float yRotO;
+ public float xRotO;
+ private AABB bb;
++ private boolean boundingBoxChanged = false; // DivineMC - vmp: skip entity move if movement is zero
+ public boolean onGround;
+ public boolean horizontalCollision;
+ public boolean verticalCollision;
+@@ -1032,6 +1033,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
+ // Paper end - detailed watchdog information
+
+ public void move(MoverType movementType, Vec3 movement) {
++ // DivineMC start - vmp: skip entity move if movement is zero
++ if (!boundingBoxChanged && movement.equals(Vec3.ZERO)) {
++ boundingBoxChanged = false;
++ return;
++ }
++ // DivineMC end
+ // Paper start - detailed watchdog information
+ io.papermc.paper.util.TickThread.ensureTickThread("Cannot move an entity off-main");
+ synchronized (this.posLock) {
+@@ -3755,6 +3762,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
+ }
+
+ public final void setBoundingBox(AABB boundingBox) {
++ if (!this.bb.equals(boundingBox)) boundingBoxChanged = true; // DivineMC - vmp: skip entity move if movement is zero
+ // CraftBukkit start - block invalid bounding boxes
+ double minX = boundingBox.minX,
+ minY = boundingBox.minY,
diff --git a/DivineMC/patches/server/0045-lithium-suffocation.patch b/DivineMC/patches/server/0045-lithium-suffocation.patch
new file mode 100644
index 0000000..15f50a9
--- /dev/null
+++ b/DivineMC/patches/server/0045-lithium-suffocation.patch
@@ -0,0 +1,100 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: etil2jz <81570777+etil2jz@users.noreply.github.com>
+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 8a614fd335810b38c95f9f8b71f98b378893b985..e1edcc723428717b5a03621fcf6072ca857f5c28 100644
+--- a/src/main/java/net/minecraft/world/entity/Entity.java
++++ b/src/main/java/net/minecraft/world/entity/Entity.java
+@@ -2584,39 +2584,64 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
+ return !this.isRemoved();
+ }
+
++ // DivineMC 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;
+ }
++ // DivineMC end
+
+ public InteractionResult interact(Player player, InteractionHand hand) {
+ return InteractionResult.PASS;
diff --git a/DivineMC/patches/server/0046-lithium-ai.sensor.secondary_poi.patch b/DivineMC/patches/server/0046-lithium-ai.sensor.secondary_poi.patch
new file mode 100644
index 0000000..eb5defb
--- /dev/null
+++ b/DivineMC/patches/server/0046-lithium-ai.sensor.secondary_poi.patch
@@ -0,0 +1,25 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: 2No2Name <2No2Name@web.de>
+Date: Tue, 15 Mar 2022 07:14:26 +0100
+Subject: [PATCH] lithium: ai.sensor.secondary_poi
+
+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/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java
+index cb1d91f9fe98f21c2afbe3894dfd9bca3bdd3ba6..d3f1a26cf3b68d85b8d8daef73730f5c4af76cf1 100644
+--- a/src/main/java/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java
++++ b/src/main/java/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java
+@@ -22,6 +22,12 @@ public class SecondaryPoiSensor extends Sensor {
+
+ @Override
+ protected void doTick(ServerLevel world, Villager entity) {
++ // DivineMC start - lithium: ai.sensor.secondary_poi
++ if (entity.getVillagerData().getProfession().secondaryPoi().isEmpty()) {
++ entity.getBrain().eraseMemory(MemoryModuleType.SECONDARY_JOB_SITE);
++ return;
++ }
++ // DivineMC end
+ ResourceKey resourceKey = world.dimension();
+ BlockPos blockPos = entity.blockPosition();
+ List list = Lists.newArrayList();
diff --git a/DivineMC/patches/server/0047-lithium-store-gamerules-in-fastutil-hashmap.patch b/DivineMC/patches/server/0047-lithium-store-gamerules-in-fastutil-hashmap.patch
new file mode 100644
index 0000000..21ee0bf
--- /dev/null
+++ b/DivineMC/patches/server/0047-lithium-store-gamerules-in-fastutil-hashmap.patch
@@ -0,0 +1,40 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: 2No2Name <2No2Name@web.de>
+Date: Tue, 21 Dec 2021 09:43:24 -0500
+Subject: [PATCH] lithium: store gamerules in fastutil hashmap
+
+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/net/minecraft/world/level/GameRules.java b/src/main/java/net/minecraft/world/level/GameRules.java
+index 17e869074b8cf29a8c3280499a27e95179896750..97a5aec7da267b8b9f6d191c871316ccb89c448c 100644
+--- a/src/main/java/net/minecraft/world/level/GameRules.java
++++ b/src/main/java/net/minecraft/world/level/GameRules.java
+@@ -27,6 +27,7 @@ import net.minecraft.network.protocol.game.ClientboundGameEventPacket;
+ import net.minecraft.server.MinecraftServer;
+ import net.minecraft.server.level.ServerPlayer;
+ import org.slf4j.Logger;
++import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; // JettPack
+
+ public class GameRules {
+
+@@ -111,14 +112,16 @@ public class GameRules {
+
+ public GameRules() {
+ // Pufferfish start - use this to ensure gameruleArray is initialized
+- this((Map) GameRules.GAME_RULE_TYPES.entrySet().stream().collect(ImmutableMap.toImmutableMap(Entry::getKey, (entry) -> {
++ // JettPack start - lithium: store gamerules in fastutil hashmap
++ this(new Object2ObjectOpenHashMap<>((Map) GameRules.GAME_RULE_TYPES.entrySet().stream().collect(ImmutableMap.toImmutableMap(Entry::getKey, (entry) -> {
+ return ((GameRules.Type) entry.getValue()).createRule();
+- })));
++ }))));
++ // JettPack end
+ // Pufferfish end
+ }
+
+ private GameRules(Map, GameRules.Value>> rules) {
+- this.rules = rules;
++ this.rules = new Object2ObjectOpenHashMap<>(rules); // JettPack - lithium: store gamerules in fastutil hashmap
+
+ // Pufferfish start
+ int arraySize = rules.keySet().stream().mapToInt(key -> key.gameRuleIndex).max().orElse(-1) + 1;
diff --git a/DivineMC/patches/server/0048-lithium-precompute-shape-arrays.patch b/DivineMC/patches/server/0048-lithium-precompute-shape-arrays.patch
new file mode 100644
index 0000000..6a8af23
--- /dev/null
+++ b/DivineMC/patches/server/0048-lithium-precompute-shape-arrays.patch
@@ -0,0 +1,77 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: jellysquid3
+Date: Sat, 1 Jan 2022 03:59:58 -0500
+Subject: [PATCH] lithium: precompute shape arrays
+
+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/net/minecraft/core/Direction.java b/src/main/java/net/minecraft/core/Direction.java
+index 2217968eb5ecac0a2063cf1eae7d754d760e9f28..445f21c3764d148de937f558e3f087ae2006733d 100644
+--- a/src/main/java/net/minecraft/core/Direction.java
++++ b/src/main/java/net/minecraft/core/Direction.java
+@@ -41,7 +41,7 @@ public enum Direction implements StringRepresentable {
+ private final Direction.Axis axis;
+ private final Direction.AxisDirection axisDirection;
+ private final Vec3i normal;
+- private static final Direction[] VALUES = values();
++ public static final Direction[] VALUES = values(); // JettPack
+ private static final Direction[] BY_3D_DATA = Arrays.stream(VALUES).sorted(Comparator.comparingInt((direction) -> {
+ return direction.data3d;
+ })).toArray((i) -> {
+diff --git a/src/main/java/net/minecraft/world/phys/shapes/CubePointRange.java b/src/main/java/net/minecraft/world/phys/shapes/CubePointRange.java
+index a544db042c8d2ecec8d323770552c4f10ca758a6..c04da8da5b40430b61972bce32cec4e8c0370bac 100644
+--- a/src/main/java/net/minecraft/world/phys/shapes/CubePointRange.java
++++ b/src/main/java/net/minecraft/world/phys/shapes/CubePointRange.java
+@@ -4,6 +4,7 @@ import it.unimi.dsi.fastutil.doubles.AbstractDoubleList;
+
+ public class CubePointRange extends AbstractDoubleList {
+ private final int parts;
++ private double scale; // JettPack - lithium: shapes.precompute_shape_arrays
+
+ CubePointRange(int sectionCount) {
+ if (sectionCount <= 0) {
+@@ -11,10 +12,11 @@ public class CubePointRange extends AbstractDoubleList {
+ } else {
+ this.parts = sectionCount;
+ }
++ this.scale = 1.0D / sectionCount; // JettPack - lithium: shapes.precompute_shape_arrays
+ }
+
+ public double getDouble(int i) {
+- return (double)i / (double)this.parts;
++ return i * this.scale; // JettPack - lithium: shapes.precompute_shape_arrays
+ }
+
+ public int size() {
+diff --git a/src/main/java/net/minecraft/world/phys/shapes/CubeVoxelShape.java b/src/main/java/net/minecraft/world/phys/shapes/CubeVoxelShape.java
+index 68e89dbd79171627046e89699057964e44c40e7d..959588962acb0196ec9f1cc2502e62117f6ccdc4 100644
+--- a/src/main/java/net/minecraft/world/phys/shapes/CubeVoxelShape.java
++++ b/src/main/java/net/minecraft/world/phys/shapes/CubeVoxelShape.java
+@@ -3,15 +3,25 @@ package net.minecraft.world.phys.shapes;
+ import it.unimi.dsi.fastutil.doubles.DoubleList;
+ import net.minecraft.core.Direction;
+ import net.minecraft.util.Mth;
++import net.minecraft.world.phys.shapes.CubePointRange; // JettPack
+
+ public final class CubeVoxelShape extends VoxelShape {
++ private DoubleList[] list; // JettPack - lithium: shapes.precompute_shape_arrays
++
+ protected CubeVoxelShape(DiscreteVoxelShape voxels) {
+ super(voxels);
++ // JettPack start - lithium: shapes.precompute_shape_arrays
++ this.list = new DoubleList[Direction.VALUES.length];
++
++ for (Direction.Axis axis : Direction.Axis.VALUES) {
++ this.list[axis.ordinal()] = new CubePointRange(voxels.getSize(axis));
++ }
++ // JettPack end
+ }
+
+ @Override
+ protected DoubleList getCoords(Direction.Axis axis) {
+- return new CubePointRange(this.shape.getSize(axis));
++ return this.list[axis.ordinal()]; // JettPack - lithium: shapes.precompute_shape_arrays
+ }
+
+ @Override
diff --git a/DivineMC/patches/server/0049-lithium-entity.fast_elytra_check.patch b/DivineMC/patches/server/0049-lithium-entity.fast_elytra_check.patch
new file mode 100644
index 0000000..6a83da1
--- /dev/null
+++ b/DivineMC/patches/server/0049-lithium-entity.fast_elytra_check.patch
@@ -0,0 +1,21 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: 2No2Name <2No2Name@web.de>
+Date: Sat, 8 Jan 2022 04:32:41 +0100
+Subject: [PATCH] lithium: entity.fast_elytra_check
+
+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/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
+index c0e316582e085873c05a76c16e612eabd2e8cf2a..dbcabd230bd9bd070e157f35d098553f3ed06987 100644
+--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
+@@ -3428,6 +3428,8 @@ public abstract class LivingEntity extends Entity {
+ }
+
+ private void updateFallFlying() {
++ if (!this.isFallFlying()) return; // DivineMC
++
+ boolean flag = this.getSharedFlag(7);
+
+ if (flag && !this.onGround && !this.isPassenger() && !this.hasEffect(MobEffects.LEVITATION)) {
diff --git a/DivineMC/patches/server/0050-lithium-entity.fast_hand_swing.patch b/DivineMC/patches/server/0050-lithium-entity.fast_hand_swing.patch
new file mode 100644
index 0000000..b40ce55
--- /dev/null
+++ b/DivineMC/patches/server/0050-lithium-entity.fast_hand_swing.patch
@@ -0,0 +1,21 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: 2No2Name <2No2Name@web.de>
+Date: Sun, 9 Jan 2022 06:03:28 +0100
+Subject: [PATCH] lithium: entity.fast_hand_swing
+
+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/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
+index dbcabd230bd9bd070e157f35d098553f3ed06987..2cd8dfe953ac72f6be14557ab39d3cec1108499e 100644
+--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
+@@ -2488,6 +2488,8 @@ public abstract class LivingEntity extends Entity {
+ }
+
+ protected void updateSwingTime() {
++ if (!this.swinging && this.swingTime == 0) return; // DivineMC
++
+ int i = this.getCurrentSwingDuration();
+
+ if (this.swinging) {
diff --git a/DivineMC/patches/server/0051-lithium-entity.fast_powder_snow_check.patch b/DivineMC/patches/server/0051-lithium-entity.fast_powder_snow_check.patch
new file mode 100644
index 0000000..f4a24fe
--- /dev/null
+++ b/DivineMC/patches/server/0051-lithium-entity.fast_powder_snow_check.patch
@@ -0,0 +1,35 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: 2No2Name <2No2Name@web.de>
+Date: Sat, 8 Jan 2022 03:51:28 +0100
+Subject: [PATCH] lithium: entity.fast_powder_snow_check
+
+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/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
+index 2cd8dfe953ac72f6be14557ab39d3cec1108499e..d6f7fd9dc4804e7565c89a9cbb0948f256559f03 100644
+--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
+@@ -569,11 +569,11 @@ public abstract class LivingEntity extends Entity {
+ }
+
+ protected void tryAddFrost() {
+- if (!this.getBlockStateOnLegacy().isAir()) {
++ //if (!this.getBlockStateOnLegacy().isAir()) { // DivineMC
+ int i = this.getTicksFrozen();
+
+ if (i > 0) {
+- AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED);
++ AttributeInstance attributemodifiable = this.getBlockStateOnLegacy().isAir() ? null : this.getAttribute(Attributes.MOVEMENT_SPEED); // DivineMC
+
+ if (attributemodifiable == null) {
+ return;
+@@ -583,7 +583,7 @@ public abstract class LivingEntity extends Entity {
+
+ attributemodifiable.addTransientModifier(new AttributeModifier(LivingEntity.SPEED_MODIFIER_POWDER_SNOW_UUID, "Powder snow slow", (double) f, AttributeModifier.Operation.ADDITION));
+ }
+- }
++ //} // DivineMC
+
+ }
+
diff --git a/DivineMC/patches/server/0052-lithium-collections.attributes.patch b/DivineMC/patches/server/0052-lithium-collections.attributes.patch
new file mode 100644
index 0000000..8cc6009
--- /dev/null
+++ b/DivineMC/patches/server/0052-lithium-collections.attributes.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: 2No2Name <2No2Name@web.de>
+Date: Sun, 9 Jan 2022 17:53:11 +0100
+Subject: [PATCH] lithium: collections.attributes
+
+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/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java
+index 9bce290eb0c2cfef4896a3f2076c80bf3d76bd56..ac56484b1bf19dabe4bdd5b25eafa4ac38f08cbe 100644
+--- a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java
++++ b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java
+@@ -16,11 +16,13 @@ import net.minecraft.nbt.CompoundTag;
+ import net.minecraft.nbt.ListTag;
+ import net.minecraft.resources.ResourceLocation;
+ import org.slf4j.Logger;
++import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; // DivineMC
++import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; // DivineMC
+
+ public class AttributeMap {
+ private static final Logger LOGGER = LogUtils.getLogger();
+- private final Map attributes = Maps.newHashMap();
+- private final Set dirtyAttributes = Sets.newHashSet();
++ private final Map attributes = new Reference2ReferenceOpenHashMap<>(0); // DivineMC
++ private final Set dirtyAttributes = new ReferenceOpenHashSet<>(0); // DivineMC
+ private final AttributeSupplier supplier;
+ private final java.util.function.Function createInstance; // Pufferfish
+
diff --git a/DivineMC/patches/server/0053-lithium-collections.entity_by_type.patch b/DivineMC/patches/server/0053-lithium-collections.entity_by_type.patch
new file mode 100644
index 0000000..ab195eb
--- /dev/null
+++ b/DivineMC/patches/server/0053-lithium-collections.entity_by_type.patch
@@ -0,0 +1,38 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: 2No2Name <2No2Name@web.de>
+Date: Fri, 7 Jan 2022 06:43:30 +0100
+Subject: [PATCH] lithium: collections.entity_by_type
+
+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/net/minecraft/util/ClassInstanceMultiMap.java b/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java
+index 50a9f33aa31e9273c7c52d4bb2b02f0f884f7ba5..9698c093dd8c18a5a5a4b157c3799191841552e2 100644
+--- a/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java
++++ b/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java
+@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList;
+ import com.google.common.collect.Iterators;
+ import com.google.common.collect.Lists;
+ import com.google.common.collect.Maps;
++import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; // JettPack
+ import java.util.AbstractCollection;
+ import java.util.Collection;
+ import java.util.Collections;
+@@ -13,7 +14,7 @@ import java.util.Map;
+ import java.util.stream.Collectors;
+
+ public class ClassInstanceMultiMap extends AbstractCollection {
+- private final Map, List> byClass = Maps.newHashMap();
++ private final Map, List> byClass = new Reference2ReferenceOpenHashMap<>(); // JettPack
+ private final Class baseClass;
+ private final List allInstances = Lists.newArrayList();
+
+@@ -58,7 +59,7 @@ public class ClassInstanceMultiMap extends AbstractCollection {
+ if (!this.baseClass.isAssignableFrom(type)) {
+ throw new IllegalArgumentException("Don't know how to search for " + type);
+ } else {
+- List extends T> list = this.byClass.computeIfAbsent(type, (typeClass) -> {
++ List list = this.byClass.computeIfAbsent(type, (typeClass) -> { // JettPack - decomp fix
+ return this.allInstances.stream().filter(typeClass::isInstance).collect(Collectors.toList());
+ });
+ return Collections.unmodifiableCollection(list);
diff --git a/DivineMC/patches/server/0054-lithium-collections.entity_filtering.patch b/DivineMC/patches/server/0054-lithium-collections.entity_filtering.patch
new file mode 100644
index 0000000..4280e8a
--- /dev/null
+++ b/DivineMC/patches/server/0054-lithium-collections.entity_filtering.patch
@@ -0,0 +1,52 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: 2No2Name <2No2Name@web.de>
+Date: Sat, 8 Jan 2022 03:33:04 +0100
+Subject: [PATCH] lithium: collections.entity_filtering
+
+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/net/minecraft/util/ClassInstanceMultiMap.java b/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java
+index 9698c093dd8c18a5a5a4b157c3799191841552e2..6f181fc878a96b09f126ea8d3b19ce3ee4588e19 100644
+--- a/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java
++++ b/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java
+@@ -56,15 +56,32 @@ public class ClassInstanceMultiMap extends AbstractCollection {
+ }
+
+ public Collection find(Class type) {
+- if (!this.baseClass.isAssignableFrom(type)) {
+- throw new IllegalArgumentException("Don't know how to search for " + type);
+- } else {
+- List list = this.byClass.computeIfAbsent(type, (typeClass) -> { // JettPack - decomp fix
+- return this.allInstances.stream().filter(typeClass::isInstance).collect(Collectors.toList());
+- });
+- return Collections.unmodifiableCollection(list);
++ // JettPack start
++ Collection collection = this.byClass.get(type);
++
++ if (collection == null) {
++ collection = this.createAllOfType(type);
+ }
++
++ return (Collection) Collections.unmodifiableCollection(collection);
++ // JettPack end
++ }
++
++ // JettPack start
++ private Collection createAllOfType(Class type) {
++ List list = new java.util.ArrayList<>();
++
++ for (T allElement : this.allInstances) {
++ if (type.isInstance(allElement)) {
++ list.add(allElement);
++ }
++ }
++
++ this.byClass.put(type, list);
++
++ return list;
+ }
++ // JettPack end
+
+ @Override
+ public Iterator iterator() {
diff --git a/DivineMC/patches/server/0055-lithium-chunk.serialization.patch b/DivineMC/patches/server/0055-lithium-chunk.serialization.patch
new file mode 100644
index 0000000..073c398
--- /dev/null
+++ b/DivineMC/patches/server/0055-lithium-chunk.serialization.patch
@@ -0,0 +1,458 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: jellysquid3
+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..5f578da4a7251b17d6a12821a3cd090e66b52a8a 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/DivineMC/patches/server/0056-lithium-cache-iterate-outwards.patch b/DivineMC/patches/server/0056-lithium-cache-iterate-outwards.patch
new file mode 100644
index 0000000..8664b26
--- /dev/null
+++ b/DivineMC/patches/server/0056-lithium-cache-iterate-outwards.patch
@@ -0,0 +1,175 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: 2No2Name <2No2Name@web.de>
+Date: Thu, 13 Jan 2022 15:38:29 -0500
+Subject: [PATCH] lithium: cache iterate outwards
+
+Original code by the PR below, licensed under GNU Lesser General Public License v3.0
+You can find the original code on https://github.com/CaffeineMC/lithium-fabric/pull/123 (Yarn mappings)
+
+diff --git a/src/main/java/me/jellysquid/mods/lithium/common/cached_blockpos_iteration/IterateOutwardsCache.java b/src/main/java/me/jellysquid/mods/lithium/common/cached_blockpos_iteration/IterateOutwardsCache.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..a5d3aa309d3fdaab9e0fea2dfb91a080a3ac1193
+--- /dev/null
++++ b/src/main/java/me/jellysquid/mods/lithium/common/cached_blockpos_iteration/IterateOutwardsCache.java
+@@ -0,0 +1,71 @@
++package me.jellysquid.mods.lithium.common.cached_blockpos_iteration;
++
++import it.unimi.dsi.fastutil.longs.LongArrayList;
++import it.unimi.dsi.fastutil.longs.LongList;
++import java.util.Iterator;
++import java.util.Random;
++import java.util.concurrent.ConcurrentHashMap;
++import net.minecraft.core.BlockPos;
++
++/**
++ * @author 2No2Name, original implemenation by SuperCoder7979 and Gegy1000
++ */
++public class IterateOutwardsCache {
++ //POS_ZERO must not be replaced with BlockPos.ORIGIN, otherwise iterateOutwards at BlockPos.ORIGIN will not use the cache
++ public static final BlockPos POS_ZERO = new BlockPos(0,0,0);
++
++
++ private final ConcurrentHashMap table;
++ private final int capacity;
++ private final Random random;
++
++ public IterateOutwardsCache(int capacity) {
++ this.capacity = capacity;
++ this.table = new ConcurrentHashMap<>(31);
++ this.random = new Random();
++ }
++
++ private void fillPositionsWithIterateOutwards(LongList entry, int xRange, int yRange, int zRange) {
++ // Add all positions to the cached list
++ for (BlockPos pos : BlockPos.withinManhattan(POS_ZERO, xRange, yRange, zRange)) {
++ entry.add(pos.asLong());
++ }
++ }
++
++ public LongList getOrCompute(int xRange, int yRange, int zRange) {
++ long key = BlockPos.asLong(xRange, yRange, zRange);
++
++ LongArrayList entry = this.table.get(key);
++ if (entry != null) {
++ return entry;
++ }
++
++ // Cache miss: compute and store
++ entry = new LongArrayList(128);
++
++ this.fillPositionsWithIterateOutwards(entry, xRange, yRange, zRange);
++
++ //decrease the array size, as of now it won't be modified anymore anyways
++ entry.trim();
++
++ //this might overwrite an entry as the same entry could have been computed and added during this thread's computation
++ //we do not use computeIfAbsent, as it can delay other threads for too long
++ Object previousEntry = this.table.put(key, entry);
++
++
++ if (previousEntry == null && this.table.size() > this.capacity) {
++ //prevent a memory leak by randomly removing about 1/8th of the elements when the exceed the desired capacity is exceeded
++ final Iterator iterator = this.table.keySet().iterator();
++ //prevent an unlikely infinite loop caused by another thread filling the table concurrently using counting
++ for (int i = -this.capacity; iterator.hasNext() && i < 5; i++) {
++ Long key2 = iterator.next();
++ //random is not threadsafe, but it doesn't matter here, because we don't need quality random numbers
++ if (this.random.nextInt(8) == 0 && key2 != key) {
++ iterator.remove();
++ }
++ }
++ }
++
++ return entry;
++ }
++}
+\ No newline at end of file
+diff --git a/src/main/java/me/jellysquid/mods/lithium/common/cached_blockpos_iteration/LongList2BlockPosMutableIterable.java b/src/main/java/me/jellysquid/mods/lithium/common/cached_blockpos_iteration/LongList2BlockPosMutableIterable.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..493661ff3ac7247b68b7b02784b09b0eaf88fc52
+--- /dev/null
++++ b/src/main/java/me/jellysquid/mods/lithium/common/cached_blockpos_iteration/LongList2BlockPosMutableIterable.java
+@@ -0,0 +1,46 @@
++package me.jellysquid.mods.lithium.common.cached_blockpos_iteration;
++
++import it.unimi.dsi.fastutil.longs.LongIterator;
++import it.unimi.dsi.fastutil.longs.LongList;
++import java.util.Iterator;
++import net.minecraft.core.BlockPos;
++
++/**
++ * @author 2No2Name
++ */
++public class LongList2BlockPosMutableIterable implements Iterable {
++
++ private final LongList positions;
++ private final int xOffset, yOffset, zOffset;
++
++ public LongList2BlockPosMutableIterable(BlockPos offset, LongList posList) {
++ this.xOffset = offset.getX();
++ this.yOffset = offset.getY();
++ this.zOffset = offset.getZ();
++ this.positions = posList;
++ }
++
++ @Override
++ public Iterator iterator() {
++ return new Iterator() {
++
++ private final LongIterator it = LongList2BlockPosMutableIterable.this.positions.iterator();
++ private final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
++
++ @Override
++ public boolean hasNext() {
++ return it.hasNext();
++ }
++
++ @Override
++ public net.minecraft.core.BlockPos next() {
++ long nextPos = this.it.nextLong();
++ return this.pos.set(
++ LongList2BlockPosMutableIterable.this.xOffset + BlockPos.getX(nextPos),
++ LongList2BlockPosMutableIterable.this.yOffset + BlockPos.getY(nextPos),
++ LongList2BlockPosMutableIterable.this.zOffset + BlockPos.getZ(nextPos));
++ }
++ };
++ }
++
++}
+\ No newline at end of file
+diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java
+index 153451ecd5b3c8e8ecb2d5ec91ccd582d4300899..4487752469f9ab95e9d2aeb76a9627dc02095d76 100644
+--- a/src/main/java/net/minecraft/core/BlockPos.java
++++ b/src/main/java/net/minecraft/core/BlockPos.java
+@@ -18,6 +18,12 @@ import net.minecraft.world.phys.AABB;
+ import net.minecraft.world.phys.Vec3;
+ import org.apache.commons.lang3.Validate;
+ import org.slf4j.Logger;
++// JettPack start
++import it.unimi.dsi.fastutil.longs.LongList;
++import me.jellysquid.mods.lithium.common.cached_blockpos_iteration.IterateOutwardsCache;
++import me.jellysquid.mods.lithium.common.cached_blockpos_iteration.LongList2BlockPosMutableIterable;
++import static me.jellysquid.mods.lithium.common.cached_blockpos_iteration.IterateOutwardsCache.POS_ZERO;
++// JettPack end
+
+ @Immutable
+ public class BlockPos extends Vec3i {
+@@ -284,7 +290,18 @@ public class BlockPos extends Vec3i {
+ };
+ }
+
++ // JettPack start - lithium: cached iterate outwards
++ private static final IterateOutwardsCache ITERATE_OUTWARDS_CACHE = new IterateOutwardsCache(50);
++ private static final LongList HOGLIN_PIGLIN_CACHE = ITERATE_OUTWARDS_CACHE.getOrCompute(8, 4, 8);
++ // JettPack end
++
+ public static Iterable withinManhattan(BlockPos center, int rangeX, int rangeY, int rangeZ) {
++ // JettPack start - lithium: cached iterate outwards
++ if (center != POS_ZERO) {
++ final LongList positions = rangeX == 8 && rangeY == 4 && rangeZ == 8 ? HOGLIN_PIGLIN_CACHE : ITERATE_OUTWARDS_CACHE.getOrCompute(rangeX, rangeY, rangeZ);
++ return new LongList2BlockPosMutableIterable(center, positions);
++ }
++ // JettPack end
+ int i = rangeX + rangeY + rangeZ;
+ // Paper start - rename variables to fix conflict with anonymous class (remap fix)
+ int centerX = center.getX();
diff --git a/DivineMC/patches/server/0057-vmp-use-linked-map-for-entity-trackers-for-faster-it.patch b/DivineMC/patches/server/0057-vmp-use-linked-map-for-entity-trackers-for-faster-it.patch
new file mode 100644
index 0000000..e4e7b11
--- /dev/null
+++ b/DivineMC/patches/server/0057-vmp-use-linked-map-for-entity-trackers-for-faster-it.patch
@@ -0,0 +1,31 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: ishland
+Date: Sat, 12 Mar 2022 16:03:35 +0100
+Subject: [PATCH] vmp: use linked map for entity trackers for faster iteration
+
+Copyright (c) 2021-2022 ishland
+
+Original code by RelativityMC, licensed under MIT
+You can find the original code on https://github.com/RelativityMC/VMP-fabric (Yarn mappings)
+
+diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
+index 9976630fad886392057f642e84f919f0b95cc040..c01c22b6fda9e36a2336a992c760b813b71469ce 100644
+--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
+@@ -111,6 +111,7 @@ import org.bukkit.entity.Player;
+ // CraftBukkit end
+
+ import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; // Paper
++import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap; // DivineMC - vmp: use linked map for entity trackers for faster iteration
+
+ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider {
+
+@@ -291,7 +292,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
+ // Paper - rewrite chunk system
+ this.tickingGenerated = new AtomicInteger();
+ this.playerMap = new PlayerMap();
+- this.entityMap = new Int2ObjectOpenHashMap();
++ this.entityMap = new Int2ObjectLinkedOpenHashMap<>(); // DivineMC - vmp: use linked map for entity trackers for faster iteration
+ this.chunkTypeCache = new Long2ByteOpenHashMap();
+ this.chunkSaveCooldowns = new Long2LongOpenHashMap();
+ this.unloadQueue = Queues.newConcurrentLinkedQueue();
diff --git a/DivineMC/patches/server/0058-lithium-block.moving_block_shapes.patch b/DivineMC/patches/server/0058-lithium-block.moving_block_shapes.patch
new file mode 100644
index 0000000..c230043
--- /dev/null
+++ b/DivineMC/patches/server/0058-lithium-block.moving_block_shapes.patch
@@ -0,0 +1,164 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: 2No2Name <2No2Name@web.de>
+Date: Fri, 21 Jan 2022 08:41:34 -0500
+Subject: [PATCH] lithium: block.moving_block_shapes
+
+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/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
+index 7c59d44a3bafdc65f453d77ff3e25cffb742ad6c..636721a111cad13e7329f1157981ca03a8f339b3 100644
+--- a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
++++ b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
+@@ -52,6 +52,74 @@ public class PistonMovingBlockEntity extends BlockEntity {
+ this.extending = extending;
+ this.isSourcePiston = source;
+ }
++ // JettPack start - lithium: block.moving_block_shapes
++ private static final VoxelShape[] PISTON_BASE_WITH_MOVING_HEAD_SHAPES = precomputePistonBaseWithMovingHeadShapes();
++
++ /**
++ * We cache the offset and simplified VoxelShapes that are otherwise constructed on every call of getCollisionShape.
++ * For each offset direction and distance (6 directions, 2 distances each, and no direction with 0 distance) we
++ * store the offset and simplified VoxelShapes in the original VoxelShape when they are accessed the first time.
++ * We use safe publication, because both the Render and Server thread are using the cache.
++ *
++ * @param blockShape the original shape, must not be modified after passing it as an argument to this method
++ * @param offset the offset distance
++ * @param direction the offset direction
++ * @return blockShape offset and simplified
++ */
++ private static VoxelShape getOffsetAndSimplified(VoxelShape blockShape, float offset, Direction direction) {
++ VoxelShape offsetSimplifiedShape = blockShape.getOffsetSimplifiedShape(offset, direction);
++ if (offsetSimplifiedShape == null) {
++ //create the offset shape and store it for later use
++ offsetSimplifiedShape = blockShape.move(direction.getStepX() * offset, direction.getStepY() * offset, direction.getStepZ() * offset).optimize();
++ blockShape.setShape(offset, direction, offsetSimplifiedShape);
++ }
++ return offsetSimplifiedShape;
++ }
++
++ /**
++ * Precompute all 18 possible configurations for the merged piston base and head shape.
++ *
++ * @return The array of the merged VoxelShapes, indexed by {@link PistonBlockEntityMixin#getIndexForMergedShape(float, Direction)}
++ */
++ private static VoxelShape[] precomputePistonBaseWithMovingHeadShapes() {
++ float[] offsets = {0f, 0.5f, 1f};
++ Direction[] directions = Direction.values();
++
++ VoxelShape[] mergedShapes = new VoxelShape[offsets.length * directions.length];
++
++ for (Direction facing : directions) {
++ VoxelShape baseShape = Blocks.PISTON.defaultBlockState().setValue(PistonBaseBlock.EXTENDED, true)
++ .setValue(PistonBaseBlock.FACING, facing).getCollisionShape(null, null);
++ for (float offset : offsets) {
++ //this cache is only required for the merged piston head + base shape.
++ //this shape is only used when !this.extending
++ //here: isShort = this.extending != 1.0F - this.progress < 0.25F can be simplified to:
++ //isShort = f < 0.25F , because f = getAmountExtended(this.progress) can be simplified to f == 1.0F - this.progress
++ //therefore isShort is dependent on the offset:
++ boolean isShort = offset < 0.25f;
++
++ VoxelShape headShape = (Blocks.PISTON_HEAD.defaultBlockState().setValue(PistonHeadBlock.FACING, facing))
++ .setValue(PistonHeadBlock.SHORT, isShort).getCollisionShape(null, null);
++
++ VoxelShape offsetHead = headShape.move(facing.getStepX() * offset,
++ facing.getStepY() * offset,
++ facing.getStepZ() * offset);
++ mergedShapes[getIndexForMergedShape(offset, facing)] = Shapes.or(baseShape, offsetHead);
++ }
++
++ }
++
++ return mergedShapes;
++ }
++
++ private static int getIndexForMergedShape(float offset, Direction direction) {
++ if (offset != 0f && offset != 0.5f && offset != 1f) {
++ return -1;
++ }
++ //shape of offset 0 is still dependent on the direction, due to piston head and base being directional blocks
++ return (int) (2 * offset) + (3 * direction.get3DDataValue());
++ }
++ // JettPack end
+
+ @Override
+ public CompoundTag getUpdateTag() {
+@@ -351,10 +419,27 @@ public class PistonMovingBlockEntity extends BlockEntity {
+ }
+
+ float f = this.getExtendedProgress(this.progress);
++ // JettPack start - lithium: block.moving_block_shapes
++ if (this.extending || !this.isSourcePiston || !(this.movedState.getBlock() instanceof PistonBaseBlock)) {
++ //here voxelShape2.isEmpty() is guaranteed, vanilla code would call union() which calls simplify()
++ VoxelShape blockShape = blockState.getCollisionShape(world, pos);
++
++ //we cache the simplified shapes, as the simplify() method costs a lot of CPU time and allocates several objects
++ VoxelShape offsetAndSimplified = getOffsetAndSimplified(blockShape, Math.abs(f), f < 0f ? this.direction.getOpposite() : this.direction);
++ return offsetAndSimplified;
++ } else {
++ //retracting piston heads have to act like their base as well, as the base block is replaced with the moving block
++ //f >= 0f is guaranteed (assuming no other mod interferes)
++ int index = getIndexForMergedShape(f, this.direction);
++ return PISTON_BASE_WITH_MOVING_HEAD_SHAPES[index];
++ }
++ /*
+ double d = (double)((float)this.direction.getStepX() * f);
+ double e = (double)((float)this.direction.getStepY() * f);
+ double g = (double)((float)this.direction.getStepZ() * f);
+ return Shapes.or(voxelShape, blockState.getCollisionShape(world, pos).move(d, e, g));
++ */
++ // JettPack end
+ }
+ }
+
+diff --git a/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java b/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java
+index 2182afd1b95acf14c55bddfeec17dae0a63e1f00..461ac9a464c4a66e302798032c6019bb60f6862b 100644
+--- a/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java
++++ b/src/main/java/net/minecraft/world/phys/shapes/VoxelShape.java
+@@ -26,6 +26,44 @@ public abstract class VoxelShape {
+ }
+ // Paper end
+
++ // JettPack start - lithium: block.moving_block_shapes
++ private volatile VoxelShape[] offsetAndSimplified;
++
++ public void setShape(float offset, Direction direction, VoxelShape offsetShape) {
++ if (offsetShape == null) {
++ throw new IllegalArgumentException("offsetShape must not be null!");
++ }
++ int index = getIndexForOffsetSimplifiedShapes(offset, direction);
++ VoxelShape[] offsetAndSimplifiedShapes = this.offsetAndSimplified;
++ if (offsetAndSimplifiedShapes == null) {
++ offsetAndSimplifiedShapes = new VoxelShape[1 + 2 * 6];
++ } else {
++ offsetAndSimplifiedShapes = offsetAndSimplifiedShapes.clone();
++ }
++ offsetAndSimplifiedShapes[index] = offsetShape;
++ this.offsetAndSimplified = offsetAndSimplifiedShapes;
++ }
++
++ public VoxelShape getOffsetSimplifiedShape(float offset, Direction direction) {
++ VoxelShape[] offsetAndSimplified = this.offsetAndSimplified;
++ if (offsetAndSimplified == null) {
++ return null;
++ }
++ int index = getIndexForOffsetSimplifiedShapes(offset, direction);
++ return offsetAndSimplified[index];
++ }
++
++ private static int getIndexForOffsetSimplifiedShapes(float offset, Direction direction) {
++ if (offset != 0f && offset != 0.5f && offset != 1f) {
++ throw new IllegalArgumentException("offset must be one of {0f, 0.5f, 1f}");
++ }
++ if (offset == 0f) {
++ return 0; //can treat offsetting by 0 in all directions the same
++ }
++ return (int) (2 * offset) + 2 * direction.get3DDataValue();
++ }
++ // JettPack end
++
+ protected VoxelShape(DiscreteVoxelShape voxels) { // Paper - protected
+ this.shape = voxels;
+ }
diff --git a/DivineMC/patches/server/0059-Skip-cloning-loot-parameters.patch b/DivineMC/patches/server/0059-Skip-cloning-loot-parameters.patch
new file mode 100644
index 0000000..c18553a
--- /dev/null
+++ b/DivineMC/patches/server/0059-Skip-cloning-loot-parameters.patch
@@ -0,0 +1,19 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: NONPLAY