diff --git a/feature-patches/1049-Optimize-Voxel-Shape-Merging.patch b/feature-patches/1049-Optimize-Voxel-Shape-Merging.patch index 16a5277743..b9255fa095 100644 --- a/feature-patches/1049-Optimize-Voxel-Shape-Merging.patch +++ b/feature-patches/1049-Optimize-Voxel-Shape-Merging.patch @@ -29,32 +29,31 @@ and compute a deterministic result for the MergerList values. Additionally, this lets us avoid even allocating new objects for this too, further reducing memory usage. -diff --git a/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java b/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java -+++ b/src/main/java/net/minecraft/world/phys/shapes/IndirectMerger.java -@@ -0,0 +0,0 @@ public class IndirectMerger implements IndexMerger { +diff --git a/net/minecraft/world/phys/shapes/IndirectMerger.java b/net/minecraft/world/phys/shapes/IndirectMerger.java +index 60b56a5086b8aad0fad693f686b89138b3a4c80d..5b079ec43c259368d0eed4e8385880712abda4f7 100644 +--- a/net/minecraft/world/phys/shapes/IndirectMerger.java ++++ b/net/minecraft/world/phys/shapes/IndirectMerger.java +@@ -10,12 +10,32 @@ public class IndirectMerger implements IndexMerger { private final int[] firstIndices; private final int[] secondIndices; private final int resultLength; + // Paper start -+ private static final int[] INFINITE_B_1 = new int[]{1, 1}; -+ private static final int[] INFINITE_B_0 = new int[]{0, 0}; -+ private static final int[] INFINITE_C = new int[]{0, 1}; ++ private static final int[] INFINITE_B_1 = {1, 1}; ++ private static final int[] INFINITE_B_0 = {0, 0}; ++ private static final int[] INFINITE_C = {0, 1}; + // Paper end - public IndirectMerger(DoubleList first, DoubleList second, boolean includeFirstOnly, boolean includeSecondOnly) { + public IndirectMerger(DoubleList lower, DoubleList upper, boolean excludeUpper, boolean excludeLower) { double d = Double.NaN; - int i = first.size(); - int j = second.size(); - int k = i + j; + int size = lower.size(); + int size1 = upper.size(); + int i = size + size1; + // Paper start - optimize common path of infinity doublelist -+ int size = first.size(); -+ double tail = first.getDouble(size - 1); -+ double head = first.getDouble(0); -+ if (head == Double.NEGATIVE_INFINITY && tail == Double.POSITIVE_INFINITY && !includeFirstOnly && !includeSecondOnly && (size == 2 || size == 4)) { -+ this.result = second.toDoubleArray(); -+ this.resultLength = second.size(); ++ double tail = lower.getDouble(size - 1); ++ double head = lower.getDouble(0); ++ if (head == Double.NEGATIVE_INFINITY && tail == Double.POSITIVE_INFINITY && !excludeUpper && !excludeLower && (size == 2 || size == 4)) { ++ this.result = upper.toDoubleArray(); ++ this.resultLength = upper.size(); + if (size == 2) { + this.firstIndices = INFINITE_B_0; + } else { @@ -64,60 +63,60 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return; + } + // Paper end - this.result = new double[k]; - this.firstIndices = new int[k]; - this.secondIndices = new int[k]; -diff --git a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java -+++ b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java -@@ -0,0 +0,0 @@ public final class Shapes { + this.result = new double[i]; + this.firstIndices = new int[i]; + this.secondIndices = new int[i]; +diff --git a/net/minecraft/world/phys/shapes/Shapes.java b/net/minecraft/world/phys/shapes/Shapes.java +index e1b4c4b53844b0755e0640a05e8782fd9a7700a2..e759221fb54aa510d2d8bbba47e1d794367aec6d 100644 +--- a/net/minecraft/world/phys/shapes/Shapes.java ++++ b/net/minecraft/world/phys/shapes/Shapes.java +@@ -279,9 +279,22 @@ public final class Shapes { } @VisibleForTesting -- protected static IndexMerger createIndexMerger(int size, DoubleList first, DoubleList second, boolean includeFirst, boolean includeSecond) { -+ private static IndexMerger createIndexMerger(int size, DoubleList first, DoubleList second, boolean includeFirst, boolean includeSecond) { // Paper - private +- protected static IndexMerger createIndexMerger(int size, DoubleList list1, DoubleList list2, boolean excludeUpper, boolean excludeLower) { ++ private static IndexMerger createIndexMerger(int size, DoubleList list1, DoubleList list2, boolean excludeUpper, boolean excludeLower) { // Paper - private + // Paper start - fast track the most common scenario + // doublelist is usually a DoubleArrayList with Infinite head/tails that falls to the final else clause + // This is actually the most common path, so jump to it straight away -+ if (first.getDouble(0) == Double.NEGATIVE_INFINITY && first.getDouble(first.size() - 1) == Double.POSITIVE_INFINITY) { -+ return new IndirectMerger(first, second, includeFirst, includeSecond); ++ if (list1.getDouble(0) == Double.NEGATIVE_INFINITY && list1.getDouble(list1.size() - 1) == Double.POSITIVE_INFINITY) { ++ return new IndirectMerger(list1, list2, excludeUpper, excludeLower); + } + // Split out rest to hopefully inline the above -+ return lessCommonMerge(size, first, second, includeFirst, includeSecond); ++ return lessCommonMerge(size, list1, list2, excludeUpper, excludeLower); + } + -+ private static IndexMerger lessCommonMerge(int size, DoubleList first, DoubleList second, boolean includeFirst, boolean includeSecond) { - int i = first.size() - 1; - int j = second.size() - 1; ++ private static IndexMerger lessCommonMerge(int size, DoubleList list1, DoubleList list2, boolean excludeUpper, boolean excludeLower) { ++ // Paper end - fast track the most common scenario + int i = list1.size() - 1; + int i1 = list2.size() - 1; + // Paper note - Rewrite below as optimized order if instead of nasty ternary - if (first instanceof CubePointRange && second instanceof CubePointRange) { - long l = lcm(i, j); - if ((long)size * l <= 256L) { -@@ -0,0 +0,0 @@ public final class Shapes { + if (list1 instanceof CubePointRange && list2 instanceof CubePointRange) { + long l = lcm(i, i1); + if (size * l <= 256L) { +@@ -289,14 +302,21 @@ public final class Shapes { } } -- if (first.getDouble(i) < second.getDouble(0) - 1.0E-7) { +- if (list1.getDouble(i) < list2.getDouble(0) - 1.0E-7) { + // Paper start - Identical happens more often than Disjoint -+ if (i == j && Objects.equals(first, second)) { -+ if (first instanceof IdenticalMerger) { -+ return (IndexMerger) first; -+ } else if (second instanceof IdenticalMerger) { -+ return (IndexMerger) second; ++ if (i == i1 && Objects.equals(list1, list2)) { ++ if (list1 instanceof IdenticalMerger) { ++ return (IndexMerger) list1; ++ } else if (list2 instanceof IdenticalMerger) { ++ return (IndexMerger) list2; + } -+ return new IdenticalMerger(first); -+ } else if (first.getDouble(i) < second.getDouble(0) - 1.0E-7) { - return new NonOverlappingMerger(first, second, false); - } else if (second.getDouble(j) < first.getDouble(0) - 1.0E-7) { - return new NonOverlappingMerger(second, first, true); ++ return new IdenticalMerger(list1); ++ } else if (list1.getDouble(i) < list2.getDouble(0) - 1.0E-7) { ++ // Paper end - Identical happens more often than Disjoint + return new NonOverlappingMerger(list1, list2, false); + } else if (list2.getDouble(i1) < list1.getDouble(0) - 1.0E-7) { + return new NonOverlappingMerger(list2, list1, true); } else { -- return (IndexMerger)(i == j && Objects.equals(first, second) -- ? new IdenticalMerger(first) -- : new IndirectMerger(first, second, includeFirst, includeSecond)); -+ return new IndirectMerger(first, second, includeFirst, includeSecond); +- return (IndexMerger)(i == i1 && Objects.equals(list1, list2) +- ? new IdenticalMerger(list1) +- : new IndirectMerger(list1, list2, excludeUpper, excludeLower)); ++ return new IndirectMerger(list1, list2, excludeUpper, excludeLower); // Paper - Identical happens more often than Disjoint } -+ // Paper end } - public interface DoubleLineConsumer { diff --git a/feature-patches/1053-Fix-entity-type-tags-suggestions-in-selectors.patch b/feature-patches/1053-Fix-entity-type-tags-suggestions-in-selectors.patch index d5c45f7291..0f7eeec9d8 100644 --- a/feature-patches/1053-Fix-entity-type-tags-suggestions-in-selectors.patch +++ b/feature-patches/1053-Fix-entity-type-tags-suggestions-in-selectors.patch @@ -9,11 +9,11 @@ when if this was fixed on the client, that wouldn't be needed. Mojira Issue: https://bugs.mojang.com/browse/MC-235045 -diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/commands/CommandSourceStack.java -+++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java -@@ -0,0 +0,0 @@ public class CommandSourceStack implements ExecutionCommandSource, CommandNode> commandNodeToSuggestionNode + ) { + commandNodeToSuggestionNode.keySet().removeIf((node) -> !org.spigotmc.SpigotConfig.sendNamespaced && node.getName().contains(":")); // Paper - Remove namedspaced from result nodes to prevent redirect trimming ~ see comment below + boolean registeredAskServerSuggestionsForTree = false; // Paper - tell clients to ask server for suggestions for EntityArguments - while (iterator.hasNext()) { - CommandNode commandnode2 = (CommandNode) iterator.next(); + for (CommandNode commandNode : children) { // Paper - Perf: Async command map building; pass copy of children // Paper start - Brigadier API -@@ -0,0 +0,0 @@ public class Commands { - - if (requiredargumentbuilder.getSuggestionsProvider() != null) { - requiredargumentbuilder.suggests(SuggestionProviders.safelySwap(requiredargumentbuilder.getSuggestionsProvider())); + if (commandNode.clientNode != null) { +@@ -572,6 +573,12 @@ public class Commands { + RequiredArgumentBuilder requiredArgumentBuilder = (RequiredArgumentBuilder)argumentBuilder; + if (requiredArgumentBuilder.getSuggestionsProvider() != null) { + requiredArgumentBuilder.suggests(SuggestionProviders.safelySwap(requiredArgumentBuilder.getSuggestionsProvider())); + // Paper start - tell clients to ask server for suggestions for EntityArguments -+ registeredAskServerSuggestionsForTree = requiredargumentbuilder.getSuggestionsProvider() == net.minecraft.commands.synchronization.SuggestionProviders.ASK_SERVER; -+ } else if (io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && !registeredAskServerSuggestionsForTree && requiredargumentbuilder.getType() instanceof net.minecraft.commands.arguments.EntityArgument) { -+ requiredargumentbuilder.suggests(requiredargumentbuilder.getType()::listSuggestions); ++ registeredAskServerSuggestionsForTree = requiredArgumentBuilder.getSuggestionsProvider() == net.minecraft.commands.synchronization.SuggestionProviders.ASK_SERVER; ++ } else if (io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && !registeredAskServerSuggestionsForTree && requiredArgumentBuilder.getType() instanceof net.minecraft.commands.arguments.EntityArgument) { ++ requiredArgumentBuilder.suggests(requiredArgumentBuilder.getType()::listSuggestions); + registeredAskServerSuggestionsForTree = true; // You can only + // Paper end - tell clients to ask server for suggestions for EntityArguments } } -diff --git a/src/main/java/net/minecraft/commands/arguments/EntityArgument.java b/src/main/java/net/minecraft/commands/arguments/EntityArgument.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/commands/arguments/EntityArgument.java -+++ b/src/main/java/net/minecraft/commands/arguments/EntityArgument.java -@@ -0,0 +0,0 @@ public class EntityArgument implements ArgumentType { - final boolean permission = object instanceof CommandSourceStack stack - ? stack.bypassSelectorPermissions || stack.hasPermission(2, "minecraft.command.selector") - : icompletionprovider.hasPermission(2); -- EntitySelectorParser argumentparserselector = new EntitySelectorParser(stringreader, permission); -+ EntitySelectorParser argumentparserselector = new EntitySelectorParser(stringreader, permission, true); // Paper - tell clients to ask server for suggestions for EntityArguments +diff --git a/net/minecraft/commands/arguments/EntityArgument.java b/net/minecraft/commands/arguments/EntityArgument.java +index ba9a7636e158222bcfb50ae8487f29df6fdbdd0c..8957b99116cb087198fe372d4d2c2b3397fed19f 100644 +--- a/net/minecraft/commands/arguments/EntityArgument.java ++++ b/net/minecraft/commands/arguments/EntityArgument.java +@@ -138,7 +138,7 @@ public class EntityArgument implements ArgumentType { + final boolean permission = sharedSuggestionProvider instanceof CommandSourceStack stack + ? stack.bypassSelectorPermissions || stack.hasPermission(2, "minecraft.command.selector") + : sharedSuggestionProvider.hasPermission(2); +- EntitySelectorParser entitySelectorParser = new EntitySelectorParser(stringReader, permission); ++ EntitySelectorParser entitySelectorParser = new EntitySelectorParser(stringReader, permission, true); // Paper - tell clients to ask server for suggestions for EntityArguments // Paper end - Fix EntityArgument permissions try { -@@ -0,0 +0,0 @@ public class EntityArgument implements ArgumentType { - } - - return argumentparserselector.fillSuggestions(suggestionsbuilder, (suggestionsbuilder1) -> { -- Collection collection = icompletionprovider.getOnlinePlayerNames(); -+ // Paper start - tell clients to ask server for suggestions for EntityArguments -+ final Collection collection; -+ if (icompletionprovider instanceof CommandSourceStack commandSourceStack && commandSourceStack.getEntity() instanceof ServerPlayer sourcePlayer) { -+ collection = new java.util.ArrayList<>(); -+ for (final ServerPlayer player : commandSourceStack.getServer().getPlayerList().getPlayers()) { -+ if (sourcePlayer.getBukkitEntity().canSee(player.getBukkitEntity())) { -+ collection.add(player.getGameProfile().getName()); +@@ -149,7 +149,19 @@ public class EntityArgument implements ArgumentType { + return entitySelectorParser.fillSuggestions( + builder, + offsetBuilder -> { +- Collection onlinePlayerNames = sharedSuggestionProvider.getOnlinePlayerNames(); ++ // Paper start - tell clients to ask server for suggestions for EntityArguments ++ final Collection onlinePlayerNames; ++ if (sharedSuggestionProvider instanceof CommandSourceStack commandSourceStack && commandSourceStack.getEntity() instanceof ServerPlayer sourcePlayer) { ++ onlinePlayerNames = new java.util.ArrayList<>(); ++ for (final ServerPlayer player : commandSourceStack.getServer().getPlayerList().getPlayers()) { ++ if (sourcePlayer.getBukkitEntity().canSee(player.getBukkitEntity())) { ++ onlinePlayerNames.add(player.getGameProfile().getName()); ++ } + } ++ } else { ++ onlinePlayerNames = sharedSuggestionProvider.getOnlinePlayerNames(); + } -+ } else { -+ collection = icompletionprovider.getOnlinePlayerNames(); -+ } -+ // Paper end - tell clients to ask server for suggestions for EntityArguments - Iterable iterable = this.playersOnly ? collection : Iterables.concat(collection, icompletionprovider.getSelectedEntities()); - - SharedSuggestionProvider.suggest((Iterable) iterable, suggestionsbuilder1); -diff --git a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java -+++ b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java -@@ -0,0 +0,0 @@ public class EntitySelectorParser { ++ // Paper end - tell clients to ask server for suggestions for EntityArguments + Iterable iterable = (Iterable)(this.playersOnly + ? onlinePlayerNames + : Iterables.concat(onlinePlayerNames, sharedSuggestionProvider.getSelectedEntities())); +diff --git a/net/minecraft/commands/arguments/selector/EntitySelectorParser.java b/net/minecraft/commands/arguments/selector/EntitySelectorParser.java +index a6f232747df631f6afe440606bea94c588f1a0dd..fb42630741674c6cbd20b7d45d78dea1dc73a78f 100644 +--- a/net/minecraft/commands/arguments/selector/EntitySelectorParser.java ++++ b/net/minecraft/commands/arguments/selector/EntitySelectorParser.java +@@ -115,8 +115,15 @@ public class EntitySelectorParser { private boolean hasScores; private boolean hasAdvancements; private boolean usesSelectors; + public boolean parsingEntityArgumentSuggestions; // Paper - tell clients to ask server for suggestions for EntityArguments - public EntitySelectorParser(StringReader reader, boolean atAllowed) { + public EntitySelectorParser(StringReader reader, boolean allowSelectors) { + // Paper start - tell clients to ask server for suggestions for EntityArguments -+ this(reader, atAllowed, false); ++ this(reader, allowSelectors, false); + } -+ public EntitySelectorParser(StringReader reader, boolean atAllowed, boolean parsingEntityArgumentSuggestions) { ++ public EntitySelectorParser(StringReader reader, boolean allowSelectors, boolean parsingEntityArgumentSuggestions) { + this.parsingEntityArgumentSuggestions = parsingEntityArgumentSuggestions; + // Paper end - tell clients to ask server for suggestions for EntityArguments - this.distance = MinMaxBounds.Doubles.ANY; - this.level = MinMaxBounds.Ints.ANY; - this.rotX = WrappedMinMaxBounds.ANY; -diff --git a/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java b/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java -+++ b/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java -@@ -0,0 +0,0 @@ public class EntitySelectorOptions { + this.reader = reader; + this.allowSelectors = allowSelectors; + } +diff --git a/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java b/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java +index f6b58139aace70436034f0a16370236d975cb4ae..ee9949c41d38817b21b6f4fd728059a46fddf135 100644 +--- a/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java ++++ b/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java +@@ -76,6 +76,19 @@ public class EntitySelectorOptions { public static final DynamicCommandExceptionType ERROR_ENTITY_TYPE_INVALID = new DynamicCommandExceptionType( - entity -> Component.translatableEscape("argument.entity.options.type.invalid", entity) + type -> Component.translatableEscape("argument.entity.options.type.invalid", type) ); + // Paper start - tell clients to ask server for suggestions for EntityArguments + public static final DynamicCommandExceptionType ERROR_ENTITY_TAG_INVALID = new DynamicCommandExceptionType((object) -> { @@ -135,18 +135,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + }); + // Paper end - tell clients to ask server for suggestions for EntityArguments - private static void register(String id, EntitySelectorOptions.Modifier handler, Predicate condition, Component description) { - OPTIONS.put(id, new EntitySelectorOptions.Option(handler, condition, description)); -@@ -0,0 +0,0 @@ public class EntitySelectorOptions { + private static void register(String id, EntitySelectorOptions.Modifier handler, Predicate predicate, Component tooltip) { + OPTIONS.put(id, new EntitySelectorOptions.Option(handler, predicate, tooltip)); +@@ -299,6 +312,12 @@ public class EntitySelectorOptions { - if (reader.isTag()) { - TagKey> tagKey = TagKey.create(Registries.ENTITY_TYPE, ResourceLocation.read(reader.getReader())); + if (parser.isTag()) { + TagKey> tagKey = TagKey.create(Registries.ENTITY_TYPE, ResourceLocation.read(parser.getReader())); + // Paper start - tell clients to ask server for suggestions for EntityArguments; throw error if invalid entity tag (only on suggestions to keep cmd success behavior) -+ if (reader.parsingEntityArgumentSuggestions && io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && net.minecraft.core.registries.BuiltInRegistries.ENTITY_TYPE.get(tagKey).isEmpty()) { -+ reader.getReader().setCursor(i); -+ throw ERROR_ENTITY_TAG_INVALID.createWithContext(reader.getReader(), tagKey); ++ if (parser.parsingEntityArgumentSuggestions && io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && net.minecraft.core.registries.BuiltInRegistries.ENTITY_TYPE.get(tagKey).isEmpty()) { ++ parser.getReader().setCursor(cursor); ++ throw ERROR_ENTITY_TAG_INVALID.createWithContext(parser.getReader(), tagKey); + } + // Paper end - tell clients to ask server for suggestions for EntityArguments - reader.addPredicate(entity -> entity.getType().is(tagKey) != bl); + parser.addPredicate(entity -> entity.getType().is(tagKey) != shouldInvertValue); } else { - ResourceLocation resourceLocation = ResourceLocation.read(reader.getReader()); + ResourceLocation resourceLocation = ResourceLocation.read(parser.getReader()); diff --git a/feature-patches/1057-Optimise-getChunkAt-calls-for-loaded-chunks.patch b/feature-patches/1057-Optimise-getChunkAt-calls-for-loaded-chunks.patch index 1138fb6f90..0fcf7dd22f 100644 --- a/feature-patches/1057-Optimise-getChunkAt-calls-for-loaded-chunks.patch +++ b/feature-patches/1057-Optimise-getChunkAt-calls-for-loaded-chunks.patch @@ -51,7 +51,7 @@ index d310e7489fc4ecede8deef59241444769d87b0a1..f268808cb250e374f2d5652b20eece01 - - return null; - } -+ return this.getChunkAtIfLoadedMainThread(chunkX, chunkZ); // Paper - Perf: Optimise getChunkAt calls for loaded chunk ++ return this.getChunkAtIfLoadedMainThread(chunkX, chunkZ); // Paper - Perf: Optimise getChunkAt calls for loaded chunks } }