From d166b820ceab871ea8a5e28f135ff7b5fcbdd5e8 Mon Sep 17 00:00:00 2001 From: violetc <58360096+s-yh-china@users.noreply.github.com> Date: Thu, 20 Jul 2023 16:19:59 +0800 Subject: [PATCH] Use optimized collection --- ...004-Leaves-Server-Config-And-Command.patch | 9 +- .../0102-Use-optimized-collection.patch | 180 ++++++++++++++++++ 2 files changed, 187 insertions(+), 2 deletions(-) create mode 100644 patches/server/0102-Use-optimized-collection.patch diff --git a/patches/server/0004-Leaves-Server-Config-And-Command.patch b/patches/server/0004-Leaves-Server-Config-And-Command.patch index c06159ea..efd614b9 100644 --- a/patches/server/0004-Leaves-Server-Config-And-Command.patch +++ b/patches/server/0004-Leaves-Server-Config-And-Command.patch @@ -128,10 +128,10 @@ index 35d2da9d91dcdd89de7c0f4af028fd182376ea8d..d73482fb1e71fe2951e96ae0593de268 .withRequiredArg() diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java new file mode 100644 -index 0000000000000000000000000000000000000000..85a94d60e52c6a6d0f1bd46b67436fbb53081073 +index 0000000000000000000000000000000000000000..b72d7a188183c6fb3f9ed8978336bc1a188854d4 --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java -@@ -0,0 +1,896 @@ +@@ -0,0 +1,901 @@ +package top.leavesmc.leaves; + +import com.destroystokyo.paper.util.SneakyThrow; @@ -853,6 +853,11 @@ index 0000000000000000000000000000000000000000..85a94d60e52c6a6d0f1bd46b67436fbb + removeDamageLambda = getBoolean("settings.performance.remove.damage-lambda", removeDamageLambda); + } + ++ public static boolean useOptimizedCollection = true; ++ private static void useOptimizedCollection() { ++ useOptimizedCollection = getBoolean("settings.performance.use-optimized-collection", useOptimizedCollection); ++ } ++ + public static final class WorldConfig { + + public final String worldName; diff --git a/patches/server/0102-Use-optimized-collection.patch b/patches/server/0102-Use-optimized-collection.patch new file mode 100644 index 00000000..dec1cfde --- /dev/null +++ b/patches/server/0102-Use-optimized-collection.patch @@ -0,0 +1,180 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: violetc <58360096+s-yh-china@users.noreply.github.com> +Date: Thu, 20 Jul 2023 16:09:56 +0800 +Subject: [PATCH] Use optimized collection + +This patch is Powered by Gale(https://github.com/GaleMC/Gale) + +diff --git a/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java b/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java +index 50a9f33aa31e9273c7c52d4bb2b02f0f884f7ba5..53021c7d173b3c067322e356fead0949aac3fc60 100644 +--- a/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java ++++ b/src/main/java/net/minecraft/util/ClassInstanceMultiMap.java +@@ -13,7 +13,7 @@ import java.util.Map; + import java.util.stream.Collectors; + + public class ClassInstanceMultiMap extends AbstractCollection { +- private final Map, List> byClass = Maps.newHashMap(); ++ private final Map, List> byClass = top.leavesmc.leaves.LeavesConfig.useOptimizedCollection ? new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(2) : Maps.newHashMap(); // Leaves - replace class map with optimized collection + private final Class baseClass; + private final List allInstances = Lists.newArrayList(); + +@@ -58,7 +58,7 @@ public class ClassInstanceMultiMap extends AbstractCollection { + if (!this.baseClass.isAssignableFrom(type)) { + throw new IllegalArgumentException("Don't know how to search for " + type); + } else { +- List list = this.byClass.computeIfAbsent(type, (typeClass) -> { ++ List list = this.byClass.computeIfAbsent(type, (typeClass) -> { // Leaves - dev fix + return this.allInstances.stream().filter(typeClass::isInstance).collect(Collectors.toList()); + }); + return Collections.unmodifiableCollection(list); +diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java +index 53c094c8a674b2842009727569e7e1f6ac6510b7..c5b0ef5fa68e10987e75535fe18450930966ba24 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java ++++ b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeMap.java +@@ -20,8 +20,10 @@ import org.slf4j.Logger; + + public class AttributeMap { + private static final Logger LOGGER = LogUtils.getLogger(); +- private final Map attributes = Maps.newHashMap(); +- private final Set dirtyAttributes = Sets.newHashSet(); ++ // Leaves start - replace AI attributes with optimized collections ++ private final Map attributes = top.leavesmc.leaves.LeavesConfig.useOptimizedCollection ? new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(0) : Maps.newHashMap(); ++ private final Set dirtyAttributes = top.leavesmc.leaves.LeavesConfig.useOptimizedCollection ? new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(0) : Sets.newHashSet(); ++ // Leaves end - replace AI attributes with optimized collections + private final AttributeSupplier supplier; + private final java.util.function.Function createInstance; // Leaves - reduce entity allocations + +diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java +index b738ee2d3801fadfd09313f05ae24593e56b0ec6..2d1abb9518795875b3719efe91e60508c2c73163 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java ++++ b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java +@@ -28,7 +28,7 @@ public class GoalSelector { + } + }; + private final Map lockedFlags = new EnumMap<>(Goal.Flag.class); +- private final Set availableGoals = Sets.newLinkedHashSet(); ++ private final Set availableGoals = top.leavesmc.leaves.LeavesConfig.useOptimizedCollection ? new it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet<>() : Sets.newLinkedHashSet(); // Leaves - replace AI goal set with optimized collection + private final Supplier profiler; + private final EnumSet disabledFlags = EnumSet.noneOf(Goal.Flag.class); // Paper unused, but dummy to prevent plugins from crashing as hard. Theyll need to support paper in a special case if this is super important, but really doesn't seem like it would be. + private final com.destroystokyo.paper.util.set.OptimizedSmallEnumSet goalTypes = new com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from pathfindergoalselector +diff --git a/src/main/java/net/minecraft/world/level/GameRules.java b/src/main/java/net/minecraft/world/level/GameRules.java +index 6fa00d9239546aa82b9e92e25a33103868084c38..5d50d9d2700a8943105301ef0ac467e49ce86a02 100644 +--- a/src/main/java/net/minecraft/world/level/GameRules.java ++++ b/src/main/java/net/minecraft/world/level/GameRules.java +@@ -127,7 +127,7 @@ public class GameRules { + } + + private GameRules(Map, GameRules.Value> rules) { +- this.rules = rules; ++ this.rules = top.leavesmc.leaves.LeavesConfig.useOptimizedCollection ? new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(rules) : rules; // Leaves - replace game rules map with optimized collection + + // Paper start + int arraySize = rules.keySet().stream().mapToInt(key -> key.gameRuleIndex).max().orElse(-1) + 1; +diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java +index 96b9d47aa3720491424c35c9e73fc996bfc8cd20..b87ce8e774e1030de8986067a308505c735a494d 100644 +--- a/src/main/java/net/minecraft/world/level/block/Block.java ++++ b/src/main/java/net/minecraft/world/level/block/Block.java +@@ -61,6 +61,7 @@ import net.minecraft.world.phys.shapes.BooleanOp; + import net.minecraft.world.phys.shapes.Shapes; + import net.minecraft.world.phys.shapes.VoxelShape; + import org.slf4j.Logger; ++import top.leavesmc.leaves.lithium.common.util.collections.Object2BooleanCacheTable; + + public class Block extends BlockBehaviour implements ItemLike { + +@@ -72,6 +73,12 @@ public class Block extends BlockBehaviour implements ItemLike { + return !Shapes.joinIsNotEmpty(Shapes.block(), voxelshape, BooleanOp.NOT_SAME); + } + }); ++ // Leaves start - replace shape full block cache with hashtable ++ private static final Object2BooleanCacheTable LITHIUM_SHAPE_FULL_BLOCK_CACHE = new Object2BooleanCacheTable<>( ++ 1536, ++ shape -> !Shapes.joinIsNotEmpty(Shapes.block(), shape, BooleanOp.NOT_SAME) ++ ); ++ // Leaves end - replace shape full block cache with hashtable + public static final int UPDATE_NEIGHBORS = 1; + public static final int UPDATE_CLIENTS = 2; + public static final int UPDATE_INVISIBLE = 4; +@@ -277,7 +284,13 @@ public class Block extends BlockBehaviour implements ItemLike { + } + + public static boolean isShapeFullBlock(VoxelShape shape) { +- return (Boolean) Block.SHAPE_FULL_BLOCK_CACHE.getUnchecked(shape); ++ // Leaves start - replace shape full block cache with hashtable ++ if (!top.leavesmc.leaves.LeavesConfig.useOptimizedCollection) { ++ return (Boolean) Block.SHAPE_FULL_BLOCK_CACHE.getUnchecked(shape); ++ } else { ++ return Block.LITHIUM_SHAPE_FULL_BLOCK_CACHE.get(shape); ++ } ++ // Leaves end - replace shape full block cache with hashtable + } + + public boolean propagatesSkylightDown(BlockState state, BlockGetter world, BlockPos pos) { +diff --git a/src/main/java/top/leavesmc/leaves/lithium/common/util/collections/Object2BooleanCacheTable.java b/src/main/java/top/leavesmc/leaves/lithium/common/util/collections/Object2BooleanCacheTable.java +new file mode 100644 +index 0000000000000000000000000000000000000000..45232059b188b5f072e28c4cdf05929005972220 +--- /dev/null ++++ b/src/main/java/top/leavesmc/leaves/lithium/common/util/collections/Object2BooleanCacheTable.java +@@ -0,0 +1,62 @@ ++package top.leavesmc.leaves.lithium.common.util.collections; ++ ++import it.unimi.dsi.fastutil.HashCommon; ++import net.minecraft.util.Mth; ++ ++import java.util.function.Predicate; ++ ++// Powered by Gale(https://github.com/GaleMC/Gale) ++ ++/** ++ * A lossy hashtable implementation that stores a mapping between an object and a boolean. ++ *

++ * Any hash collisions will result in an overwrite: this is safe because the correct value can always be recomputed, ++ * given that the given operator is deterministic. ++ *

++ * This implementation is safe to use from multiple threads ++ */ ++public final class Object2BooleanCacheTable { ++ ++ private final int mask; ++ private final Node[] nodes; ++ private final Predicate operator; ++ ++ @SuppressWarnings("unchecked") ++ public Object2BooleanCacheTable(int capacity, Predicate operator) { ++ int capacity1 = Mth.smallestEncompassingPowerOfTwo(capacity); ++ this.mask = capacity1 - 1; ++ this.nodes = (Node[]) new Node[capacity1]; ++ this.operator = operator; ++ } ++ ++ private static int hash(T key) { ++ return HashCommon.mix(key.hashCode()); ++ } ++ ++ public boolean get(T key) { ++ int idx = hash(key) & this.mask; ++ ++ Node node = this.nodes[idx]; ++ if (node != null && key.equals(node.key)) { ++ return node.value; ++ } ++ ++ boolean test = this.operator.test(key); ++ this.nodes[idx] = new Node<>(key, test); ++ ++ return test; ++ } ++ ++ static class Node { ++ ++ final T key; ++ final boolean value; ++ ++ Node(T key, boolean value) { ++ this.key = key; ++ this.value = value; ++ } ++ ++ } ++ ++}