From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: epserv Date: Mon, 21 Dec 2020 23:12:15 +0500 Subject: [PATCH] Optimise Bukkit's MapPalette diff --git a/src/main/java/org/bukkit/map/MapPalette.java b/src/main/java/org/bukkit/map/MapPalette.java index 95fe3f4d081053a6cf484e4ef07b474f2dc2ab02..84daffdda568039423d0f6d18981bb9d9a392e1f 100644 --- a/src/main/java/org/bukkit/map/MapPalette.java +++ b/src/main/java/org/bukkit/map/MapPalette.java @@ -22,7 +22,9 @@ public final class MapPalette { return new Color(r, g, b); } - private static double getDistance(@NotNull Color c1, @NotNull Color c2) { + // Yatopia start - faster method + private static int getDistanceSquared(@NotNull Color c1, @NotNull Color c2) { + /* double rmean = (c1.getRed() + c2.getRed()) / 2.0; double r = c1.getRed() - c2.getRed(); double g = c1.getGreen() - c2.getGreen(); @@ -31,7 +33,23 @@ public final class MapPalette { double weightG = 4.0; double weightB = 2 + (255 - rmean) / 256.0; return weightR * r * r + weightG * g * g + weightB * b * b; + */ + if (c1.getRGB() == c2.getRGB()) { // check if colors are same + return 0; + } + int r = c1.getRed() - c2.getRed(), + g = c1.getGreen() - c2.getGreen(), + b = c1.getBlue() - c2.getBlue(); + // (x1 - x2)^2 + (y1 - y2)^2 + (z1 - z2)^2 formula + // but with colors. red is x, green is y, blue is z + return r * r + g * g + b * b; + } + + // getDistance method itself to keep it plugins-compatible + public static double getDistance(@NotNull Color c1, @NotNull Color c2) { + return Math.sqrt(getDistanceSquared(c1, c2)); } + // Yatopia end @NotNull static final Color[] colors = { @@ -95,6 +113,52 @@ public final class MapPalette { c(60, 31, 43), c(74, 37, 53), c(86, 44, 62), c(45, 23, 32), c(14, 127, 93), c(17, 155, 114), c(20, 180, 133), c(10, 95, 70) }; + // Yatopia start + @NotNull + private static final int[] modifiers = {180, 220, 255, 135}; // vanilla color modifiers + @NotNull + static Color[] vanillaColors; // vanilla colors + @NotNull + static Color[][] doubleColors; // two-dimensional array where doubleColors[index] is an array of possible modifications of vanillaColors[index] + @NotNull + static int[] rgbColors; // an array of rgb values of each color + + static { + // getting an array of rgb values of each color + rgbColors = java.util.Arrays.stream(colors).mapToInt(Color::getRGB).toArray(); + + try { + // load net.minecraft.server.MaterialMapColor class. using reflection because build fails. maven thinks nms isn't accessible from Yatopia-API + Class materialMapColorClass = MapPalette.class.getClassLoader().loadClass("net.minecraft.server.MaterialMapColor"); + // get vanilla colors + Object[] vanillaColorObjects = (Object[]) java.util.Arrays.stream(materialMapColorClass.getFields()).filter(f -> f.getType().isArray() && f.getType().getComponentType().equals(materialMapColorClass)).findAny().get().get(null); + // get MaterialMapColor.rgb instance field + java.lang.reflect.Field rgbField = materialMapColorClass.getDeclaredField("rgb"); + // get vanilla colors array as java.awt.Color instances array + vanillaColors = java.util.Arrays.stream(vanillaColorObjects).filter(java.util.Objects::nonNull).mapToInt(objColor -> { + try { + return rgbField.getInt(materialMapColorClass.cast(objColor)); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + }).mapToObj(Color::new).toArray(Color[]::new); + // get two-dimensional array where doubleColors[index] is an array of possible modifications of vanillaColors[index] + doubleColors = new Color[vanillaColors.length][modifiers.length]; + for (int i = 0; i < vanillaColors.length; i++) { + Color vanillaColor = vanillaColors[i]; + for (int j = 0; j < modifiers.length; j++) { + int modifier = modifiers[j]; + int mr = vanillaColor.getRed() * modifier / 255; + int mg = vanillaColor.getGreen() * modifier / 255; + int mb = vanillaColor.getBlue() * modifier / 255; + doubleColors[i][j] = c(mr, mg, mb); + } + } + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + // Yatopia end // Interface /** @@ -235,6 +299,8 @@ public final class MapPalette { public static byte matchColor(@NotNull Color color) { if (color.getAlpha() < 128) return 0; + // Yatopia start - foreach a maximum of 62 colors instead of 236 per pixel + /* int index = 0; double best = -1; @@ -245,9 +311,45 @@ public final class MapPalette { index = i; } } + */ + + int index = 0; + int best = -1; + + for (int i = 0; i < vanillaColors.length; i++) { + int distance = getDistanceSquared(color, vanillaColors[i]); + if (distance == 0) { + index = i; + break; + } + if (distance < best || best == -1) { + best = distance; + index = i; + } + } + Color[] modColors = doubleColors[index]; + best = -1; + for (int i = 0; i < modColors.length; i++) { + int distance = getDistanceSquared(color, modColors[i]); + if (distance == 0) { + index = i; + break; + } + if (distance < best || best == -1) { + best = distance; + index = i; + } + } + + index = com.google.common.primitives.Ints.indexOf(rgbColors, modColors[index].getRGB()); + // we have already checked if color is transparent so now there aren't any transparent colors + // and if (index < 4) then nearest color was black (hex #000000), so we need to return the most black color + if (index < 4) + index = 119; + // Yatopia end // Minecraft has 143 colors, some of which have negative byte representations - return (byte) (index < 128 ? index : -129 + (index - 127)); + return (byte) (index < 128 ? index : index - 256); // Yatopia } /** @@ -260,7 +362,7 @@ public final class MapPalette { @Deprecated @NotNull public static Color getColor(byte index) { - if ((index > -21 && index < 0) || index > 127) { + if (index > -21 && index < 0) { // Yatopia throw new IndexOutOfBoundsException(); } else { // Minecraft has 143 colors, some of which have negative byte representations