diff --git a/sources/pom.xml b/sources/pom.xml index ac7e7229a..6d4f83f17 100644 --- a/sources/pom.xml +++ b/sources/pom.xml @@ -133,6 +133,11 @@ mixin 0.7.8-SNAPSHOT + + me.nallar.whocalled + WhoCalled + 1.1 + @@ -148,6 +153,10 @@ spongepowered-repo https://repo.spongepowered.org/maven/ + + nallar-repo + http://repo.nallar.me/ + diff --git a/sources/src/main/java/co/aikar/timings/TimingHandler.java b/sources/src/main/java/co/aikar/timings/TimingHandler.java index f51b4eeb2..38ea1a44f 100644 --- a/sources/src/main/java/co/aikar/timings/TimingHandler.java +++ b/sources/src/main/java/co/aikar/timings/TimingHandler.java @@ -24,6 +24,7 @@ package co.aikar.timings; import co.aikar.util.LoadingIntMap; +import io.akarin.api.Akari; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import org.bukkit.Bukkit; diff --git a/sources/src/main/java/io/akarin/api/Akari.java b/sources/src/main/java/io/akarin/api/Akari.java index b8c084fce..cc32887e4 100644 --- a/sources/src/main/java/io/akarin/api/Akari.java +++ b/sources/src/main/java/io/akarin/api/Akari.java @@ -8,12 +8,14 @@ import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.bukkit.entity.Minecart; import com.google.common.collect.Queues; import com.google.common.util.concurrent.ThreadFactoryBuilder; import co.aikar.timings.Timing; import co.aikar.timings.Timings; +import net.minecraft.server.MinecraftServer; public abstract class Akari { /** @@ -41,6 +43,12 @@ public abstract class Akari { */ public static final ExecutorCompletionService STAGE_TICK = new ExecutorCompletionService<>(Executors.newSingleThreadExecutor(Akari.STAGE_FACTORY)); + public static volatile boolean mayMock; + + public static boolean isPrimaryThread() { + return Thread.currentThread().equals(MinecraftServer.getServer().primaryThread); + } + /* * The unsafe */ diff --git a/sources/src/main/java/io/akarin/server/core/AkarinGlobalConfig.java b/sources/src/main/java/io/akarin/server/core/AkarinGlobalConfig.java index 27c03288b..95835cde8 100644 --- a/sources/src/main/java/io/akarin/server/core/AkarinGlobalConfig.java +++ b/sources/src/main/java/io/akarin/server/core/AkarinGlobalConfig.java @@ -189,6 +189,26 @@ public class AkarinGlobalConfig { asyncLightingThreads = getInt("core.async-lighting.executor-threads", 2); } + public static boolean enableMockPlugin; + private static void enableMockPlugin() { + enableMockPlugin = getBoolean("core.thread-safe.enable-mock-plugins", false); + } + + public static List mockPackageList; + private static void mockPluginList() { + mockPackageList = getList("core.thread-safe.mock-package-name-contains", Lists.newArrayList()); + } + + public static boolean enableAsyncCatcher; + private static void enableAsyncCatcher() { + enableAsyncCatcher = getBoolean("core.thread-safe.async-catcher.enable", false); + } + + public static boolean throwOnAsyncCaught; + private static void throwOnAsyncCaught() { + throwOnAsyncCaught = getBoolean("core.thread-safe.async-catcher.throw-on-caught", true); + } + public static boolean asyncLightingWorkStealing; private static void asyncLightingWorkStealing() { asyncLightingWorkStealing = getBoolean("core.async-lighting.use-work-stealing", false); diff --git a/sources/src/main/java/io/akarin/server/mixin/core/MixinCraftServer.java b/sources/src/main/java/io/akarin/server/mixin/core/MixinCraftServer.java index d2cca76b7..170d71da4 100644 --- a/sources/src/main/java/io/akarin/server/mixin/core/MixinCraftServer.java +++ b/sources/src/main/java/io/akarin/server/mixin/core/MixinCraftServer.java @@ -7,9 +7,14 @@ import org.spongepowered.asm.mixin.Mutable; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; +import io.akarin.server.core.AkarinGlobalConfig; +import me.nallar.whocalled.WhoCalled; +import net.minecraft.server.MinecraftServer; + @Mixin(value = CraftServer.class, remap = false) public class MixinCraftServer { @Shadow @Final @Mutable private String serverName; + @Shadow @Final protected MinecraftServer console; private boolean needApplyServerName = true; @Overwrite @@ -22,4 +27,18 @@ public class MixinCraftServer { } return serverName; } + + @Overwrite + public boolean isPrimaryThread() { + if (AkarinGlobalConfig.enableMockPlugin) { + // Mock forcely main thread plugins + String callerPackage = WhoCalled.$.getCallingClass().getPackage().getName(); + if (callerPackage.startsWith("net.minecraft") || callerPackage.startsWith("org.bukkit") || + callerPackage.startsWith("co.aikar") || callerPackage.startsWith("io.akarin")) return Thread.currentThread().equals(console.primaryThread); + for (String contains : AkarinGlobalConfig.mockPackageList) { + if (callerPackage.contains(contains)) return true; + } + } + return Thread.currentThread().equals(console.primaryThread); + } } diff --git a/sources/src/main/java/io/akarin/server/mixin/core/MixinTimingHandler.java b/sources/src/main/java/io/akarin/server/mixin/core/MixinTimingHandler.java index 5e293cdba..ad0653ad1 100644 --- a/sources/src/main/java/io/akarin/server/mixin/core/MixinTimingHandler.java +++ b/sources/src/main/java/io/akarin/server/mixin/core/MixinTimingHandler.java @@ -20,7 +20,7 @@ public class MixinTimingHandler { @Overwrite public void stopTimingIfSync() { - if (Bukkit.isPrimaryThread()) { + if (Akari.isPrimaryThread()) { // Akarin stopTiming(true); // Avoid twice thread check } } @@ -38,7 +38,7 @@ public class MixinTimingHandler { start = 0; return; } else { - if (!sync && !Bukkit.isPrimaryThread()) { + if (!sync && !Akari.isPrimaryThread()) { // Akarin if (AkarinGlobalConfig.silentAsyncTimings) { Bukkit.getLogger().log(Level.SEVERE, "stopTiming called async for " + name); new Throwable().printStackTrace(); diff --git a/sources/src/main/java/io/akarin/server/mixin/lighting/MixinChunk.java b/sources/src/main/java/io/akarin/server/mixin/lighting/MixinChunk.java index 4ff00811a..3d9761279 100644 --- a/sources/src/main/java/io/akarin/server/mixin/lighting/MixinChunk.java +++ b/sources/src/main/java/io/akarin/server/mixin/lighting/MixinChunk.java @@ -45,6 +45,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import com.google.common.collect.Lists; +import io.akarin.api.Akari; import io.akarin.api.mixin.IMixinChunk; import io.akarin.api.mixin.IMixinWorldServer; import net.minecraft.server.BlockPosition; @@ -245,7 +246,7 @@ public abstract class MixinChunk implements IMixinChunk { return; } - if (Bukkit.isPrimaryThread()) { + if (Akari.isPrimaryThread()) { // Akarin try { this.lightExecutorService.execute(() -> { this.checkLightAsync(neighborChunks); diff --git a/sources/src/main/java/io/akarin/server/mixin/lighting/MixinWorldServer.java b/sources/src/main/java/io/akarin/server/mixin/lighting/MixinWorldServer.java index 05439b423..008dfb7fa 100644 --- a/sources/src/main/java/io/akarin/server/mixin/lighting/MixinWorldServer.java +++ b/sources/src/main/java/io/akarin/server/mixin/lighting/MixinWorldServer.java @@ -33,6 +33,7 @@ import org.bukkit.Bukkit; import org.spongepowered.asm.mixin.Mixin; import com.google.common.util.concurrent.ThreadFactoryBuilder; +import io.akarin.api.Akari; import io.akarin.api.mixin.IMixinChunk; import io.akarin.api.mixin.IMixinWorldServer; import io.akarin.server.core.AkarinGlobalConfig; @@ -240,7 +241,7 @@ public abstract class MixinWorldServer extends MixinWorld implements IMixinWorld neighbor.setLightUpdateTime(chunk.getWorld().getTime()); } - if (Bukkit.isPrimaryThread()) { + if (Akari.isPrimaryThread()) { // Akarin this.lightExecutorService.execute(() -> { this.checkLightAsync(lightType, pos, chunk, neighbors); }); diff --git a/sources/src/main/java/net/minecraft/server/PlayerConnection.java b/sources/src/main/java/net/minecraft/server/PlayerConnection.java index 42489ffe5..c3e505ee9 100644 --- a/sources/src/main/java/net/minecraft/server/PlayerConnection.java +++ b/sources/src/main/java/net/minecraft/server/PlayerConnection.java @@ -3,6 +3,7 @@ package net.minecraft.server; import com.google.common.primitives.Doubles; import com.google.common.primitives.Floats; +import io.akarin.api.Akari; import io.akarin.server.core.AkarinGlobalConfig; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; @@ -1384,7 +1385,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable { if (!async && s.startsWith("/")) { // Paper Start - if (!org.spigotmc.AsyncCatcher.shuttingDown && !org.bukkit.Bukkit.isPrimaryThread()) { + if (!org.spigotmc.AsyncCatcher.shuttingDown && !Akari.isPrimaryThread()) { // Akarin final String fCommandLine = s; MinecraftServer.LOGGER.log(org.apache.logging.log4j.Level.ERROR, "Command Dispatched Async: " + fCommandLine); MinecraftServer.LOGGER.log(org.apache.logging.log4j.Level.ERROR, "Please notify author of plugin causing this execution to fix this bug! see: http://bit.ly/1oSiM6C", new Throwable());