Refactored Feature to Mod
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
package org.saturnclient.mod;
|
||||
|
||||
import org.saturnclient.ui.RenderScope;
|
||||
|
||||
public interface HudMod {
|
||||
public ModLayout getDimensions();
|
||||
|
||||
public void renderDummy(RenderScope scope);
|
||||
|
||||
public void renderHud(RenderScope scope);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package org.saturnclient.mod;
|
||||
|
||||
import org.saturnclient.common.ref.asset.IdentifierRef;
|
||||
import org.saturnclient.config.ConfigManager;
|
||||
import org.saturnclient.config.property.NamedProperty;
|
||||
import org.saturnclient.ui.RenderScope;
|
||||
import org.saturnclient.ui.resources.Textures;
|
||||
|
||||
public abstract class Mod {
|
||||
private final ModSpec details;
|
||||
private final ConfigManager configManager;
|
||||
|
||||
public Mod(ModSpec details, NamedProperty... props) {
|
||||
this.details = details;
|
||||
configManager = new ConfigManager(details.name);
|
||||
for (NamedProperty prop : props) {
|
||||
configManager.property(prop.name, prop.prop);
|
||||
}
|
||||
}
|
||||
|
||||
public void render(RenderScope scope) {
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
}
|
||||
|
||||
public abstract boolean isEnabled();
|
||||
|
||||
public final void setEnabled(boolean e) {
|
||||
onEnabled(e);
|
||||
ModManager.updateEnabledModules();
|
||||
}
|
||||
|
||||
public abstract void onEnabled(boolean e);
|
||||
|
||||
public final String getName() {
|
||||
return details.name;
|
||||
}
|
||||
|
||||
public IdentifierRef getIconTexture() {
|
||||
return Textures.getModIcon(details.namespace);
|
||||
}
|
||||
|
||||
public ConfigManager getConfig() {
|
||||
return configManager;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return details.description;
|
||||
}
|
||||
|
||||
public String[] getTags() {
|
||||
return details.tags;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return details.version;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package org.saturnclient.mod;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.saturnclient.config.property.Property;
|
||||
import org.saturnclient.config.property.SelectProperty;
|
||||
import org.saturnclient.config.property.ColorProperty;
|
||||
import org.saturnclient.config.property.FloatProperty;
|
||||
import org.saturnclient.config.property.IntProperty;
|
||||
import org.saturnclient.config.property.NamedProperty;
|
||||
|
||||
public class ModLayout {
|
||||
public IntProperty x = Property.integer(0);
|
||||
public IntProperty y = Property.integer(0);
|
||||
public FloatProperty scale = Property.floatProp(1.0f);
|
||||
public ColorProperty bgColor = Property.color(0x00000000);
|
||||
public ColorProperty fgColor = Property.color(0xFFffffff);
|
||||
public IntProperty radius = Property.integer(0);
|
||||
public SelectProperty font = Property.font(0);
|
||||
public boolean renderBackground = true;
|
||||
|
||||
public int width = 0;
|
||||
public int height = 0;
|
||||
|
||||
public NamedProperty prop() {
|
||||
return Property.namespace(Map.of(
|
||||
"X", x,
|
||||
"Y", y,
|
||||
"Scale", scale,
|
||||
"Background Color", bgColor,
|
||||
"Foreground Color", fgColor,
|
||||
"Corner Radius", radius,
|
||||
"Font", font)).named("In-Game Display");
|
||||
}
|
||||
|
||||
public ModLayout() {
|
||||
}
|
||||
|
||||
public ModLayout(int width, int height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public ModLayout(int x, int y, int width, int height) {
|
||||
this.x.value = x;
|
||||
this.y.value = y;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public ModLayout(int x, int y, int width, int height, float scale) {
|
||||
this.x.value = x;
|
||||
this.y.value = y;
|
||||
this.scale.value = scale;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.saturnclient.mod;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.saturnclient.mod.mods.*;
|
||||
|
||||
public class ModManager {
|
||||
public static List<Mod> ENABLED_MODS = new ArrayList<>();
|
||||
public static Mod[] MODS = {
|
||||
new ArmorDisplayFeature(), new DayCounterFeature(), new KeystrokesFeature(), new StatusEffectsFeature(),
|
||||
new AutoSprintFeature(), new FpsFeature(), new NametagsFeature(), new TpsFeature(),
|
||||
new ClockFeature(), new FreelookFeature(), new NoFogFeature(), new ZoomFeature(),
|
||||
new CoordinatesFeature(), new FullbrightFeature(), new PingFeature(),
|
||||
new CrosshairFeature(), new HealthDisplayFeature(), new SpeedometerFeature(),
|
||||
};
|
||||
|
||||
public static void init() {
|
||||
updateEnabledModules();
|
||||
}
|
||||
|
||||
public static synchronized void updateEnabledModules() {
|
||||
ENABLED_MODS.clear();
|
||||
for (Mod m : MODS) {
|
||||
if (m.isEnabled()) {
|
||||
ENABLED_MODS.add(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.saturnclient.mod;
|
||||
|
||||
public class ModSpec {
|
||||
public String name;
|
||||
public String namespace;
|
||||
public String description;
|
||||
public String version;
|
||||
public String[] tags = {};
|
||||
|
||||
public ModSpec(String name, String namespace) {
|
||||
this.name = name;
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
public ModSpec name(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModSpec namespace(String namespace) {
|
||||
this.namespace = namespace;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModSpec description(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModSpec version(String version) {
|
||||
this.version = version;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ModSpec tags(String... tags) {
|
||||
this.tags = tags;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package org.saturnclient.mod.mods;
|
||||
|
||||
import org.saturnclient.common.provider.Providers;
|
||||
import org.saturnclient.common.module.PlayerModule;
|
||||
import org.saturnclient.common.ref.game.ItemStackRef;
|
||||
import org.saturnclient.config.property.BoolProperty;
|
||||
import org.saturnclient.config.property.Property;
|
||||
import org.saturnclient.mod.HudMod;
|
||||
import org.saturnclient.mod.Mod;
|
||||
import org.saturnclient.mod.ModLayout;
|
||||
import org.saturnclient.mod.ModSpec;
|
||||
import org.saturnclient.ui.RenderScope;
|
||||
|
||||
/**
|
||||
* ArmorDisplayFeature renders the durability of the player's equipped
|
||||
* armor pieces (and optionally the main-hand item) as a HUD overlay.
|
||||
*
|
||||
* Engine access is provided exclusively through {@link ModuleProvider}.
|
||||
*/
|
||||
public class ArmorDisplayFeature extends Mod implements HudMod {
|
||||
|
||||
private static final BoolProperty enabled = Property.bool(false);
|
||||
private static final BoolProperty useMainHand = Property.bool(true);
|
||||
private static final ModLayout layout = new ModLayout(40, 75);
|
||||
|
||||
public ArmorDisplayFeature() {
|
||||
super(
|
||||
new ModSpec("Armor Display", "armor")
|
||||
.description("Displays armor durability")
|
||||
.version("v0.2.0")
|
||||
.tags("Utility"),
|
||||
enabled.named("Enabled"),
|
||||
useMainHand.named("Use Main Hand"),
|
||||
layout.prop());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// HudFeature
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void renderHud(RenderScope scope) {
|
||||
PlayerModule player = Providers.module.player();
|
||||
renderArmor(scope,
|
||||
player.getMainHand(),
|
||||
player.getHelmet(),
|
||||
player.getChestplate(),
|
||||
player.getLeggings(),
|
||||
player.getBoots());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderDummy(RenderScope scope) {
|
||||
PlayerModule player = Providers.module.player();
|
||||
renderArmor(scope,
|
||||
player.getDummyMainHand(),
|
||||
player.getDummyHelmet(),
|
||||
player.getDummyChestplate(),
|
||||
player.getDummyLeggings(),
|
||||
player.getDummyBoots());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Rendering helpers
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
private void renderArmor(RenderScope scope,
|
||||
ItemStackRef mainHand,
|
||||
ItemStackRef helmet,
|
||||
ItemStackRef chestplate,
|
||||
ItemStackRef leggings,
|
||||
ItemStackRef boots) {
|
||||
|
||||
int row = 0;
|
||||
|
||||
if (useMainHand.value && !mainHand.isEmpty()) {
|
||||
row = renderSlot(scope, mainHand, row);
|
||||
}
|
||||
if (!helmet.isEmpty())
|
||||
row = renderSlot(scope, helmet, row);
|
||||
if (!chestplate.isEmpty())
|
||||
row = renderSlot(scope, chestplate, row);
|
||||
if (!leggings.isEmpty())
|
||||
row = renderSlot(scope, leggings, row);
|
||||
if (!boots.isEmpty())
|
||||
row = renderSlot(scope, boots, row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a single equipment slot and returns the next row index.
|
||||
*/
|
||||
private int renderSlot(RenderScope scope, ItemStackRef item, int row) {
|
||||
scope.drawItem(item, 0, 15 * row);
|
||||
|
||||
if (item.getMaxDamage() > 0) {
|
||||
int remaining = item.getMaxDamage() - item.getDamage();
|
||||
scope.drawText(0.5f, String.valueOf(remaining),
|
||||
17, (15 * row) + 3,
|
||||
layout.font.value, layout.fgColor.value);
|
||||
}
|
||||
|
||||
return row + 1;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Feature contract
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public ModLayout getDimensions() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled(boolean e) {
|
||||
enabled.value = e;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package org.saturnclient.mod.mods;
|
||||
|
||||
import org.saturnclient.common.provider.Providers;
|
||||
import org.saturnclient.config.property.BoolProperty;
|
||||
import org.saturnclient.config.property.Property;
|
||||
import org.saturnclient.mod.Mod;
|
||||
import org.saturnclient.mod.ModSpec;
|
||||
import org.saturnclient.common.module.NetworkModule;
|
||||
import org.saturnclient.common.module.PlayerModule;
|
||||
|
||||
/**
|
||||
* AutoSprintFeature automatically enables sprinting whenever the
|
||||
* player moves forward and no sprint-blocking condition is active.
|
||||
*/
|
||||
public class AutoSprintFeature extends Mod {
|
||||
|
||||
private static final BoolProperty enabled = Property.bool(false);
|
||||
|
||||
public AutoSprintFeature() {
|
||||
super(
|
||||
new ModSpec("Auto Sprint", "sprint")
|
||||
.description("Makes the player always sprint")
|
||||
.tags("Movement")
|
||||
.version("v0.2.0"),
|
||||
enabled.named("Enabled"));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Feature contract
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
PlayerModule player = Providers.module.player();
|
||||
NetworkModule network = Providers.module.network();
|
||||
|
||||
if (!player.hasPlayer() || !network.hasNetwork()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.isForwardPressed()
|
||||
&& !player.isBackPressed()
|
||||
&& !player.isSneaking()
|
||||
&& !player.hasHorizontalCollision()
|
||||
&& !player.isUsingItem()) {
|
||||
|
||||
player.setSprinting(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled(boolean e) {
|
||||
enabled.value = e;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package org.saturnclient.mod.mods;
|
||||
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import org.saturnclient.ui.RenderScope;
|
||||
import org.saturnclient.ui.resources.Fonts;
|
||||
import org.saturnclient.config.property.BoolProperty;
|
||||
import org.saturnclient.config.property.Property;
|
||||
import org.saturnclient.config.property.SelectProperty;
|
||||
import org.saturnclient.mod.HudMod;
|
||||
import org.saturnclient.mod.Mod;
|
||||
import org.saturnclient.mod.ModLayout;
|
||||
import org.saturnclient.mod.ModSpec;
|
||||
|
||||
/**
|
||||
* ClockFeature displays the real-world time as a HUD element.
|
||||
* No engine access is required; {@link LocalTime} is used directly.
|
||||
*/
|
||||
public class ClockFeature extends Mod implements HudMod {
|
||||
|
||||
private static final BoolProperty enabled = Property.bool(false);
|
||||
private static final SelectProperty format = Property.select(0, "24 hour", "12 hour");
|
||||
private static final BoolProperty showSeconds = Property.bool(false);
|
||||
private static final ModLayout layout = new ModLayout(60, Fonts.getHeight());
|
||||
|
||||
public ClockFeature() {
|
||||
super(
|
||||
new ModSpec("Clock", "clock")
|
||||
.description("Displays the current real-world time")
|
||||
.version("v0.2.0")
|
||||
.tags("Utility"),
|
||||
enabled.named("Enabled"),
|
||||
format.named("Format"),
|
||||
showSeconds.named("Show seconds"),
|
||||
layout.prop());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// HudFeature
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void renderHud(RenderScope scope) {
|
||||
renderClock(scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderDummy(RenderScope scope) {
|
||||
renderClock(scope);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Rendering
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
private void renderClock(RenderScope scope) {
|
||||
String text = buildTimeString(LocalTime.now());
|
||||
|
||||
scope.drawText(text, 0, 0, layout.font.value, layout.fgColor.value);
|
||||
layout.width = Fonts.getWidth(text, layout.font.value);
|
||||
layout.height = 18 * text.split("\n").length;
|
||||
}
|
||||
|
||||
private String buildTimeString(LocalTime time) {
|
||||
return switch (format.value) {
|
||||
case 1 -> time.format(showSeconds.value
|
||||
? DateTimeFormatter.ofPattern("hh:mm:ss a")
|
||||
: DateTimeFormatter.ofPattern("hh:mm a"));
|
||||
default -> time.format(showSeconds.value
|
||||
? DateTimeFormatter.ofPattern("HH:mm:ss")
|
||||
: DateTimeFormatter.ofPattern("HH:mm"));
|
||||
};
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Feature contract
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public ModLayout getDimensions() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled(boolean e) {
|
||||
enabled.value = e;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package org.saturnclient.mod.mods;
|
||||
|
||||
import org.saturnclient.common.provider.Providers;
|
||||
import org.saturnclient.config.property.BoolProperty;
|
||||
import org.saturnclient.config.property.Property;
|
||||
import org.saturnclient.config.property.SelectProperty;
|
||||
import org.saturnclient.mod.HudMod;
|
||||
import org.saturnclient.mod.Mod;
|
||||
import org.saturnclient.mod.ModLayout;
|
||||
import org.saturnclient.mod.ModSpec;
|
||||
import org.saturnclient.ui.RenderScope;
|
||||
import org.saturnclient.ui.resources.Fonts;
|
||||
|
||||
/**
|
||||
* CoordinatesFeature displays the player's current XYZ position as a
|
||||
* HUD element with multiple configurable display formats.
|
||||
*/
|
||||
public class CoordinatesFeature extends Mod implements HudMod {
|
||||
|
||||
private static final BoolProperty enabled = Property.bool(false);
|
||||
private static final SelectProperty displayMethod = Property.select(0,
|
||||
"Flat",
|
||||
"Flat annotated",
|
||||
"Newline",
|
||||
"Newline annotated");
|
||||
private static final ModLayout layout = new ModLayout(40, 18);
|
||||
|
||||
public CoordinatesFeature() {
|
||||
super(
|
||||
new ModSpec("Coordinates", "coords")
|
||||
.description("Displays your current coordinates")
|
||||
.version("v0.2.0")
|
||||
.tags("Utility"),
|
||||
enabled.named("Enabled"),
|
||||
displayMethod.named("Display Method"),
|
||||
layout.prop());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// HudFeature
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void renderHud(RenderScope scope) {
|
||||
renderCoords(
|
||||
Providers.module.player().getX(),
|
||||
Providers.module.player().getY(),
|
||||
Providers.module.player().getZ(),
|
||||
scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderDummy(RenderScope scope) {
|
||||
renderCoords(532, 69, 253, scope);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Rendering
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
private void renderCoords(int x, int y, int z, RenderScope scope) {
|
||||
String fmt = switch (displayMethod.value) {
|
||||
case 1 -> "X: %d Y: %d Z: %d";
|
||||
case 2 -> "%d\n%d\n%d";
|
||||
case 3 -> "X: %d\nY: %d\nZ: %d";
|
||||
default -> "%d %d %d";
|
||||
};
|
||||
|
||||
String text = String.format(fmt, x, y, z);
|
||||
scope.drawText(text, 0, 0, layout.font.value, layout.fgColor.value);
|
||||
|
||||
layout.width = Fonts.getWidth(text, layout.font.value);
|
||||
layout.height = 18 * text.split("\n").length;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Feature contract
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public ModLayout getDimensions() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled(boolean e) {
|
||||
enabled.value = e;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package org.saturnclient.mod.mods;
|
||||
|
||||
import org.saturnclient.common.provider.Providers;
|
||||
import org.saturnclient.config.property.BoolProperty;
|
||||
import org.saturnclient.config.property.Property;
|
||||
import org.saturnclient.mod.Mod;
|
||||
import org.saturnclient.mod.ModSpec;
|
||||
import org.saturnclient.common.module.RenderModule;
|
||||
import org.saturnclient.ui.RenderScope;
|
||||
import org.saturnclient.ui.resources.Textures;
|
||||
|
||||
/**
|
||||
* CrosshairFeature renders an alternative crosshair texture when the
|
||||
* player is aiming at a living entity.
|
||||
*/
|
||||
public class CrosshairFeature extends Mod {
|
||||
|
||||
public static final BoolProperty enabled = Property.bool(false);
|
||||
|
||||
private static final int CROSSHAIR_SIZE = 15;
|
||||
|
||||
public CrosshairFeature() {
|
||||
super(
|
||||
new ModSpec("Crosshair", "crosshair")
|
||||
.description("Changes the crosshair when aiming at an entity")
|
||||
.tags("Visuals", "Utility")
|
||||
.version("v0.2.0"),
|
||||
enabled.named("Enabled"));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Feature contract
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void render(RenderScope scope) {
|
||||
if (!enabled.value || !Providers.module.entity().isTargetingLivingEntity()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RenderModule render = Providers.module.render();
|
||||
int x = (render.getScaledWindowWidth() - CROSSHAIR_SIZE) / 2;
|
||||
int y = (render.getScaledWindowHeight() - CROSSHAIR_SIZE) / 2;
|
||||
|
||||
scope.drawTexture(
|
||||
Textures.CROSSHAIR_RANGE,
|
||||
x, y,
|
||||
0.0F, 0.0F,
|
||||
CROSSHAIR_SIZE, CROSSHAIR_SIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled(boolean e) {
|
||||
enabled.value = e;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package org.saturnclient.mod.mods;
|
||||
|
||||
import org.saturnclient.common.module.WorldModule;
|
||||
import org.saturnclient.common.provider.Providers;
|
||||
import org.saturnclient.config.property.BoolProperty;
|
||||
import org.saturnclient.config.property.Property;
|
||||
import org.saturnclient.mod.HudMod;
|
||||
import org.saturnclient.mod.Mod;
|
||||
import org.saturnclient.mod.ModLayout;
|
||||
import org.saturnclient.mod.ModSpec;
|
||||
import org.saturnclient.ui.RenderScope;
|
||||
import org.saturnclient.ui.resources.Fonts;
|
||||
|
||||
/**
|
||||
* DayCounterFeature shows how many in-game days have elapsed.
|
||||
* Day count is derived from the world age via {@link WorldModule}.
|
||||
*/
|
||||
public class DayCounterFeature extends Mod implements HudMod {
|
||||
|
||||
private static final BoolProperty enabled = Property.bool(false);
|
||||
private static final ModLayout layout = new ModLayout(40, 18);
|
||||
|
||||
public DayCounterFeature() {
|
||||
super(
|
||||
new ModSpec("Day Counter", "day")
|
||||
.description("Displays the number of in-game days elapsed")
|
||||
.version("v0.2.0")
|
||||
.tags("Utility"),
|
||||
enabled.named("Enabled"),
|
||||
layout.prop());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// HudFeature
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void renderHud(RenderScope scope) {
|
||||
renderDay(Providers.module.world().getDay(), scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderDummy(RenderScope scope) {
|
||||
renderDay(271L, scope);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Rendering
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
private void renderDay(long day, RenderScope scope) {
|
||||
String text = "Day: " + day;
|
||||
|
||||
scope.drawText(text, 0, 0, layout.font.value, layout.fgColor.value);
|
||||
layout.width = Fonts.getWidth(text, layout.font.value);
|
||||
layout.height = 18 * text.split("\n").length;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Feature contract
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public ModLayout getDimensions() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled(boolean e) {
|
||||
enabled.value = e;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package org.saturnclient.mod.mods;
|
||||
|
||||
import org.saturnclient.common.module.RenderModule;
|
||||
import org.saturnclient.common.provider.Providers;
|
||||
import org.saturnclient.config.property.BoolProperty;
|
||||
import org.saturnclient.config.property.Property;
|
||||
import org.saturnclient.mod.HudMod;
|
||||
import org.saturnclient.mod.Mod;
|
||||
import org.saturnclient.mod.ModLayout;
|
||||
import org.saturnclient.mod.ModSpec;
|
||||
import org.saturnclient.ui.RenderScope;
|
||||
import org.saturnclient.ui.resources.Fonts;
|
||||
|
||||
/**
|
||||
* FpsFeature displays the current frames-per-second as a HUD element.
|
||||
* FPS is obtained from {@link RenderModule} rather than cached in the feature.
|
||||
*/
|
||||
public class FpsFeature extends Mod implements HudMod {
|
||||
|
||||
private static final BoolProperty enabled = Property.bool(false);
|
||||
private static final ModLayout layout = new ModLayout(60, Fonts.getHeight());
|
||||
|
||||
public FpsFeature() {
|
||||
super(
|
||||
new ModSpec("FPS Display", "fps")
|
||||
.description("Displays current FPS")
|
||||
.version("v0.2.0")
|
||||
.tags("Utility"),
|
||||
enabled.named("Enabled"),
|
||||
layout.prop());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// HudFeature
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void renderHud(RenderScope scope) {
|
||||
renderFps(Providers.module.render().getFps(), scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderDummy(RenderScope scope) {
|
||||
renderFps(369, scope);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Rendering
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
private void renderFps(int fps, RenderScope scope) {
|
||||
String text = fps + " FPS";
|
||||
scope.drawText(text, 0, 0, layout.font.value, layout.fgColor.value);
|
||||
layout.width = Fonts.getWidth(text, layout.font.value);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Feature contract
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public ModLayout getDimensions() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled(boolean e) {
|
||||
enabled.value = e;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package org.saturnclient.mod.mods;
|
||||
|
||||
import org.saturnclient.common.provider.Providers;
|
||||
import org.saturnclient.config.property.BoolProperty;
|
||||
import org.saturnclient.config.property.KeybindingProperty;
|
||||
import org.saturnclient.config.property.Property;
|
||||
import org.saturnclient.mod.Mod;
|
||||
import org.saturnclient.mod.ModSpec;
|
||||
import org.saturnclient.common.module.RenderModule;
|
||||
import org.saturnclient.common.provider.GLFWProvider;
|
||||
|
||||
/**
|
||||
* FreelookFeature lets the player look around freely (in third-person)
|
||||
* without changing the direction their character walks.
|
||||
*
|
||||
* Camera perspective is controlled through {@link RenderModule} so
|
||||
* that the feature itself contains no direct Minecraft API calls.
|
||||
*/
|
||||
public class FreelookFeature extends Mod {
|
||||
|
||||
private static final BoolProperty enabled = Property.bool(false);
|
||||
private static final BoolProperty toggle = Property.bool(true);
|
||||
public static final KeybindingProperty freelookKey = Property.keybinding(GLFWProvider.GLFW_KEY_H);
|
||||
|
||||
/** Whether freelook is currently active (read by the camera mixin). */
|
||||
public static boolean isFreeLooking = false;
|
||||
private static boolean wasFirstPerson = false;
|
||||
|
||||
public FreelookFeature() {
|
||||
super(
|
||||
new ModSpec("Freelook", "freelook")
|
||||
.description("Look around freely without moving your character")
|
||||
.tags("Movement", "Camera")
|
||||
.version("v0.2.0"),
|
||||
enabled.named("Enabled"),
|
||||
toggle.named("Toggle freelook"),
|
||||
freelookKey.named("Freelook Keybinding"));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Feature contract
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (toggle.value) {
|
||||
if (freelookKey.wasKeyPressed()) {
|
||||
if (isFreeLooking)
|
||||
stopFreelook();
|
||||
else
|
||||
startFreelook();
|
||||
}
|
||||
} else if (freelookKey.isKeyPressed()) {
|
||||
if (!isFreeLooking)
|
||||
startFreelook();
|
||||
} else if (isFreeLooking) {
|
||||
stopFreelook();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled(boolean e) {
|
||||
enabled.value = e;
|
||||
if (!e && isFreeLooking)
|
||||
stopFreelook();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Helpers
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
private void startFreelook() {
|
||||
RenderModule render = Providers.module.render();
|
||||
wasFirstPerson = render.isFirstPerson();
|
||||
render.setThirdPersonBack();
|
||||
isFreeLooking = true;
|
||||
}
|
||||
|
||||
private void stopFreelook() {
|
||||
if (wasFirstPerson) {
|
||||
Providers.module.render().setFirstPerson();
|
||||
}
|
||||
isFreeLooking = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package org.saturnclient.mod.mods;
|
||||
|
||||
import org.saturnclient.config.property.BoolProperty;
|
||||
import org.saturnclient.config.property.IntProperty;
|
||||
import org.saturnclient.config.property.Property;
|
||||
import org.saturnclient.mod.Mod;
|
||||
import org.saturnclient.mod.ModSpec;
|
||||
|
||||
/**
|
||||
* FullbrightFeature overrides the game's gamma/brightness to let the
|
||||
* player see in complete darkness.
|
||||
*
|
||||
* Actual brightness injection happens in a mixin; this class owns only
|
||||
* the configuration and the two static query methods the mixin calls.
|
||||
*
|
||||
* No ModuleProvider is needed — this feature has no per-tick engine
|
||||
* interaction; the mixin polls the static helpers directly.
|
||||
*/
|
||||
public class FullbrightFeature extends Mod {
|
||||
|
||||
private static final BoolProperty enabled = Property.bool(false);
|
||||
private static final IntProperty brightness = Property.integer(100);
|
||||
|
||||
public FullbrightFeature() {
|
||||
super(
|
||||
new ModSpec("Fullbright", "fullbright")
|
||||
.description("Allows you to see in the dark")
|
||||
.tags("Camera")
|
||||
.version("v0.2.0"),
|
||||
enabled.named("Enabled"),
|
||||
brightness.named("Brightness %"));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Mixin query API (static so the mixin can call without an instance)
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/** Returns {@code true} when the brightness override should be applied. */
|
||||
public static boolean shouldOverrideBrightness() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the brightness multiplier to apply.
|
||||
* The property stores a percentage (0–100+); the mixin expects a
|
||||
* normalised float where 1.0 ≈ 100 %.
|
||||
*/
|
||||
public static float getBrightnessValue() {
|
||||
return brightness.value / 10.0f;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Feature contract
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled(boolean e) {
|
||||
enabled.value = e;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package org.saturnclient.mod.mods;
|
||||
|
||||
import org.saturnclient.common.provider.Providers;
|
||||
import org.saturnclient.config.property.BoolProperty;
|
||||
import org.saturnclient.config.property.Property;
|
||||
import org.saturnclient.config.property.SelectProperty;
|
||||
import org.saturnclient.mod.HudMod;
|
||||
import org.saturnclient.mod.Mod;
|
||||
import org.saturnclient.mod.ModLayout;
|
||||
import org.saturnclient.mod.ModSpec;
|
||||
import org.saturnclient.ui.RenderScope;
|
||||
import org.saturnclient.ui.resources.Fonts;
|
||||
|
||||
/**
|
||||
* HealthDisplayFeature renders the player's current health as a HUD
|
||||
* element, with configurable display modes (raw health vs. hearts) and
|
||||
* decimal precision.
|
||||
*/
|
||||
public class HealthDisplayFeature extends Mod implements HudMod {
|
||||
|
||||
private static final BoolProperty enabled = Property.bool(false);
|
||||
private static final SelectProperty displayMode = Property.select(0, "Health", "Hearts");
|
||||
private static final SelectProperty decimals = Property.select(0, "0", "1", "2");
|
||||
private static final ModLayout layout = new ModLayout(40, 18);
|
||||
|
||||
public HealthDisplayFeature() {
|
||||
super(
|
||||
new ModSpec("Health Display", "health")
|
||||
.description("Displays your current health")
|
||||
.version("v0.2.0")
|
||||
.tags("Utility"),
|
||||
enabled.named("Enabled"),
|
||||
displayMode.named("Display mode"),
|
||||
decimals.named("Decimals"),
|
||||
layout.prop());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// HudFeature
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void renderHud(RenderScope scope) {
|
||||
float health = Providers.module.player().getHealth();
|
||||
if (displayMode.value == 1)
|
||||
health /= 2f; // convert to hearts
|
||||
renderHealth(health, scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderDummy(RenderScope scope) {
|
||||
renderHealth(10f, scope);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Rendering
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
private void renderHealth(float health, RenderScope scope) {
|
||||
String fmt = switch (decimals.value) {
|
||||
case 1 -> "%.1f ";
|
||||
case 2 -> "%.2f ";
|
||||
default -> "%.0f ";
|
||||
};
|
||||
|
||||
String text = String.format(fmt, health);
|
||||
scope.drawText(text, 0, 0, layout.font.value, layout.fgColor.value);
|
||||
|
||||
layout.width = Fonts.getWidth(text, layout.font.value);
|
||||
layout.height = 18 * text.split("\n").length;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Feature contract
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public ModLayout getDimensions() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled(boolean e) {
|
||||
enabled.value = e;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
package org.saturnclient.mod.mods;
|
||||
|
||||
import org.saturnclient.common.provider.Providers;
|
||||
import org.saturnclient.config.property.BoolProperty;
|
||||
import org.saturnclient.config.property.ColorProperty;
|
||||
import org.saturnclient.config.property.Property;
|
||||
import org.saturnclient.mod.HudMod;
|
||||
import org.saturnclient.mod.Mod;
|
||||
import org.saturnclient.mod.ModLayout;
|
||||
import org.saturnclient.mod.ModSpec;
|
||||
import org.saturnclient.common.module.PlayerModule;
|
||||
import org.saturnclient.ui.RenderScope;
|
||||
|
||||
/**
|
||||
* KeystrokesFeature renders the WASD / mouse / space key states as an
|
||||
* on-screen overlay.
|
||||
*/
|
||||
public class KeystrokesFeature extends Mod implements HudMod {
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Configuration
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
private static final BoolProperty enabled = Property.bool(false);
|
||||
private static final BoolProperty showMouse = Property.bool(true);
|
||||
private static final BoolProperty showSpace = Property.bool(false);
|
||||
|
||||
private static final ColorProperty clickBg = Property.color(0xFFCCCCCC);
|
||||
private static final ColorProperty clickFg = Property.color(0xFFFFFFFF);
|
||||
|
||||
private static final ModLayout layout = new ModLayout(78, 54);
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Layout constants
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
private static final int KEY_SIZE = 24;
|
||||
private static final int KEY_SPACING = 3;
|
||||
private static final int MOUSE_WIDTH = 38;
|
||||
private static final int MOUSE_H = 24;
|
||||
private static final int SPACE_H = 19;
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Cached key states (updated in tick)
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
private boolean w, a, s, d, lmb, rmb, space;
|
||||
|
||||
public KeystrokesFeature() {
|
||||
super(
|
||||
new ModSpec("Keystrokes", "keystrokes")
|
||||
.description("Displays movement keystrokes")
|
||||
.version("v0.2.0")
|
||||
.tags("Utility"),
|
||||
enabled.named("Enabled"),
|
||||
showMouse.named("Show mouse clicks"),
|
||||
showSpace.named("Show space"),
|
||||
layout.prop(),
|
||||
clickFg.named("Clicked fg"),
|
||||
clickBg.named("Clicked bg"));
|
||||
layout.renderBackground = false;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Feature contract
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
PlayerModule player = Providers.module.player();
|
||||
w = player.isForwardPressed();
|
||||
a = player.isLeftPressed();
|
||||
s = player.isBackPressed();
|
||||
d = player.isRightPressed();
|
||||
lmb = player.isAttackPressed();
|
||||
rmb = player.isUsePressed();
|
||||
space = player.isJumpPressed();
|
||||
refreshHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderHud(RenderScope scope) {
|
||||
render(scope, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderDummy(RenderScope scope) {
|
||||
render(scope, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModLayout getDimensions() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled(boolean e) {
|
||||
enabled.value = e;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Rendering
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
private void render(RenderScope scope, boolean live) {
|
||||
int yOffset = 0;
|
||||
|
||||
// W (top centre)
|
||||
renderKey(scope, live && w, 'W', KEY_SIZE + KEY_SPACING, yOffset);
|
||||
yOffset += KEY_SIZE + KEY_SPACING;
|
||||
|
||||
// A S D
|
||||
renderKey(scope, live && a, 'A', 0, yOffset);
|
||||
renderKey(scope, live && s, 'S', KEY_SIZE + KEY_SPACING, yOffset);
|
||||
renderKey(scope, live && d, 'D', (KEY_SIZE + KEY_SPACING) * 2, yOffset);
|
||||
yOffset += KEY_SIZE + KEY_SPACING;
|
||||
|
||||
// Spacebar (optional)
|
||||
if (showSpace.value) {
|
||||
renderSpaceKey(scope, live && space, 0, yOffset);
|
||||
yOffset += SPACE_H + KEY_SPACING;
|
||||
}
|
||||
|
||||
// Mouse buttons (optional)
|
||||
if (showMouse.value) {
|
||||
renderMouseKey(scope, live && lmb, "LMB", 0, yOffset);
|
||||
renderMouseKey(scope, live && rmb, "RMB", MOUSE_WIDTH + KEY_SPACING, yOffset);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderKey(RenderScope scope, boolean pressed, char c, int x, int y) {
|
||||
int bg = pressed ? clickBg.value : layout.bgColor.value;
|
||||
int fg = pressed ? clickFg.value : layout.fgColor.value;
|
||||
scope.drawRoundedRectangle(x, y, KEY_SIZE, KEY_SIZE, layout.radius.value, bg);
|
||||
scope.drawText(0.6f, String.valueOf(c), x + 9, y + 7, layout.font.value, fg);
|
||||
}
|
||||
|
||||
private void renderMouseKey(RenderScope scope, boolean pressed, String label, int x, int y) {
|
||||
int bg = pressed ? clickBg.value : layout.bgColor.value;
|
||||
int fg = pressed ? clickFg.value : layout.fgColor.value;
|
||||
scope.drawRoundedRectangle(x, y, MOUSE_WIDTH, MOUSE_H, layout.radius.value, bg);
|
||||
scope.drawText(0.6f, label, x + 9, y + 7, layout.font.value, fg);
|
||||
}
|
||||
|
||||
private void renderSpaceKey(RenderScope scope, boolean pressed, int x, int y) {
|
||||
int bg = pressed ? clickBg.value : layout.bgColor.value;
|
||||
int fg = pressed ? clickFg.value : layout.fgColor.value;
|
||||
scope.drawRoundedRectangle(x, y, layout.width, SPACE_H, layout.radius.value, bg);
|
||||
int lineY = y + SPACE_H / 2;
|
||||
scope.drawRect(x + (layout.width - 30) / 2, lineY, 30, 1, fg);
|
||||
}
|
||||
|
||||
private void refreshHeight() {
|
||||
int h = KEY_SIZE * 2 + KEY_SPACING;
|
||||
if (showSpace.value)
|
||||
h += SPACE_H + KEY_SPACING;
|
||||
if (showMouse.value)
|
||||
h += MOUSE_H + KEY_SPACING;
|
||||
layout.height = h;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
package org.saturnclient.mod.mods;
|
||||
|
||||
import org.saturnclient.common.module.EntityModule;
|
||||
import org.saturnclient.config.property.BoolProperty;
|
||||
import org.saturnclient.config.property.Property;
|
||||
import org.saturnclient.config.property.SelectProperty;
|
||||
import org.saturnclient.mod.Mod;
|
||||
import org.saturnclient.mod.ModSpec;
|
||||
|
||||
/**
|
||||
* NametagsFeature modifies the nametags displayed above entities.
|
||||
*
|
||||
* Actual rendering is injected via a mixin; this class owns the
|
||||
* configuration and exposes two static query methods the mixin uses:
|
||||
* {@link #shouldReplaceName()} and
|
||||
* {@link #getNametagString(EntityModule.EntityState)}.
|
||||
*
|
||||
* No ModuleProvider is required here because the mixin passes the
|
||||
* already-resolved {@link EntityModule.EntityState} directly.
|
||||
*/
|
||||
public class NametagsFeature extends Mod {
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Configuration
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
private static final BoolProperty enabled = Property.bool(false);
|
||||
private static final BoolProperty healthDisplay = Property.bool(false);
|
||||
private static final BoolProperty players = Property.bool(true);
|
||||
private static final BoolProperty hostile = Property.bool(false);
|
||||
private static final BoolProperty passive = Property.bool(false);
|
||||
private static final BoolProperty heartEmoji = Property.bool(true);
|
||||
private static final BoolProperty obfuscate = Property.bool(false);
|
||||
|
||||
private static final SelectProperty unit = Property.select(0, "Health", "Hearts");
|
||||
private static final SelectProperty format = Property.select(0, "Value", "Value / Total", "%");
|
||||
|
||||
private static final SelectProperty nameColor = Property.select(15,
|
||||
"Black", "Dark Blue", "Dark Green", "Dark Aqua", "Dark Red", "Dark Purple",
|
||||
"Gold", "Gray", "Dark Gray", "Blue", "Green", "Aqua", "Red", "Light Purple", "Yellow", "White");
|
||||
private static final SelectProperty healthColor = Property.select(12,
|
||||
"Black", "Dark Blue", "Dark Green", "Dark Aqua", "Dark Red", "Dark Purple",
|
||||
"Gold", "Gray", "Dark Gray", "Blue", "Green", "Aqua", "Red", "Light Purple", "Yellow", "White");
|
||||
|
||||
private static final String[] COLOR_CODES = {
|
||||
"§0", "§1", "§2", "§3", "§4", "§5", "§6", "§7",
|
||||
"§8", "§9", "§a", "§b", "§c", "§d", "§e", "§f"
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Constructor
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
public NametagsFeature() {
|
||||
super(
|
||||
new ModSpec("Nametags", "nametags")
|
||||
.description("Allows you to modify entity nametags")
|
||||
.tags("Camera", "Utility")
|
||||
.version("v0.2.0"),
|
||||
enabled.named("Enabled"),
|
||||
healthDisplay.named("Display health"),
|
||||
players.named("Players"),
|
||||
hostile.named("Hostile"),
|
||||
passive.named("Passive"),
|
||||
heartEmoji.named("Heart emoji"),
|
||||
obfuscate.named("Obfuscate enemy names"),
|
||||
unit.named("Unit"),
|
||||
format.named("Format"),
|
||||
nameColor.named("Name color"),
|
||||
healthColor.named("Health color"));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Mixin query API
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/** Returns {@code true} when nametag replacement is active. */
|
||||
public static boolean shouldReplaceName() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the replacement nametag string for the given entity state,
|
||||
* or {@code null} if this entity should not have its tag replaced.
|
||||
*/
|
||||
public static String getNametagString(EntityModule.EntityState state) {
|
||||
if (state.getCustomName() == null)
|
||||
return null;
|
||||
if (!healthDisplay.value)
|
||||
return state.getCustomName();
|
||||
|
||||
float health = state.getHealth();
|
||||
float maxHealth = state.getMaxHealth();
|
||||
|
||||
EntityModule.EntityType type = state.getEntityType();
|
||||
if (type == EntityModule.EntityType.PASSIVE && !passive.value)
|
||||
return null;
|
||||
if (type == EntityModule.EntityType.HOSTILE && !hostile.value)
|
||||
return null;
|
||||
if (type == EntityModule.EntityType.PLAYER && !players.value)
|
||||
return null;
|
||||
if (type == EntityModule.EntityType.OTHER)
|
||||
return null;
|
||||
|
||||
if (health < 0f || maxHealth < 0f || health > maxHealth)
|
||||
return null;
|
||||
|
||||
String hpText = buildHealthString(health, maxHealth);
|
||||
String hpClr = COLOR_CODES[healthColor.value];
|
||||
String nameClr = COLOR_CODES[nameColor.value];
|
||||
String obfCode = obfuscate.value ? "§k" : "";
|
||||
String heart = heartEmoji.value ? " ❤" : "";
|
||||
|
||||
return nameClr + obfCode + state.getCustomName() + "§r "
|
||||
+ hpClr + hpText + heart;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Helpers
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
private static String buildHealthString(float health, float maxHealth) {
|
||||
float divisor = unit.value + 1;
|
||||
return switch (format.value) {
|
||||
case 1 -> String.format("%.1f", health / divisor)
|
||||
+ " / " + String.format("%.1f", maxHealth / divisor);
|
||||
case 2 -> String.format("%.0f%%", (health / maxHealth) * 100f);
|
||||
default -> String.format("%.1f", health / divisor);
|
||||
};
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Feature contract
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled(boolean e) {
|
||||
enabled.value = e;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.saturnclient.mod.mods;
|
||||
|
||||
import org.saturnclient.config.property.BoolProperty;
|
||||
import org.saturnclient.config.property.Property;
|
||||
import org.saturnclient.mod.Mod;
|
||||
import org.saturnclient.mod.ModSpec;
|
||||
|
||||
/**
|
||||
* NoFogFeature suppresses distance fog and (optionally) liquid fog.
|
||||
*
|
||||
* Like {@link FullbrightFeature}, the actual suppression is applied
|
||||
* inside a mixin. This class owns the configuration and provides
|
||||
* static query methods the mixin calls.
|
||||
*/
|
||||
public class NoFogFeature extends Mod {
|
||||
|
||||
private static final BoolProperty enabled = Property.bool(false);
|
||||
|
||||
public NoFogFeature() {
|
||||
super(
|
||||
new ModSpec("No Fog", "nofog")
|
||||
.description("Stops fog from rendering")
|
||||
.tags("Camera")
|
||||
.version("v0.2.0"),
|
||||
enabled.named("Enabled"));
|
||||
}
|
||||
|
||||
/** Returns {@code true} when fog should be suppressed. */
|
||||
public static boolean isActive() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Feature contract
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled(boolean e) {
|
||||
enabled.value = e;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package org.saturnclient.mod.mods;
|
||||
|
||||
import org.saturnclient.common.provider.Providers;
|
||||
import org.saturnclient.config.property.BoolProperty;
|
||||
import org.saturnclient.config.property.Property;
|
||||
import org.saturnclient.mod.HudMod;
|
||||
import org.saturnclient.mod.Mod;
|
||||
import org.saturnclient.mod.ModLayout;
|
||||
import org.saturnclient.mod.ModSpec;
|
||||
import org.saturnclient.ui.RenderScope;
|
||||
import org.saturnclient.ui.resources.Fonts;
|
||||
|
||||
/**
|
||||
* PingFeature displays the current server round-trip time in
|
||||
* milliseconds as a HUD element.
|
||||
*/
|
||||
public class PingFeature extends Mod implements HudMod {
|
||||
|
||||
private static final BoolProperty enabled = Property.bool(false);
|
||||
private static final ModLayout layout = new ModLayout(60, Fonts.getHeight());
|
||||
|
||||
public PingFeature() {
|
||||
super(
|
||||
new ModSpec("Ping Display", "ping")
|
||||
.description("Displays ping to the server")
|
||||
.version("v0.2.0")
|
||||
.tags("Utility"),
|
||||
enabled.named("Enabled"),
|
||||
layout.prop());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// HudFeature
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void renderHud(RenderScope scope) {
|
||||
renderPing(Providers.module.network().getPing(), scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderDummy(RenderScope scope) {
|
||||
renderPing(10, scope);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Rendering
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
private void renderPing(int ping, RenderScope scope) {
|
||||
String text = ping + " ms";
|
||||
scope.drawText(text, 0, 0, layout.font.value, layout.fgColor.value);
|
||||
layout.width = Fonts.getWidth(text, layout.font.value);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Feature contract
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public ModLayout getDimensions() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled(boolean e) {
|
||||
enabled.value = e;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package org.saturnclient.mod.mods;
|
||||
|
||||
import org.saturnclient.common.provider.Providers;
|
||||
import org.saturnclient.config.property.BoolProperty;
|
||||
import org.saturnclient.config.property.Property;
|
||||
import org.saturnclient.config.property.SelectProperty;
|
||||
import org.saturnclient.mod.HudMod;
|
||||
import org.saturnclient.mod.Mod;
|
||||
import org.saturnclient.mod.ModLayout;
|
||||
import org.saturnclient.mod.ModSpec;
|
||||
import org.saturnclient.common.module.PlayerModule;
|
||||
import org.saturnclient.ui.RenderScope;
|
||||
import org.saturnclient.ui.resources.Fonts;
|
||||
|
||||
/**
|
||||
* SpeedometerFeature displays the player's current movement speed as
|
||||
* a HUD element. Velocity data comes from {@link PlayerModule}.
|
||||
*/
|
||||
public class SpeedometerFeature extends Mod implements HudMod {
|
||||
|
||||
private static final BoolProperty enabled = Property.bool(false);
|
||||
private static final SelectProperty axis = Property.select(1, "Absolute", "Horizontal", "Vertical");
|
||||
private static final SelectProperty unitText = Property.select(0, "None", "Blocks/s", "blocks/s", "b/s");
|
||||
private static final BoolProperty showLabel = Property.bool(true);
|
||||
private static final ModLayout layout = new ModLayout(40, 18);
|
||||
|
||||
private double cachedSpeed = 0.0;
|
||||
|
||||
public SpeedometerFeature() {
|
||||
super(
|
||||
new ModSpec("Speedometer", "speed")
|
||||
.description("Displays your current movement speed")
|
||||
.version("v0.2.0")
|
||||
.tags("Utility"),
|
||||
enabled.named("Enabled"),
|
||||
axis.named("Speed type"),
|
||||
unitText.named("Unit text"),
|
||||
showLabel.named("Show speed label"),
|
||||
layout.prop());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// HudFeature
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void renderHud(RenderScope scope) {
|
||||
PlayerModule player = Providers.module.player();
|
||||
PlayerModule.Velocity v = player.getVelocity();
|
||||
boolean onGround = player.isOnGround();
|
||||
|
||||
double effectiveY = onGround ? 0.0 : v.y;
|
||||
|
||||
cachedSpeed = switch (axis.value) {
|
||||
case 0 -> Math.sqrt(v.x * v.x + effectiveY * effectiveY + v.z * v.z); // absolute 3-D
|
||||
case 2 -> Math.abs(effectiveY); // vertical only
|
||||
default -> Math.sqrt(v.x * v.x + v.z * v.z); // horizontal
|
||||
};
|
||||
|
||||
renderSpeed(cachedSpeed * 20.0, scope); // blocks/tick → blocks/s
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderDummy(RenderScope scope) {
|
||||
renderSpeed(2.71, scope);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Rendering
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
private void renderSpeed(double bps, RenderScope scope) {
|
||||
String text = String.format("%.2f ", bps);
|
||||
|
||||
text += switch (unitText.value) {
|
||||
case 1 -> "Blocks/s";
|
||||
case 2 -> "blocks/s";
|
||||
case 3 -> "b/s";
|
||||
default -> "";
|
||||
};
|
||||
|
||||
if (showLabel.value) {
|
||||
text = "Speed: " + text;
|
||||
}
|
||||
|
||||
scope.drawText(text, 0, 0, layout.font.value, layout.fgColor.value);
|
||||
layout.width = Fonts.getWidth(text, layout.font.value);
|
||||
layout.height = 18 * text.split("\n").length;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Feature contract
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public ModLayout getDimensions() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled(boolean e) {
|
||||
enabled.value = e;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package org.saturnclient.mod.mods;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.saturnclient.common.provider.ModuleProvider;
|
||||
import org.saturnclient.common.provider.Providers;
|
||||
import org.saturnclient.common.ref.game.EffectRef;
|
||||
import org.saturnclient.config.property.BoolProperty;
|
||||
import org.saturnclient.config.property.Property;
|
||||
import org.saturnclient.mod.HudMod;
|
||||
import org.saturnclient.mod.Mod;
|
||||
import org.saturnclient.mod.ModLayout;
|
||||
import org.saturnclient.mod.ModSpec;
|
||||
import org.saturnclient.ui.RenderScope;
|
||||
|
||||
/**
|
||||
* StatusEffectsFeature displays the player's active potion effects as
|
||||
* a HUD overlay.
|
||||
*
|
||||
* The effect list is supplied by the platform through an interface
|
||||
* returned by a future {@code PlayerModule#getActiveEffects()} call.
|
||||
* Until that is wired up, the existing {@link StatusEffectsInterface}
|
||||
* bridge is used, accessed via {@link ModuleProvider}.
|
||||
*/
|
||||
public class StatusEffectsFeature extends Mod implements HudMod {
|
||||
|
||||
public static final BoolProperty enabled = Property.bool(false);
|
||||
private static final ModLayout layout = new ModLayout(60, 0);
|
||||
|
||||
public StatusEffectsFeature() {
|
||||
super(
|
||||
new ModSpec("Status Effects", "effect")
|
||||
.description("Displays active status effects")
|
||||
.version("v0.2.0")
|
||||
.tags("Utility"),
|
||||
enabled.named("Enabled"),
|
||||
layout.prop());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// HudFeature
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void renderHud(RenderScope scope) {
|
||||
renderEffects(scope, Providers.module.player().getActiveEffects());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderDummy(RenderScope scope) {
|
||||
renderEffects(scope, Providers.module.player().getDummyEffects());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Rendering
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
private void renderEffects(RenderScope scope, List<? extends EffectRef> effects) {
|
||||
int row = 0;
|
||||
|
||||
for (EffectRef effect : effects) {
|
||||
if (!effect.shouldShowIcon())
|
||||
continue;
|
||||
|
||||
scope.drawSpriteStretched(effect.getIcon(), 0, 18 * row, 16, 16);
|
||||
scope.drawText(0.5f, durationString(effect),
|
||||
18, 18 * row + 3,
|
||||
layout.font.value, -1);
|
||||
row++;
|
||||
}
|
||||
|
||||
layout.height = 18 * row;
|
||||
}
|
||||
|
||||
private static String durationString(EffectRef effect) {
|
||||
if (effect.isInfinite())
|
||||
return effect.getInfiniteText();
|
||||
|
||||
int totalSeconds = effect.getDurationSeconds();
|
||||
if (totalSeconds >= 3600) {
|
||||
return (totalSeconds / 3600) + "h";
|
||||
} else if (totalSeconds >= 60) {
|
||||
return String.format("%d:%02d", totalSeconds / 60, totalSeconds % 60);
|
||||
} else {
|
||||
return totalSeconds + "s";
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Feature contract
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public ModLayout getDimensions() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled(boolean e) {
|
||||
enabled.value = e;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package org.saturnclient.mod.mods;
|
||||
|
||||
import org.saturnclient.ui.RenderScope;
|
||||
import org.saturnclient.ui.resources.Fonts;
|
||||
import org.saturnclient.config.property.BoolProperty;
|
||||
import org.saturnclient.config.property.Property;
|
||||
import org.saturnclient.mod.HudMod;
|
||||
import org.saturnclient.mod.Mod;
|
||||
import org.saturnclient.mod.ModLayout;
|
||||
import org.saturnclient.mod.ModSpec;
|
||||
|
||||
/**
|
||||
* TpsFeature estimates the server's ticks-per-second by measuring the
|
||||
* elapsed real time between consecutive world-time packets.
|
||||
*
|
||||
* TPS calculation is event-driven: the networking layer (or mixin)
|
||||
* calls {@link #onTimePacket(long)} whenever a time-update packet
|
||||
* arrives. No ModuleProvider is required because there is no
|
||||
* per-frame polling of the engine.
|
||||
*/
|
||||
public class TpsFeature extends Mod implements HudMod {
|
||||
|
||||
private static final BoolProperty enabled = Property.bool(false);
|
||||
private static final ModLayout layout = new ModLayout(60, Fonts.getHeight());
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// TPS sampling state (static — shared across all instances)
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
private static final int SAMPLE_COUNT = 2;
|
||||
private static final double[] samples = new double[SAMPLE_COUNT];
|
||||
|
||||
static {
|
||||
java.util.Arrays.fill(samples, 20.0);
|
||||
}
|
||||
|
||||
private static long lastWorldAge = -1L;
|
||||
private static long lastRealTime = -1L;
|
||||
private static double currentTps = 20.0;
|
||||
private static int sampleIndex = 0;
|
||||
private static int samplesFilled = SAMPLE_COUNT;
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Constructor
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
public TpsFeature() {
|
||||
super(
|
||||
new ModSpec("TPS Display", "tps")
|
||||
.description("Displays the server's ticks per second")
|
||||
.version("v0.2.0")
|
||||
.tags("Utility"),
|
||||
enabled.named("Enabled"),
|
||||
layout.prop());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Packet hook (called by the networking mixin)
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Must be called every time the client receives a world-time packet
|
||||
* carrying the updated {@code worldAge} value.
|
||||
*/
|
||||
public static void onTimePacket(long worldAge) {
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
if (lastWorldAge != -1L && lastRealTime != -1L) {
|
||||
long tickDelta = worldAge - lastWorldAge;
|
||||
long timeDelta = now - lastRealTime;
|
||||
|
||||
if (timeDelta > 0 && tickDelta > 0) {
|
||||
double sample = Math.min((tickDelta / (double) timeDelta) * 1000.0, 20.0);
|
||||
|
||||
samples[sampleIndex % SAMPLE_COUNT] = sample;
|
||||
sampleIndex++;
|
||||
samplesFilled = Math.min(samplesFilled + 1, SAMPLE_COUNT);
|
||||
|
||||
double sum = 0;
|
||||
for (int i = 0; i < samplesFilled; i++)
|
||||
sum += samples[i];
|
||||
currentTps = sum / samplesFilled;
|
||||
}
|
||||
}
|
||||
|
||||
lastWorldAge = worldAge;
|
||||
lastRealTime = now;
|
||||
}
|
||||
|
||||
/** Resets TPS history (e.g. on server disconnect). */
|
||||
public static void reset() {
|
||||
lastWorldAge = -1L;
|
||||
lastRealTime = -1L;
|
||||
currentTps = 20.0;
|
||||
sampleIndex = 0;
|
||||
samplesFilled = SAMPLE_COUNT;
|
||||
java.util.Arrays.fill(samples, 20.0);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// HudFeature
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void renderHud(RenderScope scope) {
|
||||
renderTps(currentTps, scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderDummy(RenderScope scope) {
|
||||
renderTps(20.0, scope);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Rendering
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
private void renderTps(double tps, RenderScope scope) {
|
||||
String text = String.format("%.1f TPS", tps);
|
||||
scope.drawText(text, 0, 0, layout.font.value, layout.fgColor.value);
|
||||
layout.width = Fonts.getWidth(text, layout.font.value);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Feature contract
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public ModLayout getDimensions() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled(boolean e) {
|
||||
enabled.value = e;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package org.saturnclient.mod.mods;
|
||||
|
||||
import org.saturnclient.common.provider.GLFWProvider;
|
||||
import org.saturnclient.config.property.BoolProperty;
|
||||
import org.saturnclient.config.property.FloatProperty;
|
||||
import org.saturnclient.config.property.KeybindingProperty;
|
||||
import org.saturnclient.config.property.Property;
|
||||
import org.saturnclient.mod.Mod;
|
||||
import org.saturnclient.mod.ModSpec;
|
||||
|
||||
/**
|
||||
* ZoomFeature multiplies the camera's field-of-view to create an
|
||||
* optical-zoom effect.
|
||||
*
|
||||
* The FOV override is applied inside a mixin that polls
|
||||
* {@link #shouldZoom()} and {@link #getZoomLevel()} each frame.
|
||||
* No ModuleProvider is needed — there is no per-tick engine query.
|
||||
*/
|
||||
public class ZoomFeature extends Mod {
|
||||
|
||||
private static final BoolProperty enabled = Property.bool(false);
|
||||
private static final BoolProperty toggle = Property.bool(false);
|
||||
public static final KeybindingProperty zoomKey = Property.keybinding(GLFWProvider.GLFW_KEY_C);
|
||||
public static final FloatProperty zoomLevel = Property.floatProp(3.0f);
|
||||
|
||||
/** Whether zoom is currently active (read by the FOV mixin). */
|
||||
public static boolean isZooming = false;
|
||||
|
||||
public ZoomFeature() {
|
||||
super(
|
||||
new ModSpec("Zoom", "zoom")
|
||||
.description("Zoom in for a closer view")
|
||||
.tags("Camera", "Utility")
|
||||
.version("v0.2.0"),
|
||||
enabled.named("Enabled"),
|
||||
toggle.named("Toggle zoom"),
|
||||
zoomKey.named("Zoom Keybinding"),
|
||||
zoomLevel.named("Zoom Level"));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Feature contract
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (toggle.value) {
|
||||
if (zoomKey.wasKeyPressed()) {
|
||||
isZooming = !isZooming;
|
||||
}
|
||||
} else {
|
||||
isZooming = zoomKey.isKeyPressed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled(boolean e) {
|
||||
enabled.value = e;
|
||||
if (!e)
|
||||
isZooming = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled.value;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Mixin query API
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/** Returns {@code true} when the FOV override should be applied. */
|
||||
public static boolean shouldZoom() {
|
||||
return enabled.value && isZooming;
|
||||
}
|
||||
|
||||
/** Returns the zoom divisor (e.g. 3.0 → one-third of normal FOV). */
|
||||
public static float getZoomLevel() {
|
||||
return zoomLevel.value;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user