diff --git a/patches/unapplied/server/0039-NachoSpigot-Async-Explosion.patch b/patches/unapplied/server/0039-NachoSpigot-Async-Explosion.patch new file mode 100644 index 00000000..b649aa86 --- /dev/null +++ b/patches/unapplied/server/0039-NachoSpigot-Async-Explosion.patch @@ -0,0 +1,178 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com> +Date: Sun, 3 Sep 2023 05:14:45 -0400 +Subject: [PATCH] NachoSpigot: Async Explosion + +Original code by CobbleSword, licensed under GPL v3 +You can find the original code on https://github.com/CobbleSword/NachoSpigot + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 312ba9705533f5790a95ed484d32ca46e9377887..40e8d55244f53ac867dad0f56994e60ca83a80f0 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -988,6 +988,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop io.papermc.paper.util.MCUtil.ensureMain(() -> { ++ + double d13 = (1.0D - d7) * d12; + + // CraftBukkit start +@@ -259,8 +269,8 @@ public class Explosion { + // - Damaging ComplexEntityPart while forward the damage to EntityEnderDragon + // - Damaging EntityEnderDragon does nothing + // - EntityEnderDragon hitbock always covers the other parts and is therefore always present +- if (entity instanceof EnderDragonPart) { +- continue; ++ if (!(entity instanceof EnderDragonPart)) { ++ return; + } + + CraftEventFactory.entityDamage = this.source; +@@ -280,8 +290,8 @@ public class Explosion { + } + + CraftEventFactory.entityDamage = null; +- if (entity.lastDamageCancelled) { // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Skip entity if damage event was cancelled +- continue; ++ if (!entity.lastDamageCancelled) { // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Skip entity if damage event was cancelled ++ return; + } + // CraftBukkit end + double d14; +@@ -294,10 +304,7 @@ public class Explosion { + d14 = d13; + } + +- d8 *= d14; +- d9 *= d14; +- d10 *= d14; +- Vec3 vec3d1 = new Vec3(d8, d9, d10); ++ Vec3 vec3d1 = new Vec3(finalD8 * d14, finalD9 * d14, finalD10 * d14); + + entity.setDeltaMovement(entity.getDeltaMovement().add(vec3d1)); + if (entity instanceof Player) { +@@ -306,7 +313,7 @@ public class Explosion { + if (!entityhuman.isSpectator() && (!entityhuman.isCreative() || !entityhuman.getAbilities().flying) && !level.paperConfig().environment.disableExplosionKnockback) { // Paper - Disable explosion knockback + this.hitPlayers.put(entityhuman, vec3d1); + } +- } ++ }})); + } + } + } +@@ -539,7 +546,8 @@ public class Explosion { + private BlockInteraction() {} + } + // Paper start - Optimize explosions +- private float getBlockDensity(Vec3 vec3d, Entity entity) { ++ private CompletableFuture getBlockDensity(Vec3 vec3d, Entity entity) { ++ return CompletableFuture.supplyAsync(() -> { + if (!this.level.paperConfig().environment.optimizeExplosions) { + return getSeenPercent(vec3d, entity); + } +@@ -551,6 +559,7 @@ public class Explosion { + } + + return blockDensity; ++ }, AsyncExplosions.EXECUTOR); + } + + static class CacheKey { +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 804a784cae66cdc876b94c94373478438d75fd5b..6ab032f7e5f3d4381d4135d40e20e510ceeecfed 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -485,6 +485,7 @@ public final class CraftServer implements Server { + } + datapackManager = new io.papermc.paper.datapack.PaperDatapackManager(console.getPackRepository()); // Paper + top.leavesmc.leaves.protocol.JadeProtocol.init(); // Leaves - Jade ++ org.dreeam.leaf.async.AsyncExplosions.initExecutor(org.dreeam.leaf.LeafConfig.useFixedPoolForTNT, org.dreeam.leaf.LeafConfig.fixedPoolSize); + } + + public boolean getCommandBlockOverride(String command) { +diff --git a/src/main/java/org/dreeam/leaf/LeafConfig.java b/src/main/java/org/dreeam/leaf/LeafConfig.java +index 32980bd223a68e7ac2c953e953434d1fef6e0f9f..5c71d9dd8c362ca8a940a4b75d31414f03c56315 100644 +--- a/src/main/java/org/dreeam/leaf/LeafConfig.java ++++ b/src/main/java/org/dreeam/leaf/LeafConfig.java +@@ -205,6 +205,8 @@ public class LeafConfig { + public static boolean enableAsyncEntityTrackerInitialized; + public static boolean enableSyncEventCallsOnAsyncThreads = true; + public static boolean enableSyncEventCallsOnAsyncThreadsInitialized; ++ public static boolean useFixedPoolForTNT = false; ++ public static int fixedPoolSize = 500; + private static void performance() { + boolean asyncMobSpawning = getBoolean("performance.enable-async-mob-spawning", enableAsyncMobSpawning, + "Whether or not asynchronous mob spawning should be enabled.", +@@ -279,6 +281,8 @@ public class LeafConfig { + enableSyncEventCallsOnAsyncThreadsInitialized = true; + enableSyncEventCallsOnAsyncThreads = syncEventCalls; + } ++ useFixedPoolForTNT = getBoolean("performance.async-explosion.use-fixed-pools-for-explosions", useFixedPoolForTNT); ++ fixedPoolSize = getInt("performance.async-explosion.fixed-pools-size", fixedPoolSize); + } + + public static boolean jadeProtocol = false; +diff --git a/src/main/java/org/dreeam/leaf/async/AsyncExplosions.java b/src/main/java/org/dreeam/leaf/async/AsyncExplosions.java +new file mode 100644 +index 0000000000000000000000000000000000000000..caacc7e1d180b13644fbfc44a1ae6eb925268fef +--- /dev/null ++++ b/src/main/java/org/dreeam/leaf/async/AsyncExplosions.java +@@ -0,0 +1,18 @@ ++package org.dreeam.leaf.async; ++import java.util.concurrent.Executors; ++import java.util.concurrent.ThreadPoolExecutor; ++ ++public class AsyncExplosions { ++ public static ThreadPoolExecutor EXECUTOR; ++ ++ public static void initExecutor(boolean fixed, int size) { ++ if (fixed) ++ EXECUTOR = (ThreadPoolExecutor) Executors.newFixedThreadPool(size); ++ else ++ EXECUTOR = (ThreadPoolExecutor) Executors.newCachedThreadPool(); ++ } ++ ++ public static void stopExecutor() { ++ if (EXECUTOR != null) EXECUTOR.shutdown(); ++ } ++} +\ No newline at end of file diff --git a/patches/unapplied/server/0040-Use-commons-lang3.patch b/patches/unapplied/server/0040-Use-commons-lang3.patch new file mode 100644 index 00000000..12d246dd --- /dev/null +++ b/patches/unapplied/server/0040-Use-commons-lang3.patch @@ -0,0 +1,200 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com> +Date: Tue, 5 Sep 2023 03:51:38 -0400 +Subject: [PATCH] Use commons-lang3 + +Plugin incompatible + +diff --git a/build.gradle.kts b/build.gradle.kts +index 6efb27e3b86f36aed1dc76e9b95124e557a6894e..1fa65de0bc0cc51876baa86b043bfefd2968e57e 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -44,7 +44,7 @@ dependencies { + implementation("org.ow2.asm:asm-commons:9.5") // Paper - ASM event executor generation + testImplementation("org.mockito:mockito-core:5.5.0") // Paper - switch to mockito + implementation("org.spongepowered:configurate-yaml:4.2.0-SNAPSHOT") // Paper - config files +- implementation("commons-lang:commons-lang:2.6") ++ implementation("org.apache.commons:commons-lang3:3.13.0") + implementation("net.fabricmc:mapping-io:0.4.2") // Paper - needed to read mappings for stacktrace deobfuscation + runtimeOnly("org.xerial:sqlite-jdbc:3.43.0.0") + runtimeOnly("com.mysql:mysql-connector-j:8.1.0") +diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java +index 61fc65624f7d9a3bfa399a58112efb7f55b31652..5b08d669d348787453bce57a7f439c6ecbae8df0 100644 +--- a/src/main/java/co/aikar/timings/TimingsExport.java ++++ b/src/main/java/co/aikar/timings/TimingsExport.java +@@ -29,7 +29,7 @@ import net.kyori.adventure.text.event.ClickEvent; + import net.kyori.adventure.text.format.NamedTextColor; + import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; + import net.minecraft.server.MinecraftServer; +-import org.apache.commons.lang.StringUtils; ++import org.apache.commons.lang3.StringUtils; // Leaf - Use commons-lang3 + import org.bukkit.Bukkit; + import org.bukkit.Material; + import org.bukkit.configuration.ConfigurationSection; +diff --git a/src/main/java/com/destroystokyo/paper/entity/PaperPathfinder.java b/src/main/java/com/destroystokyo/paper/entity/PaperPathfinder.java +index 064712e7b27a200b29c72076a82f4f5611fa507f..d4b1f608248bad0ecde768e125ef49c5f481ea78 100644 +--- a/src/main/java/com/destroystokyo/paper/entity/PaperPathfinder.java ++++ b/src/main/java/com/destroystokyo/paper/entity/PaperPathfinder.java +@@ -1,6 +1,6 @@ + package com.destroystokyo.paper.entity; + +-import org.apache.commons.lang.Validate; ++import org.apache.commons.lang3.Validate; // Leaf - Use commons-lang3 + import org.bukkit.Location; + import org.bukkit.craftbukkit.entity.CraftLivingEntity; + import org.bukkit.entity.LivingEntity; +diff --git a/src/main/java/gg/airplane/structs/ItemListWithBitset.java b/src/main/java/gg/airplane/structs/ItemListWithBitset.java +index a45b135af87324c99a9fdd6ba9564255e5beb199..f1b1fcdb36957404042255c212cd0fbb40a55ad2 100644 +--- a/src/main/java/gg/airplane/structs/ItemListWithBitset.java ++++ b/src/main/java/gg/airplane/structs/ItemListWithBitset.java +@@ -4,7 +4,7 @@ package gg.airplane.structs; + + import net.minecraft.core.NonNullList; + import net.minecraft.world.item.ItemStack; +-import org.apache.commons.lang.Validate; ++import org.apache.commons.lang3.Validate; // Leaf - Use commons-lang3 + import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; + +diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java +index 1eaa559b177f2dc982865f96dfc7654bcfabc62c..6b0f3029e539892f4a8c2ec9af2324d42fa362b5 100644 +--- a/src/main/java/io/papermc/paper/util/MCUtil.java ++++ b/src/main/java/io/papermc/paper/util/MCUtil.java +@@ -33,7 +33,7 @@ import net.minecraft.world.level.Level; + import net.minecraft.world.level.chunk.ChunkAccess; + import net.minecraft.world.level.chunk.ChunkStatus; + import net.minecraft.world.phys.Vec3; +-import org.apache.commons.lang.exception.ExceptionUtils; ++import org.apache.commons.lang3.exception.ExceptionUtils; // Leaf - Use commons-lang3 + import com.mojang.authlib.GameProfile; + import org.bukkit.Location; + import org.bukkit.block.BlockFace; +@@ -195,7 +195,7 @@ public final class MCUtil { + * @return Stacktrace + */ + public static String stack() { +- return ExceptionUtils.getFullStackTrace(new Throwable()); ++ return ExceptionUtils.getStackTrace(new Throwable()); // Leaf - Use commons-lang3 + } + + /** +@@ -205,8 +205,8 @@ public final class MCUtil { + * @return Stacktrace + */ + public static String stack(String str) { +- return ExceptionUtils.getFullStackTrace(new Throwable(str)); +- } ++ return ExceptionUtils.getStackTrace(new Throwable(str)); ++ } // Leaf - Use commons-lang3 + + public static long getCoordinateKey(final BlockPos blockPos) { + return ((long)(blockPos.getZ() >> 4) << 32) | ((blockPos.getX() >> 4) & 0xFFFFFFFFL); +diff --git a/src/main/java/io/papermc/paper/util/ServerEnvironment.java b/src/main/java/io/papermc/paper/util/ServerEnvironment.java +index 148d233f4f5278ff39eacdaa0f4f0e7d73be936a..91eb919fd7465958bdd8cea8e8c18ee3480c0a71 100644 +--- a/src/main/java/io/papermc/paper/util/ServerEnvironment.java ++++ b/src/main/java/io/papermc/paper/util/ServerEnvironment.java +@@ -2,7 +2,7 @@ package io.papermc.paper.util; + + import com.sun.security.auth.module.NTSystem; + import com.sun.security.auth.module.UnixSystem; +-import org.apache.commons.lang.SystemUtils; ++import org.apache.commons.lang3.SystemUtils; // Leaf - Use commons-lang3 + + import java.io.IOException; + import java.io.InputStream; +diff --git a/src/main/java/net/minecraft/world/food/FoodData.java b/src/main/java/net/minecraft/world/food/FoodData.java +index e54af9ff2a786e919b8261aa27509be942e70261..29e5e752f65d19c55edf8eb9001c6b1457d47550 100644 +--- a/src/main/java/net/minecraft/world/food/FoodData.java ++++ b/src/main/java/net/minecraft/world/food/FoodData.java +@@ -27,7 +27,7 @@ public class FoodData { + + // CraftBukkit start - added EntityHuman constructor + public FoodData(Player entityhuman) { +- org.apache.commons.lang.Validate.notNull(entityhuman); ++ org.apache.commons.lang3.Validate.notNull(entityhuman); // Leaf - Use commons-lang3 + this.entityhuman = entityhuman; + } + // CraftBukkit end +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java b/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java +index eafba0532920a3162575dbe656e07734605590f5..64a3cae53997c3fe061c486299c6dd1d87ebd395 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftCampfire.java +@@ -63,7 +63,7 @@ public class CraftCampfire extends CraftBlockEntityState im + + @Override + public boolean stopCooking(int index) { +- org.apache.commons.lang.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)"); ++ org.apache.commons.lang3.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)"); // Leaf - Use commons-lang3 + boolean previous = this.isCookingDisabled(index); + getSnapshot().stopCooking[index] = true; + return previous; +@@ -71,7 +71,7 @@ public class CraftCampfire extends CraftBlockEntityState im + + @Override + public boolean startCooking(int index) { +- org.apache.commons.lang.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)"); ++ org.apache.commons.lang3.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)"); // Leaf - Use commons-lang3 + boolean previous = this.isCookingDisabled(index); + getSnapshot().stopCooking[index] = false; + return previous; +@@ -79,7 +79,7 @@ public class CraftCampfire extends CraftBlockEntityState im + + @Override + public boolean isCookingDisabled(int index) { +- org.apache.commons.lang.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)"); ++ org.apache.commons.lang3.Validate.isTrue(-1 < index && index < 4, "Slot index must be between 0 (incl) to 3 (incl)"); // Leaf - Use commons-lang3 + return getSnapshot().stopCooking[index]; + } + // Paper end +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragon.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragon.java +index 492fdc855fe9735b614b6831aa5baaa6b252cfb6..498205a7eb265f56fc47f1f2ee6d0240880547e1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragon.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragon.java +@@ -86,7 +86,7 @@ public class CraftEnderDragon extends CraftMob implements EnderDragon, CraftEnem + if (location == null) { + this.getHandle().setPodium(null); + } else { +- org.apache.commons.lang.Validate.isTrue(location.getWorld() == null || location.getWorld().equals(getWorld()), "You cannot set a podium in a different world to where the dragon is"); ++ org.apache.commons.lang3.Validate.isTrue(location.getWorld() == null || location.getWorld().equals(getWorld()), "You cannot set a podium in a different world to where the dragon is"); // Leaf - Use commons-lang3 + this.getHandle().setPodium(io.papermc.paper.util.MCUtil.toBlockPos(location)); + } + } +diff --git a/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java b/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java +index 58ea78d3917d2f264515c41f4df2f9ff6f8e4667..89b721088e84f12f3aaf575022055b6e97f28eb9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java ++++ b/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java +@@ -18,7 +18,7 @@ import javax.annotation.Nonnull; + import javax.annotation.Nullable; + import net.minecraft.Util; + import net.minecraft.server.dedicated.DedicatedServer; +-import org.apache.commons.lang.StringUtils; ++import org.apache.commons.lang3.StringUtils; // Leaf - Use commons-lang3 + import org.bukkit.Bukkit; + import org.bukkit.configuration.serialization.SerializableAs; + import org.bukkit.craftbukkit.CraftServer; +diff --git a/src/main/java/org/dreeam/leaf/path/NodeEvaluatorCache.java b/src/main/java/org/dreeam/leaf/path/NodeEvaluatorCache.java +index 13e01a9ec678804a6e670c08d8757efea5fa0b8c..f0ff597679bd5dc3b1378188607e4bdfd4caa291 100644 +--- a/src/main/java/org/dreeam/leaf/path/NodeEvaluatorCache.java ++++ b/src/main/java/org/dreeam/leaf/path/NodeEvaluatorCache.java +@@ -2,7 +2,7 @@ package org.dreeam.leaf.path; + + import net.minecraft.world.level.pathfinder.NodeEvaluator; + +-import org.apache.commons.lang.Validate; ++import org.apache.commons.lang3.Validate; // Leaf - Use commons-lang3 + import org.jetbrains.annotations.NotNull; + + import java.util.Map; +diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java +index 2056fc462ab11a86f17c630e868b70eea4f35553..5a1d9daba0db678446e1e8a0d63a9f0c2645cd21 100644 +--- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java ++++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java +@@ -16,7 +16,7 @@ import org.purpurmc.purpur.tool.Strippable; + import org.purpurmc.purpur.tool.Tillable; + import org.purpurmc.purpur.tool.Waxable; + import org.purpurmc.purpur.tool.Weatherable; +-import org.apache.commons.lang.BooleanUtils; ++import org.apache.commons.lang3.BooleanUtils; // Leaf - Use commons-lang3 + import org.bukkit.ChatColor; + import org.bukkit.World; + import org.bukkit.configuration.ConfigurationSection; diff --git a/patches/unapplied/server/0044-Carpet-Fixes-Use-optimized-PoweredRailBlock-logic.patch b/patches/unapplied/server/0044-Carpet-Fixes-Use-optimized-PoweredRailBlock-logic.patch new file mode 100644 index 00000000..10623ba7 --- /dev/null +++ b/patches/unapplied/server/0044-Carpet-Fixes-Use-optimized-PoweredRailBlock-logic.patch @@ -0,0 +1,394 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com> +Date: Thu, 6 Apr 2023 20:53:05 -0400 +Subject: [PATCH] Carpet-Fixes: Use optimized PoweredRailBlock logic + +Original license: MIT +Original project: https://github.com/fxmorin/carpet-fixes + +Full Rewrite of the powered rail iteration logic. +This rewrite brings a massive performance boost while keeping the vanilla order. This is achieved by running all the +powered rail logic from a single rail instead of each block iterating separately. Which was not only very +expensive but also completely unnecessary and with a lot of massive overhead + +diff --git a/src/main/java/net/minecraft/world/level/block/PoweredRailBlock.java b/src/main/java/net/minecraft/world/level/block/PoweredRailBlock.java +index 0ec427fe0e1f85c07585e1a05269c4c38fc3e9f5..c86278caae67fde06d3dcb6ffcf51f5bd77804a3 100644 +--- a/src/main/java/net/minecraft/world/level/block/PoweredRailBlock.java ++++ b/src/main/java/net/minecraft/world/level/block/PoweredRailBlock.java +@@ -1,6 +1,7 @@ + package net.minecraft.world.level.block; + + import net.minecraft.core.BlockPos; ++import net.minecraft.core.Direction; + import net.minecraft.world.level.Level; + import net.minecraft.world.level.block.state.BlockBehaviour; + import net.minecraft.world.level.block.state.BlockState; +@@ -12,6 +13,8 @@ import net.minecraft.world.level.block.state.properties.Property; + import net.minecraft.world.level.block.state.properties.RailShape; + import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit + ++import java.util.HashMap; ++ + public class PoweredRailBlock extends BaseRailBlock { + + public static final EnumProperty SHAPE = BlockStateProperties.RAIL_SHAPE_STRAIGHT; +@@ -22,7 +25,13 @@ public class PoweredRailBlock extends BaseRailBlock { + this.registerDefaultState((BlockState) ((BlockState) ((BlockState) ((BlockState) this.stateDefinition.any()).setValue(PoweredRailBlock.SHAPE, RailShape.NORTH_SOUTH)).setValue(PoweredRailBlock.POWERED, false)).setValue(PoweredRailBlock.WATERLOGGED, false)); + } + +- protected boolean findPoweredRailSignal(Level world, BlockPos pos, BlockState state, boolean flag, int distance) { ++ private static final Direction[] EAST_WEST_DIR = new Direction[]{Direction.WEST, Direction.EAST}; ++ private static final Direction[] NORTH_SOUTH_DIR = new Direction[]{Direction.SOUTH, Direction.NORTH}; ++ ++ private static final int FORCE_PLACE = UPDATE_MOVE_BY_PISTON | UPDATE_KNOWN_SHAPE | UPDATE_CLIENTS; ++ ; ++ ++ protected boolean findPoweredRailSignal(Level world, BlockPos pos, BlockState state, boolean flag, int distance, HashMap checkedPos) { + if (distance >= world.purpurConfig.railActivationRange) { // Purpur + return false; + } else { +@@ -33,22 +42,22 @@ public class PoweredRailBlock extends BaseRailBlock { + RailShape blockpropertytrackposition = (RailShape) state.getValue(PoweredRailBlock.SHAPE); + + // Leaf start - Optimize PoweredRail swtich +- switch (blockpropertytrackposition) { +- case NORTH_SOUTH -> { ++ switch (blockpropertytrackposition.ordinal()) { ++ case 0 -> { + if (flag) { + ++l; + } else { + --l; + } + } +- case EAST_WEST -> { ++ case 1 -> { + if (flag) { + --j; + } else { + ++j; + } + } +- case ASCENDING_EAST -> { ++ case 2 -> { + if (flag) { + --j; + } else { +@@ -58,7 +67,7 @@ public class PoweredRailBlock extends BaseRailBlock { + } + blockpropertytrackposition = RailShape.EAST_WEST; + } +- case ASCENDING_WEST -> { ++ case 3 -> { + if (flag) { + --j; + ++k; +@@ -68,7 +77,7 @@ public class PoweredRailBlock extends BaseRailBlock { + } + blockpropertytrackposition = RailShape.EAST_WEST; + } +- case ASCENDING_NORTH -> { ++ case 4 -> { + if (flag) { + ++l; + } else { +@@ -78,7 +87,7 @@ public class PoweredRailBlock extends BaseRailBlock { + } + blockpropertytrackposition = RailShape.NORTH_SOUTH; + } +- case ASCENDING_SOUTH -> { ++ case 5 -> { + if (flag) { + ++l; + ++k; +@@ -91,19 +100,38 @@ public class PoweredRailBlock extends BaseRailBlock { + } + // Leaf end + +- return this.isSameRailWithPower(world, new BlockPos(j, k, l), flag, distance, blockpropertytrackposition) || flag1 && this.isSameRailWithPower(world, new BlockPos(j, k - 1, l), flag, distance, blockpropertytrackposition); // Leaf - Optimize PoweredRail ++ return this.isSameRailWithPower(world, new BlockPos(j, k, l), flag, distance, blockpropertytrackposition, checkedPos) || flag1 && this.isSameRailWithPower(world, new BlockPos(j, k - 1, l), flag, distance, blockpropertytrackposition, checkedPos); // Leaf - Optimize PoweredRail + } + } + +- protected boolean isSameRailWithPower(Level world, BlockPos pos, boolean flag, int distance, RailShape shape) { ++ protected boolean isSameRailWithPower(Level world, BlockPos pos, boolean flag, int distance, RailShape shape, HashMap checkedPos) { + BlockState iblockdata = world.getBlockState(pos); ++ boolean speedCheck = checkedPos.containsKey(pos) && checkedPos.get(pos); + +- if (!iblockdata.is((Block) this)) { +- return false; ++ if (speedCheck) { ++ return world.hasNeighborSignal(pos) || ++ this.findPoweredRailSignal(world, pos, iblockdata, flag, distance + 1, checkedPos); + } else { +- RailShape blockpropertytrackposition1 = (RailShape) iblockdata.getValue(PoweredRailBlock.SHAPE); +- +- return (shape != RailShape.EAST_WEST || (blockpropertytrackposition1 != RailShape.NORTH_SOUTH && blockpropertytrackposition1 != RailShape.ASCENDING_NORTH && blockpropertytrackposition1 != RailShape.ASCENDING_SOUTH)) && ((shape != RailShape.NORTH_SOUTH || (blockpropertytrackposition1 != RailShape.EAST_WEST && blockpropertytrackposition1 != RailShape.ASCENDING_EAST && blockpropertytrackposition1 != RailShape.ASCENDING_WEST)) && ((Boolean) iblockdata.getValue(PoweredRailBlock.POWERED) && (world.hasNeighborSignal(pos) || this.findPoweredRailSignal(world, pos, iblockdata, flag, distance + 1)))); // Leaf - Optimize PoweredRail ++ if (iblockdata.is((Block) this)) { ++ RailShape blockpropertytrackposition1 = (RailShape) iblockdata.getValue(PoweredRailBlock.SHAPE); ++ if (shape == RailShape.EAST_WEST && ( ++ blockpropertytrackposition1 == RailShape.NORTH_SOUTH || ++ blockpropertytrackposition1 == RailShape.ASCENDING_NORTH || ++ blockpropertytrackposition1 == RailShape.ASCENDING_SOUTH ++ ) || shape == RailShape.NORTH_SOUTH && ( ++ blockpropertytrackposition1 == RailShape.EAST_WEST || ++ blockpropertytrackposition1 == RailShape.ASCENDING_EAST || ++ blockpropertytrackposition1 == RailShape.ASCENDING_WEST ++ )) { ++ return false; ++ } else if ((Boolean) iblockdata.getValue(PoweredRailBlock.POWERED)) { ++ return world.hasNeighborSignal(pos) || ++ this.findPoweredRailSignal(world, pos, iblockdata, flag, distance + 1, checkedPos); ++ } else { ++ return false; ++ } ++ } ++ return false; + } + } + +@@ -120,13 +148,16 @@ public class PoweredRailBlock extends BaseRailBlock { + return; + } + // CraftBukkit end +- world.setBlock(pos, (BlockState) state.setValue(PoweredRailBlock.POWERED, flag1), 3); +- world.updateNeighborsAt(pos.below(), this); + if (((RailShape) state.getValue(PoweredRailBlock.SHAPE)).isAscending()) { +- world.updateNeighborsAt(pos.above(), this); ++ world.setBlock(pos, (BlockState) state.setValue(PoweredRailBlock.POWERED, flag1), 3); ++ world.updateNeighborsAtExceptFromFacing(pos.below(), this, Direction.UP); ++ world.updateNeighborsAtExceptFromFacing(pos.above(), this, Direction.DOWN); //isAscending ++ } else if (flag1) { ++ powerLane(world, pos, state, ((RailShape) state.getValue(PoweredRailBlock.SHAPE))); ++ } else { ++ dePowerLane(world, pos, state, ((RailShape) state.getValue(PoweredRailBlock.SHAPE))); + } + } +- + } + + @Override +@@ -258,4 +289,201 @@ public class PoweredRailBlock extends BaseRailBlock { + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(PoweredRailBlock.SHAPE, PoweredRailBlock.POWERED, PoweredRailBlock.WATERLOGGED); + } ++ ++ public static void giveShapeUpdate(Level world, BlockState state, BlockPos pos, BlockPos fromPos, Direction direction) { ++ BlockState oldState = world.getBlockState(pos); ++ Block.updateOrDestroy( ++ oldState, ++ oldState.updateShape(direction.getOpposite(), state, world, pos, fromPos), ++ world, ++ pos, ++ Block.UPDATE_CLIENTS & -34, ++ 0 ++ ); ++ } ++ ++ protected boolean findPoweredRailSignal(Level world, BlockPos pos, BlockState state, boolean flag, int distance) { ++ return false; ++ } ++ ++ public void powerLane(Level world, BlockPos pos, BlockState state, RailShape railShape) { ++ world.setBlock(pos, (BlockState) state.setValue(PoweredRailBlock.POWERED, true), FORCE_PLACE); ++ HashMap checkedPos = new HashMap<>(); ++ checkedPos.put(pos, true); ++ int[] count = new int[2]; ++ if (railShape == RailShape.NORTH_SOUTH) { //Order: +z, -z ++ for (int i = 0; i < NORTH_SOUTH_DIR.length; ++i) { ++ setRailPositionsPower(world, pos, checkedPos, count, i, NORTH_SOUTH_DIR[i]); ++ } ++ updateRails(false, world, pos, state, count); ++ } else if (railShape == RailShape.EAST_WEST) { //Order: -x, +x ++ for (int i = 0; i < EAST_WEST_DIR.length; ++i) { ++ setRailPositionsPower(world, pos, checkedPos, count, i, EAST_WEST_DIR[i]); ++ } ++ updateRails(true, world, pos, state, count); ++ } ++ } ++ ++ public void dePowerLane(Level world, BlockPos pos, BlockState state, RailShape railShape) { ++ world.setBlock(pos, (BlockState) state.setValue(PoweredRailBlock.POWERED, false), FORCE_PLACE); ++ int[] count = new int[2]; ++ if (railShape == RailShape.NORTH_SOUTH) { //Order: +z, -z ++ for (int i = 0; i < NORTH_SOUTH_DIR.length; ++i) { ++ setRailPositionsDePower(world, pos, count, i, NORTH_SOUTH_DIR[i]); ++ } ++ updateRails(false, world, pos, state, count); ++ } else if (railShape == RailShape.EAST_WEST) { //Order: -x, +x ++ for (int i = 0; i < EAST_WEST_DIR.length; ++i) { ++ setRailPositionsDePower(world, pos, count, i, EAST_WEST_DIR[i]); ++ } ++ updateRails(true, world, pos, state, count); ++ } ++ } ++ ++ private void setRailPositionsPower(Level world, BlockPos pos, HashMap checkedPos, ++ int[] count, int i, Direction direction) { ++ for (int z = 1; z < world.purpurConfig.railActivationRange; z++) { ++ BlockPos newPos = pos.relative(direction, z); ++ BlockState state = world.getBlockState(newPos); ++ if (checkedPos.containsKey(newPos)) { ++ if (!checkedPos.get(newPos)) break; ++ count[i]++; ++ } else if (!state.is((Block) this) || state.getValue(PoweredRailBlock.POWERED) || !( ++ world.hasNeighborSignal(newPos) || ++ this.findPoweredRailSignal(world, newPos, state, true, 0, checkedPos) || ++ this.findPoweredRailSignal(world, newPos, state, false, 0, checkedPos) ++ )) { ++ checkedPos.put(newPos, false); ++ break; ++ } else { ++ checkedPos.put(newPos, true); ++ world.setBlock(newPos, (BlockState) state.setValue(PoweredRailBlock.POWERED, true), FORCE_PLACE); ++ count[i]++; ++ } ++ } ++ } ++ ++ private void setRailPositionsDePower(Level world, BlockPos pos, int[] count, int i, Direction direction) { ++ for (int z = 1; z < world.purpurConfig.railActivationRange; z++) { ++ BlockPos newPos = pos.relative(direction, z); ++ BlockState state = world.getBlockState(newPos); ++ if (!state.is((Block) this) || !state.getValue(PoweredRailBlock.POWERED) || world.hasNeighborSignal(newPos) || ++ this.findPoweredRailSignal(world, newPos, state, true, 0) || ++ this.findPoweredRailSignal(world, newPos, state, false, 0)) break; ++ world.setBlock(newPos, (BlockState) state.setValue(PoweredRailBlock.POWERED, false), FORCE_PLACE); ++ count[i]++; ++ } ++ } ++ ++ private void shapeUpdateEnd(Level world, BlockPos pos, BlockState state, int endPos, ++ Direction direction, int currentPos, BlockPos blockPos) { ++ if (currentPos == endPos) { ++ BlockPos newPos = pos.relative(direction, currentPos + 1); ++ giveShapeUpdate(world, state, newPos, pos, direction); ++ BlockState iblockdata = world.getBlockState(blockPos); ++ if (iblockdata.is((Block) this) && iblockdata.getValue(PoweredRailBlock.SHAPE).isAscending()) ++ giveShapeUpdate(world, state, newPos.above(), pos, direction); ++ } ++ } ++ ++ private void neighborUpdateEnd(Level world, BlockPos pos, int endPos, Direction direction, ++ Block block, int currentPos, BlockPos blockPos) { ++ if (currentPos == endPos) { ++ BlockPos newPos = pos.relative(direction, currentPos + 1); ++ world.neighborChanged(newPos, block, pos); ++ BlockState state = world.getBlockState(blockPos); ++ if (state.is((Block) this) && state.getValue(PoweredRailBlock.SHAPE).isAscending()) ++ world.neighborChanged(newPos.above(), block, blockPos); ++ } ++ } ++ ++ private void updateRailsSectionEastWestShape(Level world, BlockPos pos, int c, BlockState state, ++ Direction dir, int[] count, int countAmt) { ++ BlockPos pos1 = pos.relative(dir, c); ++ if (c == 0 && count[1] == 0) ++ giveShapeUpdate(world, state, pos1.relative(dir.getOpposite()), pos, dir.getOpposite()); ++ shapeUpdateEnd(world, pos, state, countAmt, dir, c, pos1); ++ giveShapeUpdate(world, state, pos1.below(), pos, Direction.DOWN); ++ giveShapeUpdate(world, state, pos1.above(), pos, Direction.UP); ++ giveShapeUpdate(world, state, pos1.north(), pos, Direction.NORTH); ++ giveShapeUpdate(world, state, pos1.south(), pos, Direction.SOUTH); ++ } ++ ++ private void updateRailsSectionNorthSouthShape(Level world, BlockPos pos, int c, BlockState state, ++ Direction dir, int[] count, int countAmt) { ++ BlockPos pos1 = pos.relative(dir, c); ++ giveShapeUpdate(world, state, pos1.west(), pos, Direction.WEST); ++ giveShapeUpdate(world, state, pos1.east(), pos, Direction.EAST); ++ giveShapeUpdate(world, state, pos1.below(), pos, Direction.DOWN); ++ giveShapeUpdate(world, state, pos1.above(), pos, Direction.UP); ++ shapeUpdateEnd(world, pos, state, countAmt, dir, c, pos1); ++ if (c == 0 && count[1] == 0) ++ giveShapeUpdate( ++ world, state, pos1.relative(dir.getOpposite()), pos, dir.getOpposite() ++ ); ++ } ++ ++ private void updateRails(boolean eastWest, Level world, BlockPos pos, BlockState state, int[] count) { ++ if (eastWest) { ++ for (int i = 0; i < EAST_WEST_DIR.length; ++i) { ++ int countAmt = count[i]; ++ if (i == 1 && countAmt == 0) continue; ++ Direction dir = EAST_WEST_DIR[i]; ++ Block block = state.getBlock(); ++ for (int c = countAmt; c >= i; c--) { ++ BlockPos p = pos.relative(dir, c); ++ if (c == 0 && count[1] == 0) world.neighborChanged(p.relative(dir.getOpposite()), block, pos); ++ neighborUpdateEnd(world, pos, countAmt, dir, block, c, p); ++ world.neighborChanged(p.below(), block, pos); ++ world.neighborChanged(p.above(), block, pos); ++ world.neighborChanged(p.north(), block, pos); ++ world.neighborChanged(p.south(), block, pos); ++ BlockPos pos2 = pos.relative(dir, c).below(); ++ world.neighborChanged(pos2.below(), block, pos); ++ world.neighborChanged(pos2.north(), block, pos); ++ world.neighborChanged(pos2.south(), block, pos); ++ if (c == countAmt) world.neighborChanged(pos.relative(dir, c + 1).below(), block, pos); ++ if (c == 0 && count[1] == 0) ++ world.neighborChanged(p.relative(dir.getOpposite()).below(), block, pos); ++ } ++ if (org.dreeam.leaf.LeafConfig.reIntroduceReverseRailUpdateOrder) { ++ for (int c = i; c <= countAmt; c++) ++ updateRailsSectionEastWestShape(world, pos, c, state, dir, count, countAmt); ++ } else { ++ for (int c = countAmt; c >= i; c--) ++ updateRailsSectionEastWestShape(world, pos, c, state, dir, count, countAmt); ++ } ++ } ++ } else { ++ for (int i = 0; i < NORTH_SOUTH_DIR.length; ++i) { ++ int countAmt = count[i]; ++ if (i == 1 && countAmt == 0) continue; ++ Direction dir = NORTH_SOUTH_DIR[i]; ++ Block block = state.getBlock(); ++ for (int c = countAmt; c >= i; c--) { ++ BlockPos p = pos.relative(dir, c); ++ world.neighborChanged(p.west(), block, pos); ++ world.neighborChanged(p.east(), block, pos); ++ world.neighborChanged(p.below(), block, pos); ++ world.neighborChanged(p.above(), block, pos); ++ neighborUpdateEnd(world, pos, countAmt, dir, block, c, p); ++ if (c == 0 && count[1] == 0) world.neighborChanged(p.relative(dir.getOpposite()), block, pos); ++ BlockPos pos2 = pos.relative(dir, c).below(); ++ world.neighborChanged(pos2.west(), block, pos); ++ world.neighborChanged(pos2.east(), block, pos); ++ world.neighborChanged(pos2.below(), block, pos); ++ if (c == countAmt) world.neighborChanged(pos.relative(dir, c + 1).below(), block, pos); ++ if (c == 0 && count[1] == 0) ++ world.neighborChanged(p.relative(dir.getOpposite()).below(), block, pos); ++ } ++ if (org.dreeam.leaf.LeafConfig.reIntroduceReverseRailUpdateOrder) { ++ for (int c = i; c <= countAmt; c++) ++ updateRailsSectionNorthSouthShape(world, pos, c, state, dir, count, countAmt); ++ } else { ++ for (int c = countAmt; c >= i; c--) ++ updateRailsSectionNorthSouthShape(world, pos, c, state, dir, count, countAmt); ++ } ++ } ++ } ++ } + } +diff --git a/src/main/java/org/dreeam/leaf/LeafConfig.java b/src/main/java/org/dreeam/leaf/LeafConfig.java +index 11d3ccad179680c46b45e17b4461c5da3d9d5592..a285d391c35bc24250c85f68ac228f2d41456c78 100644 +--- a/src/main/java/org/dreeam/leaf/LeafConfig.java ++++ b/src/main/java/org/dreeam/leaf/LeafConfig.java +@@ -203,6 +203,8 @@ public class LeafConfig { + public static boolean enableAsyncEntityTrackerInitialized; + public static boolean enableSyncEventCallsOnAsyncThreads; + public static boolean enableSyncEventCallsOnAsyncThreadsInitialized; ++ public static boolean optimizedPoweredRails = false; ++ public static boolean reIntroduceReverseRailUpdateOrder = false; + private static void performance() { + String sentryEnvironment = System.getenv("SENTRY_DSN"); + String sentryConfig = getString("performance.sentry-dsn", sentryDsn, "Sentry DSN for improved error logging, leave blank to disable", "Obtain from https://sentry.io/"); +@@ -280,6 +282,8 @@ public class LeafConfig { + enableSyncEventCallsOnAsyncThreadsInitialized = true; + enableSyncEventCallsOnAsyncThreads = syncEventCalls; + } ++ optimizedPoweredRails = getBoolean("performance.optimizedPoweredRails", optimizedPoweredRails); ++ reIntroduceReverseRailUpdateOrder = getBoolean("performance.reIntroduceReverseRailUpdateOrder", reIntroduceReverseRailUpdateOrder); + } + + public static boolean jadeProtocol = false;