From ab0fc1acd07062f36f47239817151c1bf0821e2b Mon Sep 17 00:00:00 2001 From: IPECTER Date: Wed, 6 Sep 2023 16:48:27 +0900 Subject: [PATCH] Implement CarpetFixes-Optimizations --- .../api/0006-Optimize-spigot-event-bus.patch | 79 ++++++++ .../0039-Let-Me-Despawn-Configuration.patch | 0 .../0040-Implement-Let-Me-Despawn.patch | 0 .../0010-ChunkSending-Configuration.patch | 2 +- .../0039-Skip-event-if-no-listeners.patch | 31 +++ .../0040-Optimize-spigot-event-bus.patch | 33 ++++ .../0042-CarpetFixes-Configuration.patch | 40 ++++ ...rpetFixes-Optimizations-BiomeManager.patch | 179 ++++++++++++++++++ ...petFixes-Optimizations-RecipeManager.patch | 106 +++++++++++ ...0045-CarpetFixes-Optimizations-Sheep.patch | 131 +++++++++++++ 10 files changed, 600 insertions(+), 1 deletion(-) create mode 100644 patches/api/0006-Optimize-spigot-event-bus.patch rename patches/{server => removed/1.19.4}/0039-Let-Me-Despawn-Configuration.patch (100%) rename patches/{server => removed/1.19.4}/0040-Implement-Let-Me-Despawn.patch (100%) create mode 100644 patches/server/0039-Skip-event-if-no-listeners.patch create mode 100644 patches/server/0040-Optimize-spigot-event-bus.patch create mode 100644 patches/server/0042-CarpetFixes-Configuration.patch create mode 100644 patches/server/0043-CarpetFixes-Optimizations-BiomeManager.patch create mode 100644 patches/server/0044-CarpetFixes-Optimizations-RecipeManager.patch create mode 100644 patches/server/0045-CarpetFixes-Optimizations-Sheep.patch diff --git a/patches/api/0006-Optimize-spigot-event-bus.patch b/patches/api/0006-Optimize-spigot-event-bus.patch new file mode 100644 index 0000000..0d265db --- /dev/null +++ b/patches/api/0006-Optimize-spigot-event-bus.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: IPECTER +Date: Wed, 6 Sep 2023 15:04:25 +0900 +Subject: [PATCH] Optimize-spigot-event-bus + + +diff --git a/src/main/java/org/bukkit/event/Event.java b/src/main/java/org/bukkit/event/Event.java +index 8ec56cd6b8e0f5c5dd8c7c88b4671e18dcf109d0..45b8ee1945202cc673905aab5c90985c01cb205e 100644 +--- a/src/main/java/org/bukkit/event/Event.java ++++ b/src/main/java/org/bukkit/event/Event.java +@@ -14,7 +14,7 @@ import org.jetbrains.annotations.NotNull; + */ + public abstract class Event { + private String name; +- private final boolean async; ++ private final net.kyori.adventure.util.TriState async; // Plazma - Optimize spigot event bus + + /** + * The default constructor is defined for cleaner code. This constructor +@@ -32,9 +32,35 @@ public abstract class Event { + * by default from default constructor + */ + public Event(boolean isAsync) { ++ this(net.kyori.adventure.util.TriState.byBoolean(isAsync)); // Plazma - Optimize spigot event bus ++ } ++ ++ // Plazma start - Optimize spigot event bus ++ /** ++ * This constructor is used to explicitly declare an event as synchronous ++ * or asynchronous or potentially unset. ++ * ++ * @param isAsync true indicates the event will fire asynchronously, false ++ * by default from default constructor, unset indicates that the event may be called on either the server thread or off the server ++ * thread. ++ */ ++ public Event(@NotNull final net.kyori.adventure.util.TriState isAsync) { + this.async = isAsync; + } + ++ /** ++ * Returns a tristate that, when resolving to true or false, has the exact indications defined by {@link #isAsynchronous()}. ++ *

++ * If the tristate resolves to NOT_SET, the event may or may not have been fired off the main thread, meaning a plugin would have ++ * to validate what thread the spigot event bus was called on. ++ * ++ * @return the tristate enum. ++ */ ++ public final @NotNull net.kyori.adventure.util.TriState asynchronous() { ++ return this.async; ++ } ++ // Plazma end ++ + // Paper start + /** + * Calls the event and tests if cancelled. +@@ -92,7 +118,7 @@ public abstract class Event { + * @return false by default, true if the event fires asynchronously + */ + public final boolean isAsynchronous() { +- return async; ++ return this.async == net.kyori.adventure.util.TriState.TRUE; // Plazma - Optimize spigot event bus + } + + public enum Result { +diff --git a/src/main/java/org/bukkit/plugin/RegisteredListener.java b/src/main/java/org/bukkit/plugin/RegisteredListener.java +index 3b3d9642a8d63798dc28f2f8df77f0466451cbff..0702e1692f7e671188ac18e22ca29f369b0b6352 100644 +--- a/src/main/java/org/bukkit/plugin/RegisteredListener.java ++++ b/src/main/java/org/bukkit/plugin/RegisteredListener.java +@@ -62,8 +62,8 @@ public class RegisteredListener { + * @throws EventException If an event handler throws an exception. + */ + public void callEvent(@NotNull final Event event) throws EventException { +- if (event instanceof Cancellable) { +- if (((Cancellable) event).isCancelled() && isIgnoringCancelled()) { ++ if (isIgnoringCancelled()) { // Plazma - Optimize spigot event bus ++ if (event instanceof Cancellable cancellable && cancellable.isCancelled()) { // Plazma - Optimize spigot event bus + return; + } + } diff --git a/patches/server/0039-Let-Me-Despawn-Configuration.patch b/patches/removed/1.19.4/0039-Let-Me-Despawn-Configuration.patch similarity index 100% rename from patches/server/0039-Let-Me-Despawn-Configuration.patch rename to patches/removed/1.19.4/0039-Let-Me-Despawn-Configuration.patch diff --git a/patches/server/0040-Implement-Let-Me-Despawn.patch b/patches/removed/1.19.4/0040-Implement-Let-Me-Despawn.patch similarity index 100% rename from patches/server/0040-Implement-Let-Me-Despawn.patch rename to patches/removed/1.19.4/0040-Implement-Let-Me-Despawn.patch diff --git a/patches/server/0010-ChunkSending-Configuration.patch b/patches/server/0010-ChunkSending-Configuration.patch index 94b4275..1b6b0b8 100644 --- a/patches/server/0010-ChunkSending-Configuration.patch +++ b/patches/server/0010-ChunkSending-Configuration.patch @@ -16,7 +16,7 @@ index 857ddc62dd9affbbebcd7cde8a6d675dbb5f68ae..8ba1c5b6731d43c02b415e4d79a20c1d + public ChunkSending chunkSending; + public class ChunkSending extends ConfigurationPart { + -+ public boolean enabled = true; ++ public boolean enabled = DO_OPTIMIZE; + public int maxChunksPerTick = 5; + + } diff --git a/patches/server/0039-Skip-event-if-no-listeners.patch b/patches/server/0039-Skip-event-if-no-listeners.patch new file mode 100644 index 0000000..b91c185 --- /dev/null +++ b/patches/server/0039-Skip-event-if-no-listeners.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: AlphaKR93 +Date: Thu, 29 Jun 2023 05:49:26 +0000 +Subject: [PATCH] Skip event if no listeners + + +diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java +index 7ce9ebba8ce304d1f3f21d4f15ee5f3560d7700b..32305a34bcebd53aa523102a6da59bc2eb765055 100644 +--- a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java ++++ b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java +@@ -36,15 +36,17 @@ class PaperEventManager { + + // SimplePluginManager + public void callEvent(@NotNull Event event) { ++ // Plazma start ++ HandlerList handlers = event.getHandlers(); ++ RegisteredListener[] listeners = handlers.getRegisteredListeners(); ++ if (listeners.length == 0) return; ++ // Plazma end + if (event.isAsynchronous() && this.server.isPrimaryThread()) { + throw new IllegalStateException(event.getEventName() + " may only be triggered asynchronously."); + } else if (!event.isAsynchronous() && !this.server.isPrimaryThread() && !this.server.isStopping()) { + throw new IllegalStateException(event.getEventName() + " may only be triggered synchronously."); + } + +- HandlerList handlers = event.getHandlers(); +- RegisteredListener[] listeners = handlers.getRegisteredListeners(); +- + for (RegisteredListener registration : listeners) { + if (!registration.getPlugin().isEnabled()) { + continue; diff --git a/patches/server/0040-Optimize-spigot-event-bus.patch b/patches/server/0040-Optimize-spigot-event-bus.patch new file mode 100644 index 0000000..31d040e --- /dev/null +++ b/patches/server/0040-Optimize-spigot-event-bus.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: IPECTER +Date: Wed, 6 Sep 2023 14:55:37 +0900 +Subject: [PATCH] Optimize-spigot-event-bus + + +diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java +index 32305a34bcebd53aa523102a6da59bc2eb765055..6feb88b90831ec7106c9d777bdfa68fa185f1b89 100644 +--- a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java ++++ b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java +@@ -41,12 +41,17 @@ class PaperEventManager { + RegisteredListener[] listeners = handlers.getRegisteredListeners(); + if (listeners.length == 0) return; + // Plazma end +- if (event.isAsynchronous() && this.server.isPrimaryThread()) { +- throw new IllegalStateException(event.getEventName() + " may only be triggered asynchronously."); +- } else if (!event.isAsynchronous() && !this.server.isPrimaryThread() && !this.server.isStopping()) { +- throw new IllegalStateException(event.getEventName() + " may only be triggered synchronously."); ++ // Plazma start - Optimize spigot event bus ++ if (event.asynchronous() != net.kyori.adventure.util.TriState.NOT_SET) { ++ final boolean isAsync = event.isAsynchronous(); ++ final boolean onPrimaryThread = this.server.isPrimaryThread(); ++ if (isAsync && onPrimaryThread) { ++ throw new IllegalStateException(event.getEventName() + " may only be triggered asynchronously."); ++ } else if (!isAsync && !onPrimaryThread && !this.server.isStopping()) { ++ throw new IllegalStateException(event.getEventName() + " may only be triggered synchronously."); ++ } + } +- ++ // Plazma end + for (RegisteredListener registration : listeners) { + if (!registration.getPlugin().isEnabled()) { + continue; diff --git a/patches/server/0042-CarpetFixes-Configuration.patch b/patches/server/0042-CarpetFixes-Configuration.patch new file mode 100644 index 0000000..95ee5e0 --- /dev/null +++ b/patches/server/0042-CarpetFixes-Configuration.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: IPECTER +Date: Wed, 6 Sep 2023 15:40:34 +0900 +Subject: [PATCH] CarpetFixes-Configuration + + +diff --git a/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java b/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java +index 754ed13a04631c69e3fb2421a12b17d0a6f732c6..b552cb547fef8b4d87cb68e410d1b8fd669a9d4a 100644 +--- a/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java ++++ b/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java +@@ -70,4 +70,12 @@ public class GlobalConfiguration extends ConfigurationPart { + public int timerTimeOut = 0; + + } ++ ++ public CarpetFixes carpetFixes; ++ ++ public class CarpetFixes extends ConfigurationPart { ++ ++ public boolean enabled = DO_OPTIMIZE; ++ ++ } + } +diff --git a/src/main/java/org/plazmamc/plazma/configurations/LevelConfigurations.java b/src/main/java/org/plazmamc/plazma/configurations/LevelConfigurations.java +index a1b55bb5431d1712fc06da0cf06857a986efeea0..4c4cb2a6a4730b934931c78090ff31b9e8d40202 100644 +--- a/src/main/java/org/plazmamc/plazma/configurations/LevelConfigurations.java ++++ b/src/main/java/org/plazmamc/plazma/configurations/LevelConfigurations.java +@@ -131,4 +131,12 @@ public class LevelConfigurations extends ConfigurationPart { + } + + } ++ ++ public CarpetFixes carpetFixes; ++ ++ public class CarpetFixes extends ConfigurationPart { ++ ++ public boolean enabled = DO_OPTIMIZE; ++ ++ } + } diff --git a/patches/server/0043-CarpetFixes-Optimizations-BiomeManager.patch b/patches/server/0043-CarpetFixes-Optimizations-BiomeManager.patch new file mode 100644 index 0000000..864a62d --- /dev/null +++ b/patches/server/0043-CarpetFixes-Optimizations-BiomeManager.patch @@ -0,0 +1,179 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: IPECTER +Date: Wed, 6 Sep 2023 15:53:37 +0900 +Subject: [PATCH] CarpetFixes-Optimizations-BiomeManager + +Original: fxmorin/carpet-fixes +Copyright (C) 2023 fxmorin + +Optimized getBiome call: Reduce the number of calls to the mess of +LinearCongruentialGenerator#next(long, long) which is pretty heavy on performance. + +We are able to do this by skipping around 370 of 512 possible calls to getBiome() by predicting the outcome +before doing the seed mixing. This seems to be around 25% - 75% faster depending on the use case. +We can predict much faster than the seed mixing. + +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..7fdf087a9cd77732a1f90e33bbdca2837d3482d4 100644 +--- a/src/main/java/net/minecraft/world/level/biome/BiomeManager.java ++++ b/src/main/java/net/minecraft/world/level/biome/BiomeManager.java +@@ -12,6 +12,7 @@ public class BiomeManager { + private static final int ZOOM_BITS = 2; + private static final int ZOOM = 4; + private static final int ZOOM_MASK = 3; ++ private static final double maxOffset = 0.4500000001D; // Plazma - CarpetFixes + private final BiomeManager.NoiseBiomeSource noiseBiomeSource; + private final long biomeZoomSeed; + +@@ -29,39 +30,104 @@ public class BiomeManager { + } + + 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; ++ // Plazma start - CarpetFixes - Optimized getBiome call ++ if (org.plazmamc.plazma.configurations.GlobalConfiguration.get().carpetFixes.optimizedBiomeAccess()) { ++ 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; ++ } + } +- } ++ return this.noiseBiomeSource.getNoiseBiome( ++ (smallestX & 4) == 0 ? x : x + 1, ++ (smallestX & 2) == 0 ? y : y + 1, ++ (smallestX & 1) == 0 ? z : z + 1 ++ ); ++ } else { ++ 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 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); ++ 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); ++ } ++ // Plazma end + } + + public Holder getNoiseBiomeAtPosition(double x, double y, double z) { +diff --git a/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java b/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java +index b552cb547fef8b4d87cb68e410d1b8fd669a9d4a..a21d691d9510efe960d36eb70fec97a3bb53048b 100644 +--- a/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java ++++ b/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java +@@ -76,6 +76,11 @@ public class GlobalConfiguration extends ConfigurationPart { + public class CarpetFixes extends ConfigurationPart { + + public boolean enabled = DO_OPTIMIZE; ++ boolean optimizedBiomeAccess = true; ++ ++ public boolean optimizedBiomeAccess() { ++ return enabled && optimizedBiomeAccess; ++ } + + } + } diff --git a/patches/server/0044-CarpetFixes-Optimizations-RecipeManager.patch b/patches/server/0044-CarpetFixes-Optimizations-RecipeManager.patch new file mode 100644 index 0000000..788eb7e --- /dev/null +++ b/patches/server/0044-CarpetFixes-Optimizations-RecipeManager.patch @@ -0,0 +1,106 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: IPECTER +Date: Wed, 6 Sep 2023 16:23:56 +0900 +Subject: [PATCH] CarpetFixes-Optimizations-RecipeManager + +Original: fxmorin/carpet-fixes +Copyright (C) 2023 fxmorin + +RecipeManager optimization. +Optimized by taking out streams & doing extra early checks to quickly remove unrelated recipes + +diff --git a/src/main/java/net/minecraft/world/item/crafting/RecipeManager.java b/src/main/java/net/minecraft/world/item/crafting/RecipeManager.java +index ab6dc3449a1d3b7acf1d7bf5ac1c24224cc252c7..53756f780dd0315fc18bf93cf4607b51a8d5059e 100644 +--- a/src/main/java/net/minecraft/world/item/crafting/RecipeManager.java ++++ b/src/main/java/net/minecraft/world/item/crafting/RecipeManager.java +@@ -103,13 +103,38 @@ public class RecipeManager extends SimpleJsonResourceReloadListener { + } + + public > Optional getRecipeFor(RecipeType type, C inventory, Level world) { +- // CraftBukkit start +- Optional recipe = this.byType(type).values().stream().filter((irecipe) -> { +- return irecipe.matches(inventory, world); +- }).findFirst(); +- inventory.setCurrentRecipe(recipe.orElse(null)); // CraftBukkit - Clear recipe when no recipe is found +- // CraftBukkit end +- return recipe; ++ // Plazma start - CarpetFixes - Optimized RecipeManager ++ if (world.plazmaLevelConfiguration().carpetFixes.optimizedRecipeManager() && type == RecipeType.CRAFTING) { ++ int slots = 0; ++ int count; ++ //compare size to quickly remove recipes that are not even close. Plus remove streams ++ for (int slot = 0; slot < inventory.getContainerSize(); slot++) ++ if (!inventory.getItem(slot).isEmpty()) slots++; ++ for (Recipe recipe : this.byType(type).values()) { ++ count = 0; ++ if (recipe instanceof CustomRecipe) { ++ if (recipe.matches(inventory, world)) { ++ return (Optional) Optional.of(recipe); ++ } ++ } else { ++ for (Ingredient ingredient : recipe.getIngredients()) ++ if (ingredient != Ingredient.EMPTY) count++; ++ if (count == slots && recipe.matches(inventory, world)) { ++ return (Optional) Optional.of(recipe); ++ } ++ } ++ } ++ return Optional.empty(); ++ } else { ++ // CraftBukkit start ++ Optional recipe = this.byType(type).values().stream().filter((irecipe) -> { ++ return irecipe.matches(inventory, world); ++ }).findFirst(); ++ inventory.setCurrentRecipe(recipe.orElse(null)); // CraftBukkit - Clear recipe when no recipe is found ++ // CraftBukkit end ++ return recipe; ++ } ++ // Plazma end + } + + public > Optional> getRecipeFor(RecipeType type, C inventory, Level world, @Nullable ResourceLocation id) { +@@ -131,7 +156,7 @@ public class RecipeManager extends SimpleJsonResourceReloadListener { + } + + public > List getAllRecipesFor(RecipeType type) { +- return List.copyOf(this.byType(type).values()); ++ return org.plazmamc.plazma.configurations.GlobalConfiguration.get().carpetFixes.optimizedRecipeManager() ? (List) new java.util.ArrayList<>(this.byType(type).values()) : List.copyOf(this.byType(type).values()); // Plazma start - CarpetFixes - Optimized RecipeManager + } + + public > List getRecipesFor(RecipeType type, C inventory, Level world) { +diff --git a/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java b/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java +index a21d691d9510efe960d36eb70fec97a3bb53048b..733225cd664db7a4bae7f9ff35f8920d309343c4 100644 +--- a/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java ++++ b/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java +@@ -77,10 +77,15 @@ public class GlobalConfiguration extends ConfigurationPart { + + public boolean enabled = DO_OPTIMIZE; + boolean optimizedBiomeAccess = true; ++ boolean optimizedRecipeManager = true; + + public boolean optimizedBiomeAccess() { + return enabled && optimizedBiomeAccess; + } + ++ public boolean optimizedRecipeManager() { ++ return enabled && optimizedRecipeManager; ++ } ++ + } + } +diff --git a/src/main/java/org/plazmamc/plazma/configurations/LevelConfigurations.java b/src/main/java/org/plazmamc/plazma/configurations/LevelConfigurations.java +index 4c4cb2a6a4730b934931c78090ff31b9e8d40202..dde4eeb834ed71cb7a22ec212e13afea2156a44c 100644 +--- a/src/main/java/org/plazmamc/plazma/configurations/LevelConfigurations.java ++++ b/src/main/java/org/plazmamc/plazma/configurations/LevelConfigurations.java +@@ -137,6 +137,11 @@ public class LevelConfigurations extends ConfigurationPart { + public class CarpetFixes extends ConfigurationPart { + + public boolean enabled = DO_OPTIMIZE; ++ boolean optimizedRecipeManager = true; ++ ++ public boolean optimizedRecipeManager() { ++ return enabled && optimizedRecipeManager; ++ } + + } + } diff --git a/patches/server/0045-CarpetFixes-Optimizations-Sheep.patch b/patches/server/0045-CarpetFixes-Optimizations-Sheep.patch new file mode 100644 index 0000000..34e47f0 --- /dev/null +++ b/patches/server/0045-CarpetFixes-Optimizations-Sheep.patch @@ -0,0 +1,131 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: IPECTER +Date: Wed, 6 Sep 2023 16:35:34 +0900 +Subject: [PATCH] CarpetFixes-Optimizations-Sheep + +Original: fxmorin/carpet-fixes +Copyright (C) 2023 fxmorin + +The game determines the child sheep's color by getting a wool block from the parents, putting them in a crafting +recipe, getting the output wool and getting the color from that. +I don't know in what world we would consider a data-driven method with that much overhead as a smart idea. Instead, +we used a prebaked list of all the possible colors and combinations, however this means that you can't use a +datapack to change it. + +diff --git a/src/main/java/net/minecraft/world/entity/animal/Sheep.java b/src/main/java/net/minecraft/world/entity/animal/Sheep.java +index 9399361c8d26a140fa6042988a30a1d3d552e418..5bfb246bfabf82feb805665b0be1a36ce62996ca 100644 +--- a/src/main/java/net/minecraft/world/entity/animal/Sheep.java ++++ b/src/main/java/net/minecraft/world/entity/animal/Sheep.java +@@ -431,19 +431,27 @@ public class Sheep extends Animal implements Shearable { + } + + private DyeColor getOffspringColor(Animal firstParent, Animal secondParent) { ++ // Plazma start - CarpetFixes - Optimized sheep chile color + DyeColor enumcolor = ((Sheep) firstParent).getColor(); + DyeColor enumcolor1 = ((Sheep) secondParent).getColor(); +- CraftingContainer inventorycrafting = Sheep.makeContainer(enumcolor, enumcolor1); +- Optional optional = this.level.getRecipeManager().getRecipeFor(RecipeType.CRAFTING, inventorycrafting, this.level).map((recipecrafting) -> { // CraftBukkit - decompile error +- return recipecrafting.assemble(inventorycrafting, this.level.registryAccess()); +- }).map(ItemStack::getItem); +- +- Objects.requireNonNull(DyeItem.class); +- optional = optional.filter(DyeItem.class::isInstance); +- Objects.requireNonNull(DyeItem.class); +- return (DyeColor) optional.map(DyeItem.class::cast).map(DyeItem::getDyeColor).orElseGet(() -> { +- return this.level.random.nextBoolean() ? enumcolor : enumcolor1; +- }); ++ if (this.level.plazmaLevelConfiguration().carpetFixes.optimizedSheepChildColor()) { ++ DyeColor col = org.plazmamc.plazma.util.CarpetFixesUtils.properDyeMixin(enumcolor, enumcolor1); ++ if (col == null) col = this.level.random.nextBoolean() ? enumcolor : enumcolor1; ++ return col; ++ } else { ++ CraftingContainer inventorycrafting = Sheep.makeContainer(enumcolor, enumcolor1); ++ Optional optional = this.level.getRecipeManager().getRecipeFor(RecipeType.CRAFTING, inventorycrafting, this.level).map((recipecrafting) -> { // CraftBukkit - decompile error ++ return recipecrafting.assemble(inventorycrafting, this.level.registryAccess()); ++ }).map(ItemStack::getItem); ++ ++ Objects.requireNonNull(DyeItem.class); ++ optional = optional.filter(DyeItem.class::isInstance); ++ Objects.requireNonNull(DyeItem.class); ++ return (DyeColor) optional.map(DyeItem.class::cast).map(DyeItem::getDyeColor).orElseGet(() -> { ++ return this.level.random.nextBoolean() ? enumcolor : enumcolor1; ++ }); ++ } ++ // Plazma end + } + + private static CraftingContainer makeContainer(DyeColor firstColor, DyeColor secondColor) { +diff --git a/src/main/java/org/plazmamc/plazma/configurations/LevelConfigurations.java b/src/main/java/org/plazmamc/plazma/configurations/LevelConfigurations.java +index dde4eeb834ed71cb7a22ec212e13afea2156a44c..dc0a8f9c737a29cb60cb769bb778e7e1b733fc34 100644 +--- a/src/main/java/org/plazmamc/plazma/configurations/LevelConfigurations.java ++++ b/src/main/java/org/plazmamc/plazma/configurations/LevelConfigurations.java +@@ -138,10 +138,15 @@ public class LevelConfigurations extends ConfigurationPart { + + public boolean enabled = DO_OPTIMIZE; + boolean optimizedRecipeManager = true; ++ boolean optimizedSheepChildColor = false; + + public boolean optimizedRecipeManager() { + return enabled && optimizedRecipeManager; + } + ++ public boolean optimizedSheepChildColor() { ++ return enabled && optimizedSheepChildColor; ++ } ++ + } + } +diff --git a/src/main/java/org/plazmamc/plazma/util/CarpetFixesUtils.java b/src/main/java/org/plazmamc/plazma/util/CarpetFixesUtils.java +new file mode 100644 +index 0000000000000000000000000000000000000000..aae3cf170bca4b3e6cdd0a964967dfafe2759f65 +--- /dev/null ++++ b/src/main/java/org/plazmamc/plazma/util/CarpetFixesUtils.java +@@ -0,0 +1,48 @@ ++package org.plazmamc.plazma.util; ++ ++import net.minecraft.world.item.DyeColor; ++ ++public class CarpetFixesUtils { ++ ++ //If I was actually implementing this, the color values would have been binary in order for fast calculations. ++ //Never do this in a production build, although this is better than using the RecipeManager xD ++ public static DyeColor properDyeMixin(DyeColor col1, DyeColor col2) { ++ if (col1.equals(col2)) return col1; ++ switch(col1) { ++ case WHITE -> { ++ switch(col2) { ++ case BLUE -> {return DyeColor.LIGHT_BLUE;} ++ case GRAY -> {return DyeColor.LIGHT_GRAY;} ++ case BLACK -> {return DyeColor.GRAY;} ++ case GREEN -> {return DyeColor.LIME;} ++ case RED -> {return DyeColor.PINK;} ++ } ++ } ++ case BLUE -> { ++ switch(col2) { ++ case WHITE -> {return DyeColor.LIGHT_BLUE;} ++ case GREEN -> {return DyeColor.CYAN;} ++ case RED -> {return DyeColor.PURPLE;} ++ } ++ } ++ case RED -> { ++ switch(col2) { ++ case YELLOW -> {return DyeColor.ORANGE;} ++ case WHITE -> {return DyeColor.PINK;} ++ case BLUE -> {return DyeColor.PURPLE;} ++ } ++ }case GREEN -> { ++ switch(col2) { ++ case BLUE -> {return DyeColor.CYAN;} ++ case WHITE -> {return DyeColor.LIME;} ++ } ++ } ++ case YELLOW -> {if (col2.equals(DyeColor.RED)) return DyeColor.ORANGE;} ++ case PURPLE -> {if (col2.equals(DyeColor.PINK)) return DyeColor.MAGENTA;} ++ case PINK -> {if (col2.equals(DyeColor.PURPLE)) return DyeColor.MAGENTA;} ++ case GRAY -> {if (col2.equals(DyeColor.WHITE)) return DyeColor.LIGHT_GRAY;} ++ case BLACK -> {if (col2.equals(DyeColor.WHITE)) return DyeColor.GRAY;} ++ } ++ return null; ++ } ++}