diff --git a/src/main/java/net/minestom/server/MinecraftServer.java b/src/main/java/net/minestom/server/MinecraftServer.java index 5abf69e3e..c7d2c4d4e 100644 --- a/src/main/java/net/minestom/server/MinecraftServer.java +++ b/src/main/java/net/minestom/server/MinecraftServer.java @@ -136,7 +136,7 @@ public final class MinecraftServer { private static int compressionThreshold = 256; private static boolean packetCaching = true; private static boolean groupedPacket = true; - private static boolean waitMonitoring = false; + private static boolean waitMonitoring = true; private static ResponseDataConsumer responseDataConsumer; private static String brandName = "Minestom"; private static Difficulty difficulty = Difficulty.NORMAL; diff --git a/src/main/java/net/minestom/server/UpdateManager.java b/src/main/java/net/minestom/server/UpdateManager.java index b822116a8..e67ea74f9 100644 --- a/src/main/java/net/minestom/server/UpdateManager.java +++ b/src/main/java/net/minestom/server/UpdateManager.java @@ -86,10 +86,9 @@ public final class UpdateManager { // Monitoring if (!tickMonitors.isEmpty()) { - // TODO use value final double acquisitionTimeMs = Acquisition.getCurrentWaitMonitoring() / 1e6D; final double tickTimeMs = tickTime / 1e6D; - final TickMonitor tickMonitor = new TickMonitor(tickTimeMs); + final TickMonitor tickMonitor = new TickMonitor(tickTimeMs, acquisitionTimeMs); this.tickMonitors.forEach(consumer -> consumer.accept(tickMonitor)); Acquisition.resetWaitMonitoring(); diff --git a/src/main/java/net/minestom/server/lock/AcquirableCollection.java b/src/main/java/net/minestom/server/lock/AcquirableCollection.java new file mode 100644 index 000000000..c361ebeb7 --- /dev/null +++ b/src/main/java/net/minestom/server/lock/AcquirableCollection.java @@ -0,0 +1,23 @@ +package net.minestom.server.lock; + +import net.minestom.server.utils.collection.CollectionView; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.function.Consumer; + +public class AcquirableCollection extends CollectionView> { + + private final Collection> acquirableCollection; + + public AcquirableCollection(@NotNull Collection> acquirableCollection) { + super(acquirableCollection, + LockedElement::getAcquiredElement, + Acquirable::unwrap); + this.acquirableCollection = acquirableCollection; + } + + public void forEachAcquire(@NotNull Consumer<@NotNull E> action) { + Acquisition.acquireForEach(acquirableCollection, action); + } +} diff --git a/src/main/java/net/minestom/server/monitoring/TickMonitor.java b/src/main/java/net/minestom/server/monitoring/TickMonitor.java index a92e5d40d..6e28a1c1d 100644 --- a/src/main/java/net/minestom/server/monitoring/TickMonitor.java +++ b/src/main/java/net/minestom/server/monitoring/TickMonitor.java @@ -3,12 +3,18 @@ package net.minestom.server.monitoring; public class TickMonitor { private final double tickTime; + private final double acquisitionTime; - public TickMonitor(double tickTime) { + public TickMonitor(double tickTime, double acquisitionTime) { this.tickTime = tickTime; + this.acquisitionTime = acquisitionTime; } public double getTickTime() { return tickTime; } + + public double getAcquisitionTime() { + return acquisitionTime; + } } \ No newline at end of file diff --git a/src/main/java/net/minestom/server/utils/collection/CollectionView.java b/src/main/java/net/minestom/server/utils/collection/CollectionView.java new file mode 100644 index 000000000..7fda7fc85 --- /dev/null +++ b/src/main/java/net/minestom/server/utils/collection/CollectionView.java @@ -0,0 +1,178 @@ +package net.minestom.server.utils.collection; + +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.Iterator; +import java.util.function.Function; + +/** + * A CollectionView is a class which is mapped to another collection + * and convert every result using a given function. It is more efficient + * than filling a new collection every time, as long as the two types are interchangeable. + *

+ * The view is not thread-safe. + * + * @param the type that the collection should return + * @param the type of the viewed collection + */ +public class CollectionView implements Collection { + + private final Collection collectionView; + private final Function toViewFunction; + private final Function toTypeFunction; + + public CollectionView(@NotNull Collection collectionView, + @NotNull Function toViewFunction, + @NotNull Function toTypeFunction) { + this.collectionView = collectionView; + this.toViewFunction = toViewFunction; + this.toTypeFunction = toTypeFunction; + } + + @Override + public int size() { + return collectionView.size(); + } + + @Override + public boolean isEmpty() { + return collectionView.isEmpty(); + } + + @Override + public boolean contains(Object o) { + try { + return collectionView.contains(toViewFunction.apply((E) o)); + } catch (ClassCastException e) { + return false; + } + } + + @NotNull + @Override + public Iterator iterator() { + return new IteratorView<>(collectionView.iterator(), toTypeFunction); + } + + @NotNull + @Override + public Object[] toArray() { + Object[] array = new Object[size()]; + + int i = 0; + for (E e : this) { + array[i++] = e; + } + + return array; + } + + @NotNull + @Override + public T1[] toArray(@NotNull T1[] a) { + int i = 0; + for (E e : this) { + a[i++] = (T1) e; + } + + return a; + } + + @Override + public boolean add(E e) { + return collectionView.add(toViewFunction.apply(e)); + } + + @Override + public boolean remove(Object o) { + try { + return collectionView.remove(toViewFunction.apply((E) o)); + } catch (ClassCastException e) { + return false; + } + } + + @Override + public boolean containsAll(@NotNull Collection c) { + for (Object e : c) { + if (!contains(e)) + return false; + } + + return true; + } + + @Override + public boolean addAll(@NotNull Collection c) { + boolean changed = false; + try { + for (Object e : c) { + if (add((E) e)) + changed = true; + } + } catch (ClassCastException ignored) { + } + + return changed; + } + + @Override + public boolean removeAll(@NotNull Collection c) { + boolean changed = false; + try { + for (Object e : c) { + if (remove(e)) + changed = true; + } + } catch (ClassCastException ignored) { + } + + return changed; + } + + @Override + public boolean retainAll(@NotNull Collection c) { + boolean changed = false; + try { + for (Object e : c) { + if (!contains(e)) { + remove(e); + changed = true; + } + } + } catch (ClassCastException ignored) { + } + + return changed; + } + + @Override + public void clear() { + this.collectionView.clear(); + } + + public static class IteratorView implements Iterator { + + private final Iterator iteratorView; + private final Function toTypeFunction; + + public IteratorView(Iterator iteratorView, + Function toTypeFunction) { + this.iteratorView = iteratorView; + this.toTypeFunction = toTypeFunction; + } + + @Override + public boolean hasNext() { + return iteratorView.hasNext(); + } + + @Override + public T next() { + final V viewElement = iteratorView.next(); + return toTypeFunction.apply(viewElement); + } + } + +} \ No newline at end of file diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index 043319dcc..d5be8779d 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -1,10 +1,8 @@ package demo; -import com.google.common.util.concurrent.AtomicDouble; import demo.generator.ChunkGeneratorDemo; import demo.generator.NoiseTestGenerator; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.TextColor; import net.minestom.server.MinecraftServer; import net.minestom.server.adventure.audience.Audiences; import net.minestom.server.chat.ColoredText; @@ -32,8 +30,8 @@ import net.minestom.server.item.ItemTag; import net.minestom.server.item.Material; import net.minestom.server.item.metadata.CompassMeta; import net.minestom.server.monitoring.BenchmarkManager; +import net.minestom.server.monitoring.TickMonitor; import net.minestom.server.network.ConnectionManager; -import net.minestom.server.ping.ResponseDataConsumer; import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.Position; import net.minestom.server.utils.Vector; @@ -43,8 +41,8 @@ import net.minestom.server.world.DimensionType; import java.util.Collection; import java.util.Collections; import java.util.Set; -import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicReference; public class PlayerInit { @@ -91,14 +89,14 @@ public class PlayerInit { } - private static AtomicDouble LAST_TICK_TIME = new AtomicDouble(); + private static AtomicReference LAST_TICK = new AtomicReference<>(); public static void init() { ConnectionManager connectionManager = MinecraftServer.getConnectionManager(); BenchmarkManager benchmarkManager = MinecraftServer.getBenchmarkManager(); MinecraftServer.getUpdateManager().addTickMonitor(tickMonitor -> - LAST_TICK_TIME.set(tickMonitor.getTickTime())); + LAST_TICK.set(tickMonitor)); MinecraftServer.getSchedulerManager().buildTask(() -> { @@ -110,9 +108,13 @@ public class PlayerInit { long ramUsage = benchmarkManager.getUsedMemory(); ramUsage /= 1e6; // bytes to MB + TickMonitor tickMonitor = LAST_TICK.get(); + final Component header = Component.text("RAM USAGE: " + ramUsage + " MB") .append(Component.newline()) - .append(Component.text("TICK TIME: " + MathUtils.round(LAST_TICK_TIME.get(), 2) + "ms")); + .append(Component.text("TICK TIME: " + MathUtils.round(tickMonitor.getTickTime(), 2) + "ms")) + .append(Component.newline()) + .append(Component.text("ACQ TIME: " + MathUtils.round(tickMonitor.getAcquisitionTime(), 2) + "ms")); final Component footer = benchmarkManager.getCpuMonitoringMessage(); Audiences.players().sendPlayerListHeaderAndFooter(header, footer);