diff --git a/README.md b/README.md index b365e7a..2f43ee8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Better Ping Display - Fabric Edition -[![](http://cf.way2muchnoise.eu/full_406343_downloads.svg)](https://curseforge.com/minecraft/mc-mods/better-ping-display-fabric) +[![](http://cf.way2muchnoise.eu/full_406343_downloads.svg)](https://curseforge.com/minecraft/mc-mods/better-ping-display-fabric) A [Fabric](https://fabricmc.net/) mod for Minecraft to display each player's ping in the player list as a number. @@ -23,10 +23,6 @@ This mod's config file is `betterpingdisplay.json`. It contains the following op ## Supported Minecraft Versions * **1.15.x** * **1.16.x** -* **1.17.x** -* **1.18.x** -* **1.19.x** -* **1.20.x** ## Requirements -* [Fabric](https://fabricmc.net/) \ No newline at end of file +* [Fabric](https://fabricmc.net/) diff --git a/build.gradle b/build.gradle index 1230e96..8f22a16 100644 --- a/build.gradle +++ b/build.gradle @@ -1,10 +1,10 @@ plugins { - id 'fabric-loom' version '1.2-SNAPSHOT' + id 'fabric-loom' version '0.4-SNAPSHOT' id 'maven-publish' } -sourceCompatibility = JavaVersion.VERSION_14 -targetCompatibility = JavaVersion.VERSION_14 +sourceCompatibility = JavaVersion.VERSION_1_8 +targetCompatibility = JavaVersion.VERSION_1_8 archivesBaseName = project.archives_base_name version = project.mod_version @@ -20,7 +20,6 @@ dependencies { processResources { inputs.property "version", project.version - duplicatesStrategy = 'warn' from(sourceSets.main.resources.srcDirs) { include "fabric.mod.json" @@ -32,10 +31,18 @@ processResources { } } -tasks.withType(JavaCompile).configureEach { +tasks.withType(JavaCompile) { options.encoding = "UTF-8" } +// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task +// if it is present. +// If you remove this task, sources will not be generated. +task sourcesJar(type: Jar, dependsOn: classes) { + classifier = "sources" + from sourceSets.main.allSource +} + jar { from "LICENSE" } @@ -48,6 +55,9 @@ publishing { artifact(remapJar) { builtBy remapJar } + artifact(sourcesJar) { + builtBy remapSourcesJar + } } } diff --git a/gradle.properties b/gradle.properties index 4d13014..751dc5d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,16 +2,16 @@ org.gradle.jvmargs=-Xmx1G # Fabric Properties -# check these on https://fabricmc.net/use -minecraft_version=1.20.1 -yarn_mappings=1.20.1+build.1 -loader_version=0.14.21 + # check these on https://fabricmc.net/use + minecraft_version=1.16.4 + yarn_mappings=1.16.4+build.6 + loader_version=0.10.6+build.214 # Mod Properties -mod_version = 1.1.4 -maven_group = com.vladmarica -archives_base_name = BetterPingDisplay-Fabric + mod_version = 1.1.0 + maven_group = com.vladmarica + 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 -fabric_version=0.83.0+1.20.1 + # currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api + fabric_version=0.25.1+build.416-1.16 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 62d4c05..490fda8 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index fae0804..622ab64 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index fbd7c51..2fe81a7 100755 --- a/gradlew +++ b/gradlew @@ -82,7 +82,6 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -130,7 +129,6 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath diff --git a/gradlew.bat b/gradlew.bat index 5093609..62bd9b9 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -84,7 +84,6 @@ set CMD_LINE_ARGS=%* set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% diff --git a/src/main/java/com/vladmarica/betterpingdisplay/BetterPingDisplayMod.java b/src/main/java/com/vladmarica/betterpingdisplay/BetterPingDisplayMod.java index 012b282..b9b3450 100644 --- a/src/main/java/com/vladmarica/betterpingdisplay/BetterPingDisplayMod.java +++ b/src/main/java/com/vladmarica/betterpingdisplay/BetterPingDisplayMod.java @@ -1,53 +1,52 @@ package com.vladmarica.betterpingdisplay; import com.vladmarica.betterpingdisplay.Config.ConfigData; +import java.io.File; +import java.nio.file.Path; import net.fabricmc.api.ModInitializer; import net.fabricmc.loader.api.FabricLoader; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.io.File; -import java.nio.file.Path; - public class BetterPingDisplayMod implements ModInitializer { - public static final String MODID = "betterpingdisplay"; - public static final Logger LOGGER = LogManager.getLogger(MODID); - private static final String CONFIG_FILE_NAME = MODID + ".json"; - private static BetterPingDisplayMod INSTANCE; + public static final String MODID = "betterpingdisplay"; + public static final Logger LOGGER = LogManager.getLogger(MODID); + private static final String CONFIG_FILE_NAME = MODID + ".json"; + private static BetterPingDisplayMod INSTANCE; - private Config config = new Config(); + private Config config = new Config(); - @Override - public void onInitialize() { - INSTANCE = this; + @Override + public void onInitialize() { + INSTANCE = this; - Path configFilePath = FabricLoader.getInstance().getConfigDir().resolve(CONFIG_FILE_NAME); - File configFile = configFilePath.toFile(); - if (configFile.exists()) { - 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()); - } - } else { - try { - LOGGER.warn("Could not find config file, creating a default one"); - Config.writeConfigFile(configFile, new ConfigData()); - } catch (Exception ex) { - LOGGER.error("Failed to write default config file. Error: {}", ex.getMessage()); - } - } + Path configFilePath = FabricLoader.getInstance().getConfigDir().resolve(CONFIG_FILE_NAME); + File configFile = configFilePath.toFile(); + if (configFile.exists()) { + 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()); + } + } else { + try { + LOGGER.warn("Could not find config file, creating a default one"); + Config.writeConfigFile(configFile, new ConfigData()); + } catch (Exception ex) { + LOGGER.error("Failed to write default config file. Error: {}", ex.getMessage()); + } + } - LOGGER.info("BetterPingDisplay mod loaded"); - } + LOGGER.info("BetterPingDisplay mod loaded"); + } - public Config getConfig() { - return config; - } + public Config getConfig() { + return this.config; + } - public static BetterPingDisplayMod instance() { - return INSTANCE; - } + public static BetterPingDisplayMod instance() { + return INSTANCE; + } } diff --git a/src/main/java/com/vladmarica/betterpingdisplay/Config.java b/src/main/java/com/vladmarica/betterpingdisplay/Config.java index 9e29cb8..3b65a9f 100644 --- a/src/main/java/com/vladmarica/betterpingdisplay/Config.java +++ b/src/main/java/com/vladmarica/betterpingdisplay/Config.java @@ -3,96 +3,103 @@ package com.vladmarica.betterpingdisplay; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.annotations.Expose; - -import java.io.*; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Serializable; public class Config { - private static final int DEFAULT_PING_TEXT_COLOR = 0xA0A0A0; - private static final String DEFAULT_PING_TEXT_FORMAT = "%dms"; + private static final int DEFAULT_PING_TEXT_COLOR = 0xA0A0A0; + private static final String DEFAULT_PING_TEXT_FORMAT = "%dms"; - private final boolean autoColorPingText; - private final boolean renderPingBars; - private int textColor = DEFAULT_PING_TEXT_COLOR; - private String textFormatString = DEFAULT_PING_TEXT_FORMAT; + private boolean autoColorPingText; + private boolean renderPingBars; + private int textColor = DEFAULT_PING_TEXT_COLOR; + private String textFormatString = DEFAULT_PING_TEXT_FORMAT; - public Config(ConfigData configFileFormat) { - if (configFileFormat.pingTextColor.startsWith("#")) { - try { - textColor = Integer.parseInt(configFileFormat.pingTextColor.substring(1), 16); - } catch (NumberFormatException ex) { - BetterPingDisplayMod.LOGGER.error("Config option 'pingTextColor' is invalid - it must be a hex color code"); - } - } else { - BetterPingDisplayMod.LOGGER.error("Config option 'pingTextColor' is invalid - it must be a hex color code"); - } - - if (configFileFormat.pingTextFormatString.contains("%d")) { - textFormatString = configFileFormat.pingTextFormatString; - } else { - BetterPingDisplayMod.LOGGER.error("Config option 'pingTextFormatString' is invalid - it needs to contain %d"); - } - - autoColorPingText = configFileFormat.autoColorPingText; - renderPingBars = configFileFormat.renderPingBars; + public Config(ConfigData confileFileFormat) { + if (confileFileFormat.pingTextColor.startsWith("#")) { + try { + textColor = Integer.parseInt(confileFileFormat.pingTextColor.substring(1), 16); + } + catch (NumberFormatException ex) { + BetterPingDisplayMod.LOGGER.error("Config option 'pingTextColor' is invalid - it must be a hex color code"); + } + } + else { + BetterPingDisplayMod.LOGGER.error("Config option 'pingTextColor' is invalid - it must be a hex color code"); } - public Config() { - this(new ConfigData()); + if (confileFileFormat.pingTextFormatString.contains("%d")) { + textFormatString = confileFileFormat.pingTextFormatString; + } + else { + BetterPingDisplayMod.LOGGER.error("Config option 'pingTextFormatString' is invalid - it needs to contain %d"); } - public int getTextColor() { - return this.textColor; + autoColorPingText = confileFileFormat.autoColorPingText; + renderPingBars = confileFileFormat.renderPingBars; + } + + public Config() { + this(new ConfigData()); + } + + public int getTextColor() { + return this.textColor; + } + + public String getTextFormatString() { + 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 { + Gson gson = new Gson(); + reader = new FileReader(configFile); + return gson.fromJson(reader, ConfigData.class); } - - public String getTextFormatString() { - return this.textFormatString; + finally { + if (reader != null) { + reader.close(); + } } + } - public boolean shouldAutoColorPingText() { - return this.autoColorPingText; + public static void writeConfigFile(File configFile, ConfigData data) throws IOException { + FileWriter writer = null; + try { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + writer = new FileWriter(configFile); + writer.write(gson.toJson(data)); + } finally { + if (writer != null) { + writer.close(); + } } + } - public boolean shouldRenderPingBars() { - return this.renderPingBars; - } + public static class ConfigData implements Serializable { + @Expose + private boolean autoColorPingText = true; - public static ConfigData loadConfigFile(File configFile) throws IOException { - FileReader reader = null; - try { - Gson gson = new Gson(); - reader = new FileReader(configFile); - return gson.fromJson(reader, ConfigData.class); - } finally { - if (reader != null) { - reader.close(); - } - } - } + @Expose + private boolean renderPingBars = false; - public static void writeConfigFile(File configFile, ConfigData data) throws IOException { - FileWriter writer = null; - try { - Gson gson = new GsonBuilder().setPrettyPrinting().create(); - writer = new FileWriter(configFile); - writer.write(gson.toJson(data)); - } finally { - if (writer != null) { - writer.close(); - } - } - } + @Expose + private String pingTextColor = "#A0A0A0"; - public static class ConfigData implements Serializable { - @Expose - private boolean autoColorPingText = true; - - @Expose - private boolean renderPingBars = false; - - @Expose - private String pingTextColor = "#A0A0A0"; - - @Expose - private String pingTextFormatString = "%dms"; - } + @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 index 249ccb7..599506e 100644 --- a/src/main/java/com/vladmarica/betterpingdisplay/hud/ColorUtil.java +++ b/src/main/java/com/vladmarica/betterpingdisplay/hud/ColorUtil.java @@ -1,39 +1,32 @@ package com.vladmarica.betterpingdisplay.hud; -import com.google.common.annotations.VisibleForTesting; +public class ColorUtil { -public final 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; + 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"); } - @VisibleForTesting - static int getRed(int color) { - return (color >> 16) & 0xFF; - } + int redDiff = getRed(colorEnd) - getRed(colorStart); + int greenDiff = getGreen(colorEnd) - getGreen(colorStart); + int blueDiff = getBlue(colorEnd) - getBlue(colorStart); - @VisibleForTesting - static int getGreen(int color) { - return (color >> 8) & 0xFF; - } + int newRed = Math.round(getRed(colorStart) + (redDiff * offset)); + int newGreen = Math.round(getGreen(colorStart) + (greenDiff * offset)); + int newBlue = Math.round(getBlue(colorStart) + (blueDiff * offset)); - @VisibleForTesting - static int getBlue(int color) { - return color & 0xFF; - } + return (newRed << 16) | (newGreen << 8) | newBlue; + } - private ColorUtil() { - } + 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 79d5d2b..c9a9450 100644 --- a/src/main/java/com/vladmarica/betterpingdisplay/hud/CustomPlayerListHud.java +++ b/src/main/java/com/vladmarica/betterpingdisplay/hud/CustomPlayerListHud.java @@ -1,40 +1,234 @@ package com.vladmarica.betterpingdisplay.hud; +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.BetterPingDisplayMod; import com.vladmarica.betterpingdisplay.Config; -import com.vladmarica.betterpingdisplay.mixin.PlayerListHudInvoker; +import com.vladmarica.betterpingdisplay.hud.CustomPlayerListHud.EntryOrderComparator; +import com.vladmarica.betterpingdisplay.BetterPingDisplayMod; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawableHelper; import net.minecraft.client.gui.hud.PlayerListHud; +import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.network.PlayerListEntry; +import net.minecraft.client.render.entity.PlayerModelPart; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.scoreboard.Scoreboard; +import net.minecraft.scoreboard.ScoreboardCriterion; +import net.minecraft.scoreboard.ScoreboardObjective; +import net.minecraft.scoreboard.Team; +import net.minecraft.text.OrderedText; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.world.GameMode; public final class CustomPlayerListHud { - private static final int PING_TEXT_RENDER_OFFSET = -13; - private static final int PING_BARS_WIDTH = 11; - private static final Config config = BetterPingDisplayMod.instance().getConfig(); - public static void renderPingDisplay( - MinecraftClient client, PlayerListHud hud, DrawContext context, int width, int x, int y, PlayerListEntry player) { + private static final Ordering ENTRY_ORDERING = Ordering.from(new EntryOrderComparator()); + 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, MatrixStack stack, int width, Scoreboard scoreboard, ScoreboardObjective obj) { + MinecraftClient mc = MinecraftClient.getInstance(); + TextRenderer textRenderer = mc.textRenderer; + Text header = PlayerListHudUtil.getHeader(hud); + Text footer = PlayerListHudUtil.getFooter(hud); + Config config = BetterPingDisplayMod.instance().getConfig(); + + ClientPlayNetworkHandler clientPlayNetworkHandler = mc.player.networkHandler; + List playerList = ENTRY_ORDERING.sortedCopy(clientPlayNetworkHandler.getPlayerList()); + int i = 0; + int j = 0; + Iterator playerListIterator = playerList.iterator(); + + int n; + while(playerListIterator.hasNext()) { + PlayerListEntry playerListEntry = (PlayerListEntry)playerListIterator.next(); + n = mc.textRenderer.getWidth(hud.getPlayerName(playerListEntry)); + i = Math.max(i, n); + if (obj != null && obj.getRenderType() != ScoreboardCriterion.RenderType.HEARTS) { + n = textRenderer.getWidth(" " + scoreboard.getPlayerScore(playerListEntry.getProfile().getName(), obj).getScore()); + j = Math.max(j, n); + } + } + + playerList = playerList.subList(0, Math.min(playerList.size(), 80)); + int l = playerList.size(); + int m = l; + + for(n = 1; m > 20; m = (l + n - 1) / n) { + ++n; + } + + boolean displayPlayerIcons = mc.isInSingleplayer() || mc.getNetworkHandler().getConnection().isEncrypted(); + int q; + if (obj != null) { + if (obj.getRenderType() == ScoreboardCriterion.RenderType.HEARTS) { + q = 90; + } else { + q = j; + } + } else { + q = 0; + } + int r = Math.min(n * ((displayPlayerIcons ? PLAYER_ICON_WIDTH : 0) + i + q + 13 + PLAYER_SLOT_EXTRA_WIDTH), width - 50) / n; + int s = width / 2 - (r * n + (n - 1) * 5) / 2; + int t = 10; + int u = r * n + (n - 1) * 5; + List headerLines = null; + if (header != null) { + headerLines = mc.textRenderer.wrapLines(header, width - 50); + + for (OrderedText headerLine : headerLines) { + u = Math.max(u, mc.textRenderer.getWidth(headerLine)); + } + } + + List footerLines = null; + if (footer != null) { + footerLines = mc.textRenderer.wrapLines(footer, width - 50); + + for (OrderedText footerLine : footerLines) { + u = Math.max(u, mc.textRenderer.getWidth(footerLine)); + } + } + + int var10000; + int var10001; + int var10002; + int var10004; + int y; + if (headerLines != null) { + var10000 = width / 2 - u / 2 - 1; + var10001 = t - 1; + var10002 = width / 2 + u / 2 + 1; + var10004 = headerLines.size(); + DrawableHelper.fill(stack, var10000, var10001, var10002, t + var10004 * 9, Integer.MIN_VALUE); + + for (OrderedText headerLine : headerLines) { + y = mc.textRenderer.getWidth(headerLine); + mc.textRenderer.drawWithShadow(stack, headerLine, (float)(width / 2 - y / 2), (float)t, -1); + t += 9; + } + + ++t; + } + + DrawableHelper.fill(stack, width / 2 - u / 2 - 1, t - 1, width / 2 + u / 2 + 1, t + m * 9, Integer.MIN_VALUE); + int w = mc.options.getTextBackgroundColor(553648127); + + int ai; + for(int x = 0; x < l; ++x) { + y = x / m; + ai = x % m; + int aa = s + y * r + y * 5; + int ab = t + ai * 9; + DrawableHelper.fill(stack, aa, ab, aa + r, ab + 8, w); + RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F); + RenderSystem.enableAlphaTest(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + if (x < playerList.size()) { + PlayerListEntry player = playerList.get(x); + GameProfile gameProfile = player.getProfile(); + int ah; + if (displayPlayerIcons) { + PlayerEntity playerEntity = mc.world.getPlayerByUuid(gameProfile.getId()); + boolean bl2 = playerEntity != null && playerEntity.isPartVisible(PlayerModelPart.CAPE) && ("Dinnerbone".equals(gameProfile.getName()) || "Grumm".equals(gameProfile.getName())); + mc.getTextureManager().bindTexture(player.getSkinTexture()); + ah = 8 + (bl2 ? 8 : 0); + int ad = 8 * (bl2 ? -1 : 1); + DrawableHelper.drawTexture(stack, aa, ab, 8, 8, 8.0F, (float)ah, 8, ad, 64, 64); + if (playerEntity != null && playerEntity.isPartVisible(PlayerModelPart.HAT)) { + int ae = 8 + (bl2 ? 8 : 0); + int af = 8 * (bl2 ? -1 : 1); + DrawableHelper.drawTexture(stack, aa, ab, 8, 8, 40.0F, (float)ae, 8, af, 64, 64); + } + + aa += 9; + } + + Text playerName = hud.getPlayerName(player); + if (player.getGameMode() == GameMode.SPECTATOR) { + mc.textRenderer.drawWithShadow(stack, playerName, (float)aa, (float)ab, -1862270977); + } else { + mc.textRenderer.drawWithShadow(stack, playerName, (float)aa, (float)ab, -1); + } + + if (obj != null && player.getGameMode() != GameMode.SPECTATOR) { + int ag = aa + i + 1; + ah = ag + q; + if (ah - ag > 5) { + PlayerListHudUtil.renderScoreboardObjective(hud, stack, obj, ab, gameProfile.getName(), ag, ah, player); + } + } + + // Here is the magic, rendering the ping text String pingString = String.format(config.getTextFormatString(), player.getLatency()); - int pingStringWidth = client.textRenderer.getWidth(pingString); - int pingTextColor = config.shouldAutoColorPingText() - ? PingColors.getColor(player.getLatency()) : config.getTextColor(); - int textX = width + x - pingStringWidth + PING_TEXT_RENDER_OFFSET; + int pingStringWidth = textRenderer.getWidth(pingString); + int textX = r + aa - pingStringWidth + PING_TEXT_RENDER_OFFSET; + + if (displayPlayerIcons) { + textX -= PLAYER_ICON_WIDTH; + } if (!config.shouldRenderPingBars()) { - textX += PING_BARS_WIDTH; + textX += PING_BARS_WIDTH; } - // Draw the ping text for the given player - context.drawTextWithShadow(client.textRenderer, pingString, textX, y, pingTextColor); + int pingTextColor = config.shouldAutoColorPingText() + ? PingColors.getColor(player.getLatency()) + : config.getTextColor(); + + textRenderer.drawWithShadow(stack, pingString, (float) textX, (float) ab, pingTextColor); if (config.shouldRenderPingBars()) { - ((PlayerListHudInvoker) hud).invokeRenderLatencyIcon(context, width, x, y, player); + PlayerListHudUtil.renderLatencyIcon( + hud, stack, 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.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); + // 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); } + } } -} + + if (footerLines != null) { + t += m * 9 + 1; + var10000 = width / 2 - u / 2 - 1; + var10001 = t - 1; + var10002 = width / 2 + u / 2 + 1; + var10004 = footerLines.size(); + DrawableHelper.fill(stack, var10000, var10001, var10002, t + var10004 * 9, Integer.MIN_VALUE); + + for (OrderedText footerLine : footerLines) { + ai = textRenderer.getWidth(footerLine); + textRenderer.drawWithShadow(stack, footerLine, (float)(width / 2 - ai / 2), (float)t, -1); + t += 9; + } + } + } + + @Environment(EnvType.CLIENT) + static class EntryOrderComparator implements Comparator { + public int compare(PlayerListEntry p1, PlayerListEntry p2) { + Team team = p1.getScoreboardTeam(); + Team team2 = p2.getScoreboardTeam(); + return ComparisonChain.start() + .compareTrueFirst(p1.getGameMode() != GameMode.SPECTATOR, p2.getGameMode() != GameMode.SPECTATOR) + .compare(team != null ? team.getName() : "", team2 != null ? team2.getName() : "") + .compare(p1.getProfile().getName(), p2.getProfile().getName(), String::compareToIgnoreCase) + .result(); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/vladmarica/betterpingdisplay/hud/PingColors.java b/src/main/java/com/vladmarica/betterpingdisplay/hud/PingColors.java index a22a09a..e981567 100644 --- a/src/main/java/com/vladmarica/betterpingdisplay/hud/PingColors.java +++ b/src/main/java/com/vladmarica/betterpingdisplay/hud/PingColors.java @@ -2,39 +2,36 @@ package com.vladmarica.betterpingdisplay.hud; import net.minecraft.util.math.MathHelper; -public final class PingColors { - public static final int PING_START = 0; - public static final int PING_MID = 150; - public static final int PING_END = 300; +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 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 < PING_START) { - return COLOR_GREY; - } - - 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))); + public static int getColor(int ping) { + if (ping < PING_START) { + return COLOR_GREY; } - private static float computeOffset(int start, int end, int value) { - float offset = (value - start) / (float) (end - start); - return MathHelper.clamp(offset, 0.0F, 1.0F); + if (ping < PING_MID) { + return ColorUtil.interpolate( + COLOR_START, + COLOR_MID, + computeOffset(PING_START, PING_MID, ping)); } - private PingColors() { - } + 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 new file mode 100644 index 0000000..fc1ebd5 --- /dev/null +++ b/src/main/java/com/vladmarica/betterpingdisplay/hud/PlayerListHudUtil.java @@ -0,0 +1,28 @@ +package com.vladmarica.betterpingdisplay.hud; + +import com.vladmarica.betterpingdisplay.mixin.PlayerListHudAccessor; +import net.minecraft.client.gui.hud.PlayerListHud; +import net.minecraft.client.network.PlayerListEntry; +import net.minecraft.client.util.math.MatrixStack; +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, MatrixStack stack, int x, int offsetX, int y, PlayerListEntry player) { + ((PlayerListHudAccessor) hud).invokeRenderLatencyIcon(stack, x, offsetX, y, player); + } + + /** Calls {@link net.minecraft.client.gui.hud.PlayerListHud#renderScoreboardObjective} */ + static void renderScoreboardObjective(PlayerListHud hud, MatrixStack stack, ScoreboardObjective obj, int i, String str, int j, int k, PlayerListEntry player) { + ((PlayerListHudAccessor) hud).invokeRenderScoreboardObjective(obj, i, str, j, k, player, stack); + } + + static Text getHeader(PlayerListHud hud) { + return ((PlayerListHudAccessor) hud).getHeader(); + } + + static Text getFooter(PlayerListHud hud) { + return ((PlayerListHudAccessor) hud).getFooter(); + } +} diff --git a/src/main/java/com/vladmarica/betterpingdisplay/mixin/InGameHudMixin.java b/src/main/java/com/vladmarica/betterpingdisplay/mixin/InGameHudMixin.java new file mode 100644 index 0000000..4911b83 --- /dev/null +++ b/src/main/java/com/vladmarica/betterpingdisplay/mixin/InGameHudMixin.java @@ -0,0 +1,20 @@ +package com.vladmarica.betterpingdisplay.mixin; + +import com.vladmarica.betterpingdisplay.hud.CustomPlayerListHud; +import net.minecraft.client.gui.hud.InGameHud; +import net.minecraft.client.gui.hud.PlayerListHud; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.scoreboard.Scoreboard; +import net.minecraft.scoreboard.ScoreboardObjective; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(InGameHud.class) +abstract class InGameHudMixin { + @Redirect(method = "render", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/PlayerListHud;render(Lnet/minecraft/client/util/math/MatrixStack;ILnet/minecraft/scoreboard/Scoreboard;Lnet/minecraft/scoreboard/ScoreboardObjective;)V")) + private void render(PlayerListHud hud, MatrixStack stack, int width, Scoreboard scoreboard, ScoreboardObjective objective) { + CustomPlayerListHud.render(hud, stack, width, scoreboard, objective); + } +} diff --git a/src/main/java/com/vladmarica/betterpingdisplay/mixin/PlayerListHudAccessor.java b/src/main/java/com/vladmarica/betterpingdisplay/mixin/PlayerListHudAccessor.java new file mode 100644 index 0000000..8d5f8d8 --- /dev/null +++ b/src/main/java/com/vladmarica/betterpingdisplay/mixin/PlayerListHudAccessor.java @@ -0,0 +1,25 @@ +package com.vladmarica.betterpingdisplay.mixin; + +import net.minecraft.client.gui.hud.PlayerListHud; +import net.minecraft.client.network.PlayerListEntry; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.scoreboard.ScoreboardObjective; +import net.minecraft.text.Text; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(PlayerListHud.class) +public interface PlayerListHudAccessor { + @Invoker + void invokeRenderLatencyIcon(MatrixStack stack, int x, int offsetX, int y, PlayerListEntry player); + + @Invoker + void invokeRenderScoreboardObjective(ScoreboardObjective obj, int i, String str, int j, int k, PlayerListEntry player, MatrixStack stack); + + @Accessor("header") + Text getHeader(); + + @Accessor("footer") + Text getFooter(); +} diff --git a/src/main/java/com/vladmarica/betterpingdisplay/mixin/PlayerListHudInvoker.java b/src/main/java/com/vladmarica/betterpingdisplay/mixin/PlayerListHudInvoker.java deleted file mode 100644 index 5d57e0c..0000000 --- a/src/main/java/com/vladmarica/betterpingdisplay/mixin/PlayerListHudInvoker.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.vladmarica.betterpingdisplay.mixin; - -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.hud.PlayerListHud; -import net.minecraft.client.network.PlayerListEntry; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Invoker; - -@Mixin(PlayerListHud.class) -public interface PlayerListHudInvoker { - @Invoker("renderLatencyIcon") - void invokeRenderLatencyIcon(DrawContext context, int width, int x, int y, PlayerListEntry entry); -} diff --git a/src/main/java/com/vladmarica/betterpingdisplay/mixin/PlayerListHudMixin.java b/src/main/java/com/vladmarica/betterpingdisplay/mixin/PlayerListHudMixin.java deleted file mode 100644 index e1612b5..0000000 --- a/src/main/java/com/vladmarica/betterpingdisplay/mixin/PlayerListHudMixin.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.vladmarica.betterpingdisplay.mixin; - -import com.vladmarica.betterpingdisplay.hud.CustomPlayerListHud; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.hud.PlayerListHud; -import net.minecraft.client.network.PlayerListEntry; -import org.jetbrains.annotations.NotNull; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Constant; -import org.spongepowered.asm.mixin.injection.ModifyConstant; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(PlayerListHud.class) -public abstract class PlayerListHudMixin { - @Unique - @Final - private static final int PLAYER_SLOT_EXTRA_WIDTH = 45; - - @Shadow - @Final - private MinecraftClient client; - - /** - * Increases the int constant {@code 13} in the {@link PlayerListHud#render} method by - * {@value #PLAYER_SLOT_EXTRA_WIDTH}. This constant is used to define the width of the "slots" in the player list. - * In order to fit the ping text, this needs to be increased. - */ - @ModifyConstant(method = "render", constant = @Constant(intValue = 13)) - private int modifySlotWidthConstant(int original) { - return original + PLAYER_SLOT_EXTRA_WIDTH; - } - - /** - * Redirects the call to {@code renderLatencyIcon} in {@link PlayerListHud#render} to instead call - * {@link CustomPlayerListHud#renderPingDisplay}. - */ - @Redirect(method = "render", - at = @At(value = "INVOKE", target = "net/minecraft/client/gui/hud/PlayerListHud.renderLatencyIcon(Lnet/minecraft/client/gui/DrawContext;IIILnet/minecraft/client/network/PlayerListEntry;)V")) - private void redirectRenderLatencyIconCall( - PlayerListHud instance, DrawContext context, int width, int x, int y, @NotNull PlayerListEntry entry) { - CustomPlayerListHud.renderPingDisplay(client, instance, context, width, x, y, entry); - } -} diff --git a/src/main/resources/betterpingdisplay.mixins.json b/src/main/resources/betterpingdisplay.mixins.json index 0fe092b..45b09ed 100644 --- a/src/main/resources/betterpingdisplay.mixins.json +++ b/src/main/resources/betterpingdisplay.mixins.json @@ -1,15 +1,15 @@ { - "required": true, - "minVersion": "0.8", - "package": "com.vladmarica.betterpingdisplay.mixin", - "compatibilityLevel": "JAVA_8", - "mixins": [ - ], - "client": [ - "PlayerListHudInvoker", - "PlayerListHudMixin" - ], - "injectors": { - "defaultRequire": 1 + "required": true, + "minVersion": "0.8", + "package": "com.vladmarica.betterpingdisplay.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [ + ], + "client": [ + "InGameHudMixin", + "PlayerListHudAccessor" + ], + "injectors": { + "defaultRequire": 1 } } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 7e3b308..2b2e63c 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -1,22 +1,20 @@ { "schemaVersion": 1, "id": "betterpingdisplay", - "version": "1.1.3", + "version": "1.1", "name": "Better Ping Display", "description": "Shows the actual ping number instead of just bars in the player list!", "authors": [ - "Quintinity", - "Yuuki" + "Quintinity" ], "contact": { - "homepage": "https://git.raiza.dev/Raiza.dev/better-ping-display-fabric", - "sources": "https://git.raiza.dev/Raiza.dev/better-ping-display-fabric", - "issues": "https://git.raiza.dev/Raiza.dev/better-ping-display-fabric/issues" + "homepage": "https://github.com/vladmarica/better-ping-display-fabric", + "sources": "https://github.com/vladmarica/better-ping-display-fabric" }, "license": "MIT", - "icon": "assets/betterpingdisplay/icon.png", + "icon": "assets/modid/icon.png", "environment": "client", "entrypoints": { @@ -29,8 +27,10 @@ ], "depends": { - "fabricloader": ">=0.14", - "minecraft": ">=1.19" + "fabricloader": ">=0.7.4", + "minecraft": "1.16.x" }, - "suggests": {} + "suggests": { + "flamingo": "*" + } } diff --git a/src/test/java/com/vladmarica/betterpingdisplay/hud/ColorUtilTest.java b/src/test/java/com/vladmarica/betterpingdisplay/hud/ColorUtilTest.java index 936717b..65a94c0 100644 --- a/src/test/java/com/vladmarica/betterpingdisplay/hud/ColorUtilTest.java +++ b/src/test/java/com/vladmarica/betterpingdisplay/hud/ColorUtilTest.java @@ -9,7 +9,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -/** Unit tests for {@link ColorUtil} */ @RunWith(JUnit4.class) public class ColorUtilTest { @@ -46,4 +45,4 @@ public class ColorUtilTest { assertThrows(IllegalArgumentException.class, () -> ColorUtil.interpolate(0, 1, -0.1F)); assertThrows(IllegalArgumentException.class, () -> ColorUtil.interpolate(0, 1, 1.1F)); } -} \ No newline at end of file +}