diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 815e8b2..1c3490d 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -420,7 +420,7 @@ if (wait > 100000) { - Thread.sleep(wait / 1000000); + utilizeCPU(wait); catchupTime = 0; continue; } @@ -1564,4 +1564,9 @@ file.mkdir(); return file; } + + protected void utilizeCPU(long nanos) throws InterruptedException + { + Thread.sleep(nanos / 1000000); + } } diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java index 6f9e9da..b907c12 100644 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java @@ -51,6 +51,7 @@ import org.ultramine.server.WorldsConfig.WorldConfig; import org.ultramine.server.bootstrap.UMBootstrap; import org.ultramine.server.internal.JLineSupport; +import org.ultramine.server.internal.UMHooks; import org.ultramine.server.util.BasicTypeParser; import org.ultramine.server.util.GlobalExecutors; import org.ultramine.server.world.WorldDescriptor; @@ -631,4 +632,10 @@ { return backupMgr; } + + @Override + protected void utilizeCPU(long nanos) throws InterruptedException + { + UMHooks.utilizeCPU(nanos); + } } \ No newline at end of file diff --git a/src/main/java/org/ultramine/permission/internal/SyncServerExecutorImpl.java b/src/main/java/org/ultramine/permission/internal/SyncServerExecutorImpl.java new file mode 100644 index 0000000..54d0db2 --- /dev/null +++ b/src/main/java/org/ultramine/permission/internal/SyncServerExecutorImpl.java @@ -0,0 +1,49 @@ +package org.ultramine.permission.internal; + +import com.google.common.collect.Queues; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent; +import org.ultramine.server.util.SyncServerExecutor; + +import java.util.Queue; + +public class SyncServerExecutorImpl extends SyncServerExecutor +{ + private final Queue queue = Queues.newConcurrentLinkedQueue(); + + public void register() + { + FMLCommonHandler.instance().bus().register(this); + } + + public void unregister() + { + FMLCommonHandler.instance().bus().unregister(this); + queue.clear(); + } + + @SubscribeEvent + public void onServerTick(TickEvent.ServerTickEvent e) + { + if(e.phase == TickEvent.Phase.END) + { + for(Runnable toRun; (toRun = queue.poll()) != null;) + toRun.run(); + } + } + + public boolean processOneTask() + { + Runnable toRun = queue.poll(); + if(toRun != null) + toRun.run(); + return toRun != null; + } + + @Override + public void execute(Runnable toRun) + { + queue.add(toRun); + } +} diff --git a/src/main/java/org/ultramine/server/UltramineServerModContainer.java b/src/main/java/org/ultramine/server/UltramineServerModContainer.java index fac59c9..6e81a3a 100644 --- a/src/main/java/org/ultramine/server/UltramineServerModContainer.java +++ b/src/main/java/org/ultramine/server/UltramineServerModContainer.java @@ -11,6 +11,7 @@ import org.ultramine.commands.CommandRegistry; import org.ultramine.commands.basic.BasicCommands; import org.ultramine.commands.basic.FastWarpCommand; +import org.ultramine.commands.basic.GenWorldCommand; import org.ultramine.commands.basic.OpenInvCommands; import org.ultramine.commands.basic.TechCommands; import org.ultramine.commands.basic.VanillaCommands; @@ -19,6 +20,7 @@ import org.ultramine.permission.IPermissionManager; import org.ultramine.permission.MinecraftPermissions; import org.ultramine.permission.commands.BasicPermissionCommands; +import org.ultramine.permission.internal.SyncServerExecutorImpl; import org.ultramine.server.chunk.ChunkGenerationQueue; import org.ultramine.server.chunk.ChunkProfiler; import org.ultramine.server.data.Databases; @@ -133,7 +135,7 @@ { if(e.getSide().isServer()) ConfigurationHandler.saveServerConfig(); - (GlobalExecutors.nextTick()).register(); + ((SyncServerExecutorImpl) GlobalExecutors.nextTick()).register(); } catch (Throwable t) { @@ -171,6 +173,7 @@ e.registerCommands(VanillaCommands.class); e.registerCommands(BasicCommands.class); e.registerCommands(TechCommands.class); + e.registerCommands(GenWorldCommand.class); e.registerCommands(EconomyCommands.class); e.registerCommands(OpenInvCommands.class); @@ -244,6 +247,7 @@ MinecraftServer.getServer().getMultiWorld().unregister(); ChunkGenerationQueue.instance().unregister(); ChunkProfiler.instance().setEnabled(false); + ((SyncServerExecutorImpl) GlobalExecutors.nextTick()).unregister(); if(e.getSide().isServer()) { diff --git a/src/main/java/org/ultramine/server/internal/UMHooks.java b/src/main/java/org/ultramine/server/internal/UMHooks.java index d61cf60..91a4a9e 100644 --- a/src/main/java/org/ultramine/server/internal/UMHooks.java +++ b/src/main/java/org/ultramine/server/internal/UMHooks.java @@ -15,10 +15,13 @@ import net.minecraft.util.IChatComponent; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.ultramine.permission.internal.SyncServerExecutorImpl; +import org.ultramine.server.chunk.ChunkGenerationQueue; import org.ultramine.server.event.WorldEventProxy; import org.ultramine.server.event.WorldUpdateObject; import com.mojang.authlib.GameProfile; +import org.ultramine.server.util.GlobalExecutors; public class UMHooks { @@ -144,4 +147,27 @@ text.setChatStyle(msg.getChatStyle()); return text; } + + private static final long MS = 1_000_000; + private static final long BREAK_THRESHOLD = 100_000; + private static final long SLEEP_THRESHOLD = 2 * MS; + private static final long CHUNK_GEN_THRESHOLD = 10 * MS; + + /** Called from main thread instead of Thread.sleep(nanos / 1000000) to wait until next tick time */ + public static void utilizeCPU(long nanos) throws InterruptedException + { + long till = System.nanoTime() + nanos; + long toWait; + while((toWait = till - System.nanoTime()) > BREAK_THRESHOLD) + { + if(toWait <= SLEEP_THRESHOLD || !doOneAction(toWait)) + Thread.sleep((till - System.nanoTime()) >= MS ? 1 : 0); + } + } + + private static boolean doOneAction(long toWait) + { + return ((SyncServerExecutorImpl) GlobalExecutors.nextTick()).processOneTask() || + toWait > CHUNK_GEN_THRESHOLD && ChunkGenerationQueue.instance().generateOneChunk(); + } } diff --git a/src/main/java/org/ultramine/server/util/GlobalExecutors.java b/src/main/java/org/ultramine/server/util/GlobalExecutors.java index 613bd08..46175b3 100644 --- a/src/main/java/org/ultramine/server/util/GlobalExecutors.java +++ b/src/main/java/org/ultramine/server/util/GlobalExecutors.java @@ -8,6 +8,7 @@ import java.util.concurrent.TimeUnit; import com.google.common.util.concurrent.ThreadFactoryBuilder; +import org.ultramine.permission.internal.SyncServerExecutorImpl; public class GlobalExecutors { @@ -17,7 +18,7 @@ 60L, TimeUnit.SECONDS, new SynchronousQueue(), new ThreadFactoryBuilder().setNameFormat("UM IO cached #%d").setDaemon(true).build()); - private static final SyncServerExecutor sync = new SyncServerExecutor(); + private static final SyncServerExecutor sync = new SyncServerExecutorImpl(); /** * Обрабатывает задачи на сохранение чего-либо на диск/в БД. Используется diff --git a/src/main/java/org/ultramine/server/util/SyncServerExecutor.java b/src/main/java/org/ultramine/server/util/SyncServerExecutor.java index 3acf99d..8ae633a 100644 --- a/src/main/java/org/ultramine/server/util/SyncServerExecutor.java +++ b/src/main/java/org/ultramine/server/util/SyncServerExecutor.java @@ -11,35 +11,10 @@ import cpw.mods.fml.common.eventhandler.SubscribeEvent; import cpw.mods.fml.common.gameevent.TickEvent; -public class SyncServerExecutor implements Executor +public abstract class SyncServerExecutor implements Executor { - private final Queue queue = Queues.newConcurrentLinkedQueue(); - - public void register() - { - FMLCommonHandler.instance().bus().register(this); - } - - public void unregister() - { - FMLCommonHandler.instance().bus().unregister(this); - } - - @SubscribeEvent - public void onServerTick(TickEvent.ServerTickEvent e) - { - if(e.phase == TickEvent.Phase.END) - { - for(Runnable toRun; (toRun = queue.poll()) != null;) - toRun.run(); - } - } - @Override - public void execute(Runnable toRun) - { - queue.add(toRun); - } + public abstract void execute(Runnable toRun); public CompletableFuture completable(Runnable toRun) {