== 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:
Aikar
2016-03-28 20:55:47 -04:00
parent a82a09d198
commit b01c811c2f
81 changed files with 6261 additions and 473 deletions

View File

@@ -215,7 +215,7 @@ public class GlobalConfiguration extends ConfigurationPart {
@PostProcess
private void postProcess() {
ca.spottedleaf.moonrise.common.util.MoonriseCommon.adjustWorkerThreads(this.workerThreads, this.ioThreads);
}
}

View File

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

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

View File

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

View File

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