MC Utils
== AT == public net.minecraft.server.level.ServerChunkCache mainThread public net.minecraft.server.level.ServerLevel chunkSource public org.bukkit.craftbukkit.inventory.CraftItemStack handle public net.minecraft.server.level.ChunkMap getVisibleChunkIfPresent(J)Lnet/minecraft/server/level/ChunkHolder; public net.minecraft.server.level.ServerChunkCache mainThreadProcessor public net.minecraft.server.level.ServerChunkCache$MainThreadExecutor public net.minecraft.world.level.chunk.LevelChunkSection states
This commit is contained in:
@@ -215,7 +215,7 @@ public class GlobalConfiguration extends ConfigurationPart {
|
||||
|
||||
@PostProcess
|
||||
private void postProcess() {
|
||||
|
||||
ca.spottedleaf.moonrise.common.util.MoonriseCommon.adjustWorkerThreads(this.workerThreads, this.ioThreads);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
package io.papermc.paper.util;
|
||||
|
||||
public final class IntervalledCounter {
|
||||
|
||||
private static final int INITIAL_SIZE = 8;
|
||||
|
||||
protected long[] times;
|
||||
protected long[] counts;
|
||||
protected final long interval;
|
||||
protected long minTime;
|
||||
protected long sum;
|
||||
protected int head; // inclusive
|
||||
protected int tail; // exclusive
|
||||
|
||||
public IntervalledCounter(final long interval) {
|
||||
this.times = new long[INITIAL_SIZE];
|
||||
this.counts = new long[INITIAL_SIZE];
|
||||
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 long count) {
|
||||
final long currTime = System.nanoTime();
|
||||
this.updateCurrentTime(currTime);
|
||||
this.addTime(currTime, count);
|
||||
}
|
||||
|
||||
public void updateAndAdd(final long 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) {
|
||||
// sequentially ordered from [head, tail)
|
||||
System.arraycopy(oldElements, head, newElements, 0, size);
|
||||
System.arraycopy(oldCounts, head, newCounts, 0, size);
|
||||
} else {
|
||||
// ordered from [head, length)
|
||||
// then followed by [0, tail)
|
||||
|
||||
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 (double)this.sum / ((double)this.interval * 1.0E-9);
|
||||
}
|
||||
|
||||
public long getInterval() {
|
||||
return this.interval;
|
||||
}
|
||||
|
||||
public long getSum() {
|
||||
return this.sum;
|
||||
}
|
||||
|
||||
public int totalDataPoints() {
|
||||
return this.tail >= this.head ? (this.tail - this.head) : (this.tail + (this.counts.length - this.head));
|
||||
}
|
||||
}
|
||||
205
paper-server/src/main/java/io/papermc/paper/util/MCUtil.java
Normal file
205
paper-server/src/main/java/io/papermc/paper/util/MCUtil.java
Normal file
@@ -0,0 +1,205 @@
|
||||
package io.papermc.paper.util;
|
||||
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import io.papermc.paper.math.BlockPosition;
|
||||
import io.papermc.paper.math.FinePosition;
|
||||
import io.papermc.paper.math.Position;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
|
||||
import org.bukkit.craftbukkit.util.Waitable;
|
||||
|
||||
public final class MCUtil {
|
||||
public static final java.util.concurrent.Executor MAIN_EXECUTOR = (run) -> {
|
||||
if (!isMainThread()) {
|
||||
MinecraftServer.getServer().execute(run);
|
||||
} else {
|
||||
run.run();
|
||||
}
|
||||
};
|
||||
public static final ExecutorService ASYNC_EXECUTOR = Executors.newFixedThreadPool(2, new ThreadFactoryBuilder()
|
||||
.setNameFormat("Paper Async Task Handler Thread - %1$d")
|
||||
.setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(MinecraftServer.LOGGER))
|
||||
.build()
|
||||
);
|
||||
|
||||
private MCUtil() {
|
||||
}
|
||||
|
||||
public static List<ChunkPos> getSpiralOutChunks(BlockPos blockposition, int radius) {
|
||||
List<ChunkPos> list = com.google.common.collect.Lists.newArrayList();
|
||||
|
||||
list.add(new ChunkPos(blockposition.getX() >> 4, blockposition.getZ() >> 4));
|
||||
for (int r = 1; r <= radius; r++) {
|
||||
int x = -r;
|
||||
int z = r;
|
||||
|
||||
// Iterates the edge of half of the box; then negates for other half.
|
||||
while (x <= r && z > -r) {
|
||||
list.add(new ChunkPos((blockposition.getX() + (x << 4)) >> 4, (blockposition.getZ() + (z << 4)) >> 4));
|
||||
list.add(new ChunkPos((blockposition.getX() - (x << 4)) >> 4, (blockposition.getZ() - (z << 4)) >> 4));
|
||||
|
||||
if (x < r) {
|
||||
x++;
|
||||
} else {
|
||||
z--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static <T> CompletableFuture<T> ensureMain(CompletableFuture<T> future) {
|
||||
return future.thenApplyAsync(r -> r, MAIN_EXECUTOR);
|
||||
}
|
||||
|
||||
public static <T> void thenOnMain(CompletableFuture<T> future, Consumer<T> consumer) {
|
||||
future.thenAcceptAsync(consumer, MAIN_EXECUTOR);
|
||||
}
|
||||
|
||||
public static <T> void thenOnMain(CompletableFuture<T> future, BiConsumer<T, Throwable> consumer) {
|
||||
future.whenCompleteAsync(consumer, MAIN_EXECUTOR);
|
||||
}
|
||||
|
||||
public static boolean isMainThread() {
|
||||
return MinecraftServer.getServer().isSameThread();
|
||||
}
|
||||
|
||||
public static void ensureMain(Runnable run) {
|
||||
ensureMain(null, run);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the target code is running on the main thread.
|
||||
*/
|
||||
public static void ensureMain(String reason, Runnable run) {
|
||||
if (!isMainThread()) {
|
||||
if (reason != null) {
|
||||
MinecraftServer.LOGGER.warn("Asynchronous " + reason + "!", new IllegalStateException());
|
||||
}
|
||||
MinecraftServer.getServer().processQueue.add(run);
|
||||
return;
|
||||
}
|
||||
run.run();
|
||||
}
|
||||
|
||||
public static <T> T ensureMain(Supplier<T> run) {
|
||||
return ensureMain(null, run);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the target code is running on the main thread.
|
||||
*/
|
||||
public static <T> T ensureMain(String reason, Supplier<T> run) {
|
||||
if (!isMainThread()) {
|
||||
if (reason != null) {
|
||||
MinecraftServer.LOGGER.warn("Asynchronous " + reason + "! Blocking thread until it returns ", new IllegalStateException());
|
||||
}
|
||||
Waitable<T> wait = new Waitable<>() {
|
||||
@Override
|
||||
protected T evaluate() {
|
||||
return run.get();
|
||||
}
|
||||
};
|
||||
MinecraftServer.getServer().processQueue.add(wait);
|
||||
try {
|
||||
return wait.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
MinecraftServer.LOGGER.warn("Encountered exception", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return run.get();
|
||||
}
|
||||
|
||||
public static double distance(double x1, double y1, double z1, double x2, double y2, double z2) {
|
||||
return Math.sqrt(distanceSq(x1, y1, z1, x2, y2, z2));
|
||||
}
|
||||
|
||||
public static double distanceSq(double x1, double y1, double z1, double x2, double y2, double z2) {
|
||||
return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2);
|
||||
}
|
||||
|
||||
public static Location toLocation(Level world, double x, double y, double z) {
|
||||
return new Location(world.getWorld(), x, y, z);
|
||||
}
|
||||
|
||||
public static Location toLocation(Level world, BlockPos pos) {
|
||||
return new Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ());
|
||||
}
|
||||
|
||||
public static BlockPos toBlockPosition(Location loc) {
|
||||
return new BlockPos(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
}
|
||||
|
||||
public static BlockPos toBlockPos(Position pos) {
|
||||
return new BlockPos(pos.blockX(), pos.blockY(), pos.blockZ());
|
||||
}
|
||||
|
||||
public static FinePosition toPosition(Vec3 vector) {
|
||||
return Position.fine(vector.x, vector.y, vector.z);
|
||||
}
|
||||
|
||||
public static BlockPosition toPosition(Vec3i vector) {
|
||||
return Position.block(vector.getX(), vector.getY(), vector.getZ());
|
||||
}
|
||||
|
||||
public static Vec3 toVec3(Position position) {
|
||||
return new Vec3(position.x(), position.y(), position.z());
|
||||
}
|
||||
|
||||
public static boolean isEdgeOfChunk(BlockPos pos) {
|
||||
final int modX = pos.getX() & 15;
|
||||
final int modZ = pos.getZ() & 15;
|
||||
return (modX == 0 || modX == 15 || modZ == 0 || modZ == 15);
|
||||
}
|
||||
|
||||
public static void scheduleAsyncTask(Runnable run) {
|
||||
ASYNC_EXECUTOR.execute(run);
|
||||
}
|
||||
|
||||
public static <T> ResourceKey<T> toResourceKey(
|
||||
final ResourceKey<? extends net.minecraft.core.Registry<T>> registry,
|
||||
final NamespacedKey namespacedKey
|
||||
) {
|
||||
return ResourceKey.create(registry, CraftNamespacedKey.toMinecraft(namespacedKey));
|
||||
}
|
||||
|
||||
public static NamespacedKey fromResourceKey(final ResourceKey<?> key) {
|
||||
return CraftNamespacedKey.fromMinecraft(key.location());
|
||||
}
|
||||
|
||||
public static <A, M> List<A> transformUnmodifiable(final List<? extends M> nms, final Function<? super M, ? extends A> converter) {
|
||||
return Collections.unmodifiableList(Lists.transform(nms, converter::apply));
|
||||
}
|
||||
|
||||
public static <A, M> Collection<A> transformUnmodifiable(final Collection<? extends M> nms, final Function<? super M, ? extends A> converter) {
|
||||
return Collections.unmodifiableCollection(Collections2.transform(nms, converter::apply));
|
||||
}
|
||||
|
||||
public static <A, M, C extends Collection<M>> void addAndConvert(final C target, final Collection<A> toAdd, final Function<? super A, ? extends M> converter) {
|
||||
for (final A value : toAdd) {
|
||||
target.add(converter.apply(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package io.papermc.paper.util;
|
||||
|
||||
import com.google.common.collect.ForwardingSet;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@NullMarked
|
||||
public class SizeLimitedSet<E> extends ForwardingSet<E> {
|
||||
|
||||
private final Set<E> delegate;
|
||||
private final int maxSize;
|
||||
|
||||
public SizeLimitedSet(final Set<E> delegate, final int maxSize) {
|
||||
this.delegate = delegate;
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(final E element) {
|
||||
if (this.size() >= this.maxSize) {
|
||||
return false;
|
||||
}
|
||||
return super.add(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(final Collection<? extends @Nullable E> collection) {
|
||||
if ((collection.size() + this.size()) >= this.maxSize) {
|
||||
return false;
|
||||
}
|
||||
boolean edited = false;
|
||||
|
||||
for (final E element : collection) {
|
||||
edited |= super.add(element);
|
||||
}
|
||||
return edited;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<E> delegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package io.papermc.paper.util;
|
||||
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.plugin.java.PluginClassLoader;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class StackWalkerUtil {
|
||||
|
||||
@Nullable
|
||||
public static JavaPlugin getFirstPluginCaller() {
|
||||
Optional<JavaPlugin> foundFrame = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
|
||||
.walk(stream -> stream
|
||||
.filter(frame -> frame.getDeclaringClass().getClassLoader() instanceof PluginClassLoader)
|
||||
.map((frame) -> {
|
||||
PluginClassLoader classLoader = (PluginClassLoader) frame.getDeclaringClass().getClassLoader();
|
||||
return classLoader.getPlugin();
|
||||
})
|
||||
.findFirst());
|
||||
|
||||
return foundFrame.orElse(null);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user