diff --git a/leaf-server/minecraft-patches/features/0272-Replace-EntitySelectorOptions-map-with-optimized-col.patch b/leaf-server/minecraft-patches/features/0272-Replace-EntitySelectorOptions-map-with-optimized-col.patch new file mode 100644 index 00000000..2922a776 --- /dev/null +++ b/leaf-server/minecraft-patches/features/0272-Replace-EntitySelectorOptions-map-with-optimized-col.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> +Date: Tue, 9 Nov 2077 00:00:00 +0800 +Subject: [PATCH] Replace EntitySelectorOptions map with optimized collection + + +diff --git a/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java b/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java +index 3b945ac061f192b09dd86e8627dacf11b190d2d9..9e2fd3684260fad1d94a795cb5617c5ccc231adc 100644 +--- a/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java ++++ b/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java +@@ -357,7 +357,7 @@ public class EntitySelectorOptions { + }, entitySelectorParser -> true, Component.translatable("argument.entity.options.nbt.description")); + register("scores", parser -> { + StringReader reader = parser.getReader(); +- Map map = Maps.newHashMap(); ++ it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap map = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(); // Leaf - Replace options map with optimized collection + reader.expect('{'); + reader.skipWhitespace(); + +@@ -380,7 +380,7 @@ public class EntitySelectorOptions { + parser.addPredicate(entity -> { + Scoreboard scoreboard = entity.getServer().getScoreboard(); + +- for (Entry entry : map.entrySet()) { ++ for (Entry entry : map.object2ObjectEntrySet()) { // Leaf - Replace options map with optimized collection + Objective objective = scoreboard.getObjective(entry.getKey()); + if (objective == null) { + return false; diff --git a/leaf-server/minecraft-patches/features/0273-Cache-function-execution-result.patch b/leaf-server/minecraft-patches/features/0273-Cache-function-execution-result.patch new file mode 100644 index 00000000..e75ba658 --- /dev/null +++ b/leaf-server/minecraft-patches/features/0273-Cache-function-execution-result.patch @@ -0,0 +1,98 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com> +Date: Tue, 9 Nov 2077 00:00:00 +0800 +Subject: [PATCH] Cache function execution result + + +diff --git a/net/minecraft/commands/arguments/EntityArgument.java b/net/minecraft/commands/arguments/EntityArgument.java +index 8f6a1788b5ca396b79a638955fc6a6b3a276337f..595539574b4a71e0e9f8209569700cf0c7df8197 100644 +--- a/net/minecraft/commands/arguments/EntityArgument.java ++++ b/net/minecraft/commands/arguments/EntityArgument.java +@@ -65,6 +65,37 @@ public class EntityArgument implements ArgumentType { + } + } + ++ // Leaf start - Cache function getEntity calls ++ public static final java.util.Map> TICK_ENTITY_CACHE = new java.util.concurrent.ConcurrentHashMap<>(); ++ public static Collection getOptionalEntitiesCachedAs(CommandContext context, String name) throws CommandSyntaxException { ++ if (!(context.getSource().source instanceof net.minecraft.server.MinecraftServer)) return getOptionalEntities(context, name); ++ EntitySelector selector = context.getArgument(name, EntitySelector.class); ++ List> nodes = context.getNodes(); ++ int idxStart = nodes.get(1).getRange().getStart(); ++ int idxEnd = nodes.get(2).getRange().getEnd(); ++ String selectorString = context.getInput().substring(idxStart, idxEnd); ++ List entities = TICK_ENTITY_CACHE.get(selectorString); ++ if (entities == null) { ++ entities = selector.findEntities(context.getSource()); ++ TICK_ENTITY_CACHE.put(selectorString, entities); ++ } ++ return entities; ++ } ++ public static Collection getOptionalEntitiesCachedPositionedAs(CommandContext context, String name) throws CommandSyntaxException { ++ if (!(context.getSource().source instanceof net.minecraft.server.MinecraftServer)) return getOptionalEntities(context, name); ++ EntitySelector selector = context.getArgument(name, EntitySelector.class); ++ List> nodes = context.getNodes(); ++ int idxStart = nodes.get(1).getRange().getStart(); ++ int idxEnd = nodes.get(3).getRange().getEnd(); ++ String selectorString = context.getInput().substring(idxStart, idxEnd); ++ List entities = TICK_ENTITY_CACHE.get(selectorString); ++ if (entities == null) { ++ entities = selector.findEntities(context.getSource()); ++ TICK_ENTITY_CACHE.put(selectorString, entities); ++ } ++ return entities; ++ } ++ // Leaf end - Cache function getEntity calls + public static Collection getOptionalEntities(CommandContext context, String name) throws CommandSyntaxException { + return context.getArgument(name, EntitySelector.class).findEntities(context.getSource()); + } +diff --git a/net/minecraft/server/ServerFunctionManager.java b/net/minecraft/server/ServerFunctionManager.java +index 10c79570432491bfb2bbfedf0491ab2b803d0c71..a8e64068c6ac76fe0c5bdebadd537f9f8a3435b9 100644 +--- a/net/minecraft/server/ServerFunctionManager.java ++++ b/net/minecraft/server/ServerFunctionManager.java +@@ -35,6 +35,7 @@ public class ServerFunctionManager { + return this.server.getCommands().getDispatcher(); + } + ++ int ticksCached = 0; // Leaf - Cache function getEntity calls + public void tick() { + if (this.server.tickRateManager().runsNormally()) { + if (this.postReload) { +@@ -44,6 +45,15 @@ public class ServerFunctionManager { + } + + this.executeTagFunctions(this.ticking, TICK_FUNCTION_TAG); ++ // Leaf start - Cache function getEntity calls ++ if (org.dreeam.leaf.config.modules.opt.CacheExecuteCommandResult.cacheExecuteCommandResult) { ++ ticksCached++; ++ if (ticksCached > 1) { ++ net.minecraft.commands.arguments.EntityArgument.TICK_ENTITY_CACHE.clear(); ++ ticksCached = 0; ++ } ++ } ++ // Leaf end - Cache function getEntity calls + } + } + +diff --git a/net/minecraft/server/commands/ExecuteCommand.java b/net/minecraft/server/commands/ExecuteCommand.java +index 862ab68b3904873b72928463c6651aafe69c977c..512476098a6c03132e55ecc2c4c1cbcf2d644671 100644 +--- a/net/minecraft/server/commands/ExecuteCommand.java ++++ b/net/minecraft/server/commands/ExecuteCommand.java +@@ -148,7 +148,7 @@ public class ExecuteCommand { + .then(Commands.literal("as").then(Commands.argument("targets", EntityArgument.entities()).fork(literalCommandNode, commandContext -> { + List list = Lists.newArrayList(); + +- for (Entity entity : EntityArgument.getOptionalEntities(commandContext, "targets")) { ++ for (Entity entity : org.dreeam.leaf.config.modules.opt.CacheExecuteCommandResult.cacheExecuteCommandResult ? EntityArgument.getOptionalEntitiesCachedAs(commandContext, "targets") : EntityArgument.getOptionalEntities(commandContext, "targets")) { // Leaf - Cache function getEntity calls + list.add(commandContext.getSource().withEntity(entity)); + } + +@@ -196,7 +196,7 @@ public class ExecuteCommand { + .then(Commands.literal("as").then(Commands.argument("targets", EntityArgument.entities()).fork(literalCommandNode, context -> { + List list = Lists.newArrayList(); + +- for (Entity entity : EntityArgument.getOptionalEntities(context, "targets")) { ++ for (Entity entity : org.dreeam.leaf.config.modules.opt.CacheExecuteCommandResult.cacheExecuteCommandResult ? EntityArgument.getOptionalEntitiesCachedPositionedAs(context, "targets") : EntityArgument.getOptionalEntities(context, "targets")) { // Leaf - Cache function getEntity calls + list.add(context.getSource().withPosition(entity.position())); + } + diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/CacheExecuteCommandResult.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/CacheExecuteCommandResult.java new file mode 100644 index 00000000..77dfee11 --- /dev/null +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/CacheExecuteCommandResult.java @@ -0,0 +1,28 @@ +package org.dreeam.leaf.config.modules.opt; + +import org.dreeam.leaf.config.ConfigModules; +import org.dreeam.leaf.config.EnumConfigCategory; +import org.dreeam.leaf.config.annotations.Experimental; + +public class CacheExecuteCommandResult extends ConfigModules { + + public String getBasePath() { + return EnumConfigCategory.PERF.getBaseKeyName(); + } + + @Experimental + public static boolean cacheExecuteCommandResult = false; + + @Override + public void onLoaded() { + cacheExecuteCommandResult = config.getBoolean(getBasePath() + ".cache-execute-command-result", cacheExecuteCommandResult, + config.pickStringRegionBased(""" + *** Experimental Feature *** + Cache the result of same execute command in the current and next tick. + Will improve performance on servers with massive datapack functions.""", + """ + *** 实验性功能 *** + 缓存当前和下一 tick 相同的 execute 命令结果. + 将会提升有大量数据包函数的服务器性能.""")); + } +}