diff --git a/arclight-common/build.gradle b/arclight-common/build.gradle index 891ad4e9d..591225429 100644 --- a/arclight-common/build.gradle +++ b/arclight-common/build.gradle @@ -35,6 +35,7 @@ arclight { configurations { embed + paperApiReference } java.toolchain.languageVersion = JavaLanguageVersion.of(17) @@ -50,6 +51,7 @@ repositories { maven { url = 'https://repo.spongepowered.org/repository/maven-public' } maven { url = 'https://oss.sonatype.org/content/repositories/snapshots/' } maven { url = 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' } + maven { url = 'https://repo.papermc.io/repository/maven-public/' } maven { url = 'https://files.minecraftforge.net/maven/' } maven { url = 'https://maven.izzel.io/releases' } maven { url = 'https://jitpack.io/' } @@ -60,6 +62,7 @@ repositories { dependencies { minecraft "net.minecraftforge:forge:$minecraftVersion-$forgeVersion" implementation "org.spigotmc:spigot-api:$minecraftVersion-R0.1-SNAPSHOT@jar" + implementation("io.papermc.paper:paper-api:$minecraftVersion-R0.1-SNAPSHOT@jar") { transitive = false } implementation 'org.jetbrains:annotations:23.0.0' implementation "org.spongepowered:mixin:$mixinVersion" @@ -77,6 +80,7 @@ dependencies { implementation "io.izzel:tools:$toolsVersion" implementation "io.izzel.arclight:arclight-api:$apiVersion" implementation project(':i18n-config') + paperApiReference("io.papermc.paper:paper-api:$minecraftVersion-R0.1-SNAPSHOT@jar") { transitive = false } // Adventure dependencies - core only to avoid conflicts implementation("net.kyori:adventure-api:4.17.0") { @@ -104,6 +108,7 @@ dependencies { embed 'net.md-5:bungeecord-chat:1.16-R0.4@jar' embed "org.spigotmc:spigot-api:$minecraftVersion-R0.1-SNAPSHOT@jar" + embed("io.papermc.paper:paper-api:$minecraftVersion-R0.1-SNAPSHOT@jar") { transitive = false } embed("net.kyori:adventure-api:4.17.0") { exclude group: 'org.slf4j' exclude group: 'org.checkerframework' @@ -132,6 +137,61 @@ dependencies { } } +tasks.register('paperApiSurfaceReport') { + group = 'verification' + description = 'Compare local Paper API shim classes against upstream paper-api.' + + def reportDirProvider = layout.buildDirectory.dir('reports/paper-api-surface') + outputs.dir(reportDirProvider) + + doLast { + File reportDir = reportDirProvider.get().asFile + reportDir.mkdirs() + + File paperApiJar = configurations.paperApiReference.resolve().find { it.name.endsWith('.jar') } + if (paperApiJar == null) { + throw new GradleException('Unable to resolve paper-api reference jar.') + } + + Set upstreamClasses = new TreeSet<>() + zipTree(paperApiJar).visit { details -> + if (details.isDirectory()) return + String path = details.path.replace('\\', '/') + if (!(path.startsWith('io/papermc/paper/') || path.startsWith('com/destroystokyo/paper/'))) return + if (!path.endsWith('.class')) return + if (path.endsWith('/package-info.class') || path.endsWith('/module-info.class')) return + String topLevel = path.replaceAll('\\$.*\\.class$', '.class').replace('.class', '') + upstreamClasses.add(topLevel) + } + + Set localClasses = new TreeSet<>() + fileTree('src/main/java').matching { + include 'io/papermc/paper/**/*.java' + include 'com/destroystokyo/paper/**/*.java' + }.visit { details -> + if (details.isDirectory()) return + String path = details.path.replace('\\', '/').replace('.java', '') + if (path.endsWith('/package-info') || path.endsWith('/module-info')) return + localClasses.add(path) + } + + Set missingInLocal = new TreeSet<>(upstreamClasses) + missingInLocal.removeAll(localClasses) + + Set localOnly = new TreeSet<>(localClasses) + localOnly.removeAll(upstreamClasses) + + File missingFile = new File(reportDir, 'missing-in-local.txt') + File localOnlyFile = new File(reportDir, 'local-only.txt') + missingFile.text = missingInLocal.isEmpty() ? '' : missingInLocal.join(System.lineSeparator()) + System.lineSeparator() + localOnlyFile.text = localOnly.isEmpty() ? '' : localOnly.join(System.lineSeparator()) + System.lineSeparator() + + logger.lifecycle('paperApiSurfaceReport: upstream={}, local={}, missing={}, localOnly={}', + upstreamClasses.size(), localClasses.size(), missingInLocal.size(), localOnly.size()) + logger.lifecycle('Report files: {} , {}', missingFile.absolutePath, localOnlyFile.absolutePath) + } +} + jar { manifest.attributes 'MixinConnector': 'io.izzel.arclight.common.mod.ArclightConnector' manifest.attributes 'Implementation-Title': 'Luminara' diff --git a/arclight-common/src/main/java/com/destroystokyo/paper/PaperConfig.java b/arclight-common/src/main/java/com/destroystokyo/paper/PaperConfig.java deleted file mode 100644 index 757bb2b05..000000000 --- a/arclight-common/src/main/java/com/destroystokyo/paper/PaperConfig.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.destroystokyo.paper; - -/** - * marker class for legacy Paper detection used by compatibility libraries - */ -public final class PaperConfig { - - private PaperConfig() { - } -} diff --git a/arclight-common/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java b/arclight-common/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java deleted file mode 100644 index fc318640e..000000000 --- a/arclight-common/src/main/java/com/destroystokyo/paper/event/server/AsyncTabCompleteEvent.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (c) 2017 Daniel Ennis (Aikar) MIT License - */ - -package com.destroystokyo.paper.event.server; - -import com.google.common.base.Preconditions; -import io.papermc.paper.util.TransformingRandomAccessList; -import net.kyori.adventure.text.Component; -import net.kyori.examination.Examinable; -import net.kyori.examination.ExaminableProperty; -import net.kyori.examination.string.StringExaminer; -import org.bukkit.Location; -import org.bukkit.command.CommandSender; -import org.bukkit.event.Cancellable; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.stream.Stream; - -public class AsyncTabCompleteEvent extends Event implements Cancellable { - - private static final HandlerList handlers = new HandlerList(); - @NotNull - private final CommandSender sender; - @NotNull - private final String buffer; - private final boolean isCommand; - @Nullable - private final Location loc; - private final List completions = new ArrayList<>(); - private final List stringCompletions = new TransformingRandomAccessList<>( - this.completions, - Completion::suggestion, - Completion::completion - ); - private boolean cancelled; - private boolean handled; - private boolean fireSyncHandler = true; - - public AsyncTabCompleteEvent(@NotNull CommandSender sender, @NotNull String buffer, boolean isCommand, @Nullable Location loc) { - super(true); - this.sender = sender; - this.buffer = buffer; - this.isCommand = isCommand; - this.loc = loc; - } - - @Deprecated - public AsyncTabCompleteEvent(@NotNull CommandSender sender, @NotNull List completions, @NotNull String buffer, boolean isCommand, @Nullable Location loc) { - super(true); - this.sender = sender; - this.completions.addAll(fromStrings(completions)); - this.buffer = buffer; - this.isCommand = isCommand; - this.loc = loc; - } - - @NotNull - public static HandlerList getHandlerList() { - return handlers; - } - - private static @NotNull List fromStrings(final @NotNull List strings) { - final List list = new ArrayList<>(); - for (final String it : strings) { - list.add(new CompletionImpl(it, null)); - } - return list; - } - - @NotNull - public CommandSender getSender() { - return sender; - } - - @NotNull - public List getCompletions() { - return this.stringCompletions; - } - - public void setCompletions(@NotNull List completions) { - if (completions == this.stringCompletions) { - return; - } - Preconditions.checkNotNull(completions, "completions"); - this.completions.clear(); - this.completions.addAll(fromStrings(completions)); - } - - @NotNull - public List completions() { - return this.completions; - } - - public void completions(@NotNull List newCompletions) { - Preconditions.checkNotNull(newCompletions, "new completions"); - this.completions.clear(); - this.completions.addAll(newCompletions); - } - - @NotNull - public String getBuffer() { - return buffer; - } - - public boolean isCommand() { - return isCommand; - } - - @Nullable - public Location getLocation() { - return loc; - } - - public boolean isHandled() { - return !completions.isEmpty() || handled; - } - - public void setHandled(boolean handled) { - this.handled = handled; - } - - public boolean isFireSyncHandler() { - return fireSyncHandler; - } - - public void setFireSyncHandler(boolean fireSyncHandler) { - this.fireSyncHandler = fireSyncHandler; - } - - @Override - public boolean isCancelled() { - return cancelled; - } - - @Override - public void setCancelled(boolean cancelled) { - this.cancelled = cancelled; - } - - @Override - @NotNull - public HandlerList getHandlers() { - return handlers; - } - - public interface Completion extends Examinable { - static @NotNull Completion completion(final @NotNull String suggestion) { - return new CompletionImpl(suggestion, null); - } - - static @NotNull Completion completion(final @NotNull String suggestion, final @Nullable Component tooltip) { - return new CompletionImpl(suggestion, tooltip); - } - - @NotNull - String suggestion(); - - @Nullable - Component tooltip(); - - @Override - default @NotNull Stream examinableProperties() { - return Stream.of( - ExaminableProperty.of("suggestion", this.suggestion()), - ExaminableProperty.of("tooltip", this.tooltip()) - ); - } - } - - record CompletionImpl(String suggestion, Component tooltip) implements Completion { - CompletionImpl(final @NotNull String suggestion, final @Nullable Component tooltip) { - this.suggestion = suggestion; - this.tooltip = tooltip; - } - - @Override - public @NotNull String suggestion() { - return this.suggestion; - } - - @Override - public @Nullable Component tooltip() { - return this.tooltip; - } - - @Override - public boolean equals(final @Nullable Object o) { - if (this == o) { - return true; - } - if (o == null || this.getClass() != o.getClass()) { - return false; - } - final CompletionImpl that = (CompletionImpl) o; - return this.suggestion.equals(that.suggestion) && Objects.equals(this.tooltip, that.tooltip); - } - - @Override - public @NotNull String toString() { - return StringExaminer.simpleEscaping().examine(this); - } - } -} diff --git a/arclight-common/src/main/java/com/destroystokyo/paper/util/SneakyThrow.java b/arclight-common/src/main/java/com/destroystokyo/paper/util/SneakyThrow.java deleted file mode 100644 index 2380343df..000000000 --- a/arclight-common/src/main/java/com/destroystokyo/paper/util/SneakyThrow.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.destroystokyo.paper.util; - -public final class SneakyThrow { - - private SneakyThrow() { - } - - public static RuntimeException sneaky(final Throwable throwable) { - if (throwable instanceof RuntimeException runtimeException) { - throw runtimeException; - } - if (throwable instanceof Error error) { - throw error; - } - throw new RuntimeException(throwable); - } -} diff --git a/arclight-common/src/main/java/com/destroystokyo/paper/util/concurrent/WeakSeqLock.java b/arclight-common/src/main/java/com/destroystokyo/paper/util/concurrent/WeakSeqLock.java deleted file mode 100644 index 0d34b928d..000000000 --- a/arclight-common/src/main/java/com/destroystokyo/paper/util/concurrent/WeakSeqLock.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.destroystokyo.paper.util.concurrent; - -import java.util.concurrent.atomic.AtomicLong; - -/** - * copied from https://github.com/Spottedleaf/ConcurrentUtil/blob/master/src/main/java/ca/spottedleaf/concurrentutil/lock/WeakSeqLock.java - * - * @author Spottedleaf - */ -public final class WeakSeqLock { - // TODO when the switch to J11 is made, nuke this class from orbit - - private final AtomicLong lock = new AtomicLong(); - - public WeakSeqLock() { - //VarHandle.storeStoreFence(); // warn: usages must be checked to ensure this behaviour isn't needed - } - - public void acquireWrite() { - // must be release-type write - this.lock.lazySet(this.lock.get() + 1); - } - - public boolean canRead(final long read) { - return (read & 1) == 0; - } - - public boolean tryAcquireWrite() { - this.acquireWrite(); - return true; - } - - public void releaseWrite() { - // must be acquire-type write - final long lock = this.lock.get(); // volatile here acts as store-store - this.lock.lazySet(lock + 1); - } - - public void abortWrite() { - // must be acquire-type write - final long lock = this.lock.get(); // volatile here acts as store-store - this.lock.lazySet(lock ^ 1); - } - - public long acquireRead() { - int failures = 0; - long curr; - - for (curr = this.lock.get(); !this.canRead(curr); curr = this.lock.get()) { - // without j11, our only backoff is the yield() call... - - if (++failures > 5_000) { /* TODO determine a threshold */ - Thread.yield(); - } - /* Better waiting is beyond the scope of this lock; if it is needed the lock is being misused */ - } - - //VarHandle.loadLoadFence(); // volatile acts as the load-load barrier - return curr; - } - - public boolean tryReleaseRead(final long read) { - return this.lock.get() == read; // volatile acts as the load-load barrier - } - - public long getSequentialCounter() { - return this.lock.get(); - } -} diff --git a/arclight-common/src/main/java/com/destroystokyo/paper/util/map/QueuedChangesMapLong2Int.java b/arclight-common/src/main/java/com/destroystokyo/paper/util/map/QueuedChangesMapLong2Int.java deleted file mode 100644 index c31b24c12..000000000 --- a/arclight-common/src/main/java/com/destroystokyo/paper/util/map/QueuedChangesMapLong2Int.java +++ /dev/null @@ -1,160 +0,0 @@ -package com.destroystokyo.paper.util.map; - -import com.destroystokyo.paper.util.concurrent.WeakSeqLock; -import it.unimi.dsi.fastutil.longs.Long2IntMap; -import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; -import it.unimi.dsi.fastutil.longs.LongIterator; -import it.unimi.dsi.fastutil.longs.LongOpenHashSet; -import it.unimi.dsi.fastutil.objects.ObjectIterator; - -/** - * @author Spottedleaf - */ -public class QueuedChangesMapLong2Int { - - protected final Long2IntOpenHashMap updatingMap; - protected final Long2IntOpenHashMap visibleMap; - protected final Long2IntOpenHashMap queuedPuts; - protected final LongOpenHashSet queuedRemove; - // we use a seqlock as writes are not common. - protected final WeakSeqLock updatingMapSeqLock = new WeakSeqLock(); - protected int queuedDefaultReturnValue; - - public QueuedChangesMapLong2Int() { - this(16, 0.75f); - } - - public QueuedChangesMapLong2Int(final int capacity, final float loadFactor) { - this.updatingMap = new Long2IntOpenHashMap(capacity, loadFactor); - this.visibleMap = new Long2IntOpenHashMap(capacity, loadFactor); - this.queuedPuts = new Long2IntOpenHashMap(); - this.queuedRemove = new LongOpenHashSet(); - } - - public void queueDefaultReturnValue(final int dfl) { - this.queuedDefaultReturnValue = dfl; - this.updatingMap.defaultReturnValue(dfl); - } - - public int queueUpdate(final long k, final int v) { - this.queuedRemove.remove(k); - this.queuedPuts.put(k, v); - - return this.updatingMap.put(k, v); - } - - public int queueRemove(final long k) { - this.queuedPuts.remove(k); - this.queuedRemove.add(k); - - return this.updatingMap.remove(k); - } - - public int getUpdating(final long k) { - return this.updatingMap.get(k); - } - - public int getVisible(final long k) { - return this.visibleMap.get(k); - } - - public int getVisibleAsync(final long k) { - long readlock; - int ret = 0; - - do { - readlock = this.updatingMapSeqLock.acquireRead(); - try { - ret = this.visibleMap.get(k); - } catch (final Throwable thr) { - if (thr instanceof ThreadDeath) { - throw (ThreadDeath) thr; - } - // ignore... - continue; - } - - } while (!this.updatingMapSeqLock.tryReleaseRead(readlock)); - - return ret; - } - - public boolean performUpdates() { - this.updatingMapSeqLock.acquireWrite(); - this.visibleMap.defaultReturnValue(this.queuedDefaultReturnValue); - this.updatingMapSeqLock.releaseWrite(); - - if (this.queuedPuts.isEmpty() && this.queuedRemove.isEmpty()) { - return false; - } - - // update puts - final ObjectIterator iterator0 = this.queuedPuts.long2IntEntrySet().fastIterator(); - while (iterator0.hasNext()) { - final Long2IntMap.Entry entry = iterator0.next(); - final long key = entry.getLongKey(); - final int val = entry.getIntValue(); - - this.updatingMapSeqLock.acquireWrite(); - try { - this.visibleMap.put(key, val); - } finally { - this.updatingMapSeqLock.releaseWrite(); - } - } - - this.queuedPuts.clear(); - - final LongIterator iterator1 = this.queuedRemove.iterator(); - while (iterator1.hasNext()) { - final long key = iterator1.nextLong(); - - this.updatingMapSeqLock.acquireWrite(); - try { - this.visibleMap.remove(key); - } finally { - this.updatingMapSeqLock.releaseWrite(); - } - } - - this.queuedRemove.clear(); - - return true; - } - - public boolean performUpdatesLockMap() { - this.updatingMapSeqLock.acquireWrite(); - try { - this.visibleMap.defaultReturnValue(this.queuedDefaultReturnValue); - - if (this.queuedPuts.isEmpty() && this.queuedRemove.isEmpty()) { - return false; - } - - // update puts - final ObjectIterator iterator0 = this.queuedPuts.long2IntEntrySet().fastIterator(); - while (iterator0.hasNext()) { - final Long2IntMap.Entry entry = iterator0.next(); - final long key = entry.getLongKey(); - final int val = entry.getIntValue(); - - this.visibleMap.put(key, val); - } - - this.queuedPuts.clear(); - - final LongIterator iterator1 = this.queuedRemove.iterator(); - while (iterator1.hasNext()) { - final long key = iterator1.nextLong(); - - this.visibleMap.remove(key); - } - - this.queuedRemove.clear(); - - return true; - } finally { - this.updatingMapSeqLock.releaseWrite(); - } - } -} diff --git a/arclight-common/src/main/java/com/destroystokyo/paper/util/map/QueuedChangesMapLong2Object.java b/arclight-common/src/main/java/com/destroystokyo/paper/util/map/QueuedChangesMapLong2Object.java deleted file mode 100644 index ff278b217..000000000 --- a/arclight-common/src/main/java/com/destroystokyo/paper/util/map/QueuedChangesMapLong2Object.java +++ /dev/null @@ -1,203 +0,0 @@ -package com.destroystokyo.paper.util.map; - -import com.destroystokyo.paper.util.concurrent.WeakSeqLock; -import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectMap; -import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -/** - * @author Spottedleaf - */ -public class QueuedChangesMapLong2Object { - - protected static final Object REMOVED = new Object(); - - protected final Long2ObjectLinkedOpenHashMap updatingMap; - protected final Long2ObjectLinkedOpenHashMap visibleMap; - protected final Long2ObjectLinkedOpenHashMap queuedChanges; - - // we use a seqlock as writes are not common. - protected final WeakSeqLock updatingMapSeqLock = new WeakSeqLock(); - - public QueuedChangesMapLong2Object() { - this(16, 0.75f); // dfl for fastutil - } - - public QueuedChangesMapLong2Object(final int capacity, final float loadFactor) { - this.updatingMap = new Long2ObjectLinkedOpenHashMap<>(capacity, loadFactor); - this.visibleMap = new Long2ObjectLinkedOpenHashMap<>(capacity, loadFactor); - this.queuedChanges = new Long2ObjectLinkedOpenHashMap<>(); - } - - public V queueUpdate(final long k, final V value) { - this.queuedChanges.put(k, value); - return this.updatingMap.put(k, value); - } - - public V queueRemove(final long k) { - this.queuedChanges.put(k, REMOVED); - return this.updatingMap.remove(k); - } - - public V getUpdating(final long k) { - return this.updatingMap.get(k); - } - - public boolean updatingContainsKey(final long k) { - return this.updatingMap.containsKey(k); - } - - public V getVisible(final long k) { - return this.visibleMap.get(k); - } - - public boolean visibleContainsKey(final long k) { - return this.visibleMap.containsKey(k); - } - - public V getVisibleAsync(final long k) { - long readlock; - V ret = null; - - do { - readlock = this.updatingMapSeqLock.acquireRead(); - - try { - ret = this.visibleMap.get(k); - } catch (final Throwable thr) { - if (thr instanceof ThreadDeath) { - throw (ThreadDeath) thr; - } - // ignore... - continue; - } - - } while (!this.updatingMapSeqLock.tryReleaseRead(readlock)); - - return ret; - } - - public boolean visibleContainsKeyAsync(final long k) { - long readlock; - boolean ret = false; - - do { - readlock = this.updatingMapSeqLock.acquireRead(); - - try { - ret = this.visibleMap.containsKey(k); - } catch (final Throwable thr) { - if (thr instanceof ThreadDeath) { - throw (ThreadDeath) thr; - } - // ignore... - continue; - } - - } while (!this.updatingMapSeqLock.tryReleaseRead(readlock)); - - return ret; - } - - public Long2ObjectLinkedOpenHashMap getVisibleMap() { - return this.visibleMap; - } - - public Long2ObjectLinkedOpenHashMap getUpdatingMap() { - return this.updatingMap; - } - - public int getVisibleSize() { - return this.visibleMap.size(); - } - - public int getVisibleSizeAsync() { - long readlock; - int ret; - - do { - readlock = this.updatingMapSeqLock.acquireRead(); - ret = this.visibleMap.size(); - } while (!this.updatingMapSeqLock.tryReleaseRead(readlock)); - - return ret; - } - - // unlike mojang's impl this cannot be used async since it's not a view of an immutable map - public Collection getUpdatingValues() { - return this.updatingMap.values(); - } - - public List getUpdatingValuesCopy() { - return new ArrayList<>(this.updatingMap.values()); - } - - // unlike mojang's impl this cannot be used async since it's not a view of an immutable map - public Collection getVisibleValues() { - return this.visibleMap.values(); - } - - public List getVisibleValuesCopy() { - return new ArrayList<>(this.visibleMap.values()); - } - - public boolean performUpdates() { - if (this.queuedChanges.isEmpty()) { - return false; - } - - final ObjectBidirectionalIterator> iterator = this.queuedChanges.long2ObjectEntrySet().fastIterator(); - while (iterator.hasNext()) { - final Long2ObjectMap.Entry entry = iterator.next(); - final long key = entry.getLongKey(); - final Object val = entry.getValue(); - - this.updatingMapSeqLock.acquireWrite(); - try { - if (val == REMOVED) { - this.visibleMap.remove(key); - } else { - this.visibleMap.put(key, (V) val); - } - } finally { - this.updatingMapSeqLock.releaseWrite(); - } - } - - this.queuedChanges.clear(); - return true; - } - - public boolean performUpdatesLockMap() { - if (this.queuedChanges.isEmpty()) { - return false; - } - - final ObjectBidirectionalIterator> iterator = this.queuedChanges.long2ObjectEntrySet().fastIterator(); - - try { - this.updatingMapSeqLock.acquireWrite(); - - while (iterator.hasNext()) { - final Long2ObjectMap.Entry entry = iterator.next(); - final long key = entry.getLongKey(); - final Object val = entry.getValue(); - - if (val == REMOVED) { - this.visibleMap.remove(key); - } else { - this.visibleMap.put(key, (V) val); - } - } - } finally { - this.updatingMapSeqLock.releaseWrite(); - } - - this.queuedChanges.clear(); - return true; - } -} diff --git a/arclight-common/src/main/java/com/destroystokyo/paper/util/maplist/ChunkList.java b/arclight-common/src/main/java/com/destroystokyo/paper/util/maplist/ChunkList.java deleted file mode 100644 index fb670e7f4..000000000 --- a/arclight-common/src/main/java/com/destroystokyo/paper/util/maplist/ChunkList.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.destroystokyo.paper.util.maplist; - -import io.papermc.paper.util.MCUtil; -import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; -import net.minecraft.world.level.chunk.LevelChunk; - -import java.util.Arrays; -import java.util.Iterator; -import java.util.NoSuchElementException; - -// list with O(1) remove & contains - -/** - * @author Spottedleaf - */ -public final class ChunkList implements Iterable { - - private static final LevelChunk[] EMPTY_LIST = new LevelChunk[0]; - private final Long2IntOpenHashMap chunkToIndex = new Long2IntOpenHashMap(2, 0.8f); - private LevelChunk[] chunks = EMPTY_LIST; - private int count; - - { - this.chunkToIndex.defaultReturnValue(Integer.MIN_VALUE); - } - - public int size() { - return this.count; - } - - public boolean contains(final LevelChunk chunk) { - return this.chunkToIndex.containsKey(MCUtil.getCoordinateKey(chunk.getPos())); - } - - public boolean remove(final LevelChunk chunk) { - final int index = this.chunkToIndex.remove(MCUtil.getCoordinateKey(chunk.getPos())); - if (index == Integer.MIN_VALUE) { - return false; - } - - // move the entity at the end to this index - final int endIndex = --this.count; - final LevelChunk end = this.chunks[endIndex]; - if (index != endIndex) { - // not empty after this call - this.chunkToIndex.put(MCUtil.getCoordinateKey(end.getPos()), index); // update index - } - this.chunks[index] = end; - this.chunks[endIndex] = null; - - return true; - } - - public boolean add(final LevelChunk chunk) { - final int count = this.count; - final int currIndex = this.chunkToIndex.putIfAbsent(MCUtil.getCoordinateKey(chunk.getPos()), count); - - if (currIndex != Integer.MIN_VALUE) { - return false; // already in this list - } - - LevelChunk[] list = this.chunks; - - if (list.length == count) { - // resize required - list = this.chunks = Arrays.copyOf(list, (int) Math.max(4L, count * 2L)); // overflow results in negative - } - - list[count] = chunk; - this.count = count + 1; - - return true; - } - - public LevelChunk getChecked(final int index) { - if (index < 0 || index >= this.count) { - throw new IndexOutOfBoundsException("Index: " + index + " is out of bounds, size: " + this.count); - } - return this.chunks[index]; - } - - public LevelChunk getUnchecked(final int index) { - return this.chunks[index]; - } - - public LevelChunk[] getRawData() { - return this.chunks; - } - - public void clear() { - this.chunkToIndex.clear(); - Arrays.fill(this.chunks, 0, this.count, null); - this.count = 0; - } - - @Override - public Iterator iterator() { - return new Iterator() { - - LevelChunk lastRet; - int current; - - @Override - public boolean hasNext() { - return this.current < ChunkList.this.count; - } - - @Override - public LevelChunk next() { - if (this.current >= ChunkList.this.count) { - throw new NoSuchElementException(); - } - return this.lastRet = ChunkList.this.chunks[this.current++]; - } - - @Override - public void remove() { - final LevelChunk lastRet = this.lastRet; - - if (lastRet == null) { - throw new IllegalStateException(); - } - this.lastRet = null; - - ChunkList.this.remove(lastRet); - --this.current; - } - }; - } -} diff --git a/arclight-common/src/main/java/com/destroystokyo/paper/util/maplist/EntityList.java b/arclight-common/src/main/java/com/destroystokyo/paper/util/maplist/EntityList.java deleted file mode 100644 index e7a758c84..000000000 --- a/arclight-common/src/main/java/com/destroystokyo/paper/util/maplist/EntityList.java +++ /dev/null @@ -1,129 +0,0 @@ -package com.destroystokyo.paper.util.maplist; - -import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; -import net.minecraft.world.entity.Entity; - -import java.util.Arrays; -import java.util.Iterator; -import java.util.NoSuchElementException; - -// list with O(1) remove & contains - -/** - * @author Spottedleaf - */ -public final class EntityList implements Iterable { - - private static final Entity[] EMPTY_LIST = new Entity[0]; - private final Int2IntOpenHashMap entityToIndex = new Int2IntOpenHashMap(2, 0.8f); - private Entity[] entities = EMPTY_LIST; - private int count; - - { - this.entityToIndex.defaultReturnValue(Integer.MIN_VALUE); - } - - public int size() { - return this.count; - } - - public boolean contains(final Entity entity) { - return this.entityToIndex.containsKey(entity.getId()); - } - - public boolean remove(final Entity entity) { - final int index = this.entityToIndex.remove(entity.getId()); - if (index == Integer.MIN_VALUE) { - return false; - } - - // move the entity at the end to this index - final int endIndex = --this.count; - final Entity end = this.entities[endIndex]; - if (index != endIndex) { - // not empty after this call - this.entityToIndex.put(end.getId(), index); // update index - } - this.entities[index] = end; - this.entities[endIndex] = null; - - return true; - } - - public boolean add(final Entity entity) { - final int count = this.count; - final int currIndex = this.entityToIndex.putIfAbsent(entity.getId(), count); - - if (currIndex != Integer.MIN_VALUE) { - return false; // already in this list - } - - Entity[] list = this.entities; - - if (list.length == count) { - // resize required - list = this.entities = Arrays.copyOf(list, (int) Math.max(4L, count * 2L)); // overflow results in negative - } - - list[count] = entity; - this.count = count + 1; - - return true; - } - - public Entity getChecked(final int index) { - if (index < 0 || index >= this.count) { - throw new IndexOutOfBoundsException("Index: " + index + " is out of bounds, size: " + this.count); - } - return this.entities[index]; - } - - public Entity getUnchecked(final int index) { - return this.entities[index]; - } - - public Entity[] getRawData() { - return this.entities; - } - - public void clear() { - this.entityToIndex.clear(); - Arrays.fill(this.entities, 0, this.count, null); - this.count = 0; - } - - @Override - public Iterator iterator() { - return new Iterator() { - - Entity lastRet; - int current; - - @Override - public boolean hasNext() { - return this.current < EntityList.this.count; - } - - @Override - public Entity next() { - if (this.current >= EntityList.this.count) { - throw new NoSuchElementException(); - } - return this.lastRet = EntityList.this.entities[this.current++]; - } - - @Override - public void remove() { - final Entity lastRet = this.lastRet; - - if (lastRet == null) { - throw new IllegalStateException(); - } - this.lastRet = null; - - EntityList.this.remove(lastRet); - --this.current; - } - }; - } -} diff --git a/arclight-common/src/main/java/com/destroystokyo/paper/util/maplist/IBlockDataList.java b/arclight-common/src/main/java/com/destroystokyo/paper/util/maplist/IBlockDataList.java deleted file mode 100644 index 65696ea17..000000000 --- a/arclight-common/src/main/java/com/destroystokyo/paper/util/maplist/IBlockDataList.java +++ /dev/null @@ -1,127 +0,0 @@ -package com.destroystokyo.paper.util.maplist; - -import it.unimi.dsi.fastutil.longs.LongIterator; -import it.unimi.dsi.fastutil.shorts.Short2LongOpenHashMap; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.GlobalPalette; - -import java.util.Arrays; - -/** - * @author Spottedleaf - */ -public final class IBlockDataList { - - static final GlobalPalette GLOBAL_PALETTE = new GlobalPalette<>(Block.BLOCK_STATE_REGISTRY); - private static final long[] EMPTY_LIST = new long[0]; - // map of location -> (index | (location << 16) | (palette id << 32)) - private final Short2LongOpenHashMap map = new Short2LongOpenHashMap(2, 0.8f); - private long[] byIndex = EMPTY_LIST; - private int size; - - { - this.map.defaultReturnValue(Long.MAX_VALUE); - } - - public static int getLocationKey(final int x, final int y, final int z) { - return (x & 15) | (((z & 15) << 4)) | ((y & 255) << (4 + 4)); - } - - public static BlockState getBlockDataFromRaw(final long raw) { - return GLOBAL_PALETTE.valueFor((int) (raw >>> 32)); - } - - public static int getIndexFromRaw(final long raw) { - return (int) (raw & 0xFFFF); - } - - public static int getLocationFromRaw(final long raw) { - return (int) ((raw >>> 16) & 0xFFFF); - } - - public static long getRawFromValues(final int index, final int location, final BlockState data) { - return (long) index | ((long) location << 16) | (((long) GLOBAL_PALETTE.idFor(data)) << 32); - } - - public static long setIndexRawValues(final long value, final int index) { - return value & ~(0xFFFF) | (index); - } - - public long add(final int x, final int y, final int z, final BlockState data) { - return this.add(getLocationKey(x, y, z), data); - } - - public long add(final int location, final BlockState data) { - final long curr = this.map.get((short) location); - - if (curr == Long.MAX_VALUE) { - final int index = this.size++; - final long raw = getRawFromValues(index, location, data); - this.map.put((short) location, raw); - - if (index >= this.byIndex.length) { - this.byIndex = Arrays.copyOf(this.byIndex, (int) Math.max(4L, this.byIndex.length * 2L)); - } - - this.byIndex[index] = raw; - return raw; - } else { - final int index = getIndexFromRaw(curr); - final long raw = this.byIndex[index] = getRawFromValues(index, location, data); - - this.map.put((short) location, raw); - - return raw; - } - } - - public long remove(final int x, final int y, final int z) { - return this.remove(getLocationKey(x, y, z)); - } - - public long remove(final int location) { - final long ret = this.map.remove((short) location); - final int index = getIndexFromRaw(ret); - if (ret == Long.MAX_VALUE) { - return ret; - } - - // move the entry at the end to this index - final int endIndex = --this.size; - final long end = this.byIndex[endIndex]; - if (index != endIndex) { - // not empty after this call - this.map.put((short) getLocationFromRaw(end), setIndexRawValues(end, index)); - } - this.byIndex[index] = end; - this.byIndex[endIndex] = 0L; - - return ret; - } - - public int size() { - return this.size; - } - - public long getRaw(final int index) { - return this.byIndex[index]; - } - - public int getLocation(final int index) { - return getLocationFromRaw(this.getRaw(index)); - } - - public BlockState getData(final int index) { - return getBlockDataFromRaw(this.getRaw(index)); - } - - public void clear() { - this.size = 0; - this.map.clear(); - } - - public LongIterator getRawIterator() { - return this.map.values().iterator(); - } -} diff --git a/arclight-common/src/main/java/com/destroystokyo/paper/util/maplist/ReferenceList.java b/arclight-common/src/main/java/com/destroystokyo/paper/util/maplist/ReferenceList.java deleted file mode 100644 index 410c67d08..000000000 --- a/arclight-common/src/main/java/com/destroystokyo/paper/util/maplist/ReferenceList.java +++ /dev/null @@ -1,125 +0,0 @@ -package com.destroystokyo.paper.util.maplist; - -import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; - -import java.util.Arrays; -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - * @author Spottedleaf - */ -public final class ReferenceList implements Iterable { - - private static final Object[] EMPTY_LIST = new Object[0]; - private final Reference2IntOpenHashMap referenceToIndex = new Reference2IntOpenHashMap<>(2, 0.8f); - private Object[] references = EMPTY_LIST; - private int count; - - { - this.referenceToIndex.defaultReturnValue(Integer.MIN_VALUE); - } - - public int size() { - return this.count; - } - - public boolean contains(final E obj) { - return this.referenceToIndex.containsKey(obj); - } - - public boolean remove(final E obj) { - final int index = this.referenceToIndex.removeInt(obj); - if (index == Integer.MIN_VALUE) { - return false; - } - - // move the object at the end to this index - final int endIndex = --this.count; - final E end = (E) this.references[endIndex]; - if (index != endIndex) { - // not empty after this call - this.referenceToIndex.put(end, index); // update index - } - this.references[index] = end; - this.references[endIndex] = null; - - return true; - } - - public boolean add(final E obj) { - final int count = this.count; - final int currIndex = this.referenceToIndex.putIfAbsent(obj, count); - - if (currIndex != Integer.MIN_VALUE) { - return false; // already in this list - } - - Object[] list = this.references; - - if (list.length == count) { - // resize required - list = this.references = Arrays.copyOf(list, (int) Math.max(4L, count * 2L)); // overflow results in negative - } - - list[count] = obj; - this.count = count + 1; - - return true; - } - - public E getChecked(final int index) { - if (index < 0 || index >= this.count) { - throw new IndexOutOfBoundsException("Index: " + index + " is out of bounds, size: " + this.count); - } - return (E) this.references[index]; - } - - public E getUnchecked(final int index) { - return (E) this.references[index]; - } - - public Object[] getRawData() { - return this.references; - } - - public void clear() { - this.referenceToIndex.clear(); - Arrays.fill(this.references, 0, this.count, null); - this.count = 0; - } - - @Override - public Iterator iterator() { - return new Iterator<>() { - private E lastRet; - private int current; - - @Override - public boolean hasNext() { - return this.current < ReferenceList.this.count; - } - - @Override - public E next() { - if (this.current >= ReferenceList.this.count) { - throw new NoSuchElementException(); - } - return this.lastRet = (E) ReferenceList.this.references[this.current++]; - } - - @Override - public void remove() { - final E lastRet = this.lastRet; - - if (lastRet == null) { - throw new IllegalStateException(); - } - this.lastRet = null; - - ReferenceList.this.remove(lastRet); - --this.current; - } - }; - } -} diff --git a/arclight-common/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java b/arclight-common/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java deleted file mode 100644 index 7d9dfa447..000000000 --- a/arclight-common/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java +++ /dev/null @@ -1,457 +0,0 @@ -package com.destroystokyo.paper.util.misc; - -import io.papermc.paper.util.IntegerUtil; -import io.papermc.paper.util.MCUtil; -import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; -import net.minecraft.server.MinecraftServer; -import net.minecraft.world.level.ChunkPos; - -import javax.annotation.Nullable; -import java.util.Iterator; - -/** - * @author Spottedleaf - */ -public abstract class AreaMap { - - /* Tested via https://gist.github.com/Spottedleaf/520419c6f41ef348fe9926ce674b7217 */ - - protected final Object2LongOpenHashMap objectToLastCoordinate = new Object2LongOpenHashMap<>(); - protected final Object2IntOpenHashMap objectToViewDistance = new Object2IntOpenHashMap<>(); - // we use linked for better iteration. - // map of: coordinate to set of objects in coordinate - protected final Long2ObjectOpenHashMap> areaMap = new Long2ObjectOpenHashMap<>(1024, 0.7f); - protected final PooledLinkedHashSets pooledHashSets; - protected final ChangeCallback addCallback; - protected final ChangeCallback removeCallback; - protected final ChangeSourceCallback changeSourceCallback; - - { - this.objectToViewDistance.defaultReturnValue(-1); - this.objectToLastCoordinate.defaultReturnValue(Long.MIN_VALUE); - } - - public AreaMap() { - this(new PooledLinkedHashSets<>()); - } - - // let users define a "global" or "shared" pooled sets if they wish - public AreaMap(final PooledLinkedHashSets pooledHashSets) { - this(pooledHashSets, null, null); - } - - public AreaMap(final PooledLinkedHashSets pooledHashSets, final ChangeCallback addCallback, final ChangeCallback removeCallback) { - this(pooledHashSets, addCallback, removeCallback, null); - } - - public AreaMap(final PooledLinkedHashSets pooledHashSets, final ChangeCallback addCallback, final ChangeCallback removeCallback, final ChangeSourceCallback changeSourceCallback) { - this.pooledHashSets = pooledHashSets; - this.addCallback = addCallback; - this.removeCallback = removeCallback; - this.changeSourceCallback = changeSourceCallback; - } - - /* math sign function except 0 returns 1 */ - protected static int sign(int val) { - return 1 | (val >> (Integer.SIZE - 1)); - } - - @Nullable - public final PooledLinkedHashSets.PooledObjectLinkedOpenHashSet getObjectsInRange(final long key) { - return this.areaMap.get(key); - } - - @Nullable - public final PooledLinkedHashSets.PooledObjectLinkedOpenHashSet getObjectsInRange(final ChunkPos chunkPos) { - return this.areaMap.get(MCUtil.getCoordinateKey(chunkPos)); - } - - @Nullable - public final PooledLinkedHashSets.PooledObjectLinkedOpenHashSet getObjectsInRange(final int chunkX, final int chunkZ) { - return this.areaMap.get(MCUtil.getCoordinateKey(chunkX, chunkZ)); - } - - // Long.MIN_VALUE indicates the object is not mapped - public final long getLastCoordinate(final E object) { - return this.objectToLastCoordinate.getOrDefault(object, Long.MIN_VALUE); - } - - // -1 indicates the object is not mapped - public final int getLastViewDistance(final E object) { - return this.objectToViewDistance.getOrDefault(object, -1); - } - - // returns the total number of mapped chunks - public final int size() { - return this.areaMap.size(); - } - - public final void addOrUpdate(final E object, final int chunkX, final int chunkZ, final int viewDistance) { - final int oldViewDistance = this.objectToViewDistance.put(object, viewDistance); - final long newPos = MCUtil.getCoordinateKey(chunkX, chunkZ); - final long oldPos = this.objectToLastCoordinate.put(object, newPos); - - if (oldViewDistance == -1) { - this.addObject(object, chunkX, chunkZ, Integer.MIN_VALUE, Integer.MIN_VALUE, viewDistance); - this.addObjectCallback(object, chunkX, chunkZ, viewDistance); - } else { - this.updateObject(object, oldPos, newPos, oldViewDistance, viewDistance); - this.updateObjectCallback(object, oldPos, newPos, oldViewDistance, viewDistance); - } - //this.validate(object, viewDistance); - } - - public final boolean update(final E object, final int chunkX, final int chunkZ, final int viewDistance) { - final int oldViewDistance = this.objectToViewDistance.replace(object, viewDistance); - if (oldViewDistance == -1) { - return false; - } else { - final long newPos = MCUtil.getCoordinateKey(chunkX, chunkZ); - final long oldPos = this.objectToLastCoordinate.put(object, newPos); - this.updateObject(object, oldPos, newPos, oldViewDistance, viewDistance); - this.updateObjectCallback(object, oldPos, newPos, oldViewDistance, viewDistance); - } - //this.validate(object, viewDistance); - return true; - } - - // called after the distance map updates - protected void updateObjectCallback(final E Object, final long oldPosition, final long newPosition, final int oldViewDistance, final int newViewDistance) { - if (newPosition != oldPosition && this.changeSourceCallback != null) { - this.changeSourceCallback.accept(Object, oldPosition, newPosition); - } - } - - public final boolean add(final E object, final int chunkX, final int chunkZ, final int viewDistance) { - final int oldViewDistance = this.objectToViewDistance.putIfAbsent(object, viewDistance); - if (oldViewDistance != -1) { - return false; - } - - final long newPos = MCUtil.getCoordinateKey(chunkX, chunkZ); - this.objectToLastCoordinate.put(object, newPos); - this.addObject(object, chunkX, chunkZ, Integer.MIN_VALUE, Integer.MIN_VALUE, viewDistance); - this.addObjectCallback(object, chunkX, chunkZ, viewDistance); - - //this.validate(object, viewDistance); - - return true; - } - - // called after the distance map updates - protected void addObjectCallback(final E object, final int chunkX, final int chunkZ, final int viewDistance) { - } - - public final boolean remove(final E object) { - final long position = this.objectToLastCoordinate.removeLong(object); - final int viewDistance = this.objectToViewDistance.removeInt(object); - - if (viewDistance == -1) { - return false; - } - - final int currentX = MCUtil.getCoordinateX(position); - final int currentZ = MCUtil.getCoordinateZ(position); - - this.removeObject(object, currentX, currentZ, currentX, currentZ, viewDistance); - this.removeObjectCallback(object, currentX, currentZ, viewDistance); - //this.validate(object, -1); - return true; - } - - // called after the distance map updates - protected void removeObjectCallback(final E object, final int chunkX, final int chunkZ, final int viewDistance) { - } - - protected abstract PooledLinkedHashSets.PooledObjectLinkedOpenHashSet getEmptySetFor(final E object); - - // expensive op, only for debug - protected void validate(final E object, final int viewDistance) { - int entiesGot = 0; - int expectedEntries = (2 * viewDistance + 1); - expectedEntries *= expectedEntries; - if (viewDistance < 0) { - expectedEntries = 0; - } - - final long currPosition = this.objectToLastCoordinate.getLong(object); - - final int centerX = MCUtil.getCoordinateX(currPosition); - final int centerZ = MCUtil.getCoordinateZ(currPosition); - - for (Iterator>> iterator = this.areaMap.long2ObjectEntrySet().fastIterator(); - iterator.hasNext(); ) { - - final Long2ObjectLinkedOpenHashMap.Entry> entry = iterator.next(); - final long key = entry.getLongKey(); - final PooledLinkedHashSets.PooledObjectLinkedOpenHashSet map = entry.getValue(); - - if (map.referenceCount == 0) { - throw new IllegalStateException("Invalid map"); - } - - if (map.contains(object)) { - ++entiesGot; - - final int chunkX = MCUtil.getCoordinateX(key); - final int chunkZ = MCUtil.getCoordinateZ(key); - - final int dist = Math.max(IntegerUtil.branchlessAbs(chunkX - centerX), IntegerUtil.branchlessAbs(chunkZ - centerZ)); - - if (dist > viewDistance) { - throw new IllegalStateException("Expected view distance " + viewDistance + ", got " + dist); - } - } - } - - if (entiesGot != expectedEntries) { - throw new IllegalStateException("Expected " + expectedEntries + ", got " + entiesGot); - } - } - - private void addObjectTo(final E object, final int chunkX, final int chunkZ, final int currChunkX, - final int currChunkZ, final int prevChunkX, final int prevChunkZ) { - final long key = MCUtil.getCoordinateKey(chunkX, chunkZ); - - PooledLinkedHashSets.PooledObjectLinkedOpenHashSet empty = this.getEmptySetFor(object); - PooledLinkedHashSets.PooledObjectLinkedOpenHashSet current = this.areaMap.putIfAbsent(key, empty); - - if (current != null) { - PooledLinkedHashSets.PooledObjectLinkedOpenHashSet next = this.pooledHashSets.findMapWith(current, object); - if (next == current) { - throw new IllegalStateException("Expected different map: got " + next); - } - this.areaMap.put(key, next); - - current = next; - // fall through to callback - } else { - current = empty; - } - - if (this.addCallback != null) { - try { - this.addCallback.accept(object, chunkX, chunkZ, currChunkX, currChunkZ, prevChunkX, prevChunkZ, current); - } catch (final Throwable ex) { - if (ex instanceof ThreadDeath) { - throw (ThreadDeath) ex; - } - MinecraftServer.LOGGER.error("Add callback for map threw exception ", ex); - } - } - } - - private void removeObjectFrom(final E object, final int chunkX, final int chunkZ, final int currChunkX, - final int currChunkZ, final int prevChunkX, final int prevChunkZ) { - final long key = MCUtil.getCoordinateKey(chunkX, chunkZ); - - PooledLinkedHashSets.PooledObjectLinkedOpenHashSet current = this.areaMap.get(key); - - if (current == null) { - throw new IllegalStateException("Current map may not be null for " + object + ", (" + chunkX + "," + chunkZ + ")"); - } - - PooledLinkedHashSets.PooledObjectLinkedOpenHashSet next = this.pooledHashSets.findMapWithout(current, object); - - if (next == current) { - throw new IllegalStateException("Current map [" + next + "] should have contained " + object + ", (" + chunkX + "," + chunkZ + ")"); - } - - if (next != null) { - this.areaMap.put(key, next); - } else { - this.areaMap.remove(key); - } - - if (this.removeCallback != null) { - try { - this.removeCallback.accept(object, chunkX, chunkZ, currChunkX, currChunkZ, prevChunkX, prevChunkZ, next); - } catch (final Throwable ex) { - if (ex instanceof ThreadDeath) { - throw (ThreadDeath) ex; - } - MinecraftServer.LOGGER.error("Remove callback for map threw exception ", ex); - } - } - } - - private void addObject(final E object, final int chunkX, final int chunkZ, final int prevChunkX, final int prevChunkZ, final int viewDistance) { - final int maxX = chunkX + viewDistance; - final int maxZ = chunkZ + viewDistance; - final int minX = chunkX - viewDistance; - final int minZ = chunkZ - viewDistance; - for (int x = minX; x <= maxX; ++x) { - for (int z = minZ; z <= maxZ; ++z) { - this.addObjectTo(object, x, z, chunkX, chunkZ, prevChunkX, prevChunkZ); - } - } - } - - private void removeObject(final E object, final int chunkX, final int chunkZ, final int currentChunkX, final int currentChunkZ, final int viewDistance) { - final int maxX = chunkX + viewDistance; - final int maxZ = chunkZ + viewDistance; - final int minX = chunkX - viewDistance; - final int minZ = chunkZ - viewDistance; - for (int x = minX; x <= maxX; ++x) { - for (int z = minZ; z <= maxZ; ++z) { - this.removeObjectFrom(object, x, z, currentChunkX, currentChunkZ, chunkX, chunkZ); - } - } - } - - private void updateObject(final E object, final long oldPosition, final long newPosition, final int oldViewDistance, final int newViewDistance) { - final int toX = MCUtil.getCoordinateX(newPosition); - final int toZ = MCUtil.getCoordinateZ(newPosition); - final int fromX = MCUtil.getCoordinateX(oldPosition); - final int fromZ = MCUtil.getCoordinateZ(oldPosition); - - final int dx = toX - fromX; - final int dz = toZ - fromZ; - - final int totalX = IntegerUtil.branchlessAbs(fromX - toX); - final int totalZ = IntegerUtil.branchlessAbs(fromZ - toZ); - - if (Math.max(totalX, totalZ) > (2 * Math.max(newViewDistance, oldViewDistance))) { - // teleported? - this.removeObject(object, fromX, fromZ, fromX, fromZ, oldViewDistance); - this.addObject(object, toX, toZ, fromX, fromZ, newViewDistance); - return; - } - - if (oldViewDistance != newViewDistance) { - // remove loop - - final int oldMinX = fromX - oldViewDistance; - final int oldMinZ = fromZ - oldViewDistance; - final int oldMaxX = fromX + oldViewDistance; - final int oldMaxZ = fromZ + oldViewDistance; - for (int currX = oldMinX; currX <= oldMaxX; ++currX) { - for (int currZ = oldMinZ; currZ <= oldMaxZ; ++currZ) { - - // only remove if we're outside the new view distance... - if (Math.max(IntegerUtil.branchlessAbs(currX - toX), IntegerUtil.branchlessAbs(currZ - toZ)) > newViewDistance) { - this.removeObjectFrom(object, currX, currZ, toX, toZ, fromX, fromZ); - } - } - } - - // add loop - - final int newMinX = toX - newViewDistance; - final int newMinZ = toZ - newViewDistance; - final int newMaxX = toX + newViewDistance; - final int newMaxZ = toZ + newViewDistance; - for (int currX = newMinX; currX <= newMaxX; ++currX) { - for (int currZ = newMinZ; currZ <= newMaxZ; ++currZ) { - - // only add if we're outside the old view distance... - if (Math.max(IntegerUtil.branchlessAbs(currX - fromX), IntegerUtil.branchlessAbs(currZ - fromZ)) > oldViewDistance) { - this.addObjectTo(object, currX, currZ, toX, toZ, fromX, fromZ); - } - } - } - - return; - } - - // x axis is width - // z axis is height - // right refers to the x axis of where we moved - // top refers to the z axis of where we moved - - // same view distance - - // used for relative positioning - final int up = sign(dz); // 1 if dz >= 0, -1 otherwise - final int right = sign(dx); // 1 if dx >= 0, -1 otherwise - - // The area excluded by overlapping the two view distance squares creates four rectangles: - // Two on the left, and two on the right. The ones on the left we consider the "removed" section - // and on the right the "added" section. - // https://i.imgur.com/MrnOBgI.png is a reference image. Note that the outside border is not actually - // exclusive to the regions they surround. - - // 4 points of the rectangle - int maxX; // exclusive - int minX; // inclusive - int maxZ; // exclusive - int minZ; // inclusive - - if (dx != 0) { - // handle right addition - - maxX = toX + (oldViewDistance * right) + right; // exclusive - minX = fromX + (oldViewDistance * right) + right; // inclusive - maxZ = fromZ + (oldViewDistance * up) + up; // exclusive - minZ = toZ - (oldViewDistance * up); // inclusive - - for (int currX = minX; currX != maxX; currX += right) { - for (int currZ = minZ; currZ != maxZ; currZ += up) { - this.addObjectTo(object, currX, currZ, toX, toZ, fromX, fromZ); - } - } - } - - if (dz != 0) { - // handle up addition - - maxX = toX + (oldViewDistance * right) + right; // exclusive - minX = toX - (oldViewDistance * right); // inclusive - maxZ = toZ + (oldViewDistance * up) + up; // exclusive - minZ = fromZ + (oldViewDistance * up) + up; // inclusive - - for (int currX = minX; currX != maxX; currX += right) { - for (int currZ = minZ; currZ != maxZ; currZ += up) { - this.addObjectTo(object, currX, currZ, toX, toZ, fromX, fromZ); - } - } - } - - if (dx != 0) { - // handle left removal - - maxX = toX - (oldViewDistance * right); // exclusive - minX = fromX - (oldViewDistance * right); // inclusive - maxZ = fromZ + (oldViewDistance * up) + up; // exclusive - minZ = toZ - (oldViewDistance * up); // inclusive - - for (int currX = minX; currX != maxX; currX += right) { - for (int currZ = minZ; currZ != maxZ; currZ += up) { - this.removeObjectFrom(object, currX, currZ, toX, toZ, fromX, fromZ); - } - } - } - - if (dz != 0) { - // handle down removal - - maxX = fromX + (oldViewDistance * right) + right; // exclusive - minX = fromX - (oldViewDistance * right); // inclusive - maxZ = toZ - (oldViewDistance * up); // exclusive - minZ = fromZ - (oldViewDistance * up); // inclusive - - for (int currX = minX; currX != maxX; currX += right) { - for (int currZ = minZ; currZ != maxZ; currZ += up) { - this.removeObjectFrom(object, currX, currZ, toX, toZ, fromX, fromZ); - } - } - } - } - - @FunctionalInterface - public interface ChangeCallback { - - // if there is no previous position, then prevPos = Integer.MIN_VALUE - void accept(final E object, final int rangeX, final int rangeZ, final int currPosX, final int currPosZ, final int prevPosX, final int prevPosZ, - final PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newState); - - } - - @FunctionalInterface - public interface ChangeSourceCallback { - void accept(final E object, final long prevPos, final long newPos); - } -} diff --git a/arclight-common/src/main/java/com/destroystokyo/paper/util/misc/DistanceTrackingAreaMap.java b/arclight-common/src/main/java/com/destroystokyo/paper/util/misc/DistanceTrackingAreaMap.java deleted file mode 100644 index 6ef84b81c..000000000 --- a/arclight-common/src/main/java/com/destroystokyo/paper/util/misc/DistanceTrackingAreaMap.java +++ /dev/null @@ -1,177 +0,0 @@ -package com.destroystokyo.paper.util.misc; - -import io.papermc.paper.util.IntegerUtil; -import io.papermc.paper.util.MCUtil; -import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; -import net.minecraft.world.level.ChunkPos; - -/** - * @author Spottedleaf - */ -public abstract class DistanceTrackingAreaMap extends AreaMap { - - // use this map only if you need distance tracking, the tracking here is obviously going to hit harder. - - protected final Long2IntOpenHashMap chunkToNearestDistance = new Long2IntOpenHashMap(1024, 0.7f); - protected final DistanceChangeCallback distanceChangeCallback; - - { - this.chunkToNearestDistance.defaultReturnValue(-1); - } - - public DistanceTrackingAreaMap() { - this(new PooledLinkedHashSets<>()); - } - - // let users define a "global" or "shared" pooled sets if they wish - public DistanceTrackingAreaMap(final PooledLinkedHashSets pooledHashSets) { - this(pooledHashSets, null, null, null); - } - - public DistanceTrackingAreaMap(final PooledLinkedHashSets pooledHashSets, final ChangeCallback addCallback, final ChangeCallback removeCallback, - final DistanceChangeCallback distanceChangeCallback) { - super(pooledHashSets, addCallback, removeCallback); - this.distanceChangeCallback = distanceChangeCallback; - } - - // ret -1 if there is nothing mapped - public final int getNearestObjectDistance(final long key) { - return this.chunkToNearestDistance.get(key); - } - - // ret -1 if there is nothing mapped - public final int getNearestObjectDistance(final ChunkPos chunkPos) { - return this.chunkToNearestDistance.get(MCUtil.getCoordinateKey(chunkPos)); - } - - // ret -1 if there is nothing mapped - public final int getNearestObjectDistance(final int chunkX, final int chunkZ) { - return this.chunkToNearestDistance.get(MCUtil.getCoordinateKey(chunkX, chunkZ)); - } - - protected final void recalculateDistance(final int chunkX, final int chunkZ) { - final long key = MCUtil.getCoordinateKey(chunkX, chunkZ); - final PooledLinkedHashSets.PooledObjectLinkedOpenHashSet state = this.areaMap.get(key); - if (state == null) { - final int oldDistance = this.chunkToNearestDistance.remove(key); - // nothing here. - if (oldDistance == -1) { - // nothing was here previously - return; - } - if (this.distanceChangeCallback != null) { - this.distanceChangeCallback.accept(chunkX, chunkZ, oldDistance, -1, null); - } - return; - } - - int newDistance = Integer.MAX_VALUE; - - final Object[] rawData = state.getBackingSet(); - for (int i = 0, len = rawData.length; i < len; ++i) { - final Object raw = rawData[i]; - - if (raw == null) { - continue; - } - - final E object = (E) raw; - final long location = this.objectToLastCoordinate.getLong(object); - - final int distance = Math.max(IntegerUtil.branchlessAbs(chunkX - MCUtil.getCoordinateX(location)), IntegerUtil.branchlessAbs(chunkZ - MCUtil.getCoordinateZ(location))); - - if (distance < newDistance) { - newDistance = distance; - } - } - - final int oldDistance = this.chunkToNearestDistance.put(key, newDistance); - - if (oldDistance != newDistance) { - if (this.distanceChangeCallback != null) { - this.distanceChangeCallback.accept(chunkX, chunkZ, oldDistance, newDistance, state); - } - } - } - - @Override - protected void addObjectCallback(final E object, final int chunkX, final int chunkZ, final int viewDistance) { - final int maxX = chunkX + viewDistance; - final int maxZ = chunkZ + viewDistance; - final int minX = chunkX - viewDistance; - final int minZ = chunkZ - viewDistance; - for (int x = minX; x <= maxX; ++x) { - for (int z = minZ; z <= maxZ; ++z) { - this.recalculateDistance(x, z); - } - } - } - - @Override - protected void removeObjectCallback(final E object, final int chunkX, final int chunkZ, final int viewDistance) { - final int maxX = chunkX + viewDistance; - final int maxZ = chunkZ + viewDistance; - final int minX = chunkX - viewDistance; - final int minZ = chunkZ - viewDistance; - for (int x = minX; x <= maxX; ++x) { - for (int z = minZ; z <= maxZ; ++z) { - this.recalculateDistance(x, z); - } - } - } - - @Override - protected void updateObjectCallback(final E object, final long oldPosition, final long newPosition, final int oldViewDistance, final int newViewDistance) { - if (oldPosition == newPosition && newViewDistance == oldViewDistance) { - return; - } - - final int toX = MCUtil.getCoordinateX(newPosition); - final int toZ = MCUtil.getCoordinateZ(newPosition); - final int fromX = MCUtil.getCoordinateX(oldPosition); - final int fromZ = MCUtil.getCoordinateZ(oldPosition); - - final int totalX = IntegerUtil.branchlessAbs(fromX - toX); - final int totalZ = IntegerUtil.branchlessAbs(fromZ - toZ); - - if (Math.max(totalX, totalZ) > (2 * Math.max(newViewDistance, oldViewDistance))) { - // teleported? - this.removeObjectCallback(object, fromX, fromZ, oldViewDistance); - this.addObjectCallback(object, toX, toZ, newViewDistance); - return; - } - - final int minX = Math.min(fromX - oldViewDistance, toX - newViewDistance); - final int maxX = Math.max(fromX + oldViewDistance, toX + newViewDistance); - final int minZ = Math.min(fromZ - oldViewDistance, toZ - newViewDistance); - final int maxZ = Math.max(fromZ + oldViewDistance, toZ + newViewDistance); - - for (int x = minX; x <= maxX; ++x) { - for (int z = minZ; z <= maxZ; ++z) { - final int distXOld = IntegerUtil.branchlessAbs(x - fromX); - final int distZOld = IntegerUtil.branchlessAbs(z - fromZ); - - if (Math.max(distXOld, distZOld) <= oldViewDistance) { - this.recalculateDistance(x, z); - continue; - } - - final int distXNew = IntegerUtil.branchlessAbs(x - toX); - final int distZNew = IntegerUtil.branchlessAbs(z - toZ); - - if (Math.max(distXNew, distZNew) <= newViewDistance) { - this.recalculateDistance(x, z); - continue; - } - } - } - } - - @FunctionalInterface - public interface DistanceChangeCallback { - - void accept(final int posX, final int posZ, final int oldNearestDistance, final int newNearestDistance, - final PooledLinkedHashSets.PooledObjectLinkedOpenHashSet state); - - } -} diff --git a/arclight-common/src/main/java/com/destroystokyo/paper/util/misc/PlayerAreaMap.java b/arclight-common/src/main/java/com/destroystokyo/paper/util/misc/PlayerAreaMap.java deleted file mode 100644 index 1484905fb..000000000 --- a/arclight-common/src/main/java/com/destroystokyo/paper/util/misc/PlayerAreaMap.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.destroystokyo.paper.util.misc; - -import net.minecraft.server.level.ServerPlayer; - -/** - * @author Spottedleaf - */ -public final class PlayerAreaMap extends AreaMap { - - public PlayerAreaMap() { - super(); - } - - public PlayerAreaMap(final PooledLinkedHashSets pooledHashSets) { - super(pooledHashSets); - } - - public PlayerAreaMap(final PooledLinkedHashSets pooledHashSets, final ChangeCallback addCallback, - final ChangeCallback removeCallback) { - this(pooledHashSets, addCallback, removeCallback, null); - } - - public PlayerAreaMap(final PooledLinkedHashSets pooledHashSets, final ChangeCallback addCallback, - final ChangeCallback removeCallback, final ChangeSourceCallback changeSourceCallback) { - super(pooledHashSets, addCallback, removeCallback, changeSourceCallback); - } - - @Override - protected PooledLinkedHashSets.PooledObjectLinkedOpenHashSet getEmptySetFor(final ServerPlayer player) { - return new PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<>(player); - } -} diff --git a/arclight-common/src/main/java/com/destroystokyo/paper/util/misc/PlayerDistanceTrackingAreaMap.java b/arclight-common/src/main/java/com/destroystokyo/paper/util/misc/PlayerDistanceTrackingAreaMap.java deleted file mode 100644 index 0316a3bb9..000000000 --- a/arclight-common/src/main/java/com/destroystokyo/paper/util/misc/PlayerDistanceTrackingAreaMap.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.destroystokyo.paper.util.misc; - -import net.minecraft.server.level.ServerPlayer; - -public class PlayerDistanceTrackingAreaMap extends DistanceTrackingAreaMap { - - public PlayerDistanceTrackingAreaMap() { - super(); - } - - public PlayerDistanceTrackingAreaMap(final PooledLinkedHashSets pooledHashSets) { - super(pooledHashSets); - } - - public PlayerDistanceTrackingAreaMap(final PooledLinkedHashSets pooledHashSets, final ChangeCallback addCallback, - final ChangeCallback removeCallback, final DistanceChangeCallback distanceChangeCallback) { - super(pooledHashSets, addCallback, removeCallback, distanceChangeCallback); - } - - @Override - protected PooledLinkedHashSets.PooledObjectLinkedOpenHashSet getEmptySetFor(final ServerPlayer player) { - return new PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<>(player); - } -} diff --git a/arclight-common/src/main/java/com/destroystokyo/paper/util/misc/PooledLinkedHashSets.java b/arclight-common/src/main/java/com/destroystokyo/paper/util/misc/PooledLinkedHashSets.java deleted file mode 100644 index 896bead5c..000000000 --- a/arclight-common/src/main/java/com/destroystokyo/paper/util/misc/PooledLinkedHashSets.java +++ /dev/null @@ -1,289 +0,0 @@ -package com.destroystokyo.paper.util.misc; - -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; - -import java.lang.ref.WeakReference; - -/** - * @author Spottedleaf - */ -public class PooledLinkedHashSets { - - /* Tested via https://gist.github.com/Spottedleaf/a93bb7a8993d6ce142d3efc5932bf573 */ - - // we really want to avoid that equals() check as much as possible... - protected final Object2ObjectOpenHashMap, PooledObjectLinkedOpenHashSet> mapPool = new Object2ObjectOpenHashMap<>(128, 0.25f); - - protected void decrementReferenceCount(final PooledObjectLinkedOpenHashSet current) { - if (current.referenceCount == 0) { - throw new IllegalStateException("Cannot decrement reference count for " + current); - } - if (current.referenceCount == -1 || --current.referenceCount > 0) { - return; - } - - this.mapPool.remove(current); - } - - public PooledObjectLinkedOpenHashSet findMapWith(final PooledObjectLinkedOpenHashSet current, final E object) { - final PooledObjectLinkedOpenHashSet cached = current.getAddCache(object); - - if (cached != null) { - decrementReferenceCount(current); - - if (cached.referenceCount == 0) { - // bring the map back from the dead - PooledObjectLinkedOpenHashSet contending = this.mapPool.putIfAbsent(cached, cached); - if (contending != null) { - // a map already exists with the elements we want - if (contending.referenceCount != -1) { - ++contending.referenceCount; - } - current.updateAddCache(object, contending); - return contending; - } - - cached.referenceCount = 1; - } else if (cached.referenceCount != -1) { - ++cached.referenceCount; - } - - return cached; - } - - if (!current.add(object)) { - return current; - } - - // we use get/put since we use a different key on put - PooledObjectLinkedOpenHashSet ret = this.mapPool.get(current); - - if (ret == null) { - ret = new PooledObjectLinkedOpenHashSet<>(current); - current.remove(object); - this.mapPool.put(ret, ret); - ret.referenceCount = 1; - } else { - if (ret.referenceCount != -1) { - ++ret.referenceCount; - } - current.remove(object); - } - - current.updateAddCache(object, ret); - - decrementReferenceCount(current); - return ret; - } - - // rets null if current.size() == 1 - public PooledObjectLinkedOpenHashSet findMapWithout(final PooledObjectLinkedOpenHashSet current, final E object) { - if (current.set.size() == 1) { - decrementReferenceCount(current); - return null; - } - - final PooledObjectLinkedOpenHashSet cached = current.getRemoveCache(object); - - if (cached != null) { - decrementReferenceCount(current); - - if (cached.referenceCount == 0) { - // bring the map back from the dead - PooledObjectLinkedOpenHashSet contending = this.mapPool.putIfAbsent(cached, cached); - if (contending != null) { - // a map already exists with the elements we want - if (contending.referenceCount != -1) { - ++contending.referenceCount; - } - current.updateRemoveCache(object, contending); - return contending; - } - - cached.referenceCount = 1; - } else if (cached.referenceCount != -1) { - ++cached.referenceCount; - } - - return cached; - } - - if (!current.remove(object)) { - return current; - } - - // we use get/put since we use a different key on put - PooledObjectLinkedOpenHashSet ret = this.mapPool.get(current); - - if (ret == null) { - ret = new PooledObjectLinkedOpenHashSet<>(current); - current.add(object); - this.mapPool.put(ret, ret); - ret.referenceCount = 1; - } else { - if (ret.referenceCount != -1) { - ++ret.referenceCount; - } - current.add(object); - } - - current.updateRemoveCache(object, ret); - - decrementReferenceCount(current); - return ret; - } - - static final class RawSetObjectLinkedOpenHashSet extends ObjectOpenHashSet { - - public RawSetObjectLinkedOpenHashSet() { - super(); - } - - public RawSetObjectLinkedOpenHashSet(final int capacity) { - super(capacity); - } - - public RawSetObjectLinkedOpenHashSet(final int capacity, final float loadFactor) { - super(capacity, loadFactor); - } - - @Override - public RawSetObjectLinkedOpenHashSet clone() { - return (RawSetObjectLinkedOpenHashSet) super.clone(); - } - - public E[] getRawSet() { - return this.key; - } - } - - public static final class PooledObjectLinkedOpenHashSet { - - private static final WeakReference NULL_REFERENCE = new WeakReference<>(null); - - final RawSetObjectLinkedOpenHashSet set; - int referenceCount; // -1 if special - int hash; // optimize hashcode - - // add cache - WeakReference lastAddObject = NULL_REFERENCE; - WeakReference> lastAddMap = NULL_REFERENCE; - - // remove cache - WeakReference lastRemoveObject = NULL_REFERENCE; - WeakReference> lastRemoveMap = NULL_REFERENCE; - - public PooledObjectLinkedOpenHashSet(final PooledLinkedHashSets pooledSets) { - this.set = new RawSetObjectLinkedOpenHashSet<>(2, 0.8f); - } - - public PooledObjectLinkedOpenHashSet(final E single) { - this((PooledLinkedHashSets) null); - this.referenceCount = -1; - this.add(single); - } - - public PooledObjectLinkedOpenHashSet(final PooledObjectLinkedOpenHashSet other) { - this.set = other.set.clone(); - this.hash = other.hash; - } - - // from https://github.com/Spottedleaf/ConcurrentUtil/blob/master/src/main/java/ca/spottedleaf/concurrentutil/util/IntegerUtil.java - // generated by https://github.com/skeeto/hash-prospector - private static int hash0(int x) { - x *= 0x36935555; - x ^= x >>> 16; - return x; - } - - PooledObjectLinkedOpenHashSet getAddCache(final E element) { - final E currentAdd = this.lastAddObject.get(); - - if (currentAdd == null || !(currentAdd == element || currentAdd.equals(element))) { - return null; - } - - return this.lastAddMap.get(); - } - - PooledObjectLinkedOpenHashSet getRemoveCache(final E element) { - final E currentRemove = this.lastRemoveObject.get(); - - if (currentRemove == null || !(currentRemove == element || currentRemove.equals(element))) { - return null; - } - - return this.lastRemoveMap.get(); - } - - void updateAddCache(final E element, final PooledObjectLinkedOpenHashSet map) { - this.lastAddObject = new WeakReference<>(element); - this.lastAddMap = new WeakReference<>(map); - } - - void updateRemoveCache(final E element, final PooledObjectLinkedOpenHashSet map) { - this.lastRemoveObject = new WeakReference<>(element); - this.lastRemoveMap = new WeakReference<>(map); - } - - boolean add(final E element) { - boolean added = this.set.add(element); - - if (added) { - this.hash += hash0(element.hashCode()); - } - - return added; - } - - boolean remove(Object element) { - boolean removed = this.set.remove(element); - - if (removed) { - this.hash -= hash0(element.hashCode()); - } - - return removed; - } - - public boolean contains(final Object element) { - return this.set.contains(element); - } - - public E[] getBackingSet() { - return this.set.getRawSet(); - } - - public int size() { - return this.set.size(); - } - - @Override - public int hashCode() { - return this.hash; - } - - @Override - public boolean equals(final Object other) { - if (!(other instanceof PooledObjectLinkedOpenHashSet)) { - return false; - } - if (this.referenceCount == 0) { - return other == this; - } else { - if (other == this) { - // Unfortunately we are never equal to our own instance while in use! - return false; - } - return this.hash == ((PooledObjectLinkedOpenHashSet) other).hash && this.set.equals(((PooledObjectLinkedOpenHashSet) other).set); - } - } - - @Override - public String toString() { - return "PooledHashSet: size: " + this.set.size() + ", reference count: " + this.referenceCount + ", hash: " + - this.hashCode() + ", identity: " + System.identityHashCode(this) + " map: " + this.set; - } - } -} diff --git a/arclight-common/src/main/java/com/destroystokyo/paper/util/pooled/PooledObjects.java b/arclight-common/src/main/java/com/destroystokyo/paper/util/pooled/PooledObjects.java deleted file mode 100644 index b9a86d24d..000000000 --- a/arclight-common/src/main/java/com/destroystokyo/paper/util/pooled/PooledObjects.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.destroystokyo.paper.util.pooled; - -import io.papermc.paper.util.MCUtil; -import org.apache.commons.lang3.mutable.MutableInt; - -import java.util.ArrayDeque; -import java.util.function.Consumer; -import java.util.function.Supplier; - -public final class PooledObjects { - - public static final PooledObjects POOLED_MUTABLE_INTEGERS = new PooledObjects<>(MutableInt::new, 1024); - private final Supplier creator; - private final Consumer releaser; - private final int maxPoolSize; - private final ArrayDeque queue; - public PooledObjects(final Supplier creator, int maxPoolSize) { - this(creator, maxPoolSize, null); - } - - public PooledObjects(final Supplier creator, int maxPoolSize, Consumer releaser) { - if (creator == null) { - throw new NullPointerException("Creator must not be null"); - } - if (maxPoolSize <= 0) { - throw new IllegalArgumentException("Max pool size must be greater-than 0"); - } - - this.queue = new ArrayDeque<>(maxPoolSize); - this.maxPoolSize = maxPoolSize; - this.creator = creator; - this.releaser = releaser; - } - - public AutoReleased acquireCleaner(Object holder) { - return acquireCleaner(holder, this::release); - } - - public AutoReleased acquireCleaner(Object holder, Consumer releaser) { - E resource = acquire(); - Runnable cleaner = MCUtil.registerCleaner(holder, resource, releaser); - return new AutoReleased(resource, cleaner); - } - - public E acquire() { - E value; - synchronized (queue) { - value = this.queue.pollLast(); - } - return value != null ? value : this.creator.get(); - } - - public void release(final E value) { - if (this.releaser != null) { - this.releaser.accept(value); - } - synchronized (this.queue) { - if (queue.size() < this.maxPoolSize) { - this.queue.addLast(value); - } - } - } - - /** - * Wrapper for an object that will be have a cleaner registered for it, and may be automatically returned to pool. - */ - public class AutoReleased { - private final E object; - private final Runnable cleaner; - - public AutoReleased(E object, Runnable cleaner) { - this.object = object; - this.cleaner = cleaner; - } - - public final E getObject() { - return object; - } - - public final Runnable getCleaner() { - return cleaner; - } - } -} diff --git a/arclight-common/src/main/java/com/destroystokyo/paper/util/set/OptimizedSmallEnumSet.java b/arclight-common/src/main/java/com/destroystokyo/paper/util/set/OptimizedSmallEnumSet.java deleted file mode 100644 index b3329c6fc..000000000 --- a/arclight-common/src/main/java/com/destroystokyo/paper/util/set/OptimizedSmallEnumSet.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.destroystokyo.paper.util.set; - -import java.util.Collection; - -/** - * @author Spottedleaf - */ -public final class OptimizedSmallEnumSet> { - - private final Class enumClass; - private long backingSet; - - public OptimizedSmallEnumSet(final Class clazz) { - if (clazz == null) { - throw new IllegalArgumentException("Null class"); - } - if (!clazz.isEnum()) { - throw new IllegalArgumentException("Class must be enum, not " + clazz.getCanonicalName()); - } - this.enumClass = clazz; - } - - public boolean addUnchecked(final E element) { - final int ordinal = element.ordinal(); - final long key = 1L << ordinal; - - final long prev = this.backingSet; - this.backingSet = prev | key; - - return (prev & key) == 0; - } - - public boolean removeUnchecked(final E element) { - final int ordinal = element.ordinal(); - final long key = 1L << ordinal; - - final long prev = this.backingSet; - this.backingSet = prev & ~key; - - return (prev & key) != 0; - } - - public void clear() { - this.backingSet = 0L; - } - - public int size() { - return Long.bitCount(this.backingSet); - } - - public void addAllUnchecked(final Collection enums) { - for (final E element : enums) { - if (element == null) { - throw new NullPointerException("Null element"); - } - this.backingSet |= (1L << element.ordinal()); - } - } - - public long getBackingSet() { - return this.backingSet; - } - - public boolean hasCommonElements(final OptimizedSmallEnumSet other) { - return (other.backingSet & this.backingSet) != 0; - } - - public boolean hasElement(final E element) { - return (this.backingSet & (1L << element.ordinal())) != 0; - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/chat/ChatRenderer.java b/arclight-common/src/main/java/io/papermc/paper/chat/ChatRenderer.java deleted file mode 100644 index c403b4b77..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/chat/ChatRenderer.java +++ /dev/null @@ -1,40 +0,0 @@ -package io.papermc.paper.chat; - -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.text.Component; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -// Chat renderer for player messages -@FunctionalInterface -public interface ChatRenderer { - // Create default chat renderer - @NotNull - static ChatRenderer defaultRenderer() { - return new ViewerUnawareImpl.Default((source, sourceDisplayName, message) -> Component.translatable("chat.type.text", sourceDisplayName, message)); - } - - // Create viewer-unaware renderer - @NotNull - static ChatRenderer viewerUnaware(final @NotNull ViewerUnaware renderer) { - return new ViewerUnawareImpl(renderer); - } - - // Render chat message for each audience - @ApiStatus.OverrideOnly - @NotNull - Component render(@NotNull Player source, @NotNull Component sourceDisplayName, @NotNull Component message, @NotNull Audience viewer); - - @ApiStatus.Internal - sealed interface Default extends ChatRenderer, ViewerUnaware permits ViewerUnawareImpl.Default { - } - - // Chat renderer without viewer context - interface ViewerUnaware { - // Render chat message - @ApiStatus.OverrideOnly - @NotNull - Component render(@NotNull Player source, @NotNull Component sourceDisplayName, @NotNull Component message); - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/chat/ViewerUnawareImpl.java b/arclight-common/src/main/java/io/papermc/paper/chat/ViewerUnawareImpl.java deleted file mode 100644 index 2ad76b175..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/chat/ViewerUnawareImpl.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.papermc.paper.chat; - -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.text.Component; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -sealed class ViewerUnawareImpl implements ChatRenderer, ChatRenderer.ViewerUnaware permits ViewerUnawareImpl.Default { - private final ViewerUnaware unaware; - private @Nullable Component message; - - ViewerUnawareImpl(final ViewerUnaware unaware) { - this.unaware = unaware; - } - - @Override - public @NotNull Component render(final @NotNull Player source, final @NotNull Component sourceDisplayName, final @NotNull Component message, final @NotNull Audience viewer) { - return this.render(source, sourceDisplayName, message); - } - - @Override - public @NotNull Component render(final @NotNull Player source, final @NotNull Component sourceDisplayName, final @NotNull Component message) { - if (this.message == null) { - this.message = this.unaware.render(source, sourceDisplayName, message); - } - return this.message; - } - - static final class Default extends ViewerUnawareImpl implements ChatRenderer.Default { - Default(final ViewerUnaware unaware) { - super(unaware); - } - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/chunk/SingleThreadChunkRegionManager.java b/arclight-common/src/main/java/io/papermc/paper/chunk/SingleThreadChunkRegionManager.java deleted file mode 100644 index 1bd7df14f..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/chunk/SingleThreadChunkRegionManager.java +++ /dev/null @@ -1,473 +0,0 @@ -package io.papermc.paper.chunk; - -import io.papermc.paper.util.MCUtil; -import io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet; -import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet; -import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.ChunkPos; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.function.Supplier; - -public final class SingleThreadChunkRegionManager { - - public final int regionChunkShift; // log2(REGION_CHUNK_SIZE) - public final ServerLevel world; - public final String name; - private final int regionSectionMergeRadius; - private final int regionSectionChunkSize; - private final Long2ObjectOpenHashMap regionsBySection = new Long2ObjectOpenHashMap<>(); - private final ReferenceLinkedOpenHashSet needsRecalculation = new ReferenceLinkedOpenHashSet<>(); - private final int minSectionRecalcCount; - private final double maxDeadRegionPercent; - private final Supplier regionDataSupplier; - private final Supplier regionSectionDataSupplier; - private final List toMerge = new ArrayList<>(); - - // tested via https://gist.github.com/Spottedleaf/aa7ade3451c37b4cac061fc77074db2f - - /* - protected void check() { - ReferenceOpenHashSet> checked = new ReferenceOpenHashSet<>(); - - for (RegionSection section : this.regionsBySection.values()) { - if (!checked.add(section.region)) { - section.region.check(); - } - } - for (Region region : this.needsRecalculation) { - region.check(); - } - } - */ - - public SingleThreadChunkRegionManager(final ServerLevel world, final int minSectionRecalcCount, - final double maxDeadRegionPercent, final int sectionMergeRadius, - final int regionSectionChunkShift, - final String name, final Supplier regionDataSupplier, - final Supplier regionSectionDataSupplier) { - this.regionSectionMergeRadius = sectionMergeRadius; - this.regionSectionChunkSize = 1 << regionSectionChunkShift; - this.regionChunkShift = regionSectionChunkShift; - this.world = world; - this.name = name; - this.minSectionRecalcCount = Math.max(2, minSectionRecalcCount); - this.maxDeadRegionPercent = maxDeadRegionPercent; - this.regionDataSupplier = regionDataSupplier; - this.regionSectionDataSupplier = regionSectionDataSupplier; - } - - private void addToRecalcQueue(final Region region) { - this.needsRecalculation.add(region); - } - - private void removeFromRecalcQueue(final Region region) { - this.needsRecalculation.remove(region); - } - - public RegionSection getRegionSection(final int chunkX, final int chunkZ) { - return this.regionsBySection.get(MCUtil.getCoordinateKey(chunkX >> this.regionChunkShift, chunkZ >> this.regionChunkShift)); - } - - public Region getRegion(final int chunkX, final int chunkZ) { - final RegionSection section = this.regionsBySection.get(MCUtil.getCoordinateKey(chunkX >> regionChunkShift, chunkZ >> regionChunkShift)); - return section != null ? section.region : null; - } - - private RegionSection getOrCreateAndMergeSection(final int sectionX, final int sectionZ, final RegionSection force) { - final long sectionKey = MCUtil.getCoordinateKey(sectionX, sectionZ); - - if (force == null) { - RegionSection region = this.regionsBySection.get(sectionKey); - if (region != null) { - return region; - } - } - - int mergeCandidateSectionSize = -1; - Region mergeIntoCandidate = null; - - // find optimal candidate to merge into - - final int minX = sectionX - this.regionSectionMergeRadius; - final int maxX = sectionX + this.regionSectionMergeRadius; - final int minZ = sectionZ - this.regionSectionMergeRadius; - final int maxZ = sectionZ + this.regionSectionMergeRadius; - for (int currX = minX; currX <= maxX; ++currX) { - for (int currZ = minZ; currZ <= maxZ; ++currZ) { - final RegionSection section = this.regionsBySection.get(MCUtil.getCoordinateKey(currX, currZ)); - if (section == null) { - continue; - } - final Region region = section.region; - if (region.dead) { - throw new IllegalStateException("Dead region should not be in live region manager state: " + region); - } - final int sections = region.sections.size(); - - if (sections > mergeCandidateSectionSize) { - mergeCandidateSectionSize = sections; - mergeIntoCandidate = region; - } - this.toMerge.add(region); - } - } - - // merge - if (mergeIntoCandidate != null) { - for (int i = 0; i < this.toMerge.size(); ++i) { - final Region region = this.toMerge.get(i); - if (region.dead || mergeIntoCandidate == region) { - continue; - } - region.mergeInto(mergeIntoCandidate); - } - this.toMerge.clear(); - } else { - mergeIntoCandidate = new Region(this); - } - - final RegionSection section; - if (force == null) { - this.regionsBySection.put(sectionKey, section = new RegionSection(sectionKey, this)); - } else { - final RegionSection existing = this.regionsBySection.putIfAbsent(sectionKey, force); - if (existing != null) { - throw new IllegalStateException("Attempting to override section '" + existing.toStringWithRegion() + - ", with " + force.toStringWithRegion()); - } - - section = force; - } - - mergeIntoCandidate.addRegionSection(section); - //mergeIntoCandidate.check(); - //this.check(); - - return section; - } - - public void addChunk(final int chunkX, final int chunkZ) { - this.getOrCreateAndMergeSection(chunkX >> this.regionChunkShift, chunkZ >> this.regionChunkShift, null).addChunk(chunkX, chunkZ); - } - - public void removeChunk(final int chunkX, final int chunkZ) { - final RegionSection section = this.regionsBySection.get( - MCUtil.getCoordinateKey(chunkX >> this.regionChunkShift, chunkZ >> this.regionChunkShift) - ); - if (section != null) { - section.removeChunk(chunkX, chunkZ); - } else { - throw new IllegalStateException("Cannot remove chunk at (" + chunkX + "," + chunkZ + ") from region state, section does not exist"); - } - } - - public void recalculateRegions() { - for (int i = 0, len = this.needsRecalculation.size(); i < len; ++i) { - final Region region = this.needsRecalculation.removeFirst(); - - this.recalculateRegion(region); - //this.check(); - } - } - - private void recalculateRegion(final Region region) { - region.markedForRecalc = false; - //region.check(); - // clear unused regions - for (final Iterator iterator = region.deadSections.iterator(); iterator.hasNext(); ) { - final RegionSection deadSection = iterator.next(); - - if (deadSection.hasChunks()) { - throw new IllegalStateException("Dead section '" + deadSection.toStringWithRegion() + "' is marked dead but has chunks!"); - } - if (!region.removeRegionSection(deadSection)) { - throw new IllegalStateException("Region " + region + " has inconsistent state, it should contain section " + deadSection); - } - if (!this.regionsBySection.remove(deadSection.regionCoordinate, deadSection)) { - throw new IllegalStateException("Cannot remove dead section '" + - deadSection.toStringWithRegion() + "' from section state! State at section coordinate: " + - this.regionsBySection.get(deadSection.regionCoordinate)); - } - } - region.deadSections.clear(); - - // implicitly cover cases where size == 0 - if (region.sections.size() < this.minSectionRecalcCount) { - //region.check(); - return; - } - - // run a test to see if we actually need to recalculate - // TODO - - // destroy and rebuild the region - region.dead = true; - - // destroy region state - for (final Iterator iterator = region.sections.unsafeIterator(IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext(); ) { - final RegionSection aliveSection = iterator.next(); - if (!aliveSection.hasChunks()) { - throw new IllegalStateException("Alive section '" + aliveSection.toStringWithRegion() + "' has no chunks!"); - } - if (!this.regionsBySection.remove(aliveSection.regionCoordinate, aliveSection)) { - throw new IllegalStateException("Cannot remove alive section '" + - aliveSection.toStringWithRegion() + "' from section state! State at section coordinate: " + - this.regionsBySection.get(aliveSection.regionCoordinate)); - } - } - - // rebuild regions - for (final Iterator iterator = region.sections.unsafeIterator(IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext(); ) { - final RegionSection aliveSection = iterator.next(); - this.getOrCreateAndMergeSection(aliveSection.getSectionX(), aliveSection.getSectionZ(), aliveSection); - } - } - - public interface RegionData { - - } - - public interface RegionSectionData { - - void removeFromRegion(final RegionSection section, final Region from); - - // removal from the old region is handled via removeFromRegion - void addToRegion(final RegionSection section, final Region oldRegion, final Region newRegion); - - } - - public static final class Region { - public final SingleThreadChunkRegionManager regionManager; - public final RegionData regionData; - private final IteratorSafeOrderedReferenceSet sections = new IteratorSafeOrderedReferenceSet<>(); - private final ReferenceOpenHashSet deadSections = new ReferenceOpenHashSet<>(16, 0.7f); - private boolean dead; - private boolean markedForRecalc; - - private Region(final SingleThreadChunkRegionManager regionManager) { - this.regionManager = regionManager; - this.regionData = regionManager.regionDataSupplier.get(); - } - - public IteratorSafeOrderedReferenceSet.Iterator getSections() { - return this.sections.iterator(IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); - } - - private double getDeadSectionPercent() { - return (double) this.deadSections.size() / (double) this.sections.size(); - } - - /* - protected void check() { - if (this.dead) { - throw new IllegalStateException("Dead region!"); - } - for (final Iterator> iterator = this.sections.unsafeIterator(IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) { - final RegionSection section = iterator.next(); - if (section.region != this) { - throw new IllegalStateException("Region section must point to us!"); - } - if (this.regionManager.regionsBySection.get(section.regionCoordinate) != section) { - throw new IllegalStateException("Region section must match the regionmanager state!"); - } - } - } - */ - - // note: it is not true that the region at this point is not in any region. use the region field on the section - // to see if it is currently in another region. - private boolean addRegionSection(final RegionSection section) { - if (!this.sections.add(section)) { - return false; - } - - section.sectionData.addToRegion(section, section.region, this); - - section.region = this; - return true; - } - - private boolean removeRegionSection(final RegionSection section) { - if (!this.sections.remove(section)) { - return false; - } - - section.sectionData.removeFromRegion(section, this); - - return true; - } - - private void mergeInto(final Region mergeTarget) { - if (this == mergeTarget) { - throw new IllegalStateException("Cannot merge a region onto itself"); - } - if (this.dead) { - throw new IllegalStateException("Source region is dead! Source " + this + ", target " + mergeTarget); - } else if (mergeTarget.dead) { - throw new IllegalStateException("Target region is dead! Source " + this + ", target " + mergeTarget); - } - this.dead = true; - if (this.markedForRecalc) { - this.regionManager.removeFromRecalcQueue(this); - } - - for (final Iterator iterator = this.sections.unsafeIterator(IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext(); ) { - final RegionSection section = iterator.next(); - - if (!mergeTarget.addRegionSection(section)) { - throw new IllegalStateException("Target cannot contain source's sections! Source " + this + ", target " + mergeTarget); - } - } - - for (final RegionSection deadSection : this.deadSections) { - if (!this.sections.contains(deadSection)) { - throw new IllegalStateException("Source region does not even contain its own dead sections! Missing " + deadSection + " from region " + this); - } - mergeTarget.deadSections.add(deadSection); - } - //mergeTarget.check(); - } - - private void markSectionAlive(final RegionSection section) { - this.deadSections.remove(section); - if (this.markedForRecalc && (this.sections.size() < this.regionManager.minSectionRecalcCount || this.getDeadSectionPercent() < this.regionManager.maxDeadRegionPercent)) { - this.regionManager.removeFromRecalcQueue(this); - this.markedForRecalc = false; - } - } - - private void markSectionDead(final RegionSection section) { - this.deadSections.add(section); - if (!this.markedForRecalc && (this.sections.size() >= this.regionManager.minSectionRecalcCount || this.sections.size() == this.deadSections.size()) && this.getDeadSectionPercent() >= this.regionManager.maxDeadRegionPercent) { - this.regionManager.addToRecalcQueue(this); - this.markedForRecalc = true; - } - } - - @Override - public String toString() { - final StringBuilder ret = new StringBuilder(128); - - ret.append("Region{"); - ret.append("dead=").append(this.dead).append(','); - ret.append("markedForRecalc=").append(this.markedForRecalc).append(','); - - ret.append("sectionCount=").append(this.sections.size()).append(','); - ret.append("sections=["); - for (final Iterator iterator = this.sections.unsafeIterator(IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext(); ) { - final RegionSection section = iterator.next(); - ret.append(section); - if (iterator.hasNext()) { - ret.append(','); - } - } - ret.append(']'); - - ret.append('}'); - return ret.toString(); - } - } - - public static final class RegionSection { - public final SingleThreadChunkRegionManager regionManager; - public final RegionSectionData sectionData; - private final long regionCoordinate; - private final long[] chunksBitset; - private int chunkCount; - private Region region; - - private RegionSection(final long regionCoordinate, final SingleThreadChunkRegionManager regionManager) { - this.regionCoordinate = regionCoordinate; - this.regionManager = regionManager; - this.chunksBitset = new long[Math.max(1, regionManager.regionSectionChunkSize * regionManager.regionSectionChunkSize / Long.SIZE)]; - this.sectionData = regionManager.regionSectionDataSupplier.get(); - } - - private static String toString(final long[] array) { - final StringBuilder ret = new StringBuilder(); - for (final long value : array) { - // zero pad the hex string - final char[] zeros = new char[Long.SIZE / 4]; - Arrays.fill(zeros, '0'); - final String string = Long.toHexString(value); - System.arraycopy(string.toCharArray(), 0, zeros, zeros.length - string.length(), string.length()); - - ret.append(zeros); - } - - return ret.toString(); - } - - public int getSectionX() { - return MCUtil.getCoordinateX(this.regionCoordinate); - } - - public int getSectionZ() { - return MCUtil.getCoordinateZ(this.regionCoordinate); - } - - public Region getRegion() { - return this.region; - } - - private int getChunkIndex(final int chunkX, final int chunkZ) { - return (chunkX & (this.regionManager.regionSectionChunkSize - 1)) | ((chunkZ & (this.regionManager.regionSectionChunkSize - 1)) << this.regionManager.regionChunkShift); - } - - private boolean hasChunks() { - return this.chunkCount != 0; - } - - private void addChunk(final int chunkX, final int chunkZ) { - final int index = this.getChunkIndex(chunkX, chunkZ); - final long bitset = this.chunksBitset[index >>> 6]; // index / Long.SIZE - final long after = this.chunksBitset[index >>> 6] = bitset | (1L << (index & (Long.SIZE - 1))); - if (after == bitset) { - throw new IllegalStateException("Cannot add a chunk to a section which already has the chunk! RegionSection: " + this + ", global chunk: " + new ChunkPos(chunkX, chunkZ)); - } - if (++this.chunkCount != 1) { - return; - } - this.region.markSectionAlive(this); - } - - private void removeChunk(final int chunkX, final int chunkZ) { - final int index = this.getChunkIndex(chunkX, chunkZ); - final long before = this.chunksBitset[index >>> 6]; // index / Long.SIZE - final long bitset = this.chunksBitset[index >>> 6] = before & ~(1L << (index & (Long.SIZE - 1))); - if (before == bitset) { - throw new IllegalStateException("Cannot remove a chunk from a section which does not have that chunk! RegionSection: " + this + ", global chunk: " + new ChunkPos(chunkX, chunkZ)); - } - if (--this.chunkCount != 0) { - return; - } - this.region.markSectionDead(this); - } - - @Override - public String toString() { - return "RegionSection{" + - "regionCoordinate=" + new ChunkPos(this.regionCoordinate) + "," + - "chunkCount=" + this.chunkCount + "," + - "chunksBitset=" + toString(this.chunksBitset) + "," + - "hash=" + this.hashCode() + - "}"; - } - - public String toStringWithRegion() { - return "RegionSection{" + - "regionCoordinate=" + new ChunkPos(this.regionCoordinate) + "," + - "chunkCount=" + this.chunkCount + "," + - "chunksBitset=" + toString(this.chunksBitset) + "," + - "hash=" + this.hashCode() + "," + - "region=" + this.region + - "}"; - } - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java b/arclight-common/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java deleted file mode 100644 index 93cf248e8..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java +++ /dev/null @@ -1,129 +0,0 @@ -package io.papermc.paper.chunk.system; - -import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.FullChunkStatus; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; -import org.bukkit.Bukkit; - -import java.util.Collections; -import java.util.List; -import java.util.function.Consumer; - -public final class ChunkSystem { - - private ChunkSystem() { - throw new RuntimeException(); - } - - public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run) { - scheduleChunkTask(level, chunkX, chunkZ, run, PrioritisedExecutor.Priority.NORMAL); - } - - public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final PrioritisedExecutor.Priority priority) { - if (Bukkit.isPrimaryThread()) { - run.run(); - return; - } - level.getServer().execute(run); - } - - public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final boolean gen, - final ChunkStatus toStatus, final boolean addTicket, final PrioritisedExecutor.Priority priority, - final Consumer onComplete) { - scheduleChunkTask(level, chunkX, chunkZ, () -> { - ChunkAccess chunk = null; - try { - chunk = level.getChunk(chunkX, chunkZ); - } catch (Throwable ignored) { - } - onComplete.accept(chunk); - }, priority); - } - - public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus, - final boolean addTicket, final PrioritisedExecutor.Priority priority, final Consumer onComplete) { - scheduleChunkLoad(level, chunkX, chunkZ, true, toStatus, addTicket, priority, onComplete); - } - - public static void scheduleTickingState(final ServerLevel level, final int chunkX, final int chunkZ, - final FullChunkStatus toStatus, final boolean addTicket, - final PrioritisedExecutor.Priority priority, final Consumer onComplete) { - scheduleChunkTask(level, chunkX, chunkZ, () -> { - LevelChunk chunk = null; - try { - chunk = level.getChunk(chunkX, chunkZ); - } catch (Throwable ignored) { - } - onComplete.accept(chunk); - }, priority); - } - - public static List getVisibleChunkHolders(final ServerLevel level) { - return Collections.emptyList(); - } - - public static List getUpdatingChunkHolders(final ServerLevel level) { - return Collections.emptyList(); - } - - public static int getVisibleChunkHolderCount(final ServerLevel level) { - return 0; - } - - public static int getUpdatingChunkHolderCount(final ServerLevel level) { - return 0; - } - - public static boolean hasAnyChunkHolders(final ServerLevel level) { - return false; - } - - public static void onEntityPreAdd(final ServerLevel level, final Entity entity) { - } - - public static void onChunkHolderCreate(final ServerLevel level, final ChunkHolder holder) { - } - - public static void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder) { - } - - public static void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) { - } - - public static void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder) { - } - - public static void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder) { - } - - public static void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) { - } - - public static void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { - } - - public static void onChunkNotEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { - } - - public static ChunkHolder getUnloadingChunkHolder(final ServerLevel level, final int chunkX, final int chunkZ) { - return null; - } - - public static int getSendViewDistance(final ServerPlayer player) { - return getLoadViewDistance(player); - } - - public static int getLoadViewDistance(final ServerPlayer player) { - return Bukkit.getViewDistance() + 1; - } - - public static int getTickViewDistance(final ServerPlayer player) { - return Bukkit.getSimulationDistance(); - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/configuration/Configuration.java b/arclight-common/src/main/java/io/papermc/paper/configuration/Configuration.java deleted file mode 100644 index 3e8c7f343..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/configuration/Configuration.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.papermc.paper.configuration; - -/** - * marker class for Paper detection used by compatibility libraries - */ -public final class Configuration { - - private Configuration() { - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/entity/LookAnchor.java b/arclight-common/src/main/java/io/papermc/paper/entity/LookAnchor.java deleted file mode 100644 index 441e78044..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/entity/LookAnchor.java +++ /dev/null @@ -1,9 +0,0 @@ -package io.papermc.paper.entity; - -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Experimental -public enum LookAnchor { - FEET, - EYES -} diff --git a/arclight-common/src/main/java/io/papermc/paper/entity/TeleportFlag.java b/arclight-common/src/main/java/io/papermc/paper/entity/TeleportFlag.java deleted file mode 100644 index 5a7b998e3..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/entity/TeleportFlag.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.papermc.paper.entity; - -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Experimental -public sealed interface TeleportFlag permits TeleportFlag.EntityState, TeleportFlag.Relative { - - @ApiStatus.Experimental - enum Relative implements TeleportFlag { - X, - Y, - Z, - YAW, - PITCH - } - - @ApiStatus.Experimental - enum EntityState implements TeleportFlag { - RETAIN_PASSENGERS, - RETAIN_VEHICLE, - RETAIN_OPEN_INVENTORY - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/event/player/AbstractChatEvent.java b/arclight-common/src/main/java/io/papermc/paper/event/player/AbstractChatEvent.java deleted file mode 100644 index 3b11c6e6a..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/event/player/AbstractChatEvent.java +++ /dev/null @@ -1,77 +0,0 @@ -package io.papermc.paper.event.player; - -import io.papermc.paper.chat.ChatRenderer; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.chat.SignedMessage; -import net.kyori.adventure.text.Component; -import org.bukkit.entity.Player; -import org.bukkit.event.Cancellable; -import org.bukkit.event.player.PlayerEvent; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -import java.util.Set; - -import static java.util.Objects.requireNonNull; - -@ApiStatus.NonExtendable -public abstract class AbstractChatEvent extends PlayerEvent implements Cancellable { - private final Set viewers; - private final Component originalMessage; - private final SignedMessage signedMessage; - private ChatRenderer renderer; - private Component message; - private boolean cancelled = false; - - AbstractChatEvent(final boolean async, final @NotNull Player player, final @NotNull Set viewers, final @NotNull ChatRenderer renderer, final @NotNull Component message, final @NotNull Component originalMessage, final @NotNull SignedMessage signedMessage) { - super(player); - this.viewers = viewers; - this.renderer = renderer; - this.message = message; - this.originalMessage = originalMessage; - this.signedMessage = signedMessage; - } - - @NotNull - public final Set viewers() { - return this.viewers; - } - - public final void renderer(final @NotNull ChatRenderer renderer) { - this.renderer = requireNonNull(renderer, "renderer"); - } - - @NotNull - public final ChatRenderer renderer() { - return this.renderer; - } - - @NotNull - public final Component message() { - return this.message; - } - - public final void message(final @NotNull Component message) { - this.message = requireNonNull(message, "message"); - } - - @NotNull - public final Component originalMessage() { - return this.originalMessage; - } - - @NotNull - public final SignedMessage signedMessage() { - return this.signedMessage; - } - - @Override - public final boolean isCancelled() { - return this.cancelled; - } - - @Override - public final void setCancelled(final boolean cancelled) { - this.cancelled = cancelled; - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/event/player/AsyncChatCommandDecorateEvent.java b/arclight-common/src/main/java/io/papermc/paper/event/player/AsyncChatCommandDecorateEvent.java deleted file mode 100644 index 9fbd60f25..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/event/player/AsyncChatCommandDecorateEvent.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.papermc.paper.event.player; - -import net.kyori.adventure.text.Component; -import org.bukkit.entity.Player; -import org.bukkit.event.HandlerList; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -@ApiStatus.Experimental -public class AsyncChatCommandDecorateEvent extends AsyncChatDecorateEvent { - - private static final HandlerList HANDLER_LIST = new HandlerList(); - - @ApiStatus.Internal - public AsyncChatCommandDecorateEvent(boolean async, @Nullable Player player, @NotNull Component originalMessage, @NotNull Component result) { - super(async, player, originalMessage, result); - } - - public static @NotNull HandlerList getHandlerList() { - return HANDLER_LIST; - } - - @Override - public @NotNull HandlerList getHandlers() { - return HANDLER_LIST; - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/event/player/AsyncChatDecorateEvent.java b/arclight-common/src/main/java/io/papermc/paper/event/player/AsyncChatDecorateEvent.java deleted file mode 100644 index 665f5883b..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/event/player/AsyncChatDecorateEvent.java +++ /dev/null @@ -1,79 +0,0 @@ -package io.papermc.paper.event.player; - -import net.kyori.adventure.text.Component; -import org.bukkit.entity.Player; -import org.bukkit.event.Cancellable; -import org.bukkit.event.HandlerList; -import org.bukkit.event.server.ServerEvent; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -// Event for decorating chat components before chat events -@ApiStatus.Experimental -public class AsyncChatDecorateEvent extends ServerEvent implements Cancellable { - - private static final HandlerList HANDLER_LIST = new HandlerList(); - - private final Player player; - private final Component originalMessage; - private Component result; - private boolean cancelled; - - @ApiStatus.Internal - public AsyncChatDecorateEvent(final boolean async, final @Nullable Player player, final @NotNull Component originalMessage, final @NotNull Component result) { - super(async); - this.player = player; - this.originalMessage = originalMessage; - this.result = result; - } - - public static @NotNull HandlerList getHandlerList() { - return HANDLER_LIST; - } - - // Get player (may be null for commands) - public @Nullable Player player() { - return this.player; - } - - // Get original message - public @NotNull Component originalMessage() { - return this.originalMessage; - } - - // Get decoration result - public @NotNull Component result() { - return this.result; - } - - // Set decoration result - public void result(@NotNull Component result) { - this.result = result; - } - - // Check if part of preview (deprecated) - @Deprecated(forRemoval = true) - @ApiStatus.ScheduledForRemoval(inVersion = "1.21") - @Contract(value = "-> false", pure = true) - public boolean isPreview() { - return false; - } - - @Override - public boolean isCancelled() { - return this.cancelled; - } - - // Cancel decoration (result equals original) - @Override - public void setCancelled(boolean cancel) { - this.cancelled = cancel; - } - - @Override - public @NotNull HandlerList getHandlers() { - return HANDLER_LIST; - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java b/arclight-common/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java deleted file mode 100644 index ba92f19ee..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/event/player/AsyncChatEvent.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.papermc.paper.event.player; - -import io.papermc.paper.chat.ChatRenderer; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.chat.SignedMessage; -import net.kyori.adventure.text.Component; -import org.bukkit.entity.Player; -import org.bukkit.event.HandlerList; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -import java.util.Set; - -// Event fired when player sends chat message -public final class AsyncChatEvent extends AbstractChatEvent { - private static final HandlerList HANDLERS = new HandlerList(); - - - @ApiStatus.Internal - public AsyncChatEvent(final boolean async, final @NotNull Player player, final @NotNull Set viewers, final @NotNull ChatRenderer renderer, final @NotNull Component message, final @NotNull Component originalMessage, final @NotNull SignedMessage signedMessage) { - super(async, player, viewers, renderer, message, originalMessage, signedMessage); - } - - @NotNull - public static HandlerList getHandlerList() { - return HANDLERS; - } - - @NotNull - @Override - public HandlerList getHandlers() { - return HANDLERS; - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/event/player/ChatEvent.java b/arclight-common/src/main/java/io/papermc/paper/event/player/ChatEvent.java deleted file mode 100644 index a98e65909..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/event/player/ChatEvent.java +++ /dev/null @@ -1,37 +0,0 @@ -package io.papermc.paper.event.player; - -import io.papermc.paper.chat.ChatRenderer; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.chat.SignedMessage; -import net.kyori.adventure.text.Component; -import org.bukkit.Warning; -import org.bukkit.entity.Player; -import org.bukkit.event.HandlerList; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; - -import java.util.Set; - -// Sync chat event - use AsyncChatEvent instead -@Deprecated -@Warning(reason = "Listening to this event forces chat to wait for the main thread, delaying chat messages.") -public final class ChatEvent extends AbstractChatEvent { - private static final HandlerList HANDLERS = new HandlerList(); - - - @ApiStatus.Internal - public ChatEvent(final @NotNull Player player, final @NotNull Set viewers, final @NotNull ChatRenderer renderer, final @NotNull Component message, final @NotNull Component originalMessage, final @NotNull SignedMessage signedMessage) { - super(false, player, viewers, renderer, message, originalMessage, signedMessage); - } - - @NotNull - public static HandlerList getHandlerList() { - return HANDLERS; - } - - @NotNull - @Override - public HandlerList getHandlers() { - return HANDLERS; - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/math/BlockPosition.java b/arclight-common/src/main/java/io/papermc/paper/math/BlockPosition.java deleted file mode 100644 index e154ea8fb..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/math/BlockPosition.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.papermc.paper.math; - -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Experimental -public interface BlockPosition extends Position { - - @Override - int blockX(); - - @Override - int blockY(); - - @Override - int blockZ(); -} diff --git a/arclight-common/src/main/java/io/papermc/paper/math/FinePosition.java b/arclight-common/src/main/java/io/papermc/paper/math/FinePosition.java deleted file mode 100644 index a515f7019..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/math/FinePosition.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.papermc.paper.math; - -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Experimental -public interface FinePosition extends Position { -} diff --git a/arclight-common/src/main/java/io/papermc/paper/math/Position.java b/arclight-common/src/main/java/io/papermc/paper/math/Position.java deleted file mode 100644 index 0ed83301a..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/math/Position.java +++ /dev/null @@ -1,53 +0,0 @@ -package io.papermc.paper.math; - -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Experimental -public interface Position { - - static FinePosition fine(final double x, final double y, final double z) { - return new FinePositionImpl(x, y, z); - } - - static BlockPosition block(final int x, final int y, final int z) { - return new BlockPositionImpl(x, y, z); - } - - double x(); - - double y(); - - double z(); - - default int blockX() { - return (int) Math.floor(this.x()); - } - - default int blockY() { - return (int) Math.floor(this.y()); - } - - default int blockZ() { - return (int) Math.floor(this.z()); - } - - record FinePositionImpl(double x, double y, double z) implements FinePosition { - } - - record BlockPositionImpl(int blockX, int blockY, int blockZ) implements BlockPosition { - @Override - public double x() { - return this.blockX; - } - - @Override - public double y() { - return this.blockY; - } - - @Override - public double z() { - return this.blockZ; - } - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/text/MiniMessageHelper.java b/arclight-common/src/main/java/io/papermc/paper/text/MiniMessageHelper.java deleted file mode 100644 index 39b01dc73..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/text/MiniMessageHelper.java +++ /dev/null @@ -1,74 +0,0 @@ -package io.papermc.paper.text; - -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.minimessage.MiniMessage; -import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; -import net.kyori.adventure.text.minimessage.tag.standard.StandardTags; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -// Helper class for MiniMessage operations -public final class MiniMessageHelper { - - private static final MiniMessage MINI_MESSAGE = MiniMessage.builder().build(); - private static final MiniMessage STRICT_MINI_MESSAGE = MiniMessage.builder() - .tags(TagResolver.resolver( - StandardTags.color(), - StandardTags.decorations(), - StandardTags.reset() - )) - .build(); - - private MiniMessageHelper() { - throw new RuntimeException("MiniMessageHelper is not to be instantiated!"); - } - - // Parse MiniMessage string to Component - public static @NotNull Component parse(@NotNull String miniMessage) { - return MINI_MESSAGE.deserialize(miniMessage); - } - - // Parse MiniMessage string to Component with custom tag resolvers - public static @NotNull Component parse(@NotNull String miniMessage, @NotNull TagResolver... resolvers) { - return MINI_MESSAGE.deserialize(miniMessage, resolvers); - } - - // Parse MiniMessage string to Component with strict tags (only basic formatting) - public static @NotNull Component parseStrict(@NotNull String miniMessage) { - return STRICT_MINI_MESSAGE.deserialize(miniMessage); - } - - // Serialize Component to MiniMessage string - public static @NotNull String serialize(@NotNull Component component) { - return MINI_MESSAGE.serialize(component); - } - - // Check if string contains MiniMessage tags - public static boolean containsTags(@Nullable String input) { - if (input == null || input.isEmpty()) { - return false; - } - return input.contains("<") && input.contains(">"); - } - - // Strip MiniMessage tags from string (convert to plain text) - public static @NotNull String stripTags(@NotNull String miniMessage) { - try { - Component component = MINI_MESSAGE.deserialize(miniMessage); - return PaperComponents.plainTextSerializer().serialize(component); - } catch (Exception e) { - // If parsing fails, return original string - return miniMessage; - } - } - - // Get default MiniMessage instance - public static @NotNull MiniMessage miniMessage() { - return MINI_MESSAGE; - } - - // Get strict MiniMessage instance (limited tags) - public static @NotNull MiniMessage strictMiniMessage() { - return STRICT_MINI_MESSAGE; - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/text/PaperComponents.java b/arclight-common/src/main/java/io/papermc/paper/text/PaperComponents.java deleted file mode 100644 index 13e45f486..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/text/PaperComponents.java +++ /dev/null @@ -1,73 +0,0 @@ -package io.papermc.paper.text; - -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.flattener.ComponentFlattener; -import net.kyori.adventure.text.minimessage.MiniMessage; -import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer; -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Entity; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.IOException; - -// Paper API methods for working with Components -public final class PaperComponents { - private PaperComponents() { - throw new RuntimeException("PaperComponents is not to be instantiated!"); - } - - // Resolve component with context - public static @NotNull Component resolveWithContext(@NotNull Component input, @Nullable CommandSender context, @Nullable Entity scoreboardSubject) throws IOException { - return resolveWithContext(input, context, scoreboardSubject, true); - } - - // Resolve component with context and permissions - public static @NotNull Component resolveWithContext(@NotNull Component input, @Nullable CommandSender context, @Nullable Entity scoreboardSubject, boolean bypassPermissions) throws IOException { - // TODO: Implement proper context resolution - return input; - } - - // Get component flattener - public static @NotNull ComponentFlattener flattener() { - return ComponentFlattener.basic(); - } - - // Get plain text serializer - @Deprecated(forRemoval = true) - public static @NotNull PlainComponentSerializer plainSerializer() { - return PlainComponentSerializer.plain(); - } - - // Get plain text serializer - @Deprecated(forRemoval = true) - public static @NotNull PlainTextComponentSerializer plainTextSerializer() { - return PlainTextComponentSerializer.plainText(); - } - - // Get GSON serializer - @Deprecated(forRemoval = true) - public static @NotNull GsonComponentSerializer gsonSerializer() { - return GsonComponentSerializer.gson(); - } - - // Get color downsampling GSON serializer - @Deprecated(forRemoval = true) - public static @NotNull GsonComponentSerializer colorDownsamplingGsonSerializer() { - return GsonComponentSerializer.colorDownsamplingGson(); - } - - // Get legacy section serializer - @Deprecated(forRemoval = true) - public static @NotNull LegacyComponentSerializer legacySectionSerializer() { - return LegacyComponentSerializer.legacySection(); - } - - // Get MiniMessage serializer - public static @NotNull MiniMessage miniMessage() { - return MiniMessage.builder().build(); - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/util/CachedLists.java b/arclight-common/src/main/java/io/papermc/paper/util/CachedLists.java deleted file mode 100644 index be668387f..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/util/CachedLists.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.papermc.paper.util; - -public final class CachedLists { - - public static void reset() { - - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/util/CoordinateUtils.java b/arclight-common/src/main/java/io/papermc/paper/util/CoordinateUtils.java deleted file mode 100644 index 5098c2293..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/util/CoordinateUtils.java +++ /dev/null @@ -1,127 +0,0 @@ -package io.papermc.paper.util; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.SectionPos; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; - -public final class CoordinateUtils { - - static final int SECTION_X_BITS = 22; - - // the chunk keys are compatible with vanilla - static final long SECTION_X_MASK = (1L << SECTION_X_BITS) - 1; - static final int SECTION_Y_BITS = 20; - static final long SECTION_Y_MASK = (1L << SECTION_Y_BITS) - 1; - static final int SECTION_Z_BITS = 22; - static final long SECTION_Z_MASK = (1L << SECTION_Z_BITS) - 1; - // format is y,z,x (in order of LSB to MSB) - static final int SECTION_Y_SHIFT = 0; - static final int SECTION_Z_SHIFT = SECTION_Y_SHIFT + SECTION_Y_BITS; - static final int SECTION_X_SHIFT = SECTION_Z_SHIFT + SECTION_X_BITS; - - // the section keys are compatible with vanilla's - static final int SECTION_TO_BLOCK_SHIFT = 4; - private CoordinateUtils() { - throw new RuntimeException(); - } - - // dx, dz are relative to the target chunk - // dx, dz in [-radius, radius] - public static int getNeighbourMappedIndex(final int dx, final int dz, final int radius) { - return (dx + radius) + (2 * radius + 1) * (dz + radius); - } - - public static long getChunkKey(final BlockPos pos) { - return ((long) (pos.getZ() >> 4) << 32) | ((pos.getX() >> 4) & 0xFFFFFFFFL); - } - - public static long getChunkKey(final Entity entity) { - return ((Mth.lfloor(entity.getZ()) >> 4) << 32) | ((Mth.lfloor(entity.getX()) >> 4) & 0xFFFFFFFFL); - } - - public static long getChunkKey(final ChunkPos pos) { - return ((long) pos.z << 32) | (pos.x & 0xFFFFFFFFL); - } - - public static long getChunkKey(final SectionPos pos) { - return ((long) pos.getZ() << 32) | (pos.getX() & 0xFFFFFFFFL); - } - - public static long getChunkKey(final int x, final int z) { - return ((long) z << 32) | (x & 0xFFFFFFFFL); - } - - public static int getChunkX(final long chunkKey) { - return (int) chunkKey; - } - - public static int getChunkZ(final long chunkKey) { - return (int) (chunkKey >>> 32); - } - - public static int getChunkCoordinate(final double blockCoordinate) { - return Mth.floor(blockCoordinate) >> 4; - } - - public static long getChunkSectionKey(final int x, final int y, final int z) { - return ((x & SECTION_X_MASK) << SECTION_X_SHIFT) - | ((y & SECTION_Y_MASK) << SECTION_Y_SHIFT) - | ((z & SECTION_Z_MASK) << SECTION_Z_SHIFT); - } - - public static long getChunkSectionKey(final SectionPos pos) { - return ((pos.getX() & SECTION_X_MASK) << SECTION_X_SHIFT) - | ((pos.getY() & SECTION_Y_MASK) << SECTION_Y_SHIFT) - | ((pos.getZ() & SECTION_Z_MASK) << SECTION_Z_SHIFT); - } - - public static long getChunkSectionKey(final ChunkPos pos, final int y) { - return ((pos.x & SECTION_X_MASK) << SECTION_X_SHIFT) - | ((y & SECTION_Y_MASK) << SECTION_Y_SHIFT) - | ((pos.z & SECTION_Z_MASK) << SECTION_Z_SHIFT); - } - - public static long getChunkSectionKey(final BlockPos pos) { - return (((long) pos.getX() << (SECTION_X_SHIFT - SECTION_TO_BLOCK_SHIFT)) & (SECTION_X_MASK << SECTION_X_SHIFT)) | - ((pos.getY() >> SECTION_TO_BLOCK_SHIFT) & (SECTION_Y_MASK << SECTION_Y_SHIFT)) | - (((long) pos.getZ() << (SECTION_Z_SHIFT - SECTION_TO_BLOCK_SHIFT)) & (SECTION_Z_MASK << SECTION_Z_SHIFT)); - } - - public static long getChunkSectionKey(final Entity entity) { - return ((Mth.lfloor(entity.getX()) << (SECTION_X_SHIFT - SECTION_TO_BLOCK_SHIFT)) & (SECTION_X_MASK << SECTION_X_SHIFT)) | - ((Mth.lfloor(entity.getY()) >> SECTION_TO_BLOCK_SHIFT) & (SECTION_Y_MASK << SECTION_Y_SHIFT)) | - ((Mth.lfloor(entity.getZ()) << (SECTION_Z_SHIFT - SECTION_TO_BLOCK_SHIFT)) & (SECTION_Z_MASK << SECTION_Z_SHIFT)); - } - - public static int getChunkSectionX(final long key) { - return (int) (key << (Long.SIZE - (SECTION_X_SHIFT + SECTION_X_BITS)) >> (Long.SIZE - SECTION_X_BITS)); - } - - public static int getChunkSectionY(final long key) { - return (int) (key << (Long.SIZE - (SECTION_Y_SHIFT + SECTION_Y_BITS)) >> (Long.SIZE - SECTION_Y_BITS)); - } - - // the block coordinates are not necessarily compatible with vanilla's - - public static int getChunkSectionZ(final long key) { - return (int) (key << (Long.SIZE - (SECTION_Z_SHIFT + SECTION_Z_BITS)) >> (Long.SIZE - SECTION_Z_BITS)); - } - - public static int getBlockCoordinate(final double blockCoordinate) { - return Mth.floor(blockCoordinate); - } - - public static long getBlockKey(final int x, final int y, final int z) { - return ((long) x & 0x7FFFFFF) | (((long) z & 0x7FFFFFF) << 27) | ((long) y << 54); - } - - public static long getBlockKey(final BlockPos pos) { - return ((long) pos.getX() & 0x7FFFFFF) | (((long) pos.getZ() & 0x7FFFFFF) << 27) | ((long) pos.getY() << 54); - } - - public static long getBlockKey(final Entity entity) { - return ((long) entity.getX() & 0x7FFFFFF) | (((long) entity.getZ() & 0x7FFFFFF) << 27) | ((long) entity.getY() << 54); - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/util/IntegerUtil.java b/arclight-common/src/main/java/io/papermc/paper/util/IntegerUtil.java deleted file mode 100644 index f603f58db..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/util/IntegerUtil.java +++ /dev/null @@ -1,242 +0,0 @@ -package io.papermc.paper.util; - -public final class IntegerUtil { - - public static final int HIGH_BIT_U32 = Integer.MIN_VALUE; - public static final long HIGH_BIT_U64 = Long.MIN_VALUE; - - private IntegerUtil() { - throw new RuntimeException(); - } - - public static int ceilLog2(final int value) { - return Integer.SIZE - Integer.numberOfLeadingZeros(value - 1); // see doc of numberOfLeadingZeros - } - - public static long ceilLog2(final long value) { - return Long.SIZE - Long.numberOfLeadingZeros(value - 1); // see doc of numberOfLeadingZeros - } - - public static int floorLog2(final int value) { - // xor is optimized subtract for 2^n -1 - // note that (2^n -1) - k = (2^n -1) ^ k for k <= (2^n - 1) - return (Integer.SIZE - 1) ^ Integer.numberOfLeadingZeros(value); // see doc of numberOfLeadingZeros - } - - public static int floorLog2(final long value) { - // xor is optimized subtract for 2^n -1 - // note that (2^n -1) - k = (2^n -1) ^ k for k <= (2^n - 1) - return (Long.SIZE - 1) ^ Long.numberOfLeadingZeros(value); // see doc of numberOfLeadingZeros - } - - public static int roundCeilLog2(final int value) { - // optimized variant of 1 << (32 - leading(val - 1)) - // given - // 1 << n = HIGH_BIT_32 >>> (31 - n) for n [0, 32) - // 1 << (32 - leading(val - 1)) = HIGH_BIT_32 >>> (31 - (32 - leading(val - 1))) - // HIGH_BIT_32 >>> (31 - (32 - leading(val - 1))) - // HIGH_BIT_32 >>> (31 - 32 + leading(val - 1)) - // HIGH_BIT_32 >>> (-1 + leading(val - 1)) - return HIGH_BIT_U32 >>> (Integer.numberOfLeadingZeros(value - 1) - 1); - } - - public static long roundCeilLog2(final long value) { - // see logic documented above - return HIGH_BIT_U64 >>> (Long.numberOfLeadingZeros(value - 1) - 1); - } - - public static int roundFloorLog2(final int value) { - // optimized variant of 1 << (31 - leading(val)) - // given - // 1 << n = HIGH_BIT_32 >>> (31 - n) for n [0, 32) - // 1 << (31 - leading(val)) = HIGH_BIT_32 >> (31 - (31 - leading(val))) - // HIGH_BIT_32 >> (31 - (31 - leading(val))) - // HIGH_BIT_32 >> (31 - 31 + leading(val)) - return HIGH_BIT_U32 >>> Integer.numberOfLeadingZeros(value); - } - - public static long roundFloorLog2(final long value) { - // see logic documented above - return HIGH_BIT_U64 >>> Long.numberOfLeadingZeros(value); - } - - public static boolean isPowerOfTwo(final int n) { - // 2^n has one bit - // note: this rets true for 0 still - return IntegerUtil.getTrailingBit(n) == n; - } - - public static boolean isPowerOfTwo(final long n) { - // 2^n has one bit - // note: this rets true for 0 still - return IntegerUtil.getTrailingBit(n) == n; - } - - public static int getTrailingBit(final int n) { - return -n & n; - } - - public static long getTrailingBit(final long n) { - return -n & n; - } - - public static int trailingZeros(final int n) { - return Integer.numberOfTrailingZeros(n); - } - - public static int trailingZeros(final long n) { - return Long.numberOfTrailingZeros(n); - } - - // from hacker's delight (signed division magic value) - public static int getDivisorMultiple(final long numbers) { - return (int) (numbers >>> 32); - } - - // from hacker's delight (signed division magic value) - public static int getDivisorShift(final long numbers) { - return (int) numbers; - } - - // copied from hacker's delight (signed division magic value) - // http://www.hackersdelight.org/hdcodetxt/magic.c.txt - public static long getDivisorNumbers(final int d) { - final int ad = branchlessAbs(d); - - if (ad < 2) { - throw new IllegalArgumentException("|number| must be in [2, 2^31 -1], not: " + d); - } - - final int two31 = 0x80000000; - final long mask = 0xFFFFFFFFL; // mask for enforcing unsigned behaviour - - /* - Signed usage: - int number; - long magic = getDivisorNumbers(div); - long mul = magic >>> 32; - int sign = number >> 31; - int result = (int)(((long)number * mul) >>> magic) - sign; - */ - /* - Unsigned usage: - int number; - long magic = getDivisorNumbers(div); - long mul = magic >>> 32; - int result = (int)(((long)number * mul) >>> magic); - */ - - int p = 31; - - // all these variables are UNSIGNED! - int t = two31 + (d >>> 31); - int anc = t - 1 - (int) ((t & mask) % ad); - int q1 = (int) ((two31 & mask) / (anc & mask)); - int r1 = two31 - q1 * anc; - int q2 = (int) ((two31 & mask) / (ad & mask)); - int r2 = two31 - q2 * ad; - int delta; - - do { - p = p + 1; - q1 = 2 * q1; // Update q1 = 2**p/|nc|. - r1 = 2 * r1; // Update r1 = rem(2**p, |nc|). - if ((r1 & mask) >= (anc & mask)) {// (Must be an unsigned comparison here) - q1 = q1 + 1; - r1 = r1 - anc; - } - q2 = 2 * q2; // Update q2 = 2**p/|d|. - r2 = 2 * r2; // Update r2 = rem(2**p, |d|). - if ((r2 & mask) >= (ad & mask)) {// (Must be an unsigned comparison here) - q2 = q2 + 1; - r2 = r2 - ad; - } - delta = ad - r2; - } while ((q1 & mask) < (delta & mask) || (q1 == delta && r1 == 0)); - - int magicNum = q2 + 1; - if (d < 0) { - magicNum = -magicNum; - } - int shift = p; - return ((long) magicNum << 32) | shift; - } - - public static int branchlessAbs(final int val) { - // -n = -1 ^ n + 1 - final int mask = val >> (Integer.SIZE - 1); // -1 if < 0, 0 if >= 0 - return (mask ^ val) - mask; // if val < 0, then (0 ^ val) - 0 else (-1 ^ val) + 1 - } - - //https://github.com/skeeto/hash-prospector for hash functions - - public static long branchlessAbs(final long val) { - // -n = -1 ^ n + 1 - final long mask = val >> (Long.SIZE - 1); // -1 if < 0, 0 if >= 0 - return (mask ^ val) - mask; // if val < 0, then (0 ^ val) - 0 else (-1 ^ val) + 1 - } - - //score = ~590.47984224483832 - public static int hash0(int x) { - x *= 0x36935555; - x ^= x >>> 16; - return x; - } - - //score = ~310.01596637036749 - public static int hash1(int x) { - x ^= x >>> 15; - x *= 0x356aaaad; - x ^= x >>> 17; - return x; - } - - public static int hash2(int x) { - x ^= x >>> 16; - x *= 0x7feb352d; - x ^= x >>> 15; - x *= 0x846ca68b; - x ^= x >>> 16; - return x; - } - - public static int hash3(int x) { - x ^= x >>> 17; - x *= 0xed5ad4bb; - x ^= x >>> 11; - x *= 0xac4c1b51; - x ^= x >>> 15; - x *= 0x31848bab; - x ^= x >>> 14; - return x; - } - - //score = ~365.79959673201887 - public static long hash1(long x) { - x ^= x >>> 27; - x *= 0xb24924b71d2d354bL; - x ^= x >>> 28; - return x; - } - - //h2 hash - public static long hash2(long x) { - x ^= x >>> 32; - x *= 0xd6e8feb86659fd93L; - x ^= x >>> 32; - x *= 0xd6e8feb86659fd93L; - x ^= x >>> 32; - return x; - } - - public static long hash3(long x) { - x ^= x >>> 45; - x *= 0xc161abe5704b6c79L; - x ^= x >>> 41; - x *= 0xe3e5389aedbc90f7L; - x ^= x >>> 56; - x *= 0x1f9aba75a52db073L; - x ^= x >>> 53; - return x; - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/util/IntervalledCounter.java b/arclight-common/src/main/java/io/papermc/paper/util/IntervalledCounter.java deleted file mode 100644 index 2961e38ca..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/util/IntervalledCounter.java +++ /dev/null @@ -1,115 +0,0 @@ -package io.papermc.paper.util; - -public final class IntervalledCounter { - - private final long interval; - private long[] times; - private long[] counts; - private long minTime; - private long sum; - private int head; // inclusive - private int tail; // exclusive - - public IntervalledCounter(final long interval) { - this.times = new long[8]; - this.counts = new long[8]; - this.interval = interval; - } - - public void updateCurrentTime() { - this.updateCurrentTime(System.nanoTime()); - } - - public void updateCurrentTime(final long currentTime) { - long sum = this.sum; - int head = this.head; - final int tail = this.tail; - final long minTime = currentTime - this.interval; - - final int arrayLen = this.times.length; - - // guard against overflow by using subtraction - while (head != tail && this.times[head] - minTime < 0) { - sum -= this.counts[head]; - // there are two ways we can do this: - // 1. free the count when adding - // 2. free it now - // option #2 - this.counts[head] = 0; - if (++head >= arrayLen) { - head = 0; - } - } - - this.sum = sum; - this.head = head; - this.minTime = minTime; - } - - public void addTime(final long currTime) { - this.addTime(currTime, 1L); - } - - public void addTime(final long currTime, final long count) { - // guard against overflow by using subtraction - if (currTime - this.minTime < 0) { - return; - } - int nextTail = (this.tail + 1) % this.times.length; - if (nextTail == this.head) { - this.resize(); - nextTail = (this.tail + 1) % this.times.length; - } - - this.times[this.tail] = currTime; - this.counts[this.tail] += count; - this.sum += count; - this.tail = nextTail; - } - - public void updateAndAdd(final int count) { - final long currTime = System.nanoTime(); - this.updateCurrentTime(currTime); - this.addTime(currTime, count); - } - - public void updateAndAdd(final int count, final long currTime) { - this.updateCurrentTime(currTime); - this.addTime(currTime, count); - } - - private void resize() { - final long[] oldElements = this.times; - final long[] oldCounts = this.counts; - final long[] newElements = new long[this.times.length * 2]; - final long[] newCounts = new long[this.times.length * 2]; - this.times = newElements; - this.counts = newCounts; - - final int head = this.head; - final int tail = this.tail; - final int size = tail >= head ? (tail - head) : (tail + (oldElements.length - head)); - this.head = 0; - this.tail = size; - - if (tail >= head) { - System.arraycopy(oldElements, head, newElements, 0, size); - System.arraycopy(oldCounts, head, newCounts, 0, size); - } else { - System.arraycopy(oldElements, head, newElements, 0, oldElements.length - head); - System.arraycopy(oldElements, 0, newElements, oldElements.length - head, tail); - - System.arraycopy(oldCounts, head, newCounts, 0, oldCounts.length - head); - System.arraycopy(oldCounts, 0, newCounts, oldCounts.length - head, tail); - } - } - - // returns in units per second - public double getRate() { - return this.size() / (this.interval * 1.0e-9); - } - - public long size() { - return this.sum; - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/util/MCUtil.java b/arclight-common/src/main/java/io/papermc/paper/util/MCUtil.java deleted file mode 100644 index 0ddd150bf..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/util/MCUtil.java +++ /dev/null @@ -1,84 +0,0 @@ -package io.papermc.paper.util; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; - -import java.lang.ref.Cleaner; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Consumer; - -public final class MCUtil { - - private MCUtil() { - } - - public static Runnable once(Runnable run) { - AtomicBoolean ran = new AtomicBoolean(false); - return () -> { - if (ran.compareAndSet(false, true)) { - run.run(); - } - }; - } - - public static Runnable once(List list, Consumer cb) { - return once(() -> list.forEach(cb)); - } - - public static Runnable registerCleaner(Object obj, Runnable run) { - Runnable cleaner = once(run); - CleanerHolder.CLEANER.register(obj, cleaner); - return cleaner; - } - - public static Runnable registerListCleaner(Object obj, List list, Consumer cleaner) { - return registerCleaner(obj, () -> { - list.forEach(cleaner); - list.clear(); - }); - } - - public static Runnable registerCleaner(Object obj, T resource, Consumer cleaner) { - return registerCleaner(obj, () -> cleaner.accept(resource)); - } - - public static int fastFloor(double x) { - int truncated = (int) x; - return x < (double) truncated ? truncated - 1 : truncated; - } - - public static int fastFloor(float x) { - int truncated = (int) x; - return x < (double) truncated ? truncated - 1 : truncated; - } - - public static long getCoordinateKey(final BlockPos blockPos) { - return ((long) (blockPos.getZ() >> 4) << 32) | ((blockPos.getX() >> 4) & 0xFFFFFFFFL); - } - - public static long getCoordinateKey(final Entity entity) { - return ((long) (fastFloor(entity.getZ()) >> 4) << 32) | ((fastFloor(entity.getX()) >> 4) & 0xFFFFFFFFL); - } - - public static long getCoordinateKey(final ChunkPos pair) { - return ((long) pair.z << 32) | (pair.x & 0xFFFFFFFFL); - } - - public static long getCoordinateKey(final int x, final int z) { - return ((long) z << 32) | (x & 0xFFFFFFFFL); - } - - public static int getCoordinateX(final long key) { - return (int) key; - } - - public static int getCoordinateZ(final long key) { - return (int) (key >>> 32); - } - - private static final class CleanerHolder { - private static final Cleaner CLEANER = Cleaner.create(); - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/util/StackWalkerUtil.java b/arclight-common/src/main/java/io/papermc/paper/util/StackWalkerUtil.java deleted file mode 100644 index f9f681093..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/util/StackWalkerUtil.java +++ /dev/null @@ -1,41 +0,0 @@ -package io.papermc.paper.util; - -import org.bukkit.plugin.java.JavaPlugin; -import org.jetbrains.annotations.Nullable; - -import java.lang.reflect.Method; -import java.util.Optional; - -public class StackWalkerUtil { - - @Nullable - public static JavaPlugin getFirstPluginCaller() { - Optional foundFrame = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE) - .walk(stream -> stream - .map(frame -> resolvePlugin(frame.getDeclaringClass().getClassLoader())) - .filter(Optional::isPresent) - .map(Optional::get) - .findFirst()); - - return foundFrame.orElse(null); - } - - private static Optional resolvePlugin(ClassLoader classLoader) { - if (classLoader == null) { - return Optional.empty(); - } - if (!"org.bukkit.plugin.java.PluginClassLoader".equals(classLoader.getClass().getName())) { - return Optional.empty(); - } - try { - Method method = classLoader.getClass().getDeclaredMethod("getPlugin"); - method.setAccessible(true); - Object plugin = method.invoke(classLoader); - if (plugin instanceof JavaPlugin javaPlugin) { - return Optional.of(javaPlugin); - } - } catch (ReflectiveOperationException ignored) { - } - return Optional.empty(); - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/util/TransformingRandomAccessList.java b/arclight-common/src/main/java/io/papermc/paper/util/TransformingRandomAccessList.java deleted file mode 100644 index e496a6ea0..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/util/TransformingRandomAccessList.java +++ /dev/null @@ -1,157 +0,0 @@ -package io.papermc.paper.util; - -import org.jetbrains.annotations.NotNull; - -import java.util.*; -import java.util.function.Function; -import java.util.function.Predicate; - -/** - * A mutable transforming view backed by another list. - * - * @param backing element type - * @param transformed element type - */ -public final class TransformingRandomAccessList extends AbstractList implements RandomAccess { - - private final List fromList; - private final Function toFunction; - private final Function fromFunction; - - public TransformingRandomAccessList( - final @NotNull List fromList, - final @NotNull Function toFunction, - final @NotNull Function fromFunction - ) { - this.fromList = Objects.requireNonNull(fromList, "fromList"); - this.toFunction = Objects.requireNonNull(toFunction, "toFunction"); - this.fromFunction = Objects.requireNonNull(fromFunction, "fromFunction"); - } - - @Override - public void clear() { - this.fromList.clear(); - } - - @Override - public T get(int index) { - return this.toFunction.apply(this.fromList.get(index)); - } - - @Override - public @NotNull Iterator iterator() { - return this.listIterator(); - } - - @Override - public @NotNull ListIterator listIterator(int index) { - return new TransformedListIterator(this.fromList.listIterator(index)) { - @Override - T transform(F from) { - return TransformingRandomAccessList.this.toFunction.apply(from); - } - - @Override - F transformBack(T to) { - return TransformingRandomAccessList.this.fromFunction.apply(to); - } - }; - } - - @Override - public boolean isEmpty() { - return this.fromList.isEmpty(); - } - - @Override - public boolean removeIf(Predicate filter) { - Objects.requireNonNull(filter, "filter"); - return this.fromList.removeIf(element -> filter.test(this.toFunction.apply(element))); - } - - @Override - public T remove(int index) { - return this.toFunction.apply(this.fromList.remove(index)); - } - - @Override - public int size() { - return this.fromList.size(); - } - - @Override - public T set(int index, T element) { - return this.toFunction.apply(this.fromList.set(index, this.fromFunction.apply(element))); - } - - @Override - public void add(int index, T element) { - this.fromList.add(index, this.fromFunction.apply(element)); - } - - static abstract class TransformedListIterator implements ListIterator, Iterator { - final Iterator backingIterator; - - TransformedListIterator(ListIterator backingIterator) { - this.backingIterator = Objects.requireNonNull(backingIterator, "backingIterator"); - } - - @SuppressWarnings("unchecked") - static ListIterator cast(Iterator iterator) { - return (ListIterator) iterator; - } - - private ListIterator backingIterator() { - return cast(this.backingIterator); - } - - @Override - public final boolean hasPrevious() { - return this.backingIterator().hasPrevious(); - } - - @Override - public final T previous() { - return this.transform(this.backingIterator().previous()); - } - - @Override - public final int nextIndex() { - return this.backingIterator().nextIndex(); - } - - @Override - public final int previousIndex() { - return this.backingIterator().previousIndex(); - } - - @Override - public void set(T element) { - this.backingIterator().set(this.transformBack(element)); - } - - @Override - public void add(T element) { - this.backingIterator().add(this.transformBack(element)); - } - - abstract T transform(F from); - - abstract F transformBack(T to); - - @Override - public final boolean hasNext() { - return this.backingIterator.hasNext(); - } - - @Override - public final T next() { - return this.transform(this.backingIterator.next()); - } - - @Override - public final void remove() { - this.backingIterator.remove(); - } - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/util/WorldUtil.java b/arclight-common/src/main/java/io/papermc/paper/util/WorldUtil.java deleted file mode 100644 index 7729548b0..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/util/WorldUtil.java +++ /dev/null @@ -1,44 +0,0 @@ -package io.papermc.paper.util; - -import net.minecraft.world.level.LevelHeightAccessor; - -public final class WorldUtil { - - // min, max are inclusive - - private WorldUtil() { - throw new RuntimeException(); - } - - public static int getMaxSection(final LevelHeightAccessor world) { - return world.getMaxSection() - 1; // getMaxSection() is exclusive - } - - public static int getMinSection(final LevelHeightAccessor world) { - return world.getMinSection(); - } - - public static int getMaxLightSection(final LevelHeightAccessor world) { - return getMaxSection(world) + 1; - } - - public static int getMinLightSection(final LevelHeightAccessor world) { - return getMinSection(world) - 1; - } - - public static int getTotalSections(final LevelHeightAccessor world) { - return getMaxSection(world) - getMinSection(world) + 1; - } - - public static int getTotalLightSections(final LevelHeightAccessor world) { - return getMaxLightSection(world) - getMinLightSection(world) + 1; - } - - public static int getMinBlockY(final LevelHeightAccessor world) { - return getMinSection(world) << 4; - } - - public static int getMaxBlockY(final LevelHeightAccessor world) { - return (getMaxSection(world) << 4) | 15; - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/util/maplist/IteratorSafeOrderedReferenceSet.java b/arclight-common/src/main/java/io/papermc/paper/util/maplist/IteratorSafeOrderedReferenceSet.java deleted file mode 100644 index 891241b14..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/util/maplist/IteratorSafeOrderedReferenceSet.java +++ /dev/null @@ -1,333 +0,0 @@ -package io.papermc.paper.util.maplist; - -import it.unimi.dsi.fastutil.objects.Reference2IntLinkedOpenHashMap; -import it.unimi.dsi.fastutil.objects.Reference2IntMap; -import org.bukkit.Bukkit; - -import java.util.Arrays; -import java.util.NoSuchElementException; - -public final class IteratorSafeOrderedReferenceSet { - - public static final int ITERATOR_FLAG_SEE_ADDITIONS = 1 << 0; - - private final Reference2IntLinkedOpenHashMap indexMap; - private final double maxFragFactor; - private final boolean threadRestricted; - private int firstInvalidIndex = -1; - /* list impl */ - private E[] listElements; - private int listSize; - private int iteratorCount; - - public IteratorSafeOrderedReferenceSet() { - this(16, 0.75f, 16, 0.2); - } - - public IteratorSafeOrderedReferenceSet(final boolean threadRestricted) { - this(16, 0.75f, 16, 0.2, threadRestricted); - } - - public IteratorSafeOrderedReferenceSet(final int setCapacity, final float setLoadFactor, final int arrayCapacity, - final double maxFragFactor) { - this(setCapacity, setLoadFactor, arrayCapacity, maxFragFactor, false); - } - - public IteratorSafeOrderedReferenceSet(final int setCapacity, final float setLoadFactor, final int arrayCapacity, - final double maxFragFactor, final boolean threadRestricted) { - this.indexMap = new Reference2IntLinkedOpenHashMap<>(setCapacity, setLoadFactor); - this.indexMap.defaultReturnValue(-1); - this.maxFragFactor = maxFragFactor; - this.listElements = (E[]) new Object[arrayCapacity]; - this.threadRestricted = threadRestricted; - } - - /* - public void check() { - int iterated = 0; - ReferenceOpenHashSet check = new ReferenceOpenHashSet<>(); - if (this.listElements != null) { - for (int i = 0; i < this.listSize; ++i) { - Object obj = this.listElements[i]; - if (obj != null) { - iterated++; - if (!check.add((E)obj)) { - throw new IllegalStateException("contains duplicate"); - } - if (!this.contains((E)obj)) { - throw new IllegalStateException("desync"); - } - } - } - } - - if (iterated != this.size()) { - throw new IllegalStateException("Size is mismatched! Got " + iterated + ", expected " + this.size()); - } - - check.clear(); - iterated = 0; - for (final java.util.Iterator iterator = this.unsafeIterator(IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) { - final E element = iterator.next(); - iterated++; - if (!check.add(element)) { - throw new IllegalStateException("contains duplicate (iterator is wrong)"); - } - if (!this.contains(element)) { - throw new IllegalStateException("desync (iterator is wrong)"); - } - } - - if (iterated != this.size()) { - throw new IllegalStateException("Size is mismatched! (iterator is wrong) Got " + iterated + ", expected " + this.size()); - } - } - */ - - private boolean allowSafeIteration() { - return !this.threadRestricted || Bukkit.isPrimaryThread(); - } - - private double getFragFactor() { - return 1.0 - ((double) this.indexMap.size() / (double) this.listSize); - } - - public int createRawIterator() { - if (this.allowSafeIteration()) { - ++this.iteratorCount; - } - if (this.indexMap.isEmpty()) { - return -1; - } else { - return this.firstInvalidIndex == 0 ? this.indexMap.getInt(this.indexMap.firstKey()) : 0; - } - } - - public int advanceRawIterator(final int index) { - final E[] elements = this.listElements; - int ret = index + 1; - for (int len = this.listSize; ret < len; ++ret) { - if (elements[ret] != null) { - return ret; - } - } - - return -1; - } - - public void finishRawIterator() { - if (this.allowSafeIteration() && --this.iteratorCount == 0) { - if (this.getFragFactor() >= this.maxFragFactor) { - this.defrag(); - } - } - } - - public boolean remove(final E element) { - final int index = this.indexMap.removeInt(element); - if (index >= 0) { - if (this.firstInvalidIndex < 0 || index < this.firstInvalidIndex) { - this.firstInvalidIndex = index; - } - if (this.listElements[index] != element) { - throw new IllegalStateException(); - } - this.listElements[index] = null; - if (this.allowSafeIteration() && this.iteratorCount == 0 && this.getFragFactor() >= this.maxFragFactor) { - this.defrag(); - } - //this.check(); - return true; - } - return false; - } - - public boolean contains(final E element) { - return this.indexMap.containsKey(element); - } - - public boolean add(final E element) { - final int listSize = this.listSize; - - final int previous = this.indexMap.putIfAbsent(element, listSize); - if (previous != -1) { - return false; - } - - if (listSize >= this.listElements.length) { - this.listElements = Arrays.copyOf(this.listElements, listSize * 2); - } - this.listElements[listSize] = element; - this.listSize = listSize + 1; - - //this.check(); - return true; - } - - private void defrag() { - if (this.firstInvalidIndex < 0) { - return; // nothing to do - } - - if (this.indexMap.isEmpty()) { - Arrays.fill(this.listElements, 0, this.listSize, null); - this.listSize = 0; - this.firstInvalidIndex = -1; - //this.check(); - return; - } - - final E[] backingArray = this.listElements; - - int lastValidIndex; - java.util.Iterator> iterator; - - if (this.firstInvalidIndex == 0) { - iterator = this.indexMap.reference2IntEntrySet().fastIterator(); - lastValidIndex = 0; - } else { - lastValidIndex = this.firstInvalidIndex; - final E key = backingArray[lastValidIndex - 1]; - iterator = this.indexMap.reference2IntEntrySet().fastIterator(new Reference2IntMap.Entry() { - @Override - public int getIntValue() { - throw new UnsupportedOperationException(); - } - - @Override - public int setValue(int i) { - throw new UnsupportedOperationException(); - } - - @Override - public E getKey() { - return key; - } - }); - } - - while (iterator.hasNext()) { - final Reference2IntMap.Entry entry = iterator.next(); - - final int newIndex = lastValidIndex++; - backingArray[newIndex] = entry.getKey(); - entry.setValue(newIndex); - } - - // cleanup end - Arrays.fill(backingArray, lastValidIndex, this.listSize, null); - this.listSize = lastValidIndex; - this.firstInvalidIndex = -1; - //this.check(); - } - - public E rawGet(final int index) { - return this.listElements[index]; - } - - public int size() { - // always returns the correct amount - listSize can be different - return this.indexMap.size(); - } - - public IteratorSafeOrderedReferenceSet.Iterator iterator() { - return this.iterator(0); - } - - public IteratorSafeOrderedReferenceSet.Iterator iterator(final int flags) { - if (this.allowSafeIteration()) { - ++this.iteratorCount; - } - return new BaseIterator<>(this, true, (flags & ITERATOR_FLAG_SEE_ADDITIONS) != 0 ? Integer.MAX_VALUE : this.listSize); - } - - public java.util.Iterator unsafeIterator() { - return this.unsafeIterator(0); - } - - public java.util.Iterator unsafeIterator(final int flags) { - return new BaseIterator<>(this, false, (flags & ITERATOR_FLAG_SEE_ADDITIONS) != 0 ? Integer.MAX_VALUE : this.listSize); - } - - public interface Iterator extends java.util.Iterator { - - void finishedIterating(); - - } - - protected static final class BaseIterator implements IteratorSafeOrderedReferenceSet.Iterator { - - protected final IteratorSafeOrderedReferenceSet set; - protected final boolean canFinish; - protected final int maxIndex; - protected int nextIndex; - protected E pendingValue; - protected boolean finished; - protected E lastReturned; - - protected BaseIterator(final IteratorSafeOrderedReferenceSet set, final boolean canFinish, final int maxIndex) { - this.set = set; - this.canFinish = canFinish; - this.maxIndex = maxIndex; - } - - @Override - public boolean hasNext() { - if (this.finished) { - return false; - } - if (this.pendingValue != null) { - return true; - } - - final E[] elements = this.set.listElements; - int index, len; - for (index = this.nextIndex, len = Math.min(this.maxIndex, this.set.listSize); index < len; ++index) { - final E element = elements[index]; - if (element != null) { - this.pendingValue = element; - this.nextIndex = index + 1; - return true; - } - } - - this.nextIndex = index; - return false; - } - - @Override - public E next() { - if (!this.hasNext()) { - throw new NoSuchElementException(); - } - final E ret = this.pendingValue; - - this.pendingValue = null; - this.lastReturned = ret; - - return ret; - } - - @Override - public void remove() { - final E lastReturned = this.lastReturned; - if (lastReturned == null) { - throw new IllegalStateException(); - } - this.lastReturned = null; - this.set.remove(lastReturned); - } - - @Override - public void finishedIterating() { - if (this.finished || !this.canFinish) { - throw new IllegalStateException(); - } - this.lastReturned = null; - this.finished = true; - if (this.set.allowSafeIteration()) { - this.set.finishRawIterator(); - } - } - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/util/misc/Delayed26WayDistancePropagator3D.java b/arclight-common/src/main/java/io/papermc/paper/util/misc/Delayed26WayDistancePropagator3D.java deleted file mode 100644 index 77a4b7d2c..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/util/misc/Delayed26WayDistancePropagator3D.java +++ /dev/null @@ -1,297 +0,0 @@ -package io.papermc.paper.util.misc; - -import io.papermc.paper.util.CoordinateUtils; -import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap; -import it.unimi.dsi.fastutil.longs.LongIterator; -import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet; - -public final class Delayed26WayDistancePropagator3D { - - // this map is considered "stale" unless updates are propagated. - private final Delayed8WayDistancePropagator2D.LevelMap levels = new Delayed8WayDistancePropagator2D.LevelMap(8192 * 2, 0.6f); - - // this map is never stale - private final Long2ByteOpenHashMap sources = new Long2ByteOpenHashMap(4096, 0.6f); - - // Generally updates to positions are made close to other updates, so we link to decrease cache misses when - // propagating updates - private final LongLinkedOpenHashSet updatedSources = new LongLinkedOpenHashSet(); - private final LevelChangeCallback changeCallback; - // queues used for BFS propagating levels - private final Delayed8WayDistancePropagator2D.WorkQueue[] levelIncreaseWorkQueues = new Delayed8WayDistancePropagator2D.WorkQueue[64]; - private final Delayed8WayDistancePropagator2D.WorkQueue[] levelRemoveWorkQueues = new Delayed8WayDistancePropagator2D.WorkQueue[64]; - private long levelIncreaseWorkQueueBitset; - private long levelRemoveWorkQueueBitset; - - { - for (int i = 0; i < this.levelIncreaseWorkQueues.length; ++i) { - this.levelIncreaseWorkQueues[i] = new Delayed8WayDistancePropagator2D.WorkQueue(); - } - } - - { - for (int i = 0; i < this.levelRemoveWorkQueues.length; ++i) { - this.levelRemoveWorkQueues[i] = new Delayed8WayDistancePropagator2D.WorkQueue(); - } - } - - public Delayed26WayDistancePropagator3D() { - this(null); - } - - public Delayed26WayDistancePropagator3D(final LevelChangeCallback changeCallback) { - this.changeCallback = changeCallback; - } - - public int getLevel(final long pos) { - return this.levels.get(pos); - } - - public int getLevel(final int x, final int y, final int z) { - return this.levels.get(CoordinateUtils.getChunkSectionKey(x, y, z)); - } - - public void setSource(final int x, final int y, final int z, final int level) { - this.setSource(CoordinateUtils.getChunkSectionKey(x, y, z), level); - } - - public void setSource(final long coordinate, final int level) { - if ((level & 63) != level || level == 0) { - throw new IllegalArgumentException("Level must be in (0, 63], not " + level); - } - - final byte byteLevel = (byte) level; - final byte oldLevel = this.sources.put(coordinate, byteLevel); - - if (oldLevel == byteLevel) { - return; // nothing to do - } - - // queue to update later - this.updatedSources.add(coordinate); - } - - public void removeSource(final int x, final int y, final int z) { - this.removeSource(CoordinateUtils.getChunkSectionKey(x, y, z)); - } - - public void removeSource(final long coordinate) { - if (this.sources.remove(coordinate) != 0) { - this.updatedSources.add(coordinate); - } - } - - private void addToIncreaseWorkQueue(final long coordinate, final byte level) { - final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[level]; - queue.queuedCoordinates.enqueue(coordinate); - queue.queuedLevels.enqueue(level); - - this.levelIncreaseWorkQueueBitset |= (1L << level); - } - - private void addToIncreaseWorkQueue(final long coordinate, final byte index, final byte level) { - final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[index]; - queue.queuedCoordinates.enqueue(coordinate); - queue.queuedLevels.enqueue(level); - - this.levelIncreaseWorkQueueBitset |= (1L << index); - } - - private void addToRemoveWorkQueue(final long coordinate, final byte level) { - final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelRemoveWorkQueues[level]; - queue.queuedCoordinates.enqueue(coordinate); - queue.queuedLevels.enqueue(level); - - this.levelRemoveWorkQueueBitset |= (1L << level); - } - - public boolean propagateUpdates() { - if (this.updatedSources.isEmpty()) { - return false; - } - - boolean ret = false; - - for (final LongIterator iterator = this.updatedSources.iterator(); iterator.hasNext(); ) { - final long coordinate = iterator.nextLong(); - - final byte currentLevel = this.levels.get(coordinate); - final byte updatedSource = this.sources.get(coordinate); - - if (currentLevel == updatedSource) { - continue; - } - ret = true; - - if (updatedSource > currentLevel) { - // level increase - this.addToIncreaseWorkQueue(coordinate, updatedSource); - } else { - // level decrease - this.addToRemoveWorkQueue(coordinate, currentLevel); - // if the current coordinate is a source, then the decrease propagation will detect that and queue - // the source propagation - } - } - - this.updatedSources.clear(); - - // propagate source level increases first for performance reasons (in crowded areas hopefully the additions - // make the removes remove less) - this.propagateIncreases(); - - // now we propagate the decreases (which will then re-propagate clobbered sources) - this.propagateDecreases(); - - return ret; - } - - private void propagateIncreases() { - for (int queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelIncreaseWorkQueueBitset); - this.levelIncreaseWorkQueueBitset != 0L; - this.levelIncreaseWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelIncreaseWorkQueueBitset)) { - - final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[queueIndex]; - while (!queue.queuedLevels.isEmpty()) { - final long coordinate = queue.queuedCoordinates.removeFirstLong(); - byte level = queue.queuedLevels.removeFirstByte(); - - final boolean neighbourCheck = level < 0; - - final byte currentLevel; - if (neighbourCheck) { - level = (byte) -level; - currentLevel = this.levels.get(coordinate); - } else { - currentLevel = this.levels.putIfGreater(coordinate, level); - } - - if (neighbourCheck) { - // used when propagating from decrease to indicate that this level needs to check its neighbours - // this means the level at coordinate could be equal, but would still need neighbours checked - - if (currentLevel != level) { - // something caused the level to change, which means something propagated to it (which means - // us propagating here is redundant), or something removed the level (which means we - // cannot propagate further) - continue; - } - } else if (currentLevel >= level) { - // something higher/equal propagated - continue; - } - if (this.changeCallback != null) { - this.changeCallback.onLevelUpdate(coordinate, currentLevel, level); - } - - if (level == 1) { - // can't propagate 0 to neighbours - continue; - } - - // propagate to neighbours - final byte neighbourLevel = (byte) (level - 1); - final int x = CoordinateUtils.getChunkSectionX(coordinate); - final int y = CoordinateUtils.getChunkSectionY(coordinate); - final int z = CoordinateUtils.getChunkSectionZ(coordinate); - - for (int dy = -1; dy <= 1; ++dy) { - for (int dz = -1; dz <= 1; ++dz) { - for (int dx = -1; dx <= 1; ++dx) { - if ((dy | dz | dx) == 0) { - // already propagated to coordinate - continue; - } - - // sure we can check the neighbour level in the map right now and avoid a propagation, - // but then we would still have to recheck it when popping the value off of the queue! - // so just avoid the double lookup - final long neighbourCoordinate = CoordinateUtils.getChunkSectionKey(dx + x, dy + y, dz + z); - this.addToIncreaseWorkQueue(neighbourCoordinate, neighbourLevel); - } - } - } - } - } - } - - private void propagateDecreases() { - for (int queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelRemoveWorkQueueBitset); - this.levelRemoveWorkQueueBitset != 0L; - this.levelRemoveWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelRemoveWorkQueueBitset)) { - - final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelRemoveWorkQueues[queueIndex]; - while (!queue.queuedLevels.isEmpty()) { - final long coordinate = queue.queuedCoordinates.removeFirstLong(); - final byte level = queue.queuedLevels.removeFirstByte(); - - final byte currentLevel = this.levels.removeIfGreaterOrEqual(coordinate, level); - if (currentLevel == 0) { - // something else removed - continue; - } - - if (currentLevel > level) { - // something higher propagated here or we hit the propagation of another source - // in the second case we need to re-propagate because we could have just clobbered another source's - // propagation - this.addToIncreaseWorkQueue(coordinate, currentLevel, (byte) -currentLevel); // indicate to the increase code that the level's neighbours need checking - continue; - } - - if (this.changeCallback != null) { - this.changeCallback.onLevelUpdate(coordinate, currentLevel, (byte) 0); - } - - final byte source = this.sources.get(coordinate); - if (source != 0) { - // must re-propagate source later - this.addToIncreaseWorkQueue(coordinate, source); - } - - if (level == 0) { - // can't propagate -1 to neighbours - // we have to check neighbours for removing 1 just in case the neighbour is 2 - continue; - } - - // propagate to neighbours - final byte neighbourLevel = (byte) (level - 1); - final int x = CoordinateUtils.getChunkSectionX(coordinate); - final int y = CoordinateUtils.getChunkSectionY(coordinate); - final int z = CoordinateUtils.getChunkSectionZ(coordinate); - - for (int dy = -1; dy <= 1; ++dy) { - for (int dz = -1; dz <= 1; ++dz) { - for (int dx = -1; dx <= 1; ++dx) { - if ((dy | dz | dx) == 0) { - // already propagated to coordinate - continue; - } - - // sure we can check the neighbour level in the map right now and avoid a propagation, - // but then we would still have to recheck it when popping the value off of the queue! - // so just avoid the double lookup - final long neighbourCoordinate = CoordinateUtils.getChunkSectionKey(dx + x, dy + y, dz + z); - this.addToRemoveWorkQueue(neighbourCoordinate, neighbourLevel); - } - } - } - } - } - - // propagate sources we clobbered in the process - this.propagateIncreases(); - } - - @FunctionalInterface - public interface LevelChangeCallback { - - /** - * This can be called for intermediate updates. So do not rely on newLevel being close to or - * the exact level that is expected after a full propagation has occured. - */ - void onLevelUpdate(final long coordinate, final byte oldLevel, final byte newLevel); - - } -} diff --git a/arclight-common/src/main/java/io/papermc/paper/util/misc/Delayed8WayDistancePropagator2D.java b/arclight-common/src/main/java/io/papermc/paper/util/misc/Delayed8WayDistancePropagator2D.java deleted file mode 100644 index 76338db87..000000000 --- a/arclight-common/src/main/java/io/papermc/paper/util/misc/Delayed8WayDistancePropagator2D.java +++ /dev/null @@ -1,718 +0,0 @@ -package io.papermc.paper.util.misc; - -import io.papermc.paper.util.MCUtil; -import it.unimi.dsi.fastutil.HashCommon; -import it.unimi.dsi.fastutil.bytes.ByteArrayFIFOQueue; -import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap; -import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue; -import it.unimi.dsi.fastutil.longs.LongIterator; -import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet; - -public final class Delayed8WayDistancePropagator2D { - - // Test - /* - protected static void test(int x, int z, com.destroystokyo.paper.util.misc.DistanceTrackingAreaMap reference, Delayed8WayDistancePropagator2D test) { - int got = test.getLevel(x, z); - - int expect = 0; - Object[] nearest = reference.getObjectsInRange(x, z) == null ? null : reference.getObjectsInRange(x, z).getBackingSet(); - if (nearest != null) { - for (Object _obj : nearest) { - if (_obj instanceof Ticket) { - Ticket ticket = (Ticket)_obj; - long ticketCoord = reference.getLastCoordinate(ticket); - int viewDistance = reference.getLastViewDistance(ticket); - int distance = Math.max(com.destroystokyo.paper.util.math.IntegerUtil.branchlessAbs(MCUtil.getCoordinateX(ticketCoord) - x), - com.destroystokyo.paper.util.math.IntegerUtil.branchlessAbs(MCUtil.getCoordinateZ(ticketCoord) - z)); - int level = viewDistance - distance; - if (level > expect) { - expect = level; - } - } - } - } - - if (expect != got) { - throw new IllegalStateException("Expected " + expect + " at pos (" + x + "," + z + ") but got " + got); - } - } - - static class Ticket { - - int x; - int z; - - final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet empty - = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<>(this); - - } - - public static void main(final String[] args) { - com.destroystokyo.paper.util.misc.DistanceTrackingAreaMap reference = new com.destroystokyo.paper.util.misc.DistanceTrackingAreaMap() { - @Override - protected com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet getEmptySetFor(Ticket object) { - return object.empty; - } - }; - Delayed8WayDistancePropagator2D test = new Delayed8WayDistancePropagator2D(); - - final int maxDistance = 64; - // test origin - { - Ticket originTicket = new Ticket(); - int originDistance = 31; - // test single source - reference.add(originTicket, 0, 0, originDistance); - test.setSource(0, 0, originDistance); test.propagateUpdates(); // set and propagate - for (int dx = -originDistance; dx <= originDistance; ++dx) { - for (int dz = -originDistance; dz <= originDistance; ++dz) { - test(dx, dz, reference, test); - } - } - // test single source decrease - reference.update(originTicket, 0, 0, originDistance/2); - test.setSource(0, 0, originDistance/2); test.propagateUpdates(); // set and propagate - for (int dx = -originDistance; dx <= originDistance; ++dx) { - for (int dz = -originDistance; dz <= originDistance; ++dz) { - test(dx, dz, reference, test); - } - } - // test source increase - originDistance = 2*originDistance; - reference.update(originTicket, 0, 0, originDistance); - test.setSource(0, 0, originDistance); test.propagateUpdates(); // set and propagate - for (int dx = -4*originDistance; dx <= 4*originDistance; ++dx) { - for (int dz = -4*originDistance; dz <= 4*originDistance; ++dz) { - test(dx, dz, reference, test); - } - } - - reference.remove(originTicket); - test.removeSource(0, 0); test.propagateUpdates(); - } - - // test multiple sources at origin - { - int originDistance = 31; - java.util.List list = new java.util.ArrayList<>(); - for (int i = 0; i < 10; ++i) { - Ticket a = new Ticket(); - list.add(a); - a.x = (i & 1) == 1 ? -i : i; - a.z = (i & 1) == 1 ? -i : i; - } - for (Ticket ticket : list) { - reference.add(ticket, ticket.x, ticket.z, originDistance); - test.setSource(ticket.x, ticket.z, originDistance); - } - test.propagateUpdates(); - - for (int dx = -8*originDistance; dx <= 8*originDistance; ++dx) { - for (int dz = -8*originDistance; dz <= 8*originDistance; ++dz) { - test(dx, dz, reference, test); - } - } - - // test ticket level decrease - - for (Ticket ticket : list) { - reference.update(ticket, ticket.x, ticket.z, originDistance/2); - test.setSource(ticket.x, ticket.z, originDistance/2); - } - test.propagateUpdates(); - - for (int dx = -8*originDistance; dx <= 8*originDistance; ++dx) { - for (int dz = -8*originDistance; dz <= 8*originDistance; ++dz) { - test(dx, dz, reference, test); - } - } - - // test ticket level increase - - for (Ticket ticket : list) { - reference.update(ticket, ticket.x, ticket.z, originDistance*2); - test.setSource(ticket.x, ticket.z, originDistance*2); - } - test.propagateUpdates(); - - for (int dx = -16*originDistance; dx <= 16*originDistance; ++dx) { - for (int dz = -16*originDistance; dz <= 16*originDistance; ++dz) { - test(dx, dz, reference, test); - } - } - - // test ticket remove - for (int i = 0, len = list.size(); i < len; ++i) { - if ((i & 3) != 0) { - continue; - } - Ticket ticket = list.get(i); - reference.remove(ticket); - test.removeSource(ticket.x, ticket.z); - } - test.propagateUpdates(); - - for (int dx = -16*originDistance; dx <= 16*originDistance; ++dx) { - for (int dz = -16*originDistance; dz <= 16*originDistance; ++dz) { - test(dx, dz, reference, test); - } - } - } - - // now test at coordinate offsets - // test offset - { - Ticket originTicket = new Ticket(); - int originDistance = 31; - int offX = 54432; - int offZ = -134567; - // test single source - reference.add(originTicket, offX, offZ, originDistance); - test.setSource(offX, offZ, originDistance); test.propagateUpdates(); // set and propagate - for (int dx = -originDistance; dx <= originDistance; ++dx) { - for (int dz = -originDistance; dz <= originDistance; ++dz) { - test(dx + offX, dz + offZ, reference, test); - } - } - // test single source decrease - reference.update(originTicket, offX, offZ, originDistance/2); - test.setSource(offX, offZ, originDistance/2); test.propagateUpdates(); // set and propagate - for (int dx = -originDistance; dx <= originDistance; ++dx) { - for (int dz = -originDistance; dz <= originDistance; ++dz) { - test(dx + offX, dz + offZ, reference, test); - } - } - // test source increase - originDistance = 2*originDistance; - reference.update(originTicket, offX, offZ, originDistance); - test.setSource(offX, offZ, originDistance); test.propagateUpdates(); // set and propagate - for (int dx = -4*originDistance; dx <= 4*originDistance; ++dx) { - for (int dz = -4*originDistance; dz <= 4*originDistance; ++dz) { - test(dx + offX, dz + offZ, reference, test); - } - } - - reference.remove(originTicket); - test.removeSource(offX, offZ); test.propagateUpdates(); - } - - // test multiple sources at origin - { - int originDistance = 31; - int offX = 54432; - int offZ = -134567; - java.util.List list = new java.util.ArrayList<>(); - for (int i = 0; i < 10; ++i) { - Ticket a = new Ticket(); - list.add(a); - a.x = offX + ((i & 1) == 1 ? -i : i); - a.z = offZ + ((i & 1) == 1 ? -i : i); - } - for (Ticket ticket : list) { - reference.add(ticket, ticket.x, ticket.z, originDistance); - test.setSource(ticket.x, ticket.z, originDistance); - } - test.propagateUpdates(); - - for (int dx = -8*originDistance; dx <= 8*originDistance; ++dx) { - for (int dz = -8*originDistance; dz <= 8*originDistance; ++dz) { - test(dx, dz, reference, test); - } - } - - // test ticket level decrease - - for (Ticket ticket : list) { - reference.update(ticket, ticket.x, ticket.z, originDistance/2); - test.setSource(ticket.x, ticket.z, originDistance/2); - } - test.propagateUpdates(); - - for (int dx = -8*originDistance; dx <= 8*originDistance; ++dx) { - for (int dz = -8*originDistance; dz <= 8*originDistance; ++dz) { - test(dx, dz, reference, test); - } - } - - // test ticket level increase - - for (Ticket ticket : list) { - reference.update(ticket, ticket.x, ticket.z, originDistance*2); - test.setSource(ticket.x, ticket.z, originDistance*2); - } - test.propagateUpdates(); - - for (int dx = -16*originDistance; dx <= 16*originDistance; ++dx) { - for (int dz = -16*originDistance; dz <= 16*originDistance; ++dz) { - test(dx, dz, reference, test); - } - } - - // test ticket remove - for (int i = 0, len = list.size(); i < len; ++i) { - if ((i & 3) != 0) { - continue; - } - Ticket ticket = list.get(i); - reference.remove(ticket); - test.removeSource(ticket.x, ticket.z); - } - test.propagateUpdates(); - - for (int dx = -16*originDistance; dx <= 16*originDistance; ++dx) { - for (int dz = -16*originDistance; dz <= 16*originDistance; ++dz) { - test(dx, dz, reference, test); - } - } - } - } - */ - - // this map is considered "stale" unless updates are propagated. - private final LevelMap levels = new LevelMap(8192 * 2, 0.6f); - - // this map is never stale - private final Long2ByteOpenHashMap sources = new Long2ByteOpenHashMap(4096, 0.6f); - - // Generally updates to positions are made close to other updates, so we link to decrease cache misses when - // propagating updates - private final LongLinkedOpenHashSet updatedSources = new LongLinkedOpenHashSet(); - private final LevelChangeCallback changeCallback; - // queues used for BFS propagating levels - private final WorkQueue[] levelIncreaseWorkQueues = new WorkQueue[64]; - private final WorkQueue[] levelRemoveWorkQueues = new WorkQueue[64]; - private long levelIncreaseWorkQueueBitset; - private long levelRemoveWorkQueueBitset; - - { - for (int i = 0; i < this.levelIncreaseWorkQueues.length; ++i) { - this.levelIncreaseWorkQueues[i] = new WorkQueue(); - } - } - - { - for (int i = 0; i < this.levelRemoveWorkQueues.length; ++i) { - this.levelRemoveWorkQueues[i] = new WorkQueue(); - } - } - - public Delayed8WayDistancePropagator2D() { - this(null); - } - - public Delayed8WayDistancePropagator2D(final LevelChangeCallback changeCallback) { - this.changeCallback = changeCallback; - } - - public int getLevel(final long pos) { - return this.levels.get(pos); - } - - public int getLevel(final int x, final int z) { - return this.levels.get(MCUtil.getCoordinateKey(x, z)); - } - - public void setSource(final int x, final int z, final int level) { - this.setSource(MCUtil.getCoordinateKey(x, z), level); - } - - public void setSource(final long coordinate, final int level) { - if ((level & 63) != level || level == 0) { - throw new IllegalArgumentException("Level must be in (0, 63], not " + level); - } - - final byte byteLevel = (byte) level; - final byte oldLevel = this.sources.put(coordinate, byteLevel); - - if (oldLevel == byteLevel) { - return; // nothing to do - } - - // queue to update later - this.updatedSources.add(coordinate); - } - - public void removeSource(final int x, final int z) { - this.removeSource(MCUtil.getCoordinateKey(x, z)); - } - - public void removeSource(final long coordinate) { - if (this.sources.remove(coordinate) != 0) { - this.updatedSources.add(coordinate); - } - } - - private void addToIncreaseWorkQueue(final long coordinate, final byte level) { - final WorkQueue queue = this.levelIncreaseWorkQueues[level]; - queue.queuedCoordinates.enqueue(coordinate); - queue.queuedLevels.enqueue(level); - - this.levelIncreaseWorkQueueBitset |= (1L << level); - } - - private void addToIncreaseWorkQueue(final long coordinate, final byte index, final byte level) { - final WorkQueue queue = this.levelIncreaseWorkQueues[index]; - queue.queuedCoordinates.enqueue(coordinate); - queue.queuedLevels.enqueue(level); - - this.levelIncreaseWorkQueueBitset |= (1L << index); - } - - private void addToRemoveWorkQueue(final long coordinate, final byte level) { - final WorkQueue queue = this.levelRemoveWorkQueues[level]; - queue.queuedCoordinates.enqueue(coordinate); - queue.queuedLevels.enqueue(level); - - this.levelRemoveWorkQueueBitset |= (1L << level); - } - - public boolean propagateUpdates() { - if (this.updatedSources.isEmpty()) { - return false; - } - - boolean ret = false; - - for (final LongIterator iterator = this.updatedSources.iterator(); iterator.hasNext(); ) { - final long coordinate = iterator.nextLong(); - - final byte currentLevel = this.levels.get(coordinate); - final byte updatedSource = this.sources.get(coordinate); - - if (currentLevel == updatedSource) { - continue; - } - ret = true; - - if (updatedSource > currentLevel) { - // level increase - this.addToIncreaseWorkQueue(coordinate, updatedSource); - } else { - // level decrease - this.addToRemoveWorkQueue(coordinate, currentLevel); - // if the current coordinate is a source, then the decrease propagation will detect that and queue - // the source propagation - } - } - - this.updatedSources.clear(); - - // propagate source level increases first for performance reasons (in crowded areas hopefully the additions - // make the removes remove less) - this.propagateIncreases(); - - // now we propagate the decreases (which will then re-propagate clobbered sources) - this.propagateDecreases(); - - return ret; - } - - private void propagateIncreases() { - for (int queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelIncreaseWorkQueueBitset); - this.levelIncreaseWorkQueueBitset != 0L; - this.levelIncreaseWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelIncreaseWorkQueueBitset)) { - - final WorkQueue queue = this.levelIncreaseWorkQueues[queueIndex]; - while (!queue.queuedLevels.isEmpty()) { - final long coordinate = queue.queuedCoordinates.removeFirstLong(); - byte level = queue.queuedLevels.removeFirstByte(); - - final boolean neighbourCheck = level < 0; - - final byte currentLevel; - if (neighbourCheck) { - level = (byte) -level; - currentLevel = this.levels.get(coordinate); - } else { - currentLevel = this.levels.putIfGreater(coordinate, level); - } - - if (neighbourCheck) { - // used when propagating from decrease to indicate that this level needs to check its neighbours - // this means the level at coordinate could be equal, but would still need neighbours checked - - if (currentLevel != level) { - // something caused the level to change, which means something propagated to it (which means - // us propagating here is redundant), or something removed the level (which means we - // cannot propagate further) - continue; - } - } else if (currentLevel >= level) { - // something higher/equal propagated - continue; - } - if (this.changeCallback != null) { - this.changeCallback.onLevelUpdate(coordinate, currentLevel, level); - } - - if (level == 1) { - // can't propagate 0 to neighbours - continue; - } - - // propagate to neighbours - final byte neighbourLevel = (byte) (level - 1); - final int x = (int) coordinate; - final int z = (int) (coordinate >>> 32); - - for (int dx = -1; dx <= 1; ++dx) { - for (int dz = -1; dz <= 1; ++dz) { - if ((dx | dz) == 0) { - // already propagated to coordinate - continue; - } - - // sure we can check the neighbour level in the map right now and avoid a propagation, - // but then we would still have to recheck it when popping the value off of the queue! - // so just avoid the double lookup - final long neighbourCoordinate = MCUtil.getCoordinateKey(x + dx, z + dz); - this.addToIncreaseWorkQueue(neighbourCoordinate, neighbourLevel); - } - } - } - } - } - - private void propagateDecreases() { - for (int queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelRemoveWorkQueueBitset); - this.levelRemoveWorkQueueBitset != 0L; - this.levelRemoveWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelRemoveWorkQueueBitset)) { - - final WorkQueue queue = this.levelRemoveWorkQueues[queueIndex]; - while (!queue.queuedLevels.isEmpty()) { - final long coordinate = queue.queuedCoordinates.removeFirstLong(); - final byte level = queue.queuedLevels.removeFirstByte(); - - final byte currentLevel = this.levels.removeIfGreaterOrEqual(coordinate, level); - if (currentLevel == 0) { - // something else removed - continue; - } - - if (currentLevel > level) { - // something higher propagated here or we hit the propagation of another source - // in the second case we need to re-propagate because we could have just clobbered another source's - // propagation - this.addToIncreaseWorkQueue(coordinate, currentLevel, (byte) -currentLevel); // indicate to the increase code that the level's neighbours need checking - continue; - } - - if (this.changeCallback != null) { - this.changeCallback.onLevelUpdate(coordinate, currentLevel, (byte) 0); - } - - final byte source = this.sources.get(coordinate); - if (source != 0) { - // must re-propagate source later - this.addToIncreaseWorkQueue(coordinate, source); - } - - if (level == 0) { - // can't propagate -1 to neighbours - // we have to check neighbours for removing 1 just in case the neighbour is 2 - continue; - } - - // propagate to neighbours - final byte neighbourLevel = (byte) (level - 1); - final int x = (int) coordinate; - final int z = (int) (coordinate >>> 32); - - for (int dx = -1; dx <= 1; ++dx) { - for (int dz = -1; dz <= 1; ++dz) { - if ((dx | dz) == 0) { - // already propagated to coordinate - continue; - } - - // sure we can check the neighbour level in the map right now and avoid a propagation, - // but then we would still have to recheck it when popping the value off of the queue! - // so just avoid the double lookup - final long neighbourCoordinate = MCUtil.getCoordinateKey(x + dx, z + dz); - this.addToRemoveWorkQueue(neighbourCoordinate, neighbourLevel); - } - } - } - } - - // propagate sources we clobbered in the process - this.propagateIncreases(); - } - - @FunctionalInterface - public interface LevelChangeCallback { - - /** - * This can be called for intermediate updates. So do not rely on newLevel being close to or - * the exact level that is expected after a full propagation has occured. - */ - void onLevelUpdate(final long coordinate, final byte oldLevel, final byte newLevel); - - } - - protected static final class LevelMap extends Long2ByteOpenHashMap { - public LevelMap() { - super(); - } - - public LevelMap(final int expected, final float loadFactor) { - super(expected, loadFactor); - } - - // copied from superclass - private int find(final long k) { - if (k == 0L) { - return this.containsNullKey ? this.n : -(this.n + 1); - } else { - final long[] key = this.key; - long curr; - int pos; - if ((curr = key[pos = (int) HashCommon.mix(k) & this.mask]) == 0L) { - return -(pos + 1); - } else if (k == curr) { - return pos; - } else { - while ((curr = key[pos = pos + 1 & this.mask]) != 0L) { - if (k == curr) { - return pos; - } - } - - return -(pos + 1); - } - } - } - - // copied from superclass - private void insert(final int pos, final long k, final byte v) { - if (pos == this.n) { - this.containsNullKey = true; - } - - this.key[pos] = k; - this.value[pos] = v; - if (this.size++ >= this.maxFill) { - this.rehash(HashCommon.arraySize(this.size + 1, this.f)); - } - } - - // copied from superclass - public byte putIfGreater(final long key, final byte value) { - final int pos = this.find(key); - if (pos < 0) { - if (this.defRetValue < value) { - this.insert(-pos - 1, key, value); - } - return this.defRetValue; - } else { - final byte curr = this.value[pos]; - if (value > curr) { - this.value[pos] = value; - return curr; - } - return curr; - } - } - - // copied from superclass - private void removeEntry(final int pos) { - --this.size; - this.shiftKeys(pos); - if (this.n > this.minN && this.size < this.maxFill / 4 && this.n > 16) { - this.rehash(this.n / 2); - } - } - - // copied from superclass - private void removeNullEntry() { - this.containsNullKey = false; - --this.size; - if (this.n > this.minN && this.size < this.maxFill / 4 && this.n > 16) { - this.rehash(this.n / 2); - } - } - - // copied from superclass - public byte removeIfGreaterOrEqual(final long key, final byte value) { - if (key == 0L) { - if (!this.containsNullKey) { - return this.defRetValue; - } - final byte current = this.value[this.n]; - if (value >= current) { - this.removeNullEntry(); - return current; - } - return current; - } else { - long[] keys = this.key; - byte[] values = this.value; - long curr; - int pos; - if ((curr = keys[pos = (int) HashCommon.mix(key) & this.mask]) == 0L) { - return this.defRetValue; - } else if (key == curr) { - final byte current = values[pos]; - if (value >= current) { - this.removeEntry(pos); - return current; - } - return current; - } else { - while ((curr = keys[pos = pos + 1 & this.mask]) != 0L) { - if (key == curr) { - final byte current = values[pos]; - if (value >= current) { - this.removeEntry(pos); - return current; - } - return current; - } - } - - return this.defRetValue; - } - } - } - } - - protected static final class WorkQueue { - - public final NoResizeLongArrayFIFODeque queuedCoordinates = new NoResizeLongArrayFIFODeque(); - public final NoResizeByteArrayFIFODeque queuedLevels = new NoResizeByteArrayFIFODeque(); - - } - - protected static final class NoResizeLongArrayFIFODeque extends LongArrayFIFOQueue { - - /** - * Assumes non-empty. If empty, undefined behaviour. - */ - public long removeFirstLong() { - // copied from superclass - long t = this.array[this.start]; - if (++this.start == this.length) { - this.start = 0; - } - - return t; - } - } - - protected static final class NoResizeByteArrayFIFODeque extends ByteArrayFIFOQueue { - - /** - * Assumes non-empty. If empty, undefined behaviour. - */ - public byte removeFirstByte() { - // copied from superclass - byte t = this.array[this.start]; - if (++this.start == this.length) { - this.start = 0; - } - - return t; - } - } -}