From 44e2df0b32a3ea1093d2b1b9b1977740b1e2b872 Mon Sep 17 00:00:00 2001 From: vladmarica Date: Sat, 24 Oct 2020 23:29:42 -0300 Subject: [PATCH] v1.1 - add auto ping text color based on latency --- .gitignore | 2 + build.gradle | 21 +++++--- gradle.properties | 2 +- .../BetterPingDisplayMod.java | 1 + .../vladmarica/betterpingdisplay/Config.java | 37 ++++++++++---- .../betterpingdisplay/hud/ColorUtil.java | 32 +++++++++++++ .../hud/CustomPlayerListHud.java | 32 ++++++++++--- .../betterpingdisplay/hud/PingColors.java | 38 +++++++++++---- .../hud/PlayerListHudUtil.java | 2 + src/main/resources/fabric.mod.json | 2 +- .../betterpingdisplay/hud/ColorUtilTest.java | 48 +++++++++++++++++++ 11 files changed, 183 insertions(+), 34 deletions(-) create mode 100644 src/main/java/com/vladmarica/betterpingdisplay/hud/ColorUtil.java create mode 100644 src/test/java/com/vladmarica/betterpingdisplay/hud/ColorUtilTest.java diff --git a/.gitignore b/.gitignore index c303bcb..2f33118 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ build/ out/ .idea/ run/ +logs/ +src/main/java/net/fabricmc/* \ No newline at end of file diff --git a/build.gradle b/build.gradle index ba9e972..8f22a16 100644 --- a/build.gradle +++ b/build.gradle @@ -11,13 +11,11 @@ version = project.mod_version group = project.maven_group dependencies { - //to change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - - // Fabric API. This is technically optional, but you probably want it anyway. modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + testImplementation 'junit:junit:4.13' } processResources { @@ -33,9 +31,6 @@ processResources { } } -// ensure that the encoding is set to UTF-8, no matter what the system default is -// this fixes some edge cases with special characters not displaying correctly -// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html tasks.withType(JavaCompile) { options.encoding = "UTF-8" } @@ -72,3 +67,17 @@ publishing { // mavenLocal() } } + +sourceSets { + main.java { + include 'com/vladmarica/betterpingdisplay/**/*' + exclude 'net/fabricmc/*' + } + test.java { + include 'com/vladmarica/betterpingdisplay/**/*' + } +} + +test { + useJUnit() +} diff --git a/gradle.properties b/gradle.properties index 4242fb6..76ef33a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ org.gradle.jvmargs=-Xmx1G # Mod Properties mod_version = 1.1.0 maven_group = com.vladmarica - archives_base_name = BetterPingDisplay + archives_base_name = BetterPingDisplay-Fabric # Dependencies # currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api diff --git a/src/main/java/com/vladmarica/betterpingdisplay/BetterPingDisplayMod.java b/src/main/java/com/vladmarica/betterpingdisplay/BetterPingDisplayMod.java index 0a2e622..b9b3450 100644 --- a/src/main/java/com/vladmarica/betterpingdisplay/BetterPingDisplayMod.java +++ b/src/main/java/com/vladmarica/betterpingdisplay/BetterPingDisplayMod.java @@ -26,6 +26,7 @@ public class BetterPingDisplayMod implements ModInitializer { try { ConfigData data = Config.loadConfigFile(configFile); config = new Config(data); + Config.writeConfigFile(configFile, data); } catch (Exception ex) { LOGGER.error("Failed to load config file, using default. Error: {}", ex.getMessage()); } diff --git a/src/main/java/com/vladmarica/betterpingdisplay/Config.java b/src/main/java/com/vladmarica/betterpingdisplay/Config.java index 0fba95b..3b65a9f 100644 --- a/src/main/java/com/vladmarica/betterpingdisplay/Config.java +++ b/src/main/java/com/vladmarica/betterpingdisplay/Config.java @@ -13,28 +13,33 @@ public class Config { private static final int DEFAULT_PING_TEXT_COLOR = 0xA0A0A0; private static final String DEFAULT_PING_TEXT_FORMAT = "%dms"; + private boolean autoColorPingText; + private boolean renderPingBars; private int textColor = DEFAULT_PING_TEXT_COLOR; private String textFormatString = DEFAULT_PING_TEXT_FORMAT; public Config(ConfigData confileFileFormat) { - if (confileFileFormat.textColor.startsWith("#")) { + if (confileFileFormat.pingTextColor.startsWith("#")) { try { - textColor = Integer.parseInt(confileFileFormat.textColor.substring(1), 16); + textColor = Integer.parseInt(confileFileFormat.pingTextColor.substring(1), 16); } catch (NumberFormatException ex) { - BetterPingDisplayMod.LOGGER.error("Config option 'textColor' is invalid - it must be a hex color code"); + BetterPingDisplayMod.LOGGER.error("Config option 'pingTextColor' is invalid - it must be a hex color code"); } } else { - BetterPingDisplayMod.LOGGER.error("Config option 'textColor' is invalid - it must be a hex color code"); + BetterPingDisplayMod.LOGGER.error("Config option 'pingTextColor' is invalid - it must be a hex color code"); } - if (confileFileFormat.textFormatString.contains("%d")) { - textFormatString = confileFileFormat.textFormatString; + if (confileFileFormat.pingTextFormatString.contains("%d")) { + textFormatString = confileFileFormat.pingTextFormatString; } else { - BetterPingDisplayMod.LOGGER.error("Config option 'textFormatString' is invalid - it needs to contain %d"); + BetterPingDisplayMod.LOGGER.error("Config option 'pingTextFormatString' is invalid - it needs to contain %d"); } + + autoColorPingText = confileFileFormat.autoColorPingText; + renderPingBars = confileFileFormat.renderPingBars; } public Config() { @@ -49,6 +54,14 @@ public class Config { return this.textFormatString; } + public boolean shouldAutoColorPingText() { + return this.autoColorPingText; + } + + public boolean shouldRenderPingBars() { + return this.renderPingBars; + } + public static ConfigData loadConfigFile(File configFile) throws IOException { FileReader reader = null; try { @@ -78,9 +91,15 @@ public class Config { public static class ConfigData implements Serializable { @Expose - private String textColor = "#A0A0A0"; + private boolean autoColorPingText = true; @Expose - private String textFormatString = "%dms"; + private boolean renderPingBars = false; + + @Expose + private String pingTextColor = "#A0A0A0"; + + @Expose + private String pingTextFormatString = "%dms"; } } diff --git a/src/main/java/com/vladmarica/betterpingdisplay/hud/ColorUtil.java b/src/main/java/com/vladmarica/betterpingdisplay/hud/ColorUtil.java new file mode 100644 index 0000000..599506e --- /dev/null +++ b/src/main/java/com/vladmarica/betterpingdisplay/hud/ColorUtil.java @@ -0,0 +1,32 @@ +package com.vladmarica.betterpingdisplay.hud; + +public class ColorUtil { + + public static int interpolate(int colorStart, int colorEnd, float offset) { + if (offset < 0 || offset > 1) { + throw new IllegalArgumentException("Offset must be between 0.0 and 1.0"); + } + + int redDiff = getRed(colorEnd) - getRed(colorStart); + int greenDiff = getGreen(colorEnd) - getGreen(colorStart); + int blueDiff = getBlue(colorEnd) - getBlue(colorStart); + + int newRed = Math.round(getRed(colorStart) + (redDiff * offset)); + int newGreen = Math.round(getGreen(colorStart) + (greenDiff * offset)); + int newBlue = Math.round(getBlue(colorStart) + (blueDiff * offset)); + + return (newRed << 16) | (newGreen << 8) | newBlue; + } + + static int getRed(int color) { + return (color >> 16) & 0xFF; + } + + static int getGreen(int color) { + return (color >> 8) & 0xFF; + } + + static int getBlue(int color) { + return color & 0xFF; + } +} diff --git a/src/main/java/com/vladmarica/betterpingdisplay/hud/CustomPlayerListHud.java b/src/main/java/com/vladmarica/betterpingdisplay/hud/CustomPlayerListHud.java index f68749e..6cb9637 100644 --- a/src/main/java/com/vladmarica/betterpingdisplay/hud/CustomPlayerListHud.java +++ b/src/main/java/com/vladmarica/betterpingdisplay/hud/CustomPlayerListHud.java @@ -4,8 +4,8 @@ import com.google.common.collect.ComparisonChain; import com.google.common.collect.Ordering; import com.mojang.authlib.GameProfile; import com.mojang.blaze3d.systems.RenderSystem; -import com.vladmarica.betterpingdisplay.Config; import com.vladmarica.betterpingdisplay.BetterPingDisplayMod; +import com.vladmarica.betterpingdisplay.Config; import java.util.Comparator; import java.util.Iterator; import java.util.List; @@ -33,6 +33,7 @@ public final class CustomPlayerListHud { private static final int PING_TEXT_RENDER_OFFSET = -13; private static final int PLAYER_SLOT_EXTRA_WIDTH = 45; private static final int PLAYER_ICON_WIDTH = 9; + private static final int PING_BARS_WIDTH = 11; public static void render(PlayerListHud hud, int width, Scoreboard scoreboard, ScoreboardObjective obj) { MinecraftClient mc = MinecraftClient.getInstance(); @@ -175,13 +176,30 @@ public final class CustomPlayerListHud { // Here is the magic, rendering the ping text String pingString = String.format(config.getTextFormatString(), player.getLatency()); int pingStringWidth = textRenderer.getStringWidth(pingString); - textRenderer.drawWithShadow( - pingString, - (float) r + aa - pingStringWidth + PING_TEXT_RENDER_OFFSET - (displayPlayerIcons ? PLAYER_ICON_WIDTH : 0), - (float) ab, - config.getTextColor()); + int textX = r + aa - pingStringWidth + PING_TEXT_RENDER_OFFSET; - PlayerListHudUtil.renderLatencyIcon(hud, r, aa - (displayPlayerIcons ? PLAYER_ICON_WIDTH : 0), ab, player); + if (displayPlayerIcons) { + textX -= PLAYER_ICON_WIDTH; + } + + if (!config.shouldRenderPingBars()) { + textX += PING_BARS_WIDTH; + } + + int pingTextColor = config.shouldAutoColorPingText() + ? PingColors.getColor(player.getLatency()) + : config.getTextColor(); + + textRenderer.drawWithShadow(pingString, (float) textX, (float) ab, pingTextColor); + + if (config.shouldRenderPingBars()) { + PlayerListHudUtil.renderLatencyIcon( + hud, r, aa - (displayPlayerIcons ? PLAYER_ICON_WIDTH : 0), ab, player); + } else { + // If we don't render ping bars, we need to reset the render system color so the rest + // of the player list renders properly + RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F); + } } } diff --git a/src/main/java/com/vladmarica/betterpingdisplay/hud/PingColors.java b/src/main/java/com/vladmarica/betterpingdisplay/hud/PingColors.java index ddfbf93..e981567 100644 --- a/src/main/java/com/vladmarica/betterpingdisplay/hud/PingColors.java +++ b/src/main/java/com/vladmarica/betterpingdisplay/hud/PingColors.java @@ -1,19 +1,37 @@ package com.vladmarica.betterpingdisplay.hud; +import net.minecraft.util.math.MathHelper; -// start: #00e676 -// mid #d6cd30 -// end #e53935 public class PingColors { + public static final int PING_START = 0; + public static final int PING_MID = 150; + public static final int PING_END = 300; + + public static final int COLOR_GREY = 0x535353; + public static final int COLOR_START = 0x00E676; + public static final int COLOR_MID = 0xD6CD30; + public static final int COLOR_END = 0xE53935; + public static int getColor(int ping) { - if (ping < 0) { - return 0x535353; + if (ping < PING_START) { + return COLOR_GREY; } - if (ping < 150) { - return 0x00E676; - } - if (ping < 300) { - return 0xC6FF00; + + if (ping < PING_MID) { + return ColorUtil.interpolate( + COLOR_START, + COLOR_MID, + computeOffset(PING_START, PING_MID, ping)); } + + return ColorUtil.interpolate( + COLOR_MID, + COLOR_END, + computeOffset(PING_MID, PING_END, Math.min(ping, PING_END))); + } + + static float computeOffset(int start, int end, int value) { + float offset = (value - start) / (float) ( end - start); + return MathHelper.clamp(offset, 0.0F, 1.0F); } } diff --git a/src/main/java/com/vladmarica/betterpingdisplay/hud/PlayerListHudUtil.java b/src/main/java/com/vladmarica/betterpingdisplay/hud/PlayerListHudUtil.java index 5b5af27..aeb376c 100644 --- a/src/main/java/com/vladmarica/betterpingdisplay/hud/PlayerListHudUtil.java +++ b/src/main/java/com/vladmarica/betterpingdisplay/hud/PlayerListHudUtil.java @@ -7,10 +7,12 @@ import net.minecraft.scoreboard.ScoreboardObjective; import net.minecraft.text.Text; public class PlayerListHudUtil { + /** Calls {@link net.minecraft.client.gui.hud.PlayerListHud#renderLatencyIcon}. */ static void renderLatencyIcon(PlayerListHud hud, int x, int offsetX, int y, PlayerListEntry player) { ((PlayerListHudAccessor) hud).invokeRenderLatencyIcon(x, offsetX, y, player); } + /** Calls {@link net.minecraft.client.gui.hud.PlayerListHud#renderScoreboardObjective} */ static void renderScoreboardObjective(PlayerListHud hud, ScoreboardObjective obj, int i, String str, int j, int k, PlayerListEntry player) { ((PlayerListHudAccessor) hud).invokeRenderScoreboardObjective(obj, i, str, j, k, player); } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 9d753fc..6073435 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -4,7 +4,7 @@ "version": "1.1", "name": "Better Ping Display", - "description": "Shows the actual ping number instead of just bars in the player list.!", + "description": "Shows the actual ping number instead of just bars in the player list!", "authors": [ "Quintinity" ], diff --git a/src/test/java/com/vladmarica/betterpingdisplay/hud/ColorUtilTest.java b/src/test/java/com/vladmarica/betterpingdisplay/hud/ColorUtilTest.java new file mode 100644 index 0000000..65a94c0 --- /dev/null +++ b/src/test/java/com/vladmarica/betterpingdisplay/hud/ColorUtilTest.java @@ -0,0 +1,48 @@ +package com.vladmarica.betterpingdisplay.hud; + +import static com.vladmarica.betterpingdisplay.hud.PingColors.COLOR_MID; +import static com.vladmarica.betterpingdisplay.hud.PingColors.COLOR_START; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ColorUtilTest { + + @Test + public void testExtractComponents() { + int color = 0xD6C130; + assertEquals(0xD6, ColorUtil.getRed(color)); + assertEquals(0xC1, ColorUtil.getGreen(color)); + assertEquals(0x30, ColorUtil.getBlue(color)); + } + + @Test + public void testInterpolation_zero() { + int color = ColorUtil.interpolate(COLOR_START, COLOR_MID, 0F); + assertEquals(COLOR_START, color); + } + + @Test + public void testInterpolation_middle() { + int color = ColorUtil.interpolate(COLOR_START, COLOR_MID, 0.5F); + assertEquals(0x6b, ColorUtil.getRed(color)); + assertEquals(0xda, ColorUtil.getGreen(color)); + assertEquals(0x53, ColorUtil.getBlue(color)); + } + + @Test + public void testInterpolation_one() { + int color = ColorUtil.interpolate(COLOR_START, COLOR_MID, 1F); + assertEquals(COLOR_MID, color); + } + + @Test + public void testInterpolation_invalidOffset() { + assertThrows(IllegalArgumentException.class, () -> ColorUtil.interpolate(0, 1, -0.1F)); + assertThrows(IllegalArgumentException.class, () -> ColorUtil.interpolate(0, 1, 1.1F)); + } +}