From bdc22e87aeeccff9c25b9237d2807cece5078763 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sat, 7 Mar 2026 00:37:55 +0100 Subject: [PATCH] ping, speedometer, and status effects --- .../modules/interfaces/PingInterface.java | 8 ++ .../interfaces/SpeedometerInterface.java | 20 ++++ .../interfaces/StatusEffectsInterface.java | 36 ++++++ .../org/saturnclient/modules/mods/Ping.java | 21 ++-- .../modules/mods/Speedometer.java | 63 ++++------ .../modules/mods/StatusEffects.java | 86 ++++++++++++++ .../saturnclient/impl/modules/PingFabric.java | 19 +++ .../impl/modules/SpeedometerFabric.java | 23 ++++ .../impl/modules/StatusEffectsFabric.java | 38 ++++++ .../modules/mods/StatusEffects.java | 109 ------------------ 10 files changed, 263 insertions(+), 160 deletions(-) create mode 100644 common/src/main/java/org/saturnclient/modules/interfaces/PingInterface.java create mode 100644 common/src/main/java/org/saturnclient/modules/interfaces/SpeedometerInterface.java create mode 100644 common/src/main/java/org/saturnclient/modules/interfaces/StatusEffectsInterface.java rename {versions/1.21.4 => common}/src/main/java/org/saturnclient/modules/mods/Ping.java (77%) rename {versions/1.21.4 => common}/src/main/java/org/saturnclient/modules/mods/Speedometer.java (63%) create mode 100644 common/src/main/java/org/saturnclient/modules/mods/StatusEffects.java create mode 100644 versions/1.21.4/src/main/java/org/saturnclient/impl/modules/PingFabric.java create mode 100644 versions/1.21.4/src/main/java/org/saturnclient/impl/modules/SpeedometerFabric.java create mode 100644 versions/1.21.4/src/main/java/org/saturnclient/impl/modules/StatusEffectsFabric.java delete mode 100644 versions/1.21.4/src/main/java/org/saturnclient/modules/mods/StatusEffects.java diff --git a/common/src/main/java/org/saturnclient/modules/interfaces/PingInterface.java b/common/src/main/java/org/saturnclient/modules/interfaces/PingInterface.java new file mode 100644 index 0000000..2a93473 --- /dev/null +++ b/common/src/main/java/org/saturnclient/modules/interfaces/PingInterface.java @@ -0,0 +1,8 @@ +package org.saturnclient.modules.interfaces; + +public interface PingInterface { + + /** Returns current player ping in milliseconds */ + int getPing(); + +} \ No newline at end of file diff --git a/common/src/main/java/org/saturnclient/modules/interfaces/SpeedometerInterface.java b/common/src/main/java/org/saturnclient/modules/interfaces/SpeedometerInterface.java new file mode 100644 index 0000000..da896bd --- /dev/null +++ b/common/src/main/java/org/saturnclient/modules/interfaces/SpeedometerInterface.java @@ -0,0 +1,20 @@ +package org.saturnclient.modules.interfaces; + +public interface SpeedometerInterface { + + /** Returns the current player or vehicle velocity in blocks per tick */ + Velocity getVelocity(); + + /** Returns true if player or vehicle is on ground */ + boolean isOnGround(); + + class Velocity { + public final double x, y, z; + + public Velocity(double x, double y, double z) { + this.x = x; + this.y = y; + this.z = z; + } + } +} \ No newline at end of file diff --git a/common/src/main/java/org/saturnclient/modules/interfaces/StatusEffectsInterface.java b/common/src/main/java/org/saturnclient/modules/interfaces/StatusEffectsInterface.java new file mode 100644 index 0000000..0ff0f54 --- /dev/null +++ b/common/src/main/java/org/saturnclient/modules/interfaces/StatusEffectsInterface.java @@ -0,0 +1,36 @@ +package org.saturnclient.modules.interfaces; + +import java.util.List; +import org.saturnclient.common.minecraft.bindings.SaturnSprite; + +public interface StatusEffectsInterface { + + /** Returns a list of currently active effects */ + List getActiveEffects(); + + /** Returns a dummy list of effects for dummy rendering */ + List getDummyEffects(); + + /** Represents a single effect for rendering purposes */ + class Effect { + private final SaturnSprite icon; + private final int durationSeconds; + private final boolean infinite; + private final boolean showIcon; + private final String infiniteText; + + public Effect(SaturnSprite icon, int durationSeconds, boolean infinite, boolean showIcon, String infiniteText) { + this.icon = icon; + this.durationSeconds = durationSeconds; + this.infinite = infinite; + this.showIcon = showIcon; + this.infiniteText = infiniteText; + } + + public SaturnSprite getIcon() { return icon; } + public int getDurationSeconds() { return durationSeconds; } + public boolean isInfinite() { return infinite; } + public boolean shouldShowIcon() { return showIcon; } + public String getInfiniteText() { return infiniteText; } + } +} \ No newline at end of file diff --git a/versions/1.21.4/src/main/java/org/saturnclient/modules/mods/Ping.java b/common/src/main/java/org/saturnclient/modules/mods/Ping.java similarity index 77% rename from versions/1.21.4/src/main/java/org/saturnclient/modules/mods/Ping.java rename to common/src/main/java/org/saturnclient/modules/mods/Ping.java index d579635..7d84914 100644 --- a/versions/1.21.4/src/main/java/org/saturnclient/modules/mods/Ping.java +++ b/common/src/main/java/org/saturnclient/modules/mods/Ping.java @@ -5,33 +5,32 @@ import org.saturnclient.modules.ModDimensions; import org.saturnclient.modules.Module; import org.saturnclient.modules.ModuleDetails; import org.saturnclient.config.manager.Property; +import org.saturnclient.modules.interfaces.PingInterface; import org.saturnclient.ui.RenderScope; import org.saturnclient.ui.resources.Fonts; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayNetworkHandler; - public class Ping extends Module implements HudMod { + private static Property enabled = Property.bool(false); private static ModDimensions dimensions = new ModDimensions(60, Fonts.getHeight()); - public Ping() { + private final PingInterface pingProvider; + + public Ping(PingInterface pingProvider) { super(new ModuleDetails("Ping Display", "ping") .description("Displays ping") .version("v0.1.0") .tags("Utility"), enabled.named("Enabled"), dimensions.prop()); + + this.pingProvider = pingProvider; } @Override public void renderHud(RenderScope scope) { - MinecraftClient client = MinecraftClient.getInstance(); - ClientPlayNetworkHandler handler = client.getNetworkHandler(); - String text = "0 ms"; - if (handler != null) { - text = String.valueOf(handler.getPlayerListEntry(client.player.getUuid()).getLatency()) + " ms"; - } + int ping = pingProvider.getPing(); + String text = ping + " ms"; scope.drawText(text, 0, 0, dimensions.font.value, dimensions.fgColor.value); dimensions.width = Fonts.getWidth(text, dimensions.font.value); } @@ -57,4 +56,4 @@ public class Ping extends Module implements HudMod { public ModDimensions getDimensions() { return dimensions; } -} +} \ No newline at end of file diff --git a/versions/1.21.4/src/main/java/org/saturnclient/modules/mods/Speedometer.java b/common/src/main/java/org/saturnclient/modules/mods/Speedometer.java similarity index 63% rename from versions/1.21.4/src/main/java/org/saturnclient/modules/mods/Speedometer.java rename to common/src/main/java/org/saturnclient/modules/mods/Speedometer.java index ea25316..b131ace 100644 --- a/versions/1.21.4/src/main/java/org/saturnclient/modules/mods/Speedometer.java +++ b/common/src/main/java/org/saturnclient/modules/mods/Speedometer.java @@ -4,25 +4,23 @@ import org.saturnclient.modules.HudMod; import org.saturnclient.modules.ModDimensions; import org.saturnclient.modules.Module; import org.saturnclient.modules.ModuleDetails; -import org.saturnclient.saturnclient.SaturnClient; import org.saturnclient.config.manager.Property; +import org.saturnclient.modules.interfaces.SpeedometerInterface; import org.saturnclient.ui.RenderScope; import org.saturnclient.ui.resources.Fonts; -import net.minecraft.util.math.Vec3d; -import net.minecraft.entity.Entity; - public class Speedometer extends Module implements HudMod { + private static Property enabled = Property.bool(false); private static Property axis = Property.select(1, "Absolute", "X axis", "Y axis"); private static Property unitText = Property.select(0, "None", "Blocks/s", "blocks/s", "b/s"); private static Property speedText = Property.bool(true); private static ModDimensions dimensions = new ModDimensions(40, 18); - double speed = 0.; - Vec3d velocity; - double y = 0.; - public Speedometer() { + private final SpeedometerInterface provider; + private double speed = 0.; + + public Speedometer(SpeedometerInterface provider) { super(new ModuleDetails("Speedometer", "speed") .description("Displays your current speed") .version("v0.1.0") @@ -32,6 +30,8 @@ public class Speedometer extends Module implements HudMod { unitText.named("Unit text"), speedText.named("Show speed text"), dimensions.prop()); + + this.provider = provider; } @Override @@ -41,57 +41,40 @@ public class Speedometer extends Module implements HudMod { @Override public void renderHud(RenderScope scope) { - Entity vehicle = SaturnClient.client.player.getVehicle(); - Entity player = SaturnClient.client.player; + SpeedometerInterface.Velocity velocity = provider.getVelocity(); + boolean onGround = provider.isOnGround(); - if (vehicle == null) { - velocity = player.getVelocity(); - y = player.isOnGround() ? 0. : velocity.y; - } else { - velocity = vehicle.getVelocity(); - y = vehicle.isOnGround() ? 0. : velocity.y; - } + double y = onGround ? 0.0 : velocity.y; switch (axis.value) { case 0: // Absolute - speed = (Math.sqrt(Math.pow(velocity.x, 2) + Math.pow(y, 2) + Math.pow(velocity.z, 2))); + speed = Math.sqrt(Math.pow(velocity.x, 2) + Math.pow(y, 2) + Math.pow(velocity.z, 2)); break; - - case 1: // x axis - speed = (Math.sqrt(Math.pow(velocity.x, 2) + Math.pow(velocity.z, 2))); + case 1: // X axis + speed = Math.sqrt(Math.pow(velocity.x, 2) + Math.pow(velocity.z, 2)); break; - - case 2: // y axis - speed = (Math.abs(y)); + case 2: // Y axis + speed = Math.abs(y); break; } + renderSpeed(speed * 20, scope); // blocks/tick to blocks/s } public void renderSpeed(double speed, RenderScope scope) { - String f = String.format("%.2f ", speed); + String text = String.format("%.2f ", speed); switch (unitText.value) { - case 1: - f += "Blocks/s"; - break; - - case 2: - f += "blocks/s"; - break; - case 3: - f += "b/s"; - break; + case 1 -> text += "Blocks/s"; + case 2 -> text += "blocks/s"; + case 3 -> text += "b/s"; } - String text = f; - if (speedText.value) { text = "Speed: " + text; } - scope.drawText(text, - 0, 0, dimensions.font.value, dimensions.fgColor.value); + scope.drawText(text, 0, 0, dimensions.font.value, dimensions.fgColor.value); dimensions.width = Fonts.getWidth(text, dimensions.font.value); dimensions.height = 18 * text.split("\n").length; } @@ -110,4 +93,4 @@ public class Speedometer extends Module implements HudMod { public void onEnabled(boolean e) { enabled.value = e; } -} +} \ No newline at end of file diff --git a/common/src/main/java/org/saturnclient/modules/mods/StatusEffects.java b/common/src/main/java/org/saturnclient/modules/mods/StatusEffects.java new file mode 100644 index 0000000..cbd8efe --- /dev/null +++ b/common/src/main/java/org/saturnclient/modules/mods/StatusEffects.java @@ -0,0 +1,86 @@ +package org.saturnclient.modules.mods; + +import java.util.List; + +import org.saturnclient.modules.HudMod; +import org.saturnclient.modules.ModDimensions; +import org.saturnclient.modules.Module; +import org.saturnclient.modules.ModuleDetails; +import org.saturnclient.modules.interfaces.StatusEffectsInterface; +import org.saturnclient.config.manager.Property; +import org.saturnclient.ui.RenderScope; + +public class StatusEffects extends Module implements HudMod { + + public static Property enabled = Property.bool(false); + private static ModDimensions dimensions = new ModDimensions(60, 0); + + private final StatusEffectsInterface provider; + + public StatusEffects(StatusEffectsInterface provider) { + super(new ModuleDetails("Status effects", "effect") + .description("Displays status effects") + .version("v0.1.0") + .tags("Utility"), + enabled.named("Enabled"), + dimensions.prop()); + + this.provider = provider; + } + + private void renderEffects(RenderScope scope, List effects) { + int row = 0; + + for (StatusEffectsInterface.Effect effect : effects) { + if (!effect.shouldShowIcon()) continue; + + scope.drawSpriteStretched(effect.getIcon(), 0, 18 * row, 16, 16); + scope.drawText(0.5f, getDurationAsString(effect), 18, 18 * row + 3, dimensions.font.value, -1); + row++; + } + + dimensions.height = 18 * row; + } + + @Override + public void renderHud(RenderScope scope) { + renderEffects(scope, provider.getActiveEffects()); + } + + @Override + public void renderDummy(RenderScope scope) { + renderEffects(scope, provider.getDummyEffects()); + } + + private String getDurationAsString(StatusEffectsInterface.Effect effect) { + if (effect.isInfinite()) { + return effect.getInfiniteText(); + } + + int totalSeconds = effect.getDurationSeconds(); + if (totalSeconds >= 3600) { + return totalSeconds / 3600 + "h"; + } else if (totalSeconds >= 60) { + int minutes = totalSeconds / 60; + int seconds = totalSeconds % 60; + return String.format("%d:%02d", minutes, seconds); + } else { + return totalSeconds + "s"; + } + } + + @Override + public ModDimensions getDimensions() { + return dimensions; + } + + @Override + public boolean isEnabled() { + return enabled.value; + } + + @Override + public void onEnabled(boolean e) { + enabled.value = e; + } +} \ No newline at end of file diff --git a/versions/1.21.4/src/main/java/org/saturnclient/impl/modules/PingFabric.java b/versions/1.21.4/src/main/java/org/saturnclient/impl/modules/PingFabric.java new file mode 100644 index 0000000..e7e40d3 --- /dev/null +++ b/versions/1.21.4/src/main/java/org/saturnclient/impl/modules/PingFabric.java @@ -0,0 +1,19 @@ +package org.saturnclient.impl.modules; + +import org.saturnclient.modules.interfaces.PingInterface; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayNetworkHandler; + +public class PingFabric implements PingInterface { + + private final MinecraftClient mc = MinecraftClient.getInstance(); + + @Override + public int getPing() { + if (mc.player == null || mc.getNetworkHandler() == null) return 0; + ClientPlayNetworkHandler handler = mc.getNetworkHandler(); + if (handler.getPlayerListEntry(mc.player.getUuid()) == null) return 0; + return handler.getPlayerListEntry(mc.player.getUuid()).getLatency(); + } +} \ No newline at end of file diff --git a/versions/1.21.4/src/main/java/org/saturnclient/impl/modules/SpeedometerFabric.java b/versions/1.21.4/src/main/java/org/saturnclient/impl/modules/SpeedometerFabric.java new file mode 100644 index 0000000..8b5f271 --- /dev/null +++ b/versions/1.21.4/src/main/java/org/saturnclient/impl/modules/SpeedometerFabric.java @@ -0,0 +1,23 @@ +package org.saturnclient.impl.modules; + +import org.saturnclient.modules.interfaces.SpeedometerInterface; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.Entity; + +public class SpeedometerFabric implements SpeedometerInterface { + + private final MinecraftClient mc = MinecraftClient.getInstance(); + + @Override + public Velocity getVelocity() { + Entity entity = mc.player.getVehicle() != null ? mc.player.getVehicle() : mc.player; + return new Velocity(entity.getVelocity().x, entity.getVelocity().y, entity.getVelocity().z); + } + + @Override + public boolean isOnGround() { + Entity entity = mc.player.getVehicle() != null ? mc.player.getVehicle() : mc.player; + return entity.isOnGround(); + } +} \ No newline at end of file diff --git a/versions/1.21.4/src/main/java/org/saturnclient/impl/modules/StatusEffectsFabric.java b/versions/1.21.4/src/main/java/org/saturnclient/impl/modules/StatusEffectsFabric.java new file mode 100644 index 0000000..0c133ec --- /dev/null +++ b/versions/1.21.4/src/main/java/org/saturnclient/impl/modules/StatusEffectsFabric.java @@ -0,0 +1,38 @@ +package org.saturnclient.impl.modules; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.Arrays; + +import org.saturnclient.modules.interfaces.StatusEffectsInterface; +import org.saturnclient.common.minecraft.bindings.SaturnSprite; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.texture.StatusEffectSpriteManager; +import net.minecraft.entity.effect.StatusEffectInstance; + +public class StatusEffectsFabric implements StatusEffectsInterface { + + private final MinecraftClient mc = MinecraftClient.getInstance(); + + @Override + public List getActiveEffects() { + StatusEffectSpriteManager manager = mc.getStatusEffectSpriteManager(); + return mc.player.getStatusEffects().stream() + .filter(StatusEffectInstance::shouldShowIcon) + .map(se -> new Effect( + new SaturnSprite(manager.getSprite(se.getEffectType())), + se.getDuration() / 20, + se.isInfinite(), + se.shouldShowIcon(), + "Infinite")) + .collect(Collectors.toList()); + } + + @Override + public List getDummyEffects() { + return Arrays.asList( + new Effect(new SaturnSprite(null), 600, false, true, "Infinite"), + new Effect(new SaturnSprite(null), 600, false, true, "Infinite")); + } +} \ No newline at end of file diff --git a/versions/1.21.4/src/main/java/org/saturnclient/modules/mods/StatusEffects.java b/versions/1.21.4/src/main/java/org/saturnclient/modules/mods/StatusEffects.java deleted file mode 100644 index 19c6e4f..0000000 --- a/versions/1.21.4/src/main/java/org/saturnclient/modules/mods/StatusEffects.java +++ /dev/null @@ -1,109 +0,0 @@ -package org.saturnclient.modules.mods; - -import java.util.Arrays; - -import org.saturnclient.modules.HudMod; -import org.saturnclient.modules.ModDimensions; -import org.saturnclient.modules.Module; -import org.saturnclient.modules.ModuleDetails; -import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.common.minecraft.bindings.SaturnSprite; -import org.saturnclient.config.manager.Property; -import org.saturnclient.ui.RenderScope; - -import net.minecraft.client.resource.language.I18n; -import net.minecraft.client.texture.Sprite; -import net.minecraft.client.texture.StatusEffectSpriteManager; -import net.minecraft.entity.effect.StatusEffect; -import net.minecraft.entity.effect.StatusEffectInstance; -import net.minecraft.registry.Registries; -import net.minecraft.registry.entry.RegistryEntry; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.MathHelper; - -public class StatusEffects extends Module implements HudMod { - public static Property enabled = Property.bool(false); - private static ModDimensions dimensions = new ModDimensions(60, 0); - - private final StatusEffectInstance[] dummyEffects = { - new StatusEffectInstance(Registries.STATUS_EFFECT.getEntry(Identifier.ofVanilla("speed")).get(), 12000, 2), - new StatusEffectInstance(Registries.STATUS_EFFECT.getEntry(Identifier.ofVanilla("strength")).get(), 12000, - 2), - new StatusEffectInstance(Registries.STATUS_EFFECT.getEntry(Identifier.ofVanilla("fire_resistance")).get(), - 12000, 2), - }; - - public StatusEffects() { - super(new ModuleDetails("Status effects", "effect") - .description("Displays status effects") - .version("v0.1.0") - .tags("Utility"), - - enabled.named("Enabled"), - dimensions.prop()); - } - - private void renderEffects(RenderScope scope, Iterable effects) { - int row = 0; - - StatusEffectSpriteManager statusEffectSpriteManager = SaturnClient.client.getStatusEffectSpriteManager(); - - for (StatusEffectInstance effect : effects) { - if (effect.shouldShowIcon()) { - RegistryEntry registryEntry = effect.getEffectType(); - Sprite sprite = statusEffectSpriteManager.getSprite(registryEntry); - scope.drawSpriteStretched(new SaturnSprite(sprite), 0, 18 * row, 16, 16); - scope.drawText(0.5f, getDurationAsString(effect), 18, 18 * row + 3, dimensions.font.value, -1); - row++; - } - } - - dimensions.height = 18 * row; - } - - @Override - public void renderHud(RenderScope scope) { - renderEffects(scope, SaturnClient.client.player.getStatusEffects()); - } - - @Override - public void renderDummy(RenderScope scope) { - renderEffects(scope, Arrays.asList(dummyEffects)); - } - - // This code was from: - // https://github.com/magicus/statuseffecttimer/blob/master/src/main/java/se/icus/mag/statuseffecttimer/mixin/StatusEffectTimerMixin.java - private String getDurationAsString(StatusEffectInstance statusEffectInstance) { - if (statusEffectInstance.isInfinite()) { - return I18n.translate("effect.duration.infinite"); - } - - int ticks = MathHelper.floor((float) statusEffectInstance.getDuration()); - int totalSeconds = ticks / 20; - - if (totalSeconds >= 3600) { - return totalSeconds / 3600 + "h"; - } else if (totalSeconds >= 60) { - int minutes = totalSeconds / 60; - int seconds = totalSeconds % 60; - return String.format("%d:%02d", minutes, seconds); - } else { - return String.valueOf(totalSeconds) + "s"; - } - } - - @Override - public ModDimensions getDimensions() { - return dimensions; - } - - @Override - public boolean isEnabled() { - return enabled.value; - } - - @Override - public void onEnabled(boolean e) { - enabled.value = e; - } -}