diff --git a/src/main/java/net/minestom/server/UpdateManager.java b/src/main/java/net/minestom/server/UpdateManager.java index cbeb4ccb0..eb1842975 100644 --- a/src/main/java/net/minestom/server/UpdateManager.java +++ b/src/main/java/net/minestom/server/UpdateManager.java @@ -13,11 +13,11 @@ import net.minestom.server.thread.ThreadProvider; import net.minestom.server.utils.thread.MinestomThread; import net.minestom.server.utils.validate.Check; -import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; -import java.util.function.Consumer; +import java.util.function.DoubleConsumer; /** * Manager responsible for the server ticks. @@ -36,8 +36,8 @@ public final class UpdateManager { private ThreadProvider threadProvider; - private final ArrayList tickStartCallbacks = new ArrayList<>(); - private final ArrayList> tickEndCallbacks = new ArrayList<>(); + private final ConcurrentLinkedQueue tickStartCallbacks = new ConcurrentLinkedQueue<>(); + private final ConcurrentLinkedQueue tickEndCallbacks = new ConcurrentLinkedQueue<>(); { //threadProvider = new PerInstanceThreadProvider(); @@ -63,28 +63,33 @@ public final class UpdateManager { long currentTime; while (!stopRequested) { currentTime = System.nanoTime(); - final long time = System.currentTimeMillis(); + final long tickStart = System.currentTimeMillis(); - //Tick Callbacks - tickStartCallbacks.forEach(Runnable::run); + // Tick start callbacks + if (!tickStartCallbacks.isEmpty()) { + Runnable callback; + while ((callback = tickStartCallbacks.poll()) != null) { + callback.run(); + } + } List> futures; // Server tick (instance/chunk/entity) // Synchronize with the update manager instance, like the signal for chunk load/unload synchronized (this) { - futures = threadProvider.update(time); + futures = threadProvider.update(tickStart); } // Waiting players update (newly connected clients waiting to get into the server) entityManager.updateWaitingPlayers(); // Keep Alive Handling - final KeepAlivePacket keepAlivePacket = new KeepAlivePacket(time); + final KeepAlivePacket keepAlivePacket = new KeepAlivePacket(tickStart); for (Player player : connectionManager.getOnlinePlayers()) { - final long lastKeepAlive = time - player.getLastKeepAlive(); + final long lastKeepAlive = tickStart - player.getLastKeepAlive(); if (lastKeepAlive > KEEP_ALIVE_DELAY && player.didAnswerKeepAlive()) { - player.refreshKeepAlive(time); + player.refreshKeepAlive(tickStart); player.getPlayerConnection().sendPacket(keepAlivePacket); } else if (lastKeepAlive >= KEEP_ALIVE_KICK) { player.kick(TIMEOUT_TEXT); @@ -100,13 +105,17 @@ public final class UpdateManager { } - //Tick Callbacks - double tickTime = (System.nanoTime() - currentTime) / 1000000D; - tickEndCallbacks.forEach(doubleConsumer -> doubleConsumer.accept(tickTime)); + // Tick end callbacks + if (!tickEndCallbacks.isEmpty()) { + final double tickEnd = (System.nanoTime() - currentTime) / 1000000D; + DoubleConsumer callback; + while ((callback = tickEndCallbacks.poll()) != null) { + callback.accept(tickEnd); + } + } // Sleep until next tick - long sleepTime = (tickDistance - (System.nanoTime() - currentTime)) / 1000000; - sleepTime = Math.max(1, sleepTime); + final long sleepTime = Math.max(1, (tickDistance - (System.nanoTime() - currentTime)) / 1000000); try { Thread.sleep(sleepTime); @@ -194,20 +203,42 @@ public final class UpdateManager { this.threadProvider.onChunkUnload(instance, chunkX, chunkZ); } + /** + * Adds a callback executed at the start of the next server tick. + * + * @param callback the tick start callback + */ public void addTickStartCallback(Runnable callback) { - tickStartCallbacks.add(callback); + this.tickStartCallbacks.add(callback); } + /** + * Removes a tick start callback. + * + * @param callback the callback to remove + */ public void removeTickStartCallback(Runnable callback) { - tickStartCallbacks.remove(callback); + this.tickStartCallbacks.remove(callback); } - public void addTickEndCallback(Consumer callback) { - tickEndCallbacks.add(callback); + /** + * Adds a callback executed at the end of the next server tick. + *

+ * The double in the consumer represents the duration (in ms) of the tick. + * + * @param callback the tick end callback + */ + public void addTickEndCallback(DoubleConsumer callback) { + this.tickEndCallbacks.add(callback); } - public void removeTickEndCallback(Consumer callback) { - tickEndCallbacks.remove(callback); + /** + * Removes a tick end callback. + * + * @param callback the callback to remove + */ + public void removeTickEndCallback(DoubleConsumer callback) { + this.tickEndCallbacks.remove(callback); } /** diff --git a/src/main/java/net/minestom/server/network/packet/client/handler/ClientPacketsHandler.java b/src/main/java/net/minestom/server/network/packet/client/handler/ClientPacketsHandler.java index 02ae57eee..2b6650afd 100644 --- a/src/main/java/net/minestom/server/network/packet/client/handler/ClientPacketsHandler.java +++ b/src/main/java/net/minestom/server/network/packet/client/handler/ClientPacketsHandler.java @@ -9,9 +9,9 @@ public class ClientPacketsHandler { // Max packet id private static final int SIZE = 0x30; - private final Supplier[] supplierAccesses = new Supplier[SIZE]; + private final Supplier[] supplierAccesses = new Supplier[SIZE]; - public void register(int id, Supplier packetSupplier) { + public void register(int id, Supplier packetSupplier) { supplierAccesses[id] = packetSupplier; } @@ -19,13 +19,13 @@ public class ClientPacketsHandler { if (id > SIZE) throw new IllegalStateException("Packet ID 0x" + Integer.toHexString(id) + " has been tried to be parsed, debug needed"); - Supplier supplier = supplierAccesses[id]; + Supplier supplier = supplierAccesses[id]; if (supplierAccesses[id] == null) throw new IllegalStateException("Packet id 0x" + Integer.toHexString(id) + " isn't registered!"); - ClientPacket packet = supplier.get(); + //ClientPacket packet = supplier.get(); //System.out.println("RECEIVED PACKET 0x" + Integer.toHexString(id)+" : "+packet.getClass().getSimpleName()); - return packet; + return supplier.get(); } } diff --git a/src/main/java/net/minestom/server/thread/ThreadProvider.java b/src/main/java/net/minestom/server/thread/ThreadProvider.java index c3eed3bd9..0f5e1fa51 100644 --- a/src/main/java/net/minestom/server/thread/ThreadProvider.java +++ b/src/main/java/net/minestom/server/thread/ThreadProvider.java @@ -99,9 +99,7 @@ public abstract class ThreadProvider { this.pool = new MinestomThread(threadCount, MinecraftServer.THREAD_NAME_TICK); } - /** - * INSTANCE UPDATE - */ + // INSTANCE UPDATE /** * Process a whole tick for a chunk. @@ -146,9 +144,7 @@ public abstract class ThreadProvider { chunk.tick(time, instance); } - /** - * ENTITY UPDATE - */ + // ENTITY UPDATE /** * Executes an entity tick (all entities type creatures/objects/players) in an instance's chunk.