This repository has been archived by the owner on Sep 23, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 47
/
0078-lithium-cache-iterate-outwards.patch
175 lines (171 loc) · 7.64 KB
/
0078-lithium-cache-iterate-outwards.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: 2No2Name <2No2Name@web.de>
Date: Thu, 13 Jan 2022 15:38:29 -0500
Subject: [PATCH] lithium: cache iterate outwards
Original code by the PR below, licensed under GNU Lesser General Public License v3.0
You can find the original code on https://github.com/CaffeineMC/lithium-fabric/pull/123 (Yarn mappings)
diff --git a/src/main/java/me/jellysquid/mods/lithium/common/cached_blockpos_iteration/IterateOutwardsCache.java b/src/main/java/me/jellysquid/mods/lithium/common/cached_blockpos_iteration/IterateOutwardsCache.java
new file mode 100644
index 0000000000000000000000000000000000000000..a5d3aa309d3fdaab9e0fea2dfb91a080a3ac1193
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/cached_blockpos_iteration/IterateOutwardsCache.java
@@ -0,0 +1,71 @@
+package me.jellysquid.mods.lithium.common.cached_blockpos_iteration;
+
+import it.unimi.dsi.fastutil.longs.LongArrayList;
+import it.unimi.dsi.fastutil.longs.LongList;
+import java.util.Iterator;
+import java.util.Random;
+import java.util.concurrent.ConcurrentHashMap;
+import net.minecraft.core.BlockPos;
+
+/**
+ * @author 2No2Name, original implemenation by SuperCoder7979 and Gegy1000
+ */
+public class IterateOutwardsCache {
+ //POS_ZERO must not be replaced with BlockPos.ORIGIN, otherwise iterateOutwards at BlockPos.ORIGIN will not use the cache
+ public static final BlockPos POS_ZERO = new BlockPos(0,0,0);
+
+
+ private final ConcurrentHashMap<Long, LongArrayList> table;
+ private final int capacity;
+ private final Random random;
+
+ public IterateOutwardsCache(int capacity) {
+ this.capacity = capacity;
+ this.table = new ConcurrentHashMap<>(31);
+ this.random = new Random();
+ }
+
+ private void fillPositionsWithIterateOutwards(LongList entry, int xRange, int yRange, int zRange) {
+ // Add all positions to the cached list
+ for (BlockPos pos : BlockPos.withinManhattan(POS_ZERO, xRange, yRange, zRange)) {
+ entry.add(pos.asLong());
+ }
+ }
+
+ public LongList getOrCompute(int xRange, int yRange, int zRange) {
+ long key = BlockPos.asLong(xRange, yRange, zRange);
+
+ LongArrayList entry = this.table.get(key);
+ if (entry != null) {
+ return entry;
+ }
+
+ // Cache miss: compute and store
+ entry = new LongArrayList(128);
+
+ this.fillPositionsWithIterateOutwards(entry, xRange, yRange, zRange);
+
+ //decrease the array size, as of now it won't be modified anymore anyways
+ entry.trim();
+
+ //this might overwrite an entry as the same entry could have been computed and added during this thread's computation
+ //we do not use computeIfAbsent, as it can delay other threads for too long
+ Object previousEntry = this.table.put(key, entry);
+
+
+ if (previousEntry == null && this.table.size() > this.capacity) {
+ //prevent a memory leak by randomly removing about 1/8th of the elements when the exceed the desired capacity is exceeded
+ final Iterator<Long> iterator = this.table.keySet().iterator();
+ //prevent an unlikely infinite loop caused by another thread filling the table concurrently using counting
+ for (int i = -this.capacity; iterator.hasNext() && i < 5; i++) {
+ Long key2 = iterator.next();
+ //random is not threadsafe, but it doesn't matter here, because we don't need quality random numbers
+ if (this.random.nextInt(8) == 0 && key2 != key) {
+ iterator.remove();
+ }
+ }
+ }
+
+ return entry;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/jellysquid/mods/lithium/common/cached_blockpos_iteration/LongList2BlockPosMutableIterable.java b/src/main/java/me/jellysquid/mods/lithium/common/cached_blockpos_iteration/LongList2BlockPosMutableIterable.java
new file mode 100644
index 0000000000000000000000000000000000000000..493661ff3ac7247b68b7b02784b09b0eaf88fc52
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/cached_blockpos_iteration/LongList2BlockPosMutableIterable.java
@@ -0,0 +1,46 @@
+package me.jellysquid.mods.lithium.common.cached_blockpos_iteration;
+
+import it.unimi.dsi.fastutil.longs.LongIterator;
+import it.unimi.dsi.fastutil.longs.LongList;
+import java.util.Iterator;
+import net.minecraft.core.BlockPos;
+
+/**
+ * @author 2No2Name
+ */
+public class LongList2BlockPosMutableIterable implements Iterable<BlockPos> {
+
+ private final LongList positions;
+ private final int xOffset, yOffset, zOffset;
+
+ public LongList2BlockPosMutableIterable(BlockPos offset, LongList posList) {
+ this.xOffset = offset.getX();
+ this.yOffset = offset.getY();
+ this.zOffset = offset.getZ();
+ this.positions = posList;
+ }
+
+ @Override
+ public Iterator<BlockPos> iterator() {
+ return new Iterator<BlockPos>() {
+
+ private final LongIterator it = LongList2BlockPosMutableIterable.this.positions.iterator();
+ private final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
+
+ @Override
+ public boolean hasNext() {
+ return it.hasNext();
+ }
+
+ @Override
+ public net.minecraft.core.BlockPos next() {
+ long nextPos = this.it.nextLong();
+ return this.pos.set(
+ LongList2BlockPosMutableIterable.this.xOffset + BlockPos.getX(nextPos),
+ LongList2BlockPosMutableIterable.this.yOffset + BlockPos.getY(nextPos),
+ LongList2BlockPosMutableIterable.this.zOffset + BlockPos.getZ(nextPos));
+ }
+ };
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java
index 153451ecd5b3c8e8ecb2d5ec91ccd582d4300899..4487752469f9ab95e9d2aeb76a9627dc02095d76 100644
--- a/src/main/java/net/minecraft/core/BlockPos.java
+++ b/src/main/java/net/minecraft/core/BlockPos.java
@@ -18,6 +18,12 @@ import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
+// JettPack start
+import it.unimi.dsi.fastutil.longs.LongList;
+import me.jellysquid.mods.lithium.common.cached_blockpos_iteration.IterateOutwardsCache;
+import me.jellysquid.mods.lithium.common.cached_blockpos_iteration.LongList2BlockPosMutableIterable;
+import static me.jellysquid.mods.lithium.common.cached_blockpos_iteration.IterateOutwardsCache.POS_ZERO;
+// JettPack end
@Immutable
public class BlockPos extends Vec3i {
@@ -284,7 +290,18 @@ public class BlockPos extends Vec3i {
};
}
+ // JettPack start - lithium: cached iterate outwards
+ private static final IterateOutwardsCache ITERATE_OUTWARDS_CACHE = new IterateOutwardsCache(50);
+ private static final LongList HOGLIN_PIGLIN_CACHE = ITERATE_OUTWARDS_CACHE.getOrCompute(8, 4, 8);
+ // JettPack end
+
public static Iterable<BlockPos> withinManhattan(BlockPos center, int rangeX, int rangeY, int rangeZ) {
+ // JettPack start - lithium: cached iterate outwards
+ if (center != POS_ZERO) {
+ final LongList positions = rangeX == 8 && rangeY == 4 && rangeZ == 8 ? HOGLIN_PIGLIN_CACHE : ITERATE_OUTWARDS_CACHE.getOrCompute(rangeX, rangeY, rangeZ);
+ return new LongList2BlockPosMutableIterable(center, positions);
+ }
+ // JettPack end
int i = rangeX + rangeY + rangeZ;
// Paper start - rename variables to fix conflict with anonymous class (remap fix)
int centerX = center.getX();