diff --git a/sources/src/main/java/io/akarin/api/Akari.java b/sources/src/main/java/io/akarin/api/Akari.java new file mode 100644 index 000000000..70e66f4ef --- /dev/null +++ b/sources/src/main/java/io/akarin/api/Akari.java @@ -0,0 +1,54 @@ +package io.akarin.api; + +import java.lang.reflect.Method; +import java.util.Queue; +import java.util.concurrent.ThreadFactory; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.google.common.collect.Queues; +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +import co.aikar.timings.Timing; +import co.aikar.timings.Timings; + +public abstract class Akari { + /** + * A common logger used by mixin classes + */ + public final static Logger logger = LogManager.getLogger("Akarin"); + + /** + * Temporarily disable desync timings error, moreover it's worthless to trace async operation + */ + public static volatile boolean silentTiming; + + /** + * A common thread pool factory + */ + public static final ThreadFactory STAGE_FACTORY = new ThreadFactoryBuilder().setNameFormat("Akarin Schedule Thread - %1$d").build(); + + /** + * Main thread callback tasks + */ + public static final Queue callbackQueue = Queues.newConcurrentLinkedQueue(); + + /* + * Timings + */ + private static Timing callbackTiming; + + public static Timing callbackTiming() { + if (callbackTiming == null) { + try { + Method ofSafe = Timings.class.getDeclaredMethod("ofSafe", String.class); + ofSafe.setAccessible(true); + callbackTiming = (Timing) ofSafe.invoke(null, "Akarin - Callback"); + } catch (Throwable t) { + t.printStackTrace(); + } + } + return callbackTiming; + } +} diff --git a/sources/src/main/java/io/akarin/api/CheckedConcurrentLinkedQueue.java b/sources/src/main/java/io/akarin/api/CheckedConcurrentLinkedQueue.java new file mode 100644 index 000000000..d053bdf3c --- /dev/null +++ b/sources/src/main/java/io/akarin/api/CheckedConcurrentLinkedQueue.java @@ -0,0 +1,9 @@ +package io.akarin.api; + +import java.io.Serializable; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + +public class CheckedConcurrentLinkedQueue extends ConcurrentLinkedQueue implements Queue, Serializable { + +} \ No newline at end of file diff --git a/sources/src/main/java/io/akarin/api/LogWrapper.java b/sources/src/main/java/io/akarin/api/LogWrapper.java deleted file mode 100644 index 6164a4115..000000000 --- a/sources/src/main/java/io/akarin/api/LogWrapper.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.akarin.api; - -import java.util.concurrent.ThreadFactory; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; - -public abstract class LogWrapper { - /** - * A common logger used by mixin classes - */ - public final static Logger logger = LogManager.getLogger("Akarin"); - - /** - * Temporarily disable desync timings error, moreover it's worthless to trace async operation - */ - public static volatile boolean silentTiming; - - /** - * A common thread pool factory - */ - public static final ThreadFactory STAGE_FACTORY = new ThreadFactoryBuilder().setNameFormat("Akarin Schedule Thread - %1$d").build(); -} 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 fe30a6816..06e2dc4f8 100644 --- a/sources/src/main/java/io/akarin/server/core/AkarinGlobalConfig.java +++ b/sources/src/main/java/io/akarin/server/core/AkarinGlobalConfig.java @@ -14,7 +14,7 @@ import java.util.regex.Pattern; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; -import io.akarin.api.LogWrapper; +import io.akarin.api.Akari; public class AkarinGlobalConfig { @@ -35,7 +35,7 @@ public class AkarinGlobalConfig { config.load(CONFIG_FILE); } catch (IOException ex) { } catch (InvalidConfigurationException ex) { - LogWrapper.logger.error("Could not load akarin.yml, please correct your syntax errors", ex); + Akari.logger.error("Could not load akarin.yml, please correct your syntax errors", ex); throw Throwables.propagate(ex); } config.options().header(HEADER); @@ -56,7 +56,7 @@ public class AkarinGlobalConfig { } catch (InvocationTargetException ex) { throw Throwables.propagate(ex.getCause()); } catch (Exception ex) { - LogWrapper.logger.error("Error invoking " + method, ex); + Akari.logger.error("Error invoking " + method, ex); } } } @@ -65,7 +65,7 @@ public class AkarinGlobalConfig { try { config.save(CONFIG_FILE); } catch (IOException ex) { - LogWrapper.logger.error("Could not save " + CONFIG_FILE, ex); + Akari.logger.error("Could not save " + CONFIG_FILE, ex); } } diff --git a/sources/src/main/java/io/akarin/server/mixin/core/Bootstrap.java b/sources/src/main/java/io/akarin/server/mixin/core/Bootstrap.java index 1e3ba36b6..341605bd0 100644 --- a/sources/src/main/java/io/akarin/server/mixin/core/Bootstrap.java +++ b/sources/src/main/java/io/akarin/server/mixin/core/Bootstrap.java @@ -10,7 +10,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import io.akarin.api.LogWrapper; +import io.akarin.api.Akari; import io.akarin.server.core.AkarinGlobalConfig; @Mixin(value = Main.class, remap = false) @@ -29,7 +29,7 @@ public class Bootstrap { args = "ldc=*** Warning, you've not updated in a while! ***" )) private static void notifyUpdate(PrintStream stream, String text) { - LogWrapper.logger.warn("You've not updated in a while, the current version may outdated"); + Akari.logger.warn("You've not updated in a while, the current version may outdated"); } @Redirect(method = "main", at = @At( @@ -38,7 +38,7 @@ public class Bootstrap { args = "ldc=*** Please download a new build as per instructions from https://paperci.emc.gs/ ***" )) private static void notifyWebsite(PrintStream stream, String text) { - LogWrapper.logger.warn("Visit our website for latest information https://akarin.io/"); + Akari.logger.warn("Visit our website for latest information https://akarin.io/"); } @Redirect(method = "main", at = @At( @@ -47,6 +47,6 @@ public class Bootstrap { args = "ldc=Loading libraries, please wait..." )) private static void notifyLoading(PrintStream stream, String text) { - LogWrapper.logger.info("Loading libraries as parallel capable.."); + Akari.logger.info("Loading libraries as parallel capable.."); } } diff --git a/sources/src/main/java/io/akarin/server/mixin/core/MixinMinecraftServer.java b/sources/src/main/java/io/akarin/server/mixin/core/MixinMinecraftServer.java index 45b04e002..45ed44a18 100644 --- a/sources/src/main/java/io/akarin/server/mixin/core/MixinMinecraftServer.java +++ b/sources/src/main/java/io/akarin/server/mixin/core/MixinMinecraftServer.java @@ -1,5 +1,6 @@ package io.akarin.server.mixin.core; +import java.lang.reflect.InvocationTargetException; import java.util.List; import java.util.Queue; import java.util.concurrent.ExecutorCompletionService; @@ -14,8 +15,12 @@ import org.spongepowered.asm.mixin.Mutable; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; +import com.google.common.collect.Queues; + import co.aikar.timings.MinecraftTimings; -import io.akarin.api.LogWrapper; +import co.aikar.timings.Timing; +import co.aikar.timings.Timings; +import io.akarin.api.Akari; import net.minecraft.server.CrashReport; import net.minecraft.server.CustomFunctionData; import net.minecraft.server.EntityPlayer; @@ -58,7 +63,7 @@ public class MixinMinecraftServer { @Shadow public ServerConnection an() { return null; } @Shadow public CustomFunctionData aL() { return null; } - private final ExecutorCompletionService STAGE_ENTITY_TICK = new ExecutorCompletionService(Executors.newFixedThreadPool(1, LogWrapper.STAGE_FACTORY)); + private final ExecutorCompletionService STAGE_ENTITY_TICK = new ExecutorCompletionService(Executors.newFixedThreadPool(1, Akari.STAGE_FACTORY)); private void tickEntities(WorldServer world) { try { @@ -77,6 +82,11 @@ public class MixinMinecraftServer { @Overwrite public void D() throws InterruptedException { + Runnable runnable; + Akari.callbackTiming().startTiming(); + while ((runnable = Akari.callbackQueue.poll()) != null) runnable.run(); + Akari.callbackTiming().stopTiming(); + MinecraftTimings.bukkitSchedulerTimer.startTiming(); this.server.getScheduler().mainThreadHeartbeat(this.ticks); MinecraftTimings.bukkitSchedulerTimer.stopTiming(); @@ -90,10 +100,7 @@ public class MixinMinecraftServer { MinecraftTimings.minecraftSchedulerTimer.stopTiming(); MinecraftTimings.processQueueTimer.startTiming(); - Runnable runnable; - while ((runnable = processQueue.poll()) != null) { - runnable.run(); - } + while ((runnable = processQueue.poll()) != null) runnable.run(); MinecraftTimings.processQueueTimer.stopTiming(); MinecraftTimings.chunkIOTickTimer.startTiming(); @@ -115,7 +122,7 @@ public class MixinMinecraftServer { WorldServer entityWorld = worlds.get(i + 1 < worlds.size() ? i + 1 : 0); TileEntityHopper.skipHopperEvents = entityWorld.paperConfig.disableHopperMoveEvents || InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; - LogWrapper.silentTiming = true; + Akari.silentTiming = true; STAGE_ENTITY_TICK.submit(() -> tickEntities(entityWorld), null); try { @@ -138,7 +145,7 @@ public class MixinMinecraftServer { entityWorld.timings.tickEntities.stopTiming(); entityWorld.getTracker().updatePlayers(); - LogWrapper.silentTiming = false; + Akari.silentTiming = false; mainWorld.explosionDensityCache.clear(); // Paper - Optimize explosions } diff --git a/sources/src/main/java/io/akarin/server/mixin/core/MixinPlayerConnection.java b/sources/src/main/java/io/akarin/server/mixin/core/MixinPlayerConnection.java new file mode 100644 index 000000000..6ec221159 --- /dev/null +++ b/sources/src/main/java/io/akarin/server/mixin/core/MixinPlayerConnection.java @@ -0,0 +1,14 @@ +package io.akarin.server.mixin.core; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +import net.minecraft.server.PlayerConnection; + +@Mixin(value = PlayerConnection.class, remap = false) +public class MixinPlayerConnection { + @Overwrite + private long d() { + return System.currentTimeMillis(); + } +} 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 8c1822fd2..6eea9a3ff 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 @@ -8,7 +8,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; -import io.akarin.api.LogWrapper; +import io.akarin.api.Akari; @Mixin(targets = "co.aikar.timings.TimingHandler", remap = false) public class MixinTimingHandler { @@ -24,7 +24,7 @@ public class MixinTimingHandler { public void stopTiming() { if (enabled && --timingDepth == 0 && start != 0) { // Thread.currentThread() is an expensive operation, trying to avoid it - if (LogWrapper.silentTiming) { // It must be off-main thread now + if (Akari.silentTiming) { // It must be off-main thread now start = 0; return; } else { diff --git a/sources/src/main/java/io/akarin/server/mixin/core/MixinVersionCommand.java b/sources/src/main/java/io/akarin/server/mixin/core/MixinVersionCommand.java index 40af5bd22..148c185c6 100644 --- a/sources/src/main/java/io/akarin/server/mixin/core/MixinVersionCommand.java +++ b/sources/src/main/java/io/akarin/server/mixin/core/MixinVersionCommand.java @@ -9,7 +9,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; -import io.akarin.api.LogWrapper; +import io.akarin.api.Akari; import io.akarin.server.core.AkarinGlobalConfig; import net.minecraft.server.MCUtil; @@ -90,7 +90,7 @@ public class MixinVersionCommand { obtainVersion(currentSender); currentSender = null; // try release } else { - LogWrapper.logger.warn("A legacy version lookup was caught, legacy-versioning-compat enabled forcely!"); + Akari.logger.warn("A legacy version lookup was caught, legacy-versioning-compat enabled forcely!"); AkarinGlobalConfig.legacyVersioningCompat = true; AkarinGlobalConfig.set("bonus.legacy-versioning-compat", true); } diff --git a/sources/src/main/java/io/akarin/server/mixin/core/ParallelRegistry.java b/sources/src/main/java/io/akarin/server/mixin/core/ParallelRegistry.java index 957c43946..5c90c3633 100644 --- a/sources/src/main/java/io/akarin/server/mixin/core/ParallelRegistry.java +++ b/sources/src/main/java/io/akarin/server/mixin/core/ParallelRegistry.java @@ -10,7 +10,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import io.akarin.api.LogWrapper; +import io.akarin.api.Akari; import io.akarin.server.core.AkarinGlobalConfig; import net.minecraft.server.BiomeBase; import net.minecraft.server.Block; @@ -29,16 +29,16 @@ public class ParallelRegistry { /** * Registry order: SoundEffect -> Block */ - private static final ExecutorService STAGE_BLOCK = Executors.newSingleThreadExecutor(LogWrapper.STAGE_FACTORY); + private static final ExecutorService STAGE_BLOCK = Executors.newSingleThreadExecutor(Akari.STAGE_FACTORY); /** * Registry order: Item -> PotionBrewer & orderless: BlockFire, BiomeBase (After STAGE_BLOCK) */ - private static final ExecutorService STAGE_BLOCK_BASE = Executors.newFixedThreadPool(3, LogWrapper.STAGE_FACTORY); + private static final ExecutorService STAGE_BLOCK_BASE = Executors.newFixedThreadPool(3, Akari.STAGE_FACTORY); /** * Registry order: MobEffectList -> PotionRegistry & orderless: Enchantment, EntityTypes */ - private static final ExecutorService STAGE_STANDALONE = Executors.newFixedThreadPool(3, LogWrapper.STAGE_FACTORY); + private static final ExecutorService STAGE_STANDALONE = Executors.newFixedThreadPool(3, Akari.STAGE_FACTORY); private static final int TERMINATION_IN_SEC = AkarinGlobalConfig.registryTerminationSeconds;