Map API cleanup

This commit is contained in:
themode 2020-10-13 16:50:03 +02:00
parent 0e5831cdc3
commit 6e954082e1
13 changed files with 125 additions and 133 deletions

View File

@ -21,11 +21,17 @@ public class NotificationCenter {
private static final String IDENTIFIER = "minestom:notification";
/**
* Can't create an instance
* Can't create an instance, use the static methods instead.
*/
private NotificationCenter() {
}
/**
* Send a {@link Notification} to one player.
*
* @param notification the {@link Notification} to send
* @param player the player to send the notification to
*/
public static void send(Notification notification, Player player) {
final PlayerConnection playerConnection = player.getPlayerConnection();
@ -34,6 +40,12 @@ public class NotificationCenter {
playerConnection.sendPacket(AdvancementUtils.getRemovePacket(new String[]{IDENTIFIER}));
}
/**
* Send a {@link Notification} to a collection of players.
*
* @param notification the {@link Notification} to send
* @param players the collection of players to send the notification to
*/
public static void send(Notification notification, Collection<Player> players) {
// Can't use PacketWriterUtils before we need the packets to come in the correct order
players.forEach(player -> {
@ -42,7 +54,7 @@ public class NotificationCenter {
}
/**
* Create the packet responsible for showing the Toast to players
* Create the {@link AdvancementsPacket} responsible for showing the Toast to players
*
* @param notification the notification
* @return the packet used to show the Toast

View File

@ -19,7 +19,13 @@ import java.util.concurrent.ConcurrentHashMap;
import static net.minestom.server.MinecraftServer.*;
public class BenchmarkManager {
/**
* Small monitoring tools that can be used to check the current memory usage and Minestom threads CPU usage.
* <p>
* Needs to be enabled with {@link #enable(UpdateOption)}. Memory can then be accessed with {@link #getUsedMemory()}
* and the CPUs usage with {@link #getResultMap()} or {@link #getCpuMonitoringMessage()}.
*/
public final class BenchmarkManager {
public static ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
private static List<String> threads = new ArrayList<>();
@ -40,7 +46,7 @@ public class BenchmarkManager {
private final Long2LongMap lastWaitedMap = new Long2LongOpenHashMap();
private final Long2LongMap lastBlockedMap = new Long2LongOpenHashMap();
private Map<String, ThreadResult> resultMap = new ConcurrentHashMap<>();
private final Map<String, ThreadResult> resultMap = new ConcurrentHashMap<>();
private boolean enabled = false;
private volatile boolean stop = false;
@ -115,7 +121,7 @@ public class BenchmarkManager {
private void refreshData() {
ThreadInfo[] threadInfo = threadMXBean.getThreadInfo(threadMXBean.getAllThreadIds());
for (ThreadInfo threadInfo2 : threadInfo) {
String name = threadInfo2.getThreadName();
final String name = threadInfo2.getThreadName();
boolean shouldBenchmark = false;
for (String thread : threads) {
if (name.startsWith(thread)) {
@ -126,32 +132,32 @@ public class BenchmarkManager {
if (!shouldBenchmark)
continue;
long id = threadInfo2.getThreadId();
final long id = threadInfo2.getThreadId();
long lastCpuTime = lastCpuTimeMap.getOrDefault(id, 0L);
long lastUserTime = lastUserTimeMap.getOrDefault(id, 0L);
long lastWaitedTime = lastWaitedMap.getOrDefault(id, 0L);
long lastBlockedTime = lastBlockedMap.getOrDefault(id, 0L);
final long lastCpuTime = lastCpuTimeMap.getOrDefault(id, 0L);
final long lastUserTime = lastUserTimeMap.getOrDefault(id, 0L);
final long lastWaitedTime = lastWaitedMap.getOrDefault(id, 0L);
final long lastBlockedTime = lastBlockedMap.getOrDefault(id, 0L);
long blockedTime = threadInfo2.getBlockedTime();
long waitedTime = threadInfo2.getWaitedTime();
long cpuTime = threadMXBean.getThreadCpuTime(id);
long userTime = threadMXBean.getThreadUserTime(id);
final long blockedTime = threadInfo2.getBlockedTime();
final long waitedTime = threadInfo2.getWaitedTime();
final long cpuTime = threadMXBean.getThreadCpuTime(id);
final long userTime = threadMXBean.getThreadUserTime(id);
lastCpuTimeMap.put(id, cpuTime);
lastUserTimeMap.put(id, userTime);
lastWaitedMap.put(id, waitedTime);
lastBlockedMap.put(id, blockedTime);
double totalCpuTime = (double) (cpuTime - lastCpuTime) / 1000000D;
double totalUserTime = (double) (userTime - lastUserTime) / 1000000D;
long totalBlocked = blockedTime - lastBlockedTime;
long totalWaited = waitedTime - lastWaitedTime;
final double totalCpuTime = (double) (cpuTime - lastCpuTime) / 1000000D;
final double totalUserTime = (double) (userTime - lastUserTime) / 1000000D;
final long totalBlocked = blockedTime - lastBlockedTime;
final long totalWaited = waitedTime - lastWaitedTime;
double cpuPercentage = totalCpuTime / (double) time * 100L;
double userPercentage = totalUserTime / (double) time * 100L;
double waitedPercentage = totalWaited / (double) time * 100L;
double blockedPercentage = totalBlocked / (double) time * 100L;
final double cpuPercentage = totalCpuTime / (double) time * 100L;
final double userPercentage = totalUserTime / (double) time * 100L;
final double waitedPercentage = totalWaited / (double) time * 100L;
final double blockedPercentage = totalBlocked / (double) time * 100L;
ThreadResult threadResult = new ThreadResult(cpuPercentage, userPercentage, waitedPercentage, blockedPercentage);
resultMap.put(name, threadResult);

View File

@ -2,7 +2,7 @@ package net.minestom.server.benchmark;
public class ThreadResult {
private double cpuPercentage, userPercentage, waitedPercentage, blockedPercentage;
private final double cpuPercentage, userPercentage, waitedPercentage, blockedPercentage;
protected ThreadResult(double cpuPercentage, double userPercentage, double waitedPercentage, double blockedPercentage) {
this.cpuPercentage = cpuPercentage;

View File

@ -18,15 +18,15 @@ public interface Framebuffer {
default void preparePacket(MapDataPacket packet, int minX, int minY, int width, int height) {
byte[] colors;
if(minX == 0 && minY == 0 && width == WIDTH && height == HEIGHT) {
if (minX == 0 && minY == 0 && width == WIDTH && height == HEIGHT) {
colors = toMapColors();
} else {
colors = new byte[width*height];
byte[] mapColors = toMapColors();
for (int y = minY; y < Math.min(HEIGHT, minY+height); y++) {
for (int x = minX; x < Math.min(WIDTH, minX+width); x++) {
colors = new byte[width * height];
final byte[] mapColors = toMapColors();
for (int y = minY; y < Math.min(HEIGHT, minY + height); y++) {
for (int x = minX; x < Math.min(WIDTH, minX + width); x++) {
byte color = mapColors[index(x, y, WIDTH)];
colors[index(x-minX, y-minY, width)] = color;
colors[index(x - minX, y - minY, width)] = color;
}
}
}
@ -44,7 +44,7 @@ public interface Framebuffer {
}
static int index(int x, int z, int stride) {
return z*stride + x;
return z * stride + x;
}
}

View File

@ -3,19 +3,22 @@ package net.minestom.server.map;
import net.minestom.server.network.packet.server.play.MapDataPacket;
/**
* Framebuffer that is meant to be split in sub-framebuffers. Contrary to Framebuffer, LargeFramebuffer supports sizes over 128x128 pixels.
* Framebuffer that is meant to be split in sub-framebuffers.
* Contrary to {@link Framebuffer}, LargeFramebuffer supports sizes over 128x128 pixels.
*/
public interface LargeFramebuffer {
int width();
int height();
/**
* Returns a new Framebuffer that represent a 128x128 sub-view of this framebuffer.
* Returns a new {@link Framebuffer} that represent a 128x128 sub-view of this framebuffer.
* Implementations are free (but not guaranteed) to throw exceptions if left &amp; top produces out-of-bounds coordinates.
*
* @param left
* @param top
* @return
* @return the sub-view {@link Framebuffer}
*/
Framebuffer createSubView(int left, int top);
@ -23,18 +26,19 @@ public interface LargeFramebuffer {
/**
* Prepares the packet to render a 128x128 sub view of this framebuffer
* @param packet
*
* @param packet the {@link MapDataPacket} to prepare
* @param left
* @param top
*/
default void preparePacket(MapDataPacket packet, int left, int top) {
byte[] colors = new byte[Framebuffer.WIDTH*Framebuffer.WIDTH];
int width = Math.min(width(), left+Framebuffer.WIDTH) - left;
int height = Math.min(height(), top+Framebuffer.HEIGHT) - top;
byte[] colors = new byte[Framebuffer.WIDTH * Framebuffer.WIDTH];
final int width = Math.min(width(), left + Framebuffer.WIDTH) - left;
final int height = Math.min(height(), top + Framebuffer.HEIGHT) - top;
for (int y = top; y < height; y++) {
for (int x = left; x < width; x++) {
byte color = getMapColor(left, top);
colors[Framebuffer.index(x-left, y-top)] = color;
final byte color = getMapColor(left, top);
colors[Framebuffer.index(x - left, y - top)] = color;
}
}

View File

@ -7,7 +7,7 @@ import java.util.concurrent.TimeUnit;
import java.util.function.Function;
public enum MapColors {
NONE(0,0,0),
NONE(0, 0, 0),
GRASS(127, 178, 56),
SAND(247, 233, 163),
WOOL(199, 199, 199),
@ -65,8 +65,7 @@ public enum MapColors {
WARPED_NYLIUM(22, 126, 134),
WARPED_STEM(58, 142, 140),
WARPED_HYPHAE(86, 44, 62),
WARPED_WART_BLOCK(20, 180, 133),
;
WARPED_WART_BLOCK(20, 180, 133);
private final int red;
private final int green;
@ -85,13 +84,13 @@ public enum MapColors {
static {
ColorMappingStrategy strategy;
String strategyStr = System.getProperty(MAPPING_ARGUMENT);
if(strategyStr == null) {
if (strategyStr == null) {
strategy = ColorMappingStrategy.LAZY;
} else {
try {
strategy = ColorMappingStrategy.valueOf(strategyStr.toUpperCase());
} catch (IllegalArgumentException e) {
System.err.println("Unknown color mapping strategy: "+strategyStr);
System.err.println("Unknown color mapping strategy: " + strategyStr);
System.err.println("Defaulting to LAZY.");
strategy = ColorMappingStrategy.LAZY;
}
@ -100,16 +99,16 @@ public enum MapColors {
int reduction = 10;
String reductionStr = System.getProperty(REDUCTION_ARGUMENT);
if(reductionStr != null) {
if (reductionStr != null) {
try {
reduction = Integer.parseInt(reductionStr);
} catch (NumberFormatException e) {
System.err.println("Invalid integer in reduction argument: "+reductionStr);
System.err.println("Invalid integer in reduction argument: " + reductionStr);
e.printStackTrace();
}
if(reduction < 0 || reduction >= 255) {
System.err.println("Reduction was found to be invalid: "+reduction+". Must in 0-255, defaulting to 10.");
if (reduction < 0 || reduction >= 255) {
System.err.println("Reduction was found to be invalid: " + reduction + ". Must in 0-255, defaulting to 10.");
reduction = 10;
}
}
@ -133,14 +132,14 @@ public enum MapColors {
* Returns the color index with RGB multiplied by 0.53, to use on a map
*/
public byte multiply53() {
return (byte) ((ordinal() << 2) +3);
return (byte) ((ordinal() << 2) + 3);
}
/**
* Returns the color index with RGB multiplied by 0.86, to use on a map
*/
public byte multiply86() {
return (byte) ((ordinal() << 2) +1);
return (byte) ((ordinal() << 2) + 1);
}
/**
@ -154,7 +153,7 @@ public enum MapColors {
* Returns the color index to use on a map
*/
public byte baseColor() {
return (byte) ((ordinal() << 2) +2);
return (byte) ((ordinal() << 2) + 2);
}
public int red() {
@ -170,14 +169,14 @@ public enum MapColors {
}
private static void fillRGBMap() {
for(MapColors base : values()) {
if(base == NONE)
for (MapColors base : values()) {
if (base == NONE)
continue;
for(Multiplier m : Multiplier.values()) {
for (Multiplier m : Multiplier.values()) {
PreciseMapColor preciseMapColor = new PreciseMapColor(base, m);
int rgb = preciseMapColor.toRGB();
if(mappingStrategy == ColorMappingStrategy.APPROXIMATE) {
if (mappingStrategy == ColorMappingStrategy.APPROXIMATE) {
rgb = reduceColor(rgb);
}
rgbMap.put(rgb, preciseMapColor);
@ -186,7 +185,7 @@ public enum MapColors {
}
private static void fillRGBArray() {
rgbArray = new PreciseMapColor[0xFFFFFF+1];
rgbArray = new PreciseMapColor[0xFFFFFF + 1];
MinestomThread threads = new MinestomThread(Runtime.getRuntime().availableProcessors(), "RGBMapping", true);
for (int rgb = 0; rgb <= 0xFFFFFF; rgb++) {
int finalRgb = rgb;
@ -204,23 +203,23 @@ public enum MapColors {
public static PreciseMapColor closestColor(int argb) {
int noAlpha = argb & 0xFFFFFF;
if (mappingStrategy == ColorMappingStrategy.PRECISE) {
if(rgbArray == null) {
if (rgbArray == null) {
synchronized (MapColors.class) {
if(rgbArray == null) {
if (rgbArray == null) {
fillRGBArray();
}
}
}
return rgbArray[noAlpha];
}
if(rgbMap.isEmpty()) {
if (rgbMap.isEmpty()) {
synchronized (rgbMap) {
if(rgbMap.isEmpty()) {
if (rgbMap.isEmpty()) {
fillRGBMap();
}
}
}
if(mappingStrategy == ColorMappingStrategy.APPROXIMATE) {
if (mappingStrategy == ColorMappingStrategy.APPROXIMATE) {
noAlpha = reduceColor(noAlpha);
}
return rgbMap.computeIfAbsent(noAlpha, MapColors::mapColor);
@ -231,32 +230,32 @@ public enum MapColors {
int green = (rgb >> 8) & 0xFF;
int blue = rgb & 0xFF;
red = red/colorReduction;
green = green/colorReduction;
blue = blue/colorReduction;
red = red / colorReduction;
green = green / colorReduction;
blue = blue / colorReduction;
return (red << 16) | (green << 8) | blue;
}
private static PreciseMapColor mapColor(int rgb) {
PreciseMapColor closest = null;
int closestDistance = Integer.MAX_VALUE;
for(MapColors base : values()) {
for (MapColors base : values()) {
if (base == NONE)
continue;
for (Multiplier m : Multiplier.values()) {
int rgbKey = PreciseMapColor.toRGB(base, m);
int redKey = (rgbKey >> 16) & 0xFF;
int greenKey = (rgbKey >> 8) & 0xFF;
int blueKey = rgbKey & 0xFF;
final int rgbKey = PreciseMapColor.toRGB(base, m);
final int redKey = (rgbKey >> 16) & 0xFF;
final int greenKey = (rgbKey >> 8) & 0xFF;
final int blueKey = rgbKey & 0xFF;
int red = (rgb >> 16) & 0xFF;
int green = (rgb >> 8) & 0xFF;
int blue = rgb & 0xFF;
final int red = (rgb >> 16) & 0xFF;
final int green = (rgb >> 8) & 0xFF;
final int blue = rgb & 0xFF;
int dr = redKey - red;
int dg = greenKey - green;
int db = blueKey - blue;
int dist = (dr * dr + dg * dg + db * db);
final int dr = redKey - red;
final int dg = greenKey - green;
final int db = blueKey - blue;
final int dist = (dr * dr + dg * dg + db * db);
if (dist < closestDistance) {
closest = new PreciseMapColor(base, m);
closestDistance = dist;
@ -267,8 +266,8 @@ public enum MapColors {
}
public static class PreciseMapColor {
private MapColors baseColor;
private Multiplier multiplier;
private final MapColors baseColor;
private final Multiplier multiplier;
PreciseMapColor(MapColors base, Multiplier multiplier) {
this.baseColor = base;
@ -300,9 +299,9 @@ public enum MapColors {
g *= multiplier.multiplier();
b *= multiplier.multiplier();
int red = (int) r;
int green = (int) g;
int blue = (int) b;
final int red = (int) r;
final int green = (int) g;
final int blue = (int) b;
return (red << 16) | (green << 8) | blue;
}
}
@ -311,8 +310,7 @@ public enum MapColors {
x1_00(MapColors::baseColor, 1.00),
x0_53(MapColors::multiply53, 0.53),
x0_71(MapColors::multiply71, 0.71),
x0_86(MapColors::multiply86, 0.86),
;
x0_86(MapColors::multiply86, 0.86);
private final Function<MapColors, Byte> indexGetter;
private final double multiplier;

View File

@ -1,14 +0,0 @@
package net.minestom.server.map;
public class MapHandle {
private int mapId;
protected MapHandle(int mapId) {
this.mapId = mapId;
}
public int getMapId() {
return mapId;
}
}

View File

@ -1,14 +0,0 @@
package net.minestom.server.map;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class MapManager {
private Int2ObjectMap<MapHandle> objectMap = new Int2ObjectOpenHashMap<>();
public MapHandle getMap(int mapId) {
return objectMap.computeIfAbsent(mapId, id -> new MapHandle(id));
}
}

View File

@ -3,14 +3,15 @@ package net.minestom.server.map.framebuffers;
import net.minestom.server.map.Framebuffer;
/**
* Framebuffer with direct access to the colors array
* {@link Framebuffer} with direct access to the colors array
*/
public class DirectFramebuffer implements Framebuffer {
private final byte[] colors = new byte[WIDTH*HEIGHT];
private final byte[] colors = new byte[WIDTH * HEIGHT];
/**
* Mutable colors array
*
* @return
*/
public byte[] getColors() {

View File

@ -1,7 +1,6 @@
package net.minestom.server.map.framebuffers;
import net.minestom.server.map.Framebuffer;
import net.minestom.server.map.LargeFramebuffer;
import net.minestom.server.map.MapColors;
import java.awt.*;
@ -9,18 +8,18 @@ import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
/**
* Framebuffer that embeds a BufferedImage, allowing for rendering directly via Graphics2D or its pixel array
* {@link Framebuffer} that embeds a BufferedImage, allowing for rendering directly via Graphics2D or its pixel array.
*/
public class Graphics2DFramebuffer implements Framebuffer {
private final byte[] colors = new byte[WIDTH*HEIGHT];
private final byte[] colors = new byte[WIDTH * HEIGHT];
private final BufferedImage backingImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
private final Graphics2D renderer;
private final int[] pixels;
public Graphics2DFramebuffer() {
renderer = backingImage.createGraphics();
pixels = ((DataBufferInt)backingImage.getRaster().getDataBuffer()).getData();
pixels = ((DataBufferInt) backingImage.getRaster().getDataBuffer()).getData();
}
public Graphics2D getRenderer() {
@ -32,11 +31,11 @@ public class Graphics2DFramebuffer implements Framebuffer {
}
public int get(int x, int z) {
return pixels[x+z*WIDTH]; // stride is always the width of the image
return pixels[x + z * WIDTH]; // stride is always the width of the image
}
public Graphics2DFramebuffer set(int x, int z, int rgb) {
pixels[x+z*WIDTH] = rgb;
pixels[x + z * WIDTH] = rgb;
return this;
}

View File

@ -5,8 +5,8 @@ import net.minestom.server.map.LargeFramebuffer;
import net.minestom.server.map.MapColors;
/**
* Large framebuffer with direct access to the colors array.
*
* {@link LargeFramebuffer} with direct access to the colors array.
* <p>
* This implementation does not throw errors when accessing out-of-bounds coordinates through sub-views, and will instead
* use {@link MapColors#NONE}. This is only the case for sub-views, access through {@link #setMapColor(int, int, byte)}
* and {@link #getMapColor(int, int)} will throw an exception if out-of-bounds coordinates are inputted.
@ -19,13 +19,14 @@ public class LargeDirectFramebuffer implements LargeFramebuffer {
/**
* Creates a new {@link LargeDirectFramebuffer} with the desired size
*
* @param width
* @param height
*/
public LargeDirectFramebuffer(int width, int height) {
this.width = width;
this.height = height;
this.colors = new byte[width*height];
this.colors = new byte[width * height];
}
@Override
@ -44,15 +45,15 @@ public class LargeDirectFramebuffer implements LargeFramebuffer {
}
public LargeDirectFramebuffer setMapColor(int x, int y, byte color) {
if(!bounds(x, y)) throw new IndexOutOfBoundsException("Invalid x;y coordinate: "+x+";"+y);
colors[y*width+x] = color;
if (!bounds(x, y)) throw new IndexOutOfBoundsException("Invalid x;y coordinate: " + x + ";" + y);
colors[y * width + x] = color;
return this;
}
@Override
public byte getMapColor(int x, int y) {
if(!bounds(x, y)) throw new IndexOutOfBoundsException("Invalid x;y coordinate: "+x+";"+y);
return colors[y*width+x];
if (!bounds(x, y)) throw new IndexOutOfBoundsException("Invalid x;y coordinate: " + x + ";" + y);
return colors[y * width + x];
}
private boolean bounds(int x, int y) {

View File

@ -9,11 +9,11 @@ import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
/**
* LargeFramebuffer that embeds a BufferedImage, allowing for rendering directly via Graphics2D or its pixel array
* {@link LargeFramebuffer} that embeds a {@link BufferedImage},
* allowing for rendering directly via {@link Graphics2D} or its pixel array.
*/
public class LargeGraphics2DFramebuffer implements LargeFramebuffer {
private final byte[] colors;
private final BufferedImage backingImage;
private final Graphics2D renderer;
private final int[] pixels;
@ -23,10 +23,9 @@ public class LargeGraphics2DFramebuffer implements LargeFramebuffer {
public LargeGraphics2DFramebuffer(int width, int height) {
this.width = width;
this.height = height;
colors = new byte[width*height];
backingImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
renderer = backingImage.createGraphics();
pixels = ((DataBufferInt)backingImage.getRaster().getDataBuffer()).getData();
pixels = ((DataBufferInt) backingImage.getRaster().getDataBuffer()).getData();
}
public Graphics2D getRenderer() {
@ -38,11 +37,11 @@ public class LargeGraphics2DFramebuffer implements LargeFramebuffer {
}
public int get(int x, int z) {
return pixels[x+z*width]; // stride is always the width of the image
return pixels[x + z * width]; // stride is always the width of the image
}
public LargeGraphics2DFramebuffer set(int x, int z, int rgb) {
pixels[x+z*width] = rgb;
pixels[x + z * width] = rgb;
return this;
}

View File

@ -9,7 +9,7 @@ public final class AdvancementUtils {
}
/**
* Get an {@link AdvancementsPacket} which remove the specified identifiers
* Get an {@link AdvancementsPacket} which remove the specified identifiers.
*
* @param identifiers the identifiers to remove
* @return the packet to remove all the identifiers