mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-25 18:09:17 +00:00
Chunk improvements (#231)
* perf: SpatialPlayerIndex for isChunkNearPlayer * perf: ensureCapacity with collectTickingChunks * perf: optimize getSlopeDistance * perf: optimize AABB Intersections * perf: implement custom arrays for regions and caches * perf: Improve SortedArraySet sorting (needs testing) * rebase 1.21.4 * perf: optimize ClientBoundLightUpdatePacketData * perf: O(1) Array Writes during Chunk Loading * perf: Optimize LinearPalette (no not the linear format) * perf: Rewrite ConcurrentLongHashSet * rebase 1.21.4 * Fix Multithreaded Tracker (#236) * duke gonna arrest me * i hate git v2 * rebase * dont worry ill change the name of this patch * perf: Rewrite ConcurrentLongHashSet again * perf: Optimize sendChunk * [ci skip] * cleanup * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa * cleanup * remove streams on LinearPalette and SerializableChunkData * actually commit them lmao * actually commit them lmao 2 * fix * rebase * perf: clone less (could help with skyblocks) * perf: more unload stuff * perf: manual loop unrolling and bulk copy * initial size for SerializeableChunkData * perf: async chunkSend * cleanup asyncChunkSend * remove experimental tag * rebase --------- Co-authored-by: Creeam <102713261+HaHaWTH@users.noreply.github.com> Co-authored-by: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
package org.dreeam.leaf.config.modules.async;
|
||||
|
||||
import org.dreeam.leaf.config.ConfigModules;
|
||||
import org.dreeam.leaf.config.EnumConfigCategory;
|
||||
import org.dreeam.leaf.config.annotations.Experimental;
|
||||
|
||||
public class AsyncChunkSend extends ConfigModules {
|
||||
|
||||
public String getBasePath() {
|
||||
return EnumConfigCategory.ASYNC.getBaseKeyName() + ".async-chunk-send";
|
||||
}
|
||||
|
||||
@Experimental
|
||||
public static boolean enabled = false;
|
||||
|
||||
@Override
|
||||
public void onLoaded() {
|
||||
config.addCommentRegionBased(getBasePath(),
|
||||
"""
|
||||
Makes chunk packet preparation and sending asynchronous to improve server performance.
|
||||
This can significantly reduce main thread load when many players are loading chunks.""",
|
||||
"""
|
||||
使区块数据包准备和发送异步化以提高服务器性能.
|
||||
当许多玩家同时加载区块时, 这可以显著减少主线程负载.""");
|
||||
|
||||
enabled = config.getBoolean(getBasePath() + ".enabled", enabled);
|
||||
}
|
||||
}
|
||||
@@ -1,211 +1,254 @@
|
||||
package org.dreeam.leaf.util.map;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.LongCollection;
|
||||
import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* A thread-safe implementation of {@link LongOpenHashSet} using ConcurrentHashMap.KeySetView as backing storage.
|
||||
* This implementation provides concurrent access and high performance for concurrent operations.
|
||||
*/
|
||||
@SuppressWarnings({"unused", "deprecation"})
|
||||
public final class ConcurrentLongHashSet extends LongOpenHashSet implements LongSet { // Extending LongOpenHashSet for some moonrise usages
|
||||
private final ConcurrentHashMap.KeySetView<Long, Boolean> backing;
|
||||
public final class ConcurrentLongHashSet extends LongOpenHashSet implements LongSet {
|
||||
private static final int DEFAULT_SEGMENTS = 16; // Should be power-of-two
|
||||
private final Segment[] segments;
|
||||
private final int segmentMask;
|
||||
|
||||
/**
|
||||
* Creates a new empty concurrent long set.
|
||||
*/
|
||||
public ConcurrentLongHashSet() {
|
||||
this.backing = ConcurrentHashMap.newKeySet();
|
||||
this(DEFAULT_SEGMENTS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return backing.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return backing.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull LongIterator iterator() {
|
||||
return new WrappingLongIterator(backing.iterator());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Object @NotNull [] toArray() {
|
||||
return backing.toArray();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public <T> T @NotNull [] toArray(@NotNull T @NotNull [] array) {
|
||||
Objects.requireNonNull(array, "Array cannot be null");
|
||||
return backing.toArray(array);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(@NotNull Collection<?> collection) {
|
||||
Objects.requireNonNull(collection, "Collection cannot be null");
|
||||
return backing.containsAll(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(@NotNull Collection<? extends Long> collection) {
|
||||
Objects.requireNonNull(collection, "Collection cannot be null");
|
||||
return backing.addAll(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(@NotNull Collection<?> collection) {
|
||||
Objects.requireNonNull(collection, "Collection cannot be null");
|
||||
return backing.removeAll(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(@NotNull Collection<?> collection) {
|
||||
Objects.requireNonNull(collection, "Collection cannot be null");
|
||||
return backing.retainAll(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
backing.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(long key) {
|
||||
return backing.add(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(long key) {
|
||||
return backing.contains(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long[] toLongArray() {
|
||||
int size = backing.size();
|
||||
long[] result = new long[size];
|
||||
int i = 0;
|
||||
for (Long value : backing) {
|
||||
result[i++] = value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long[] toArray(long[] array) {
|
||||
Objects.requireNonNull(array, "Array cannot be null");
|
||||
long[] result = toLongArray();
|
||||
if (array.length < result.length) {
|
||||
return result;
|
||||
}
|
||||
System.arraycopy(result, 0, array, 0, result.length);
|
||||
if (array.length > result.length) {
|
||||
array[result.length] = 0;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(LongCollection c) {
|
||||
public boolean removeAll(@NotNull Collection<?> c) {
|
||||
Objects.requireNonNull(c, "Collection cannot be null");
|
||||
boolean modified = false;
|
||||
LongIterator iterator = c.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
modified |= add(iterator.nextLong());
|
||||
for (Object obj : c) {
|
||||
if (obj instanceof Long) {
|
||||
modified |= remove((Long) obj);
|
||||
}
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(LongCollection c) {
|
||||
public boolean retainAll(@NotNull Collection<?> c) {
|
||||
Objects.requireNonNull(c, "Collection cannot be null");
|
||||
LongIterator iterator = c.iterator();
|
||||
boolean modified = false;
|
||||
LongIterator iterator = iterator();
|
||||
while (iterator.hasNext()) {
|
||||
if (!contains(iterator.nextLong())) {
|
||||
return false;
|
||||
long key = iterator.nextLong();
|
||||
if (!c.contains(key)) {
|
||||
modified |= remove(key);
|
||||
}
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
public ConcurrentLongHashSet(int concurrencyLevel) {
|
||||
int numSegments = Integer.highestOneBit(concurrencyLevel) << 1;
|
||||
this.segmentMask = numSegments - 1;
|
||||
this.segments = new Segment[numSegments];
|
||||
for (int i = 0; i < numSegments; i++) {
|
||||
segments[i] = new Segment();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------- Core Methods -------------------
|
||||
@Override
|
||||
public boolean add(long key) {
|
||||
Segment segment = getSegment(key);
|
||||
segment.lock();
|
||||
try {
|
||||
return segment.set.add(key);
|
||||
} finally {
|
||||
segment.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(long key) {
|
||||
Segment segment = getSegment(key);
|
||||
segment.lock();
|
||||
try {
|
||||
return segment.set.contains(key);
|
||||
} finally {
|
||||
segment.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(long key) {
|
||||
Segment segment = getSegment(key);
|
||||
segment.lock();
|
||||
try {
|
||||
return segment.set.remove(key);
|
||||
} finally {
|
||||
segment.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------- Bulk Operations -------------------
|
||||
@Override
|
||||
public boolean containsAll(@NotNull Collection<?> c) {
|
||||
Objects.requireNonNull(c, "Collection cannot be null");
|
||||
for (Object obj : c) {
|
||||
if (obj == null || !(obj instanceof Long)) return false;
|
||||
if (!contains((Long) obj)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(LongCollection c) {
|
||||
public boolean addAll(@NotNull Collection<? extends Long> c) {
|
||||
Objects.requireNonNull(c, "Collection cannot be null");
|
||||
boolean modified = false;
|
||||
LongIterator iterator = c.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
modified |= remove(iterator.nextLong());
|
||||
for (Long value : c) {
|
||||
modified |= add(value);
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
// ------------------- Locking Helpers -------------------
|
||||
private Segment getSegment(long key) {
|
||||
int hash = spreadHash(Long.hashCode(key));
|
||||
return segments[hash & segmentMask];
|
||||
}
|
||||
|
||||
private static int spreadHash(int h) {
|
||||
return (h ^ (h >>> 16)) & 0x7fffffff; // Avoid negative indices
|
||||
}
|
||||
|
||||
// ------------------- Size Stuff -------------------
|
||||
@Override
|
||||
public boolean retainAll(LongCollection c) {
|
||||
Objects.requireNonNull(c, "Collection cannot be null");
|
||||
return backing.retainAll(c);
|
||||
public int size() {
|
||||
int count = 0;
|
||||
for (Segment segment : segments) {
|
||||
segment.lock();
|
||||
count += segment.set.size();
|
||||
segment.unlock();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(long k) {
|
||||
return backing.remove(k);
|
||||
public boolean isEmpty() {
|
||||
for (Segment segment : segments) {
|
||||
segment.lock();
|
||||
boolean empty = segment.set.isEmpty();
|
||||
segment.unlock();
|
||||
if (!empty) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------- Cleanup -------------------
|
||||
@Override
|
||||
public void clear() {
|
||||
for (Segment segment : segments) {
|
||||
segment.lock();
|
||||
segment.set.clear();
|
||||
segment.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------- Iteration -------------------
|
||||
@Override
|
||||
public LongIterator iterator() {
|
||||
return new CompositeLongIterator();
|
||||
}
|
||||
|
||||
private class CompositeLongIterator implements LongIterator {
|
||||
private int currentSegment = 0;
|
||||
private LongIterator currentIterator;
|
||||
|
||||
CompositeLongIterator() {
|
||||
advanceSegment();
|
||||
}
|
||||
|
||||
private void advanceSegment() {
|
||||
while (currentSegment < segments.length) {
|
||||
segments[currentSegment].lock();
|
||||
currentIterator = segments[currentSegment].set.iterator();
|
||||
if (currentIterator.hasNext()) break;
|
||||
segments[currentSegment].unlock();
|
||||
currentSegment++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if (currentIterator == null) return false;
|
||||
if (currentIterator.hasNext()) return true;
|
||||
segments[currentSegment].unlock();
|
||||
currentSegment++;
|
||||
advanceSegment();
|
||||
return currentIterator != null && currentIterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long nextLong() {
|
||||
if (!hasNext()) throw new NoSuchElementException();
|
||||
return currentIterator.nextLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------- Segment (these nuts) -------------------
|
||||
private static class Segment {
|
||||
final LongOpenHashSet set = new LongOpenHashSet();
|
||||
final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
void lock() {
|
||||
lock.lock();
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// ignore
|
||||
@Override
|
||||
public long[] toLongArray() {
|
||||
long[] result = new long[size()];
|
||||
int i = 0;
|
||||
LongIterator it = iterator();
|
||||
while (it.hasNext()) {
|
||||
result[i++] = it.nextLong();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long[] toArray(long[] a) {
|
||||
long[] result = toLongArray();
|
||||
if (a.length < result.length) return result;
|
||||
System.arraycopy(result, 0, a, 0, result.length);
|
||||
return a;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof LongSet that)) return false;
|
||||
if (size() != that.size()) return false;
|
||||
return containsAll(that);
|
||||
if (!(o instanceof LongSet)) return false;
|
||||
LongSet that = (LongSet) o;
|
||||
return size() == that.size() && containsAll(that);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return backing.hashCode();
|
||||
int hash = 0;
|
||||
LongIterator it = iterator();
|
||||
while (it.hasNext()) {
|
||||
hash += Long.hashCode(it.nextLong());
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return backing.toString();
|
||||
}
|
||||
@Override @NotNull public Object[] toArray() { return Collections.unmodifiableSet(this).toArray(); }
|
||||
@Override @NotNull public <T> T[] toArray(@NotNull T[] a) { return Collections.unmodifiableSet(this).toArray(a); }
|
||||
|
||||
static class WrappingLongIterator implements LongIterator {
|
||||
private final Iterator<Long> backing;
|
||||
|
||||
WrappingLongIterator(Iterator<Long> backing) {
|
||||
this.backing = Objects.requireNonNull(backing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return backing.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long nextLong() {
|
||||
return backing.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long next() {
|
||||
return backing.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
backing.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user