Upstream Paper and misc
This commit is contained in:
@@ -1,18 +1,29 @@
|
||||
package io.akarin.api.internal.utils;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class ReentrantSpinningLock {
|
||||
private final AtomicBoolean singleLock = new AtomicBoolean(false);
|
||||
/*
|
||||
* Impl Note:
|
||||
* A write lock can reentrant as a read lock, while a
|
||||
* read lock is not allowed to reentrant as a write lock.
|
||||
*/
|
||||
private final AtomicBoolean writeLocked = new AtomicBoolean(false);
|
||||
|
||||
// --------- Thread local restricted fields ---------
|
||||
private long heldThreadId = 0;
|
||||
private int reentrantLocks = 0;
|
||||
|
||||
/**
|
||||
* Lock as a typical write lock
|
||||
*/
|
||||
public void lock() {
|
||||
long currentThreadId = Thread.currentThread().getId();
|
||||
if (heldThreadId == currentThreadId) {
|
||||
reentrantLocks++;
|
||||
} else {
|
||||
while (!singleLock.compareAndSet(false, true)) ; // In case acquire one lock concurrently
|
||||
while (!writeLocked.compareAndSet(false, true)) ; // In case acquire one lock concurrently
|
||||
heldThreadId = currentThreadId;
|
||||
}
|
||||
}
|
||||
@@ -20,9 +31,68 @@ public class ReentrantSpinningLock {
|
||||
public void unlock() {
|
||||
if (reentrantLocks == 0) {
|
||||
heldThreadId = 0;
|
||||
singleLock.set(false);
|
||||
if (readerThreads.getAndDecrement() == 1) { // Micro-optimization: this saves one subtract
|
||||
writeLocked.set(false);
|
||||
}
|
||||
} else {
|
||||
--reentrantLocks;
|
||||
}
|
||||
}
|
||||
|
||||
private final AtomicInteger readerThreads = new AtomicInteger(0);
|
||||
|
||||
/**
|
||||
* Lock as a typical read lock
|
||||
*/
|
||||
public void lockWeak() {
|
||||
long currentThreadId = Thread.currentThread().getId();
|
||||
if (heldThreadId == currentThreadId) {
|
||||
reentrantLocks++;
|
||||
} else {
|
||||
if (readerThreads.get() == 0) {
|
||||
while (!writeLocked.compareAndSet(false, true)) ; // Block future write lock
|
||||
}
|
||||
heldThreadId = currentThreadId;
|
||||
readerThreads.getAndIncrement(); // Micro-optimization: this saves one plus
|
||||
}
|
||||
}
|
||||
|
||||
public void unlockWeak() {
|
||||
if (reentrantLocks == 0) {
|
||||
heldThreadId = 0;
|
||||
writeLocked.set(false);
|
||||
} else {
|
||||
--reentrantLocks;
|
||||
}
|
||||
}
|
||||
|
||||
// --------- Wrappers to allow typical usages ---------
|
||||
private SpinningWriteLock wrappedWriteLock = new SpinningWriteLock();
|
||||
private SpinningReadLock wrappedReadLock = new SpinningReadLock();
|
||||
|
||||
public class SpinningWriteLock {
|
||||
public void lock() {
|
||||
lock();
|
||||
}
|
||||
public void unlock() {
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public class SpinningReadLock {
|
||||
public void lock() {
|
||||
lockWeak();
|
||||
}
|
||||
public void unlock() {
|
||||
unlockWeak();
|
||||
}
|
||||
}
|
||||
|
||||
public SpinningWriteLock writeLock() {
|
||||
return wrappedWriteLock;
|
||||
}
|
||||
|
||||
public SpinningReadLock readLocked() {
|
||||
return wrappedReadLock;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public class AkarinGlobalConfig {
|
||||
+ "Some options may impact gameplay, so use with caution,\n"
|
||||
+ "and make sure you know what each option does before configuring.\n"
|
||||
+ "\n"
|
||||
+ "Akarin forums: https://akarin.io/ \n";
|
||||
+ "Akarin website: https://akarin.io/ \n";
|
||||
/*========================================================================*/
|
||||
public static YamlConfiguration config;
|
||||
static int version;
|
||||
|
||||
@@ -6,7 +6,6 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.spigotmc.RestartCommand;
|
||||
import org.spigotmc.WatchdogThread;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
@@ -23,6 +22,10 @@ import net.minecraft.server.MinecraftServer;
|
||||
public abstract class Watchcat extends Thread {
|
||||
@Shadow private static WatchdogThread instance;
|
||||
@Shadow private @Final long timeoutTime;
|
||||
@Shadow private @Final long earlyWarningEvery; // Paper - Timeout time for just printing a dump but not restarting
|
||||
@Shadow private @Final long earlyWarningDelay; // Paper
|
||||
@Shadow public static volatile boolean hasStarted; // Paper
|
||||
@Shadow private long lastEarlyWarning; // Paper - Keep track of short dump times to avoid spamming console with short dumps
|
||||
@Shadow private @Final boolean restart;
|
||||
@Shadow private volatile long lastTick;
|
||||
@Shadow private volatile boolean stopping;
|
||||
@@ -39,47 +42,67 @@ public abstract class Watchcat extends Thread {
|
||||
public void run() {
|
||||
while (!stopping) {
|
||||
//
|
||||
if (lastTick != 0 && System.currentTimeMillis() > lastTick + timeoutTime && !Boolean.getBoolean("disable.watchdog")) { // Paper - Add property to disable
|
||||
Logger log = Bukkit.getServer().getLogger();
|
||||
log.log(Level.SEVERE, "Server has stopped responding!");
|
||||
log.log(Level.SEVERE, "Please report this to https://github.com/Akarin-project/Akarin/issues");
|
||||
log.log(Level.SEVERE, "Be sure to include ALL relevant console errors and Minecraft crash reports");
|
||||
log.log(Level.SEVERE, "Akarin version: " + Bukkit.getServer().getVersion());
|
||||
//
|
||||
if (net.minecraft.server.World.haveWeSilencedAPhysicsCrash) {
|
||||
log.log(Level.SEVERE, "------------------------------");
|
||||
log.log(Level.SEVERE, "During the run of the server, a physics stackoverflow was supressed");
|
||||
log.log(Level.SEVERE, "near " + net.minecraft.server.World.blockLocation);
|
||||
}
|
||||
// Paper start - Warn in watchdog if an excessive velocity was ever set
|
||||
if (CraftServer.excessiveVelEx != null) {
|
||||
log.log(Level.SEVERE, "------------------------------");
|
||||
log.log(Level.SEVERE, "During the run of the server, a plugin set an excessive velocity on an entity");
|
||||
log.log(Level.SEVERE, "This may be the cause of the issue, or it may be entirely unrelated");
|
||||
log.log(Level.SEVERE, CraftServer.excessiveVelEx.getMessage());
|
||||
for (StackTraceElement stack : CraftServer.excessiveVelEx.getStackTrace()) {
|
||||
log.log(Level.SEVERE, "\t\t" + stack);
|
||||
}
|
||||
}
|
||||
long currentTime = System.currentTimeMillis(); // Paper - do we REALLY need to call this method multiple times?
|
||||
if (lastTick != 0 && currentTime > lastTick + earlyWarningEvery && !Boolean.getBoolean("disable.watchdog")) // Paper - Add property to disable and short timeout
|
||||
{
|
||||
// Paper start
|
||||
boolean isLongTimeout = currentTime > lastTick + timeoutTime;
|
||||
// Don't spam short dumps
|
||||
if (!isLongTimeout && (earlyWarningEvery <= 0 || !hasStarted || currentTime < lastEarlyWarning + earlyWarningEvery || currentTime < lastTick + earlyWarningDelay))
|
||||
continue;
|
||||
lastEarlyWarning = currentTime;
|
||||
// Paper end
|
||||
Logger log = Bukkit.getServer().getLogger();
|
||||
// Paper start - Different message when it's a short timeout
|
||||
if (isLongTimeout) {
|
||||
log.log(Level.SEVERE, "The server has stopped responding!");
|
||||
log.log(Level.SEVERE, "Please report this to https://github.com/Akarin-project/Akarin/issues"); // Akarin
|
||||
log.log(Level.SEVERE, "Be sure to include ALL relevant console errors and Minecraft crash reports");
|
||||
log.log(Level.SEVERE, "Akarin version: " + Bukkit.getServer().getVersion()); // Akarin
|
||||
//
|
||||
if (net.minecraft.server.World.haveWeSilencedAPhysicsCrash) {
|
||||
log.log(Level.SEVERE, "------------------------------");
|
||||
log.log(Level.SEVERE, "During the run of the server, a physics stackoverflow was supressed");
|
||||
log.log(Level.SEVERE, "near " + net.minecraft.server.World.blockLocation);
|
||||
}
|
||||
// Paper start - Warn in watchdog if an excessive velocity was ever set
|
||||
if (org.bukkit.craftbukkit.CraftServer.excessiveVelEx != null) {
|
||||
log.log(Level.SEVERE, "------------------------------");
|
||||
log.log(Level.SEVERE, "During the run of the server, a plugin set an excessive velocity on an entity");
|
||||
log.log(Level.SEVERE, "This may be the cause of the issue, or it may be entirely unrelated");
|
||||
log.log(Level.SEVERE, org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getMessage());
|
||||
for (StackTraceElement stack : org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getStackTrace()) {
|
||||
log.log(Level.SEVERE, "\t\t" + stack);
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
} else {
|
||||
log.log(Level.SEVERE, "The server has not responded for " + earlyWarningEvery / 1000 + " seconds! Creating thread dump");
|
||||
}
|
||||
// Paper end - Different message for short timeout
|
||||
log.log(Level.SEVERE, "------------------------------");
|
||||
log.log(Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Akarin!):");
|
||||
log.log(Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):");
|
||||
dumpThread(ManagementFactory.getThreadMXBean().getThreadInfo(MinecraftServer.getServer().primaryThread.getId(), Integer.MAX_VALUE), log);
|
||||
log.log(Level.SEVERE, "------------------------------");
|
||||
//
|
||||
log.log(Level.SEVERE, "Entire Thread Dump:");
|
||||
ThreadInfo[] threads = ManagementFactory.getThreadMXBean().dumpAllThreads(true, true);
|
||||
for (ThreadInfo thread : threads) {
|
||||
dumpThread(thread, log);
|
||||
}
|
||||
log.log(Level.SEVERE, "------------------------------");
|
||||
// Paper start - Only print full dump on long timeouts
|
||||
if (isLongTimeout) {
|
||||
log.log(Level.SEVERE, "Entire Thread Dump:");
|
||||
ThreadInfo[] threads = ManagementFactory.getThreadMXBean().dumpAllThreads(true, true);
|
||||
for (ThreadInfo thread : threads) {
|
||||
dumpThread(thread, log);
|
||||
}
|
||||
log.log(Level.SEVERE, "------------------------------");
|
||||
|
||||
if (restart) RestartCommand.restart(); // GC Inlined
|
||||
break;
|
||||
if (restart) {
|
||||
RestartCommand.restart();
|
||||
}
|
||||
break;
|
||||
} // Paper end
|
||||
}
|
||||
|
||||
try {
|
||||
sleep(9000); // Akarin
|
||||
sleep(1000); // Paper - Reduce check time to every second instead of every ten seconds, more consistent and allows for short timeout
|
||||
} catch (InterruptedException ex) {
|
||||
interrupt();
|
||||
}
|
||||
|
||||
@@ -14,9 +14,7 @@ public abstract class MixinAsyncCatcher {
|
||||
|
||||
@Overwrite
|
||||
public static void catchOp(String reason) {
|
||||
if (enabled) {
|
||||
if (Akari.isPrimaryThread()) return;
|
||||
|
||||
if (enabled && !Akari.isPrimaryThread()) {
|
||||
if (AkarinGlobalConfig.throwOnAsyncCaught) {
|
||||
throw new IllegalStateException("Asynchronous " + reason + "!");
|
||||
} else {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -395,8 +395,8 @@ public class PlayerChunkMap {
|
||||
// Paper start - Separate into two methods
|
||||
public void a(int i) {
|
||||
i = MathHelper.clamp(i, 3, 32);
|
||||
if (i != this.j) { // Akarin
|
||||
int j = i - this.j; // Akarin
|
||||
if (i != this.j) {
|
||||
int j = i - this.j;
|
||||
managedPlayersLock.readLock().lock(); // Akarin
|
||||
ArrayList arraylist = Lists.newArrayList(this.managedPlayers);
|
||||
managedPlayersLock.readLock().unlock(); // Akarin
|
||||
|
||||
@@ -92,6 +92,7 @@ import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.Recipe;
|
||||
import org.bukkit.inventory.ShapedRecipe;
|
||||
import org.bukkit.inventory.ShapelessRecipe;
|
||||
import org.bukkit.loot.LootTable;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
@@ -119,7 +120,6 @@ import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterators;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
@@ -1899,6 +1899,13 @@ public final class CraftServer implements Server {
|
||||
}
|
||||
}
|
||||
|
||||
public LootTable getLootTable(NamespacedKey key) {
|
||||
Validate.notNull(key, "NamespacedKey cannot be null");
|
||||
|
||||
LootTableRegistry registry = getServer().aP(); // PAIL getLootTableRegistry
|
||||
return new CraftLootTable(key, registry.a(CraftNamespacedKey.toMinecraft(key))); // PAIL rename getLootTable
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public UnsafeValues getUnsafe() {
|
||||
@@ -1992,17 +1999,20 @@ public final class CraftServer implements Server {
|
||||
|
||||
@Override
|
||||
public void reloadPermissions() {
|
||||
((SimplePluginManager) pluginManager).clearPermissions();
|
||||
loadCustomPermissions();
|
||||
pluginManager.clearPermissions();
|
||||
if (com.destroystokyo.paper.PaperConfig.loadPermsBeforePlugins) loadCustomPermissions();
|
||||
for (Plugin plugin : pluginManager.getPlugins()) {
|
||||
plugin.getDescription().getPermissions().forEach((perm) -> {
|
||||
for (Permission perm : plugin.getDescription().getPermissions()) {
|
||||
try {
|
||||
pluginManager.addPermission(perm);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
getLogger().log(Level.WARNING, "Plugin " + plugin.getDescription().getFullName() + " tried to register permission '" + perm.getName() + "' but it's already registered", ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!com.destroystokyo.paper.PaperConfig.loadPermsBeforePlugins) loadCustomPermissions();
|
||||
DefaultPermissions.registerCorePermissions();
|
||||
CraftDefaultPermissions.registerCorePermissions();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.destroystokyo.paper.profile.CraftPlayerProfile;
|
||||
import com.destroystokyo.paper.profile.PlayerProfile;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import io.netty.buffer.Unpooled;
|
||||
@@ -17,7 +16,6 @@ import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -131,7 +129,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
private boolean hasPlayedBefore = false;
|
||||
private final ConversationTracker conversationTracker = new ConversationTracker();
|
||||
private final Set<String> channels = new HashSet<String>();
|
||||
private final Map<UUID, Set<WeakReference<Plugin>>> hiddenPlayers = Collections.synchronizedMap(new HashMap<>()); // Akarin
|
||||
private final Map<UUID, Set<WeakReference<Plugin>>> hiddenPlayers = new java.util.concurrent.ConcurrentHashMap<>(); // Akarin
|
||||
private static final WeakHashMap<Plugin, WeakReference<Plugin>> pluginWeakReferences = new WeakHashMap<>();
|
||||
private int hash = 0;
|
||||
private double health = 20;
|
||||
@@ -1199,14 +1197,12 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
EntityTracker tracker = ((WorldServer) entity.world).tracker;
|
||||
// Paper end
|
||||
|
||||
tracker.entriesLock.updateLock().lock(); // Akarin
|
||||
tracker.entriesLock.writeLock().lock(); // Akarin
|
||||
EntityTrackerEntry entry = tracker.trackedEntities.get(other.getId());
|
||||
if (entry != null) {
|
||||
tracker.entriesLock.writeLock().lock(); // Akarin
|
||||
entry.clear(getHandle());
|
||||
tracker.entriesLock.writeLock().unlock(); // Akarin
|
||||
}
|
||||
tracker.entriesLock.updateLock().unlock(); // Akarin
|
||||
tracker.entriesLock.writeLock().unlock(); // Akarin
|
||||
|
||||
// Remove the hidden player from this player user list, if they're on it
|
||||
if (other.sentListPacket) {
|
||||
@@ -1253,14 +1249,12 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
|
||||
getHandle().playerConnection.sendPacket(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, other));
|
||||
|
||||
tracker.entriesLock.updateLock().lock(); // Akarin
|
||||
tracker.entriesLock.writeLock().lock(); // Akarin
|
||||
EntityTrackerEntry entry = tracker.trackedEntities.get(other.getId());
|
||||
if (entry != null && !entry.trackedPlayers.contains(getHandle())) {
|
||||
tracker.entriesLock.writeLock().lock(); // Akarin
|
||||
entry.updatePlayer(getHandle());
|
||||
tracker.entriesLock.writeLock().unlock(); // Akarin
|
||||
}
|
||||
tracker.entriesLock.updateLock().unlock(); // Akarin
|
||||
tracker.entriesLock.writeLock().unlock(); // Akarin
|
||||
}
|
||||
// Paper start
|
||||
private void reregisterPlayer(EntityPlayer player) {
|
||||
@@ -1871,7 +1865,6 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
public boolean getAffectsSpawning() {
|
||||
return this.getHandle().affectsSpawning;
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@Override
|
||||
public int getViewDistance() {
|
||||
@@ -1882,6 +1875,14 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
public void setViewDistance(int viewDistance) {
|
||||
((WorldServer) getHandle().world).getPlayerChunkMap().updateViewDistance(getHandle(), viewDistance);
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@Override
|
||||
public void updateCommands() {
|
||||
if (getHandle().playerConnection == null) return;
|
||||
|
||||
getHandle().server.getCommandDispatcher().a(getHandle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourcePack(String url, String hash) {
|
||||
|
||||
@@ -17,7 +17,6 @@ import com.destroystokyo.paper.event.executor.asm.ClassDefiner;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import io.akarin.api.internal.Akari;
|
||||
import io.akarin.api.internal.utils.thread.SuspendableExecutorCompletionService;
|
||||
// Paper end
|
||||
import io.akarin.server.core.AkarinGlobalConfig;
|
||||
|
||||
|
||||
Submodule work/Paper updated: 23764ece28...98b996cf40
Reference in New Issue
Block a user