diff --git a/WindSpigot-Server/src/main/java/ga/windpvp/windspigot/async/entitytracker/MultithreadedEntityTracker.java b/WindSpigot-Server/src/main/java/ga/windpvp/windspigot/async/entitytracker/MultithreadedEntityTracker.java new file mode 100644 index 00000000..eb86cf23 --- /dev/null +++ b/WindSpigot-Server/src/main/java/ga/windpvp/windspigot/async/entitytracker/MultithreadedEntityTracker.java @@ -0,0 +1,49 @@ +package ga.windpvp.windspigot.async.entitytracker; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import ga.windpvp.windspigot.async.AsyncUtil; +import ga.windpvp.windspigot.config.WindSpigotConfig; +import net.minecraft.server.EntityTracker; +import net.minecraft.server.WorldServer; + +public class MultithreadedEntityTracker extends EntityTracker { + + private static final ExecutorService trackingThreadExecutor = Executors.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("WindSpigot Entity Tracker Thread").build()); + private final WorldServer worldServer; + + public MultithreadedEntityTracker(WorldServer worldserver) { + super(worldserver); + this.worldServer = worldserver; + } + + @Override + public void updatePlayers() { + int offset = 0; + + for (int i = 1; i <= WindSpigotConfig.trackingThreads; i++) { + final int finalOffset = offset++; + + AsyncUtil.run(() -> { + for (int index = finalOffset; index < c.size(); index += WindSpigotConfig.trackingThreads) { + c.get(index).update(); + } + worldServer.ticker.getLatch().decrement(); + + }, trackingThreadExecutor); + + } + try { + worldServer.ticker.getLatch().waitTillZero(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + worldServer.ticker.getLatch().reset(); + } + + public static ExecutorService getExecutor() { + return trackingThreadExecutor; + } +} diff --git a/WindSpigot-Server/src/main/java/ga/windpvp/windspigot/config/WindSpigotConfig.java b/WindSpigot-Server/src/main/java/ga/windpvp/windspigot/config/WindSpigotConfig.java index 452ef2ba..d46f9635 100644 --- a/WindSpigot-Server/src/main/java/ga/windpvp/windspigot/config/WindSpigotConfig.java +++ b/WindSpigot-Server/src/main/java/ga/windpvp/windspigot/config/WindSpigotConfig.java @@ -116,7 +116,8 @@ static void loadComments() { c.addComment("settings.pearl-passthrough", "Configuration for ender pearls passing through certain blocks. (Credits to FlamePaper)"); c.addComment("settings.command", "Configuration for WindSpigot's commands"); c.addComment("settings.max-tick-time", "Configuration for maximum entity tick time"); - c.addComment("settings.async.entity-tracking.enable", "Enables asynchronous entity tracking"); + c.addComment("settings.async.entity-tracking.enable", "Enables multithreaded entity tracking"); + c.addComment("settings.async.entity-tracking.full-async", "Enables a faster, fully async tracker. May have issues with plugins"); c.addComment("settings.async.entity-tracking.threads", "The amount of threads used for async entity tracking per world, increase or decrease this based on your server load."); c.addComment("settings.async.entity-tracking", "Configuration for the async entity tracker."); c.addComment("settings.thread-affinity", "Only switch to true if your OS is properly configured!! (See https://github.com/OpenHFT/Java-Thread-Affinity#isolcpus) \nWhen properly configured on the OS this allocates an entire cpu core to the server, it improves performance but uses more cpu."); @@ -238,10 +239,12 @@ private static String getString(String path, String def) { } public static boolean disableTracking; + public static boolean fullAsyncTracking; public static int trackingThreads; private static void tracking() { disableTracking = !getBoolean("settings.async.entity-tracking.enable", true); + fullAsyncTracking = getBoolean("settings.async.entity-tracking.full-async", false); trackingThreads = getInt("settings.async.entity-tracking.threads", 4); } diff --git a/WindSpigot-Server/src/main/java/ga/windpvp/windspigot/world/WorldTicker.java b/WindSpigot-Server/src/main/java/ga/windpvp/windspigot/world/WorldTicker.java index 15ebe974..6f44e88e 100644 --- a/WindSpigot-Server/src/main/java/ga/windpvp/windspigot/world/WorldTicker.java +++ b/WindSpigot-Server/src/main/java/ga/windpvp/windspigot/world/WorldTicker.java @@ -31,7 +31,7 @@ public WorldTicker(WorldServer worldServer) { @Override public void run() { - run(!WindSpigotConfig.disableTracking); + run((!WindSpigotConfig.disableTracking && WindSpigotConfig.fullAsyncTracking)); } // This is mostly copied code from world ticking @@ -41,13 +41,6 @@ private void run(boolean handleTrackerAsync) { CrashReport crashreport; try { - if (handleTrackerAsync && hasTracked) { - latch.waitTillZero(); - latch.reset(); - for (EntityPlayer player : MinecraftServer.getServer().getPlayerList().players) { - player.playerConnection.sendQueuedPackets(); - } - } worldserver.timings.doTick.startTiming(); // Spigot worldserver.doTick(); worldserver.timings.doTick.stopTiming(); // Spigot diff --git a/WindSpigot-Server/src/main/java/net/minecraft/server/WorldServer.java b/WindSpigot-Server/src/main/java/net/minecraft/server/WorldServer.java index 1d15bfca..a8e00b08 100644 --- a/WindSpigot-Server/src/main/java/net/minecraft/server/WorldServer.java +++ b/WindSpigot-Server/src/main/java/net/minecraft/server/WorldServer.java @@ -27,6 +27,7 @@ import com.google.common.util.concurrent.ListenableFuture; import ga.windpvp.windspigot.async.entitytracker.AsyncEntityTracker; +import ga.windpvp.windspigot.async.entitytracker.MultithreadedEntityTracker; import ga.windpvp.windspigot.config.WindSpigotConfig; import ga.windpvp.windspigot.world.WorldTicker; @@ -81,8 +82,10 @@ public WorldServer(MinecraftServer minecraftserver, IDataManager idatamanager, W // WindSpigot - async entity tracking if (WindSpigotConfig.disableTracking) { this.tracker = new EntityTracker(this); + } else if (WindSpigotConfig.fullAsyncTracking) { + this.tracker = new AsyncEntityTracker(this); } else { - this.tracker = new AsyncEntityTracker(this); + this.tracker = new MultithreadedEntityTracker(this); } this.manager = new PlayerChunkMap(this, spigotConfig.viewDistance); // Spigot this.worldProvider.a(this);