Skip to content

Commit

Permalink
Use optimized collection
Browse files Browse the repository at this point in the history
  • Loading branch information
s-yh-china committed Jul 20, 2023
1 parent 060b346 commit d166b82
Show file tree
Hide file tree
Showing 2 changed files with 187 additions and 2 deletions.
9 changes: 7 additions & 2 deletions patches/server/0004-Leaves-Server-Config-And-Command.patch
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
180 changes: 180 additions & 0 deletions patches/server/0102-Use-optimized-collection.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: violetc <[email protected]>
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<T> extends AbstractCollection<T> {
- private final Map<Class<?>, List<T>> byClass = Maps.newHashMap();
+ private final Map<Class<?>, List<T>> 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<T> baseClass;
private final List<T> allInstances = Lists.newArrayList();

@@ -58,7 +58,7 @@ public class ClassInstanceMultiMap<T> extends AbstractCollection<T> {
if (!this.baseClass.isAssignableFrom(type)) {
throw new IllegalArgumentException("Don't know how to search for " + type);
} else {
- List<? extends T> 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<Attribute, AttributeInstance> attributes = Maps.newHashMap();
- private final Set<AttributeInstance> dirtyAttributes = Sets.newHashSet();
+ // Leaves start - replace AI attributes with optimized collections
+ private final Map<Attribute, AttributeInstance> attributes = top.leavesmc.leaves.LeavesConfig.useOptimizedCollection ? new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(0) : Maps.newHashMap();
+ private final Set<AttributeInstance> 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<Attribute, AttributeInstance> 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<Goal.Flag, WrappedGoal> lockedFlags = new EnumMap<>(Goal.Flag.class);
- private final Set<WrappedGoal> availableGoals = Sets.newLinkedHashSet();
+ private final Set<WrappedGoal> 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<ProfilerFiller> profiler;
private final EnumSet<Goal.Flag> 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<net.minecraft.world.entity.ai.goal.Goal.Flag> 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.Key<?>, 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<VoxelShape> 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.
+ * <p>
+ * 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.
+ * <p>
+ * This implementation is safe to use from multiple threads
+ */
+public final class Object2BooleanCacheTable<T> {
+
+ private final int mask;
+ private final Node<T>[] nodes;
+ private final Predicate<T> operator;
+
+ @SuppressWarnings("unchecked")
+ public Object2BooleanCacheTable(int capacity, Predicate<T> operator) {
+ int capacity1 = Mth.smallestEncompassingPowerOfTwo(capacity);
+ this.mask = capacity1 - 1;
+ this.nodes = (Node<T>[]) new Node[capacity1];
+ this.operator = operator;
+ }
+
+ private static <T> int hash(T key) {
+ return HashCommon.mix(key.hashCode());
+ }
+
+ public boolean get(T key) {
+ int idx = hash(key) & this.mask;
+
+ Node<T> 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<T> {
+
+ final T key;
+ final boolean value;
+
+ Node(T key, boolean value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ }
+
+}

0 comments on commit d166b82

Please sign in to comment.