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/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java index 9969afdcd826db2c53db1d54f6e3df69a59a486e..0e0a987bf1baff5b0f907a3c0b4dfa444de6ba12 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -295,7 +295,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider // Paper - rewrite chunk system this.tickingGenerated = new AtomicInteger(); this.playerMap = new PlayerMap(); - this.entityMap = new Int2ObjectOpenHashMap(); + this.entityMap = top.leavesmc.leaves.LeavesConfig.useOptimizedCollection ? new it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap() : new Int2ObjectOpenHashMap(); // Leaves - se linked map for entity trackers - provides faster iteration this.chunkTypeCache = new Long2ByteOpenHashMap(); this.chunkSaveCooldowns = new Long2LongOpenHashMap(); this.unloadQueue = Queues.newConcurrentLinkedQueue(); 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 aa2fd4a567f5243ccd082644d56e1fa2b9ae4a7d..94fadc3814cef56d08d6ca4e932e806c1eadb4a8 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; + } + + } + +}