9
0
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:
Taiyou
2025-03-05 20:45:26 +01:00
committed by GitHub
parent ce59731e6f
commit cd7689b16f
16 changed files with 1749 additions and 160 deletions

View File

@@ -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);
}
}

View File

@@ -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();
}
}
}