Compare commits

...
Author SHA1 Message Date
selimaj-dev edbfd0306a added mod detials 2025-05-17 01:56:26 +02:00
selimaj-dev 324ffe0c8b some ui stuff 2025-05-17 01:24:27 +02:00
selimaj-dev 21daf473b1 added armor display 2025-05-16 07:34:40 -05:00
Leo Codes d1030bb235 Merge pull request #2 from saturnclientmc/refactor
Refactor
2025-05-13 02:06:52 -05:00
selimaj-dev 05fcd3032b default colors changed 2025-05-13 00:03:09 +02:00
selimaj-dev 47cafad92b cosmetic skin fix? 2025-05-12 23:40:34 +02:00
selimaj-dev 744698fd71 bye bye old ui 2025-05-12 23:07:06 +02:00
selimaj-dev 86b638afca few changes to finish today 2025-05-12 15:04:08 -05:00
selimaj-dev a016fd72c6 added the settings menu for ui 2 2025-05-12 14:39:03 -05:00
selimaj-dev 8e8737afcd added a toggle 2025-05-12 11:19:26 -05:00
selimaj-dev 6eb3fc8092 color picker 2025-05-12 10:28:37 -05:00
selimaj-dev f9baa0fe5f added FloatInput 2025-05-12 07:18:32 -05:00
selimaj-dev a6e762b0d8 Keypress implementation on ui2 2025-05-12 07:03:32 -05:00
selimaj-dev d72b152a26 ok 2025-05-11 05:00:18 -05:00
selimaj-dev 2a202c4160 added cosmetic menus 2025-05-11 04:36:14 -05:00
selimaj-dev 930d002b81 this time it should be good (aside from colors) 2025-05-11 02:53:31 -05:00
selimaj-dev 35440180ea made the mod actually good 2025-05-09 01:54:17 +02:00
selimaj-dev 7fd0565f7f better mod card design 2025-05-08 09:54:15 -05:00
selimaj-dev 1421d94647 a lot of stuff idk 2025-05-07 12:36:23 -05:00
selimaj-dev fbb1460872 slighly better font 2025-05-07 12:20:43 -05:00
selimaj-dev e7ca5c0297 slighly better font 2025-05-07 11:32:16 -05:00
selimaj-dev 3a54739410 slighly better font 2025-05-07 10:07:57 -05:00
selimaj-dev 1c80803994 title screen change 2025-05-07 12:41:01 +02:00
selimaj-dev 191e9eba4c column fix 2025-05-07 03:05:16 +02:00
selimaj-dev 3d654685d0 small ui changes 2025-05-07 00:58:38 +02:00
selimaj-dev d9bd2c60c9 logo update 2025-05-07 00:26:45 +02:00
selimaj-dev 984132991d Better module display 2025-05-06 23:46:26 +02:00
selimaj-dev 7d649efa22 Themified mods and state merging 2025-05-06 20:48:23 +02:00
selimaj-dev 1ffadc9b45 font 2025-05-06 08:00:21 -05:00
selimaj-dev 9a7b93ccbe mod ui 2025-05-06 08:00:09 -05:00
selimaj-dev d37d4e49f9 New mod ui 2025-05-06 07:23:07 -05:00
selimaj-dev b491f246c8 Dupe fix 2025-05-06 06:31:50 -05:00
selimaj-dev cfe518380a Theming 2025-05-06 06:27:42 -05:00
selimaj-dev fe2521bee2 height fix on scroll 2025-05-06 05:02:11 -05:00
selimaj-dev ae4d9786b2 functional scrolling and functional mod menu 2025-05-06 05:37:06 +02:00
selimaj-dev 0f4af22346 scrolling 2025-05-06 03:18:56 +02:00
selimaj-dev 5a8ae263e9 scissor stack 2025-05-06 01:51:32 +02:00
selimaj-dev 2458906e3b Merge branch 'refactor' of github.com:saturnclientmc/saturnclient into refactor 2025-05-05 11:21:04 -05:00
selimaj-dev 42611d4aed added scrolling (need to add scissor) 2025-05-05 11:20:17 -05:00
selimaj-dev e5cc68ecad updated horns model 2025-05-04 00:58:52 +02:00
90 changed files with 3091 additions and 4316 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ org.gradle.jvmargs=-Xmx1G
loader_version=0.16.10
# Mod Properties
mod_version = 0.0.1-alpha2
mod_version = 0.0.1-alpha4
maven_group = me.iipho3nix
archives_base_name = saturnclient
@@ -1,11 +1,11 @@
package org.saturnclient.modules;
import net.minecraft.client.gui.DrawContext;
import org.saturnclient.ui2.RenderScope;
public interface HudMod {
public ModDimensions getDimensions();
public void renderDummy(DrawContext context);
public void renderDummy(RenderScope scope);
public void render(DrawContext context);
public void renderHud(RenderScope scope);
}
@@ -1,64 +1,49 @@
package org.saturnclient.modules;
import org.saturnclient.saturnclient.config.ConfigManager;
import java.util.Map;
import org.saturnclient.saturnclient.config.NamedProperty;
import org.saturnclient.saturnclient.config.Property;
public class ModDimensions {
public Property<Integer> x = new Property<>(0);
public Property<Integer> y = new Property<>(0);
public Property<Float> scale = new Property<>(1.0f);
public Property<Integer> bgColor = new Property<>(0xFF000000, Property.PropertyType.HEX);
public Property<Integer> fgColor = new Property<>(0xFFffffff, Property.PropertyType.HEX);
public Property<Integer> radius = new Property<>(0);
public int width = 0;
public int height = 0;
private final ConfigManager dimensionsConfig;
public ModDimensions(ConfigManager configManager) {
dimensionsConfig = new ConfigManager(configManager, "Dimensions");
dimensionsConfig.property("x", this.x);
dimensionsConfig.property("y", this.y);
dimensionsConfig.property("scale", this.scale);
public NamedProperty<Map<String, Property<?>>> prop() {
return new Property<Map<String, Property<?>>>(Map.of(
"X", x,
"Y", y,
"Scale", scale,
"Background Color", bgColor,
"Foreground Color", fgColor,
"Corner Radius", radius
)).named("In-Game Display");
}
public ModDimensions(ConfigManager configManager, int x, int y) {
dimensionsConfig = new ConfigManager(configManager, "Dimensions");
this.x.value = x;
this.y.value = y;
dimensionsConfig.property("x", this.x);
dimensionsConfig.property("y", this.y);
dimensionsConfig.property("scale", this.scale);
public ModDimensions(int width, int height) {
this.width = width;
this.height = height;
}
public ModDimensions(ConfigManager configManager, int x, int y, int width, int height) {
dimensionsConfig = new ConfigManager(configManager, "Dimensions");
public ModDimensions(int x, int y, int width, int height) {
this.x.value = x;
this.y.value = y;
this.width = width;
this.height = height;
dimensionsConfig.property("x", this.x);
dimensionsConfig.property("y", this.y);
dimensionsConfig.property("scale", this.scale);
}
public ModDimensions(ConfigManager configManager, int x, int y, float scale) {
dimensionsConfig = new ConfigManager(configManager, "Dimensions");
this.x.value = x;
this.y.value = y;
this.scale.value = scale;
dimensionsConfig.property("x", this.x);
dimensionsConfig.property("y", this.y);
dimensionsConfig.property("scale", this.scale);
}
public ModDimensions(ConfigManager configManager, int x, int y, int width, int height, float scale) {
dimensionsConfig = new ConfigManager(configManager, "Dimensions");
public ModDimensions(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;
dimensionsConfig.property("x", this.x);
dimensionsConfig.property("y", this.y);
dimensionsConfig.property("scale", this.scale);
}
}
@@ -3,7 +3,6 @@ package org.saturnclient.modules;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.util.math.MatrixStack;
import org.saturnclient.modules.mods.*;
import org.saturnclient.saturnclient.SaturnClient;
@@ -15,6 +14,7 @@ public class ModManager {
public static Module[] MODS = {
new Crosshair(),
new AutoSprint(),
new ArmorDisplay()
};
public static void init() {
@@ -38,16 +38,17 @@ public class ModManager {
if (m instanceof HudMod && m.isEnabled()) {
ModDimensions dim = ((HudMod) m).getDimensions();
MatrixStack matrices = context.getMatrices();
matrices.push();
renderScope.matrices.push();
matrices.translate(dim.x.value, (float) dim.y.value, 0);
renderScope.matrices.translate(dim.x.value, (float) dim.y.value, 0);
matrices.scale(dim.scale.value, dim.scale.value, 1.0f);
renderScope.matrices.scale(dim.scale.value, dim.scale.value, 1.0f);
((HudMod) m).render(context);
renderScope.drawRoundedRectangle(0, 0, dim.width, dim.height, dim.radius.value, dim.bgColor.value);
matrices.pop();
((HudMod) m).renderHud(renderScope);
renderScope.matrices.pop();
} else {
m.render(renderScope);
}
@@ -2,34 +2,23 @@ package org.saturnclient.modules;
import org.saturnclient.saturnclient.config.ConfigManager;
import org.saturnclient.saturnclient.config.NamedProperty;
import org.saturnclient.ui.Textures;
import org.saturnclient.ui2.resources.Textures;
import org.saturnclient.ui2.RenderScope;
import net.minecraft.util.Identifier;
public abstract class Module {
private final String name;
private final String namespace;
private final ModuleDetails details;
private final ConfigManager configManager;
public Module(String name, String namespace, NamedProperty<?>... props) {
this.name = name;
this.namespace = namespace;
configManager = new ConfigManager(name);
public Module(ModuleDetails details, NamedProperty<?>... props) {
this.details = details;
configManager = new ConfigManager(details.name);
for (NamedProperty<?> prop : props) {
configManager.property(prop.name, prop.prop);
}
}
public Module(ConfigManager config, String name, String namespace) {
this.name = name;
this.namespace = namespace;
configManager = config;
}
public void render(RenderScope scope) {}
public void tick() {}
@@ -38,14 +27,26 @@ public abstract class Module {
public abstract void setEnabled(boolean e);
public final String getName() {
return name;
return details.name;
}
public Identifier getIconTexture() {
return Textures.getModIcon(namespace);
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,39 @@
package org.saturnclient.modules;
public class ModuleDetails {
public String name;
public String namespace;
public String description;
public String version;
public String[] tags = {};
public ModuleDetails(String name, String namespace) {
this.name = name;
this.namespace = namespace;
}
public ModuleDetails name(String name) {
this.name = name;
return this;
}
public ModuleDetails namespace(String namespace) {
this.namespace = namespace;
return this;
}
public ModuleDetails description(String description) {
this.description = description;
return this;
}
public ModuleDetails version(String version) {
this.version = version;
return this;
}
public ModuleDetails tags(String... tags) {
this.tags = tags;
return this;
}
}
@@ -0,0 +1,86 @@
package org.saturnclient.modules.mods;
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.saturnclient.config.Property;
import org.saturnclient.ui2.RenderScope;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
public class ArmorDisplay extends Module implements HudMod {
private static Property<Boolean> enabled = new Property<>(true);
private static ModDimensions dimensions = new ModDimensions(40, 60);
public ArmorDisplay() {
super(new ModuleDetails("Armor Display", "armor").description("Displays armor durability")
.version("v0.1.0")
.tags("Utility"),
enabled.named("Enabled"),
dimensions.prop());
}
public void renderArmor(RenderScope scope, ItemStack helmet, ItemStack chestplate, ItemStack leggings, ItemStack boots) {
int row = 0;
if (!helmet.isEmpty()) {
scope.drawItem(helmet, 0, 0);
renderHealth(scope, row, helmet.getMaxDamage(), helmet.getDamage());
row++;
}
if (!chestplate.isEmpty()) {
scope.drawItem(chestplate, 0, 15 * row);
renderHealth(scope, row, chestplate.getMaxDamage(), chestplate.getDamage());
row++;
}
if (!leggings.isEmpty()) {
scope.drawItem(leggings, 0, 15 * row);
renderHealth(scope, row, leggings.getMaxDamage(), leggings.getDamage());
row++;
}
if (!boots.isEmpty()) {
scope.drawItem(boots, 0, 15 * row);
renderHealth(scope, row, boots.getMaxDamage(), boots.getDamage());
row++;
}
}
public void renderHealth(RenderScope scope, int i, int max, int current) {
scope.drawText(0.5f, String.valueOf(((double) current / max) * 100) + "%", 17, (15 * i) + 3, false, dimensions.fgColor.value);
}
@Override
public void renderHud(RenderScope scope) {
renderArmor(scope,
SaturnClient.client.player.getEquippedStack(EquipmentSlot.HEAD),
SaturnClient.client.player.getEquippedStack(EquipmentSlot.CHEST),
SaturnClient.client.player.getEquippedStack(EquipmentSlot.LEGS),
SaturnClient.client.player.getEquippedStack(EquipmentSlot.FEET));
}
@Override
public void renderDummy(RenderScope scope) {
renderArmor(scope, new ItemStack(Items.DIAMOND_HELMET), new ItemStack(Items.DIAMOND_CHESTPLATE), new ItemStack(Items.DIAMOND_LEGGINGS), new ItemStack(Items.DIAMOND_BOOTS));
}
@Override
public ModDimensions getDimensions() {
return dimensions;
}
@Override
public boolean isEnabled() {
return enabled.value;
}
@Override
public void setEnabled(boolean e) {
enabled.value = e;
}
}
@@ -3,6 +3,7 @@ package org.saturnclient.modules.mods;
import java.util.Objects;
import org.saturnclient.modules.Module;
import org.saturnclient.modules.ModuleDetails;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.config.Property;
@@ -10,7 +11,12 @@ public class AutoSprint extends Module {
private static Property<Boolean> enabled = new Property<>(true);
public AutoSprint() {
super("Auto Sprint", "sprint", enabled.named("Enabled"));
super(
new ModuleDetails("Auto Sprint", "sprint")
.description("Makes the player always sprint")
.tags("Movement")
.version("v0.1.0"),
enabled.named("Enabled"));
}
@Override
@@ -1,6 +1,7 @@
package org.saturnclient.modules.mods;
import org.saturnclient.modules.Module;
import org.saturnclient.modules.ModuleDetails;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui2.RenderScope;
@@ -13,7 +14,13 @@ public class Crosshair extends Module {
public static Property<Boolean> range_indicator = new Property<>(false);
public Crosshair() {
super("Crosshair", "crosshair", enabled.named("Enabled"), range_indicator.named("Range Indicator"));
super(
new ModuleDetails("Crosshair", "crosshair")
.description("Changes the crosshair if you're aiming at a entity")
.tags("Visuals", "Utility")
.version("v0.1.0"),
enabled.named("Enabled"),
range_indicator.named("Range Indicator"));
}
@Override
@@ -2,18 +2,14 @@ package org.saturnclient.saturnclient;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.TitleScreen;
import org.saturnclient.modules.ModManager;
import org.saturnclient.saturnclient.auth.Auth;
import org.saturnclient.saturnclient.config.ConfigManager;
import org.saturnclient.saturnclient.config.ThemeManager;
import org.saturnclient.saturnclient.cosmetics.Hats;
import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks;
import org.saturnclient.saturnclient.event.KeyInputHandler;
import org.saturnclient.ui2.screens.TitleMenu;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -32,18 +28,10 @@ public class SaturnClient implements ModInitializer {
public void onInitialize() {
LOGGER.info("Initializing " + MOD_ID);
client = MinecraftClient.getInstance();
ModManager.init();
SaturnClientConfig.init();
ThemeManager.load();
ConfigManager.load();
ModManager.init();
ClientLifecycleEvents.CLIENT_STOPPING.register(_o -> ConfigManager.save());
ScreenEvents.BEFORE_INIT.register((client, screen, scaledWidth, scaledHeight) -> {
if (SaturnClientConfig.saturnTitleScreen.value && screen instanceof TitleScreen
&& !(screen instanceof TitleMenu)) {
client.setScreen(new TitleMenu());
}
});
SpecialModelLoaderEvents.LOAD_SCOPE.register(() -> {
return (resourceManager, location) -> MOD_ID.equals(location.getNamespace());
@@ -2,48 +2,20 @@ package org.saturnclient.saturnclient;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.saturnclient.config.ConfigManager;
import org.saturnclient.ui.SaturnAnimation;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui.Textures;
import org.saturnclient.ui.animations.FadeIn;
import org.saturnclient.ui2.resources.Textures;
import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.ColorHelper;
public class SaturnClientConfig {
public static ConfigManager config;
public static Property<Integer> color =
new Property<>(
ColorHelper.getArgb(255, 251, 60, 79),
Property.PropertyType.HEX);
public static Property<Integer> normal =
new Property<>(
ColorHelper.getArgb(255, 182, 182, 182),
Property.PropertyType.HEX);
public static Property<Boolean> realisticLogo =
new Property<>(false);
public static Property<Boolean> saturnTitleScreen =
new Property<>(true);
public static int WHITE = ColorHelper.getArgb(255, 255, 255, 255);
public static int getWhite(float alpha) {
return ((int) (alpha * 255) << 24) | (normal.value & 0x00FFFFFF);
}
public static int getColor(boolean hovering, float alpha) {
return SaturnUi.getAlpha(hovering ? color.value : normal.value, alpha);
}
public static SaturnAnimation[] getAnimations() {
return new SaturnAnimation[] { new FadeIn(1) };
}
public static Identifier getLogo() {
return realisticLogo.value ? Textures.REALISTIC_LOGO : Textures.LOGO;
}
@@ -71,9 +43,6 @@ public class SaturnClientConfig {
public static void init() {
config = new ConfigManager("Saturn Client");
config.property("Primary color", color);
config.property("Default color", normal);
config.property("Realistic logo", realisticLogo);
config.property("Saturn client title screen", saturnTitleScreen);
}
@@ -15,13 +15,14 @@ import java.util.Map;
import org.saturnclient.saturnclient.SaturnClient;
public class ConfigManager {
private static File configFile = new File(
SaturnClient.client.runDirectory,
"saturn.json");
private static Map<String, Map<String, Property<?>>> properties = new HashMap<>();
private static JsonObject cachedThemeJson = null;
private Map<String, Property<?>> currentMap;
private String namespace;
public ConfigManager(String namespace) {
currentMap = new LinkedHashMap<>();
@@ -39,13 +40,54 @@ public class ConfigManager {
System.out.println("Created sub-namespace: " + namespace);
}
public void sub(String namespace) {
Property<Map<String, Property<?>>> namespaceProperty = new Property<>(currentMap,
Property.PropertyType.NAMESPACE);
property(namespace, namespaceProperty);
}
// Generic method to store any type of property
public <T> Property<T> property(String name, Property<T> value) {
System.out.println("Adding property: " + name);
currentMap.put(name, value);
loadProp(name, value);
return value;
}
@SuppressWarnings("unchecked")
public <T> void loadProp(String name, Property<T> prop) {
if (cachedThemeJson != null) {
JsonElement element = cachedThemeJson.get(namespace);
if (element != null && element.isJsonObject()) {
JsonObject theme = element.getAsJsonObject();
JsonElement value = theme.get(name);
if (value != null && prop.matchesJson(value)) {
switch (prop.getType()) {
case BOOLEAN:
((Property<Boolean>) prop).setValue(value.getAsBoolean());
break;
case INTEGER:
((Property<Integer>) prop).setValue(value.getAsInt());
break;
case FLOAT:
((Property<Float>) prop).setValue(value.getAsFloat());
break;
case STRING:
((Property<String>) prop).setValue(value.getAsString());
break;
case HEX:
((Property<Integer>) prop).setValue(value.getAsInt());
break;
default:
break;
}
}
}
} else {
load();
}
}
public static void load() {
try {
SaturnClient.LOGGER.info("Starting to load config...");
@@ -22,6 +22,7 @@ public class ThemeManager {
SaturnClient.client.runDirectory,
"saturn.theme.json");
private static Map<String, Map<String, Property<?>>> properties = new HashMap<>();
private static JsonObject cachedThemeJson = null;
// private Map<String, Map<String, Property<?>>> states;
private Map<String, Property<?>> currentStyling;
@@ -43,25 +44,41 @@ public class ThemeManager {
}
public void setState(String state) {
this.state = state;
this.state = state;
if (this.state != null) {
for (Map.Entry<String, Property<?>> tProp : properties.get(namespace+"@"+state).entrySet()) {
currentStyling.get(tProp.getKey()).setValue(tProp.getValue().value);
}
} else {
for (Map.Entry<String, Property<?>> tProp : properties.get(namespace).entrySet()) {
currentStyling.get(tProp.getKey()).setValue(tProp.getValue().value);
}
}
}
if (this.state != null) {
for (Map.Entry<String, Property<?>> tProp : properties.get(namespace+"@"+state).entrySet()) {
currentStyling.get(tProp.getKey()).setValue(tProp.getValue().value);
}
} else {
for (Map.Entry<String, Property<?>> tProp : properties.get(namespace).entrySet()) {
currentStyling.get(tProp.getKey()).setValue(tProp.getValue().value);
public void applyState(String state) {
if (this.state != null) {
for (Map.Entry<String, Property<?>> tProp : properties.get(namespace+"@"+state).entrySet()) {
Property<?> p = currentStyling.get(tProp.getKey());
Property<?> currProp = properties.get(namespace).get(tProp.getKey());
if (p.value.equals(currProp.value)) {
p.setValue(tProp.getValue().value);
}
}
} else {
setState(state);
}
}
// Generic method to store any type of property
public <T> Property<T> property(String name, Property<T> prop) {
for (String state : states) {
properties.get(namespace+"@"+state).put(name, new Property<T>(prop.value));
Property<?> property = new Property<T>(prop.value);
properties.get(namespace+"@"+state).put(name, property);
loadProp(state, name, property);
}
loadProp(null, name, prop);
properties.get(namespace).put(name, new Property<T>(prop.value));
currentStyling.put(name, prop);
@@ -69,7 +86,43 @@ public class ThemeManager {
}
public <T> void propertyStateDefault(String state, String name, T value) {
properties.get(namespace+"@"+state).get(name).setValue(value, value); // sets the current and default value
Property<?> prop = properties.get(namespace+"@"+state).get(name);
prop.setValue(value, value); // sets the current and default value
loadProp(state, name, prop);
}
@SuppressWarnings("unchecked")
public <T> void loadProp(String state, String name, Property<T> prop) {
if (cachedThemeJson == null) {
load();
}
JsonElement element = cachedThemeJson.get(state != null ? namespace+"@"+state : namespace);
if (element != null && element.isJsonObject()) {
JsonObject theme = element.getAsJsonObject();
JsonElement value = theme.get(name);
if (value != null && prop.matchesJson(value)) {
switch (prop.getType()) {
case BOOLEAN:
((Property<Boolean>) prop).setValue(value.getAsBoolean());
break;
case INTEGER:
((Property<Integer>) prop).setValue(value.getAsInt());
break;
case FLOAT:
((Property<Float>) prop).setValue(value.getAsFloat());
break;
case STRING:
((Property<String>) prop).setValue(value.getAsString());
break;
case HEX:
((Property<Integer>) prop).setValue(value.getAsInt());
break;
default:
break;
}
}
}
}
public static void load() {
@@ -80,74 +133,15 @@ public class ThemeManager {
Files.write(themeFile.toPath(), "{}".getBytes());
}
JsonObject jsonObject = JsonParser.parseString(
new String(Files.readAllBytes(themeFile.toPath()))).getAsJsonObject();
cachedThemeJson = JsonParser.parseString(
new String(Files.readAllBytes(themeFile.toPath()))).getAsJsonObject();
for (String namespace : properties.keySet()) {
JsonElement themeElement = jsonObject.get(namespace);
if (themeElement == null)
continue;
JsonObject theme = jsonObject.get(namespace).getAsJsonObject();
if (theme == null) {
continue;
}
Map<String, Property<?>> propertyMap = properties.get(namespace);
loadProperties(theme, propertyMap);
}
SaturnClient.LOGGER.info("Theme loaded");
} catch (IOException e) {
SaturnClient.LOGGER.error("Error reading the theme file", e);
}
}
@SuppressWarnings("unchecked")
private static void loadProperties(JsonObject theme, Map<String, Property<?>> propertyMap) {
for (String propertyName : propertyMap.keySet()) {
JsonElement c = theme.get(propertyName);
if (c == null) {
continue;
}
Property<?> p = propertyMap.get(propertyName);
if (p.matchesJson(c)) {
if (p.getType() == Property.PropertyType.NAMESPACE) {
// Handle nested namespace
JsonObject nestedTheme = c.getAsJsonObject();
Map<String, Property<?>> nestedProperties = p.getNamespaceValue();
loadProperties(nestedTheme, nestedProperties);
} else {
// Handle regular properties
switch (p.getType()) {
case BOOLEAN:
((Property<Boolean>) p).value = c.getAsBoolean();
break;
case INTEGER:
((Property<Integer>) p).value = c.getAsInt();
break;
case FLOAT:
((Property<Float>) p).value = c.getAsFloat();
break;
case STRING:
((Property<String>) p).value = c.getAsString();
break;
case HEX:
((Property<Integer>) p).value = c.getAsInt();
break;
default:
break;
}
}
} else {
SaturnClient.LOGGER.warn(
"Property does not match JSON: " + propertyName);
}
}
}
public static void save() {
try {
SaturnClient.LOGGER.info("Starting to save theme...");
@@ -1,158 +0,0 @@
package org.saturnclient.saturnclient.menus;
import net.minecraft.text.Text;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.saturnclient.auth.Auth;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui.Textures;
import org.saturnclient.ui.components.SkinPreview;
import org.saturnclient.ui.widgets.SaturnClickableImage;
import org.saturnclient.ui.widgets.SaturnClickableSprite;
import org.saturnclient.ui.widgets.SaturnImage;
import org.saturnclient.ui.widgets.SaturnInputBox;
import org.saturnclient.ui.widgets.SaturnScroll;
import org.saturnclient.ui.widgets.SaturnSprite;
public class CloaksMenu extends SaturnUi {
private SaturnScroll scroll;
private Property<String> search = new Property<>("");
public CloaksMenu() {
super(Text.of("Cloaks Menu"));
}
@Override
protected void init() {
int rectWidth = 330;
int rectHeight = 228;
int rectX = (width - rectWidth) / 2;
int rectY = (height - rectHeight + 15) / 2;
draw(
new SaturnSprite(Textures.SETTINGS_BG)
.setX(rectX)
.setY(rectY)
.setWidth(rectWidth)
.setHeight(rectHeight)
.setAnimations(SaturnClientConfig.getAnimations()));
int tabsX = (width - 43) / 2;
int tabsY = rectY - 17;
draw(
new SaturnSprite(Textures.RECT)
.setX(tabsX)
.setY(tabsY)
.setWidth(43)
.setHeight(15)
.setAnimations(SaturnClientConfig.getAnimations()));
draw(
new SaturnInputBox(search, rectX + rectWidth - 72, tabsY, 70).onUpdate(() -> {
scroll.clear();
drawItems(rectX, rectY, rectWidth, rectHeight);
})
.setHeight(15)
.setWidth(72)
.setAnimations(SaturnClientConfig.getAnimations()));
int tabSize = 9;
tabsX = (width - tabSize) / 2;
draw(
new SaturnClickableImage(Textures.HAT, () -> {
client.setScreen(new HatsMenu());
})
.setX(tabsX)
.setY(tabsY + 4)
.setWidth(tabSize)
.setHeight(7)
.setAnimations(SaturnClientConfig.getAnimations()));
draw(
new SaturnClickableImage(Textures.CLOAK, () -> {
})
.setSelected(true)
.setX(tabsX - 12)
.setY(tabsY + 3)
.setWidth(tabSize)
.setHeight(tabSize)
.setAnimations(SaturnClientConfig.getAnimations()));
draw(
new SaturnClickableImage(Textures.SEARCH, () -> {
System.out.println("Pressed");
})
.setX(tabsX + 12)
.setY(tabsY + 3)
.setWidth(tabSize)
.setHeight(tabSize)
.setAnimations(SaturnClientConfig.getAnimations()));
scroll = new SaturnScroll();
drawItems(rectX, rectY, rectWidth, rectHeight);
draw(scroll
.setX(rectX + 17)
.setY(rectY + 10)
.setWidth(rectWidth - 17)
.setHeight(rectHeight - 10)
.setAnimations(SaturnClientConfig.getAnimations()));
draw(new SkinPreview()
.setScale(3.0f)
.setX((rectX + rectWidth) - 180)
.setY(rectY + 8)
.setAnimations(SaturnClientConfig.getAnimations()));
super.init();
}
private void drawItems(int rectX, int rectY, int rectWidth, int rectHeight) {
int cloakWidth = 28;
int cloakHeight = 61;
int modX = 0;
int modY = 0;
int col = 0;
String[] searchTokens = search.value.toLowerCase().split("\\ ");
outer: for (String cloak : Cloaks.availableCloaks) {
for (String searchToken : searchTokens) {
if (!cloak.contains(searchToken)) {
continue outer;
}
}
scroll.draw(
new SaturnClickableSprite(Textures.BUTTON_BORDER, () -> {
Cloaks.setCloak(Auth.uuid, cloak);
})
.setX(modX)
.setY(modY)
.setWidth(cloakWidth + 6)
.setHeight(cloakHeight + 6));
scroll.draw(
new SaturnImage(Textures.getCloakPreview(cloak))
.setX(modX + 3)
.setY(modY + 3)
.setWidth(cloakWidth)
.setHeight(cloakHeight));
col++;
if (col < 4) {
modX += cloakWidth + 21;
} else {
modX = 0;
modY += cloakHeight + 20;
col = 0;
}
}
}
}
@@ -1,234 +0,0 @@
package org.saturnclient.saturnclient.menus;
import java.util.Map;
import net.minecraft.text.Text;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.saturnclient.config.ConfigManager;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui.SaturnWidget;
import org.saturnclient.ui.Textures;
import org.saturnclient.ui.components.SaturnFloat;
import org.saturnclient.ui.components.SaturnHex;
import org.saturnclient.ui.components.SaturnInteger;
import org.saturnclient.ui.components.SaturnString;
import org.saturnclient.ui.components.SaturnToggle;
import org.saturnclient.ui.widgets.SaturnImageButton;
import org.saturnclient.ui.widgets.SaturnScroll;
import org.saturnclient.ui.widgets.SaturnSprite;
import org.saturnclient.ui.widgets.SaturnText;
public class ConfigEditor extends SaturnUi {
private ConfigManager config;
public ConfigEditor(ConfigManager config) {
super(Text.of("Config editor"));
this.config = config;
}
@Override
protected void init() {
int rectWidth = 330;
int rectHeight = 228;
int rectX = (width - rectWidth) / 2;
int rectY = (height - rectHeight + 15) / 2;
draw(
new SaturnSprite(Textures.SETTINGS_BG)
.setX(rectX)
.setY(rectY)
.setWidth(rectWidth)
.setHeight(rectHeight)
.setAnimations(SaturnClientConfig.getAnimations()));
draw(
new SaturnImageButton(Textures.CLOSE, 9, 9, () -> {
this.close();
})
.setX(rectX)
.setY(rectY - 15)
.setWidth(13)
.setHeight(13)
.setAnimations(SaturnClientConfig.getAnimations()));
SaturnScroll configScroll = new SaturnScroll();
int row = 0;
int col = 0;
drawProperties(configScroll, config.getProperties(), rectWidth, row, col);
draw(
configScroll
.setX(rectX + 17)
.setY(rectY + 10)
.setWidth(rectWidth - 17)
.setHeight(rectHeight - 10)
.setAnimations(SaturnClientConfig.getAnimations()));
super.init();
}
@SuppressWarnings("unchecked")
private int drawProperties(SaturnScroll configScroll, Map<String, Property<?>> properties, int rectWidth,
int row, int col) {
int totalRows = row;
for (Map.Entry<String, Property<?>> propEntry : properties.entrySet()) {
Property<?> prop = propEntry.getValue();
String propName = propEntry.getKey();
boolean full = isFull(prop);
if (full && col > 0) {
col = 0;
totalRows++;
}
int modX = ((rectWidth / 2) - 17) * col;
int modY = 14 * totalRows;
switch (prop.getType()) {
case BOOLEAN:
configScroll.draw(
new SaturnToggle((Property<Boolean>) prop)
.setX(modX)
.setY(modY));
configScroll.draw(
new SaturnText(
propName.substring(0, 1).toUpperCase() +
propName.substring(1))
.setX(modX + 18)
.setY(modY)
.setScale(0.8f));
break;
case INTEGER:
configScroll.draw(
new SaturnText(
propName.substring(0, 1).toUpperCase() +
propName.substring(1))
.setX(modX)
.setY(modY)
.setScale(0.8f));
configScroll.draw(
new SaturnInteger(
(Property<Integer>) prop,
(rectWidth / 2) - 17,
modY,
70));
configScroll.draw(resetButton(prop, modX, modY));
break;
case FLOAT:
configScroll.draw(
new SaturnText(
propName.substring(0, 1).toUpperCase() +
propName.substring(1))
.setX(modX)
.setY(modY)
.setScale(0.8f));
configScroll.draw(
new SaturnFloat(
(Property<Float>) prop,
(rectWidth / 2) - 17,
modY,
70));
configScroll.draw(resetButton(prop, modX, modY));
break;
case STRING:
configScroll.draw(
new SaturnText(
propName.substring(0, 1).toUpperCase() +
propName.substring(1))
.setX(modX)
.setY(modY)
.setScale(0.8f));
configScroll.draw(
new SaturnString(
(Property<String>) prop,
(rectWidth / 2) - 17,
modY,
70));
configScroll.draw(resetButton(prop, modX, modY));
break;
case HEX:
configScroll.draw(
new SaturnText(
propName.substring(0, 1).toUpperCase() +
propName.substring(1))
.setX(modX)
.setY(modY)
.setScale(0.8f));
configScroll.draw(
new SaturnHex(
(Property<Integer>) prop,
(rectWidth / 2) - 17,
modY,
70));
configScroll.draw(resetButton(prop, modX, modY));
break;
case NAMESPACE:
configScroll.draw(
new SaturnText(
propName.substring(0, 1).toUpperCase() +
propName.substring(1))
.setX(modX)
.setY(modY)
.setScale(0.8f));
// Recursively draw nested properties and update total rows
Map<String, Property<?>> nestedProperties = (Map<String, Property<?>>) prop.value;
totalRows = drawProperties(configScroll, nestedProperties, rectWidth,
totalRows + 1, 0);
}
if (full) {
totalRows++;
} else {
col++;
if (col > 1) {
col = 0;
totalRows++;
}
}
}
return totalRows;
}
public static boolean isFull(Property<?> prop) {
switch (prop.getType()) {
case BOOLEAN:
return false;
default:
return true;
}
}
@Override
public void close() {
ConfigManager.save();
super.close();
}
public SaturnWidget resetButton(Property<?> prop, int modX, int modY) {
int size = textRenderer.fontHeight - 1;
return new SaturnImageButton(
Textures.RESET,
size,
size,
() -> {
prop.reset();
})
.setX(modX + 209)
.setY(modY)
.setWidth(size + 3)
.setHeight(size + 3);
}
}
@@ -1,133 +0,0 @@
package org.saturnclient.saturnclient.menus;
import net.minecraft.text.Text;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.saturnclient.auth.Auth;
import org.saturnclient.saturnclient.cosmetics.Hats;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui.Textures;
import org.saturnclient.ui.components.SkinPreview;
import org.saturnclient.ui.widgets.SaturnClickableImage;
import org.saturnclient.ui.widgets.SaturnClickableSprite;
import org.saturnclient.ui.widgets.SaturnImage;
import org.saturnclient.ui.widgets.SaturnScroll;
import org.saturnclient.ui.widgets.SaturnSprite;
public class HatsMenu extends SaturnUi {
public HatsMenu() {
super(Text.of("Hats Menu"));
}
@Override
protected void init() {
int rectWidth = 330;
int rectHeight = 228;
int rectX = (width - rectWidth) / 2;
int rectY = (height - rectHeight + 15) / 2;
draw(
new SaturnSprite(Textures.SETTINGS_BG)
.setX(rectX)
.setY(rectY)
.setWidth(rectWidth)
.setHeight(rectHeight)
.setAnimations(SaturnClientConfig.getAnimations()));
int tabsX = (width - 43) / 2;
int tabsY = rectY - 17;
draw(
new SaturnSprite(Textures.RECT)
.setX(tabsX)
.setY(tabsY)
.setWidth(43)
.setHeight(15)
.setAnimations(SaturnClientConfig.getAnimations()));
int tabSize = 9;
tabsX = (width - tabSize) / 2;
draw(
new SaturnClickableImage(Textures.HAT, () -> {
client.setScreen(new HatsMenu());
})
.setSelected(true)
.setX(tabsX)
.setY(tabsY + 4)
.setWidth(tabSize)
.setHeight(7)
.setAnimations(SaturnClientConfig.getAnimations()));
draw(
new SaturnClickableImage(Textures.CLOAK, () -> {
client.setScreen(new CloaksMenu());
})
.setX(tabsX - 12)
.setY(tabsY + 3)
.setWidth(tabSize)
.setHeight(tabSize)
.setAnimations(SaturnClientConfig.getAnimations()));
draw(
new SaturnClickableImage(Textures.SEARCH, () -> {
System.out.println("Pressed");
})
.setX(tabsX + 12)
.setY(tabsY + 3)
.setWidth(tabSize)
.setHeight(tabSize)
.setAnimations(SaturnClientConfig.getAnimations()));
int hatSize = 28;
int modX = 0;
int modY = 0;
int col = 0;
SaturnScroll modsScroll = new SaturnScroll();
for (String hat : Hats.availableHats) {
modsScroll.draw(
new SaturnClickableSprite(Textures.BUTTON_BORDER, () -> {
Hats.setHat(Auth.uuid, hat);
})
.setX(modX)
.setY(modY)
.setWidth(hatSize + 6)
.setHeight(hatSize + 6));
modsScroll.draw(
new SaturnImage(Textures.getHatPreview(hat))
.setX(modX + 3)
.setY(modY + 3)
.setWidth(hatSize)
.setHeight(hatSize));
col++;
if (col < 4) {
modX += hatSize + 21;
} else {
modX = 0;
modY += hatSize + 20;
col = 0;
}
}
draw(
modsScroll
.setX(rectX + 17)
.setY(rectY + 10)
.setWidth(rectWidth - 17)
.setHeight(rectHeight - 10)
.setAnimations(SaturnClientConfig.getAnimations()));
draw(new SkinPreview()
.setScale(3.0f)
.setX((rectX + rectWidth) - 180)
.setY(rectY + 8)
.setAnimations(SaturnClientConfig.getAnimations()));
super.init();
}
}
@@ -10,7 +10,9 @@ import org.saturnclient.modules.ModDimensions;
import org.saturnclient.modules.ModManager;
import org.saturnclient.modules.Module;
import org.saturnclient.saturnclient.config.ConfigManager;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.saturnclient.mixin.DrawContextAccessor;
import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.SaturnScreen;
import java.util.ArrayList;
import java.util.List;
@@ -90,9 +92,11 @@ public class HudEditor extends Screen {
@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
if (client.world == null && client.getCurrentServerEntry() == null) {
SaturnUi.ROTATING_PANORAMA_RENDERER.render(context, this.width, this.height, 1.0F, delta);
SaturnScreen.ROTATING_PANORAMA_RENDERER.render(context, this.width, this.height, 1.0F, delta);
}
RenderScope scope = new RenderScope(context.getMatrices(), ((DrawContextAccessor) context).getVertexConsumers());
for (HudMod mod : hudMods) {
ModDimensions dim = mod.getDimensions();
MatrixStack matrices = context.getMatrices();
@@ -102,7 +106,7 @@ public class HudEditor extends Screen {
matrices.scale(dim.scale.value, dim.scale.value, 1.0f);
// Render the mod
mod.renderDummy(context);
mod.renderDummy(scope);
matrices.pop();
@@ -1,147 +0,0 @@
package org.saturnclient.saturnclient.menus;
import net.minecraft.text.Text;
import org.saturnclient.modules.ModManager;
import org.saturnclient.modules.Module;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.saturnclient.config.ConfigManager;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui.Textures;
import org.saturnclient.ui.components.SaturnModComp;
import org.saturnclient.ui.widgets.SaturnClickableImage;
import org.saturnclient.ui.widgets.SaturnInputBox;
import org.saturnclient.ui.widgets.SaturnScroll;
import org.saturnclient.ui.widgets.SaturnSprite;
public class ModMenu extends SaturnUi {
private SaturnScroll scroll;
private Property<String> search = new Property<>("");
public ModMenu() {
super(Text.literal("Mods"));
}
@Override
protected void init() {
int rectWidth = 330;
int rectHeight = 228;
int rectX = (width - rectWidth) / 2;
int rectY = (height - rectHeight + 15) / 2;
draw(
new SaturnSprite(Textures.SETTINGS_BG)
.setX(rectX)
.setY(rectY)
.setWidth(rectWidth)
.setHeight(rectHeight)
.setAnimations(SaturnClientConfig.getAnimations()));
int tabsX = (width - 43) / 2;
int tabsY = rectY - 17;
draw(
new SaturnSprite(Textures.RECT)
.setX(tabsX)
.setY(tabsY)
.setWidth(43)
.setHeight(15)
.setAnimations(SaturnClientConfig.getAnimations()));
draw(
new SaturnInputBox(search, rectX + rectWidth - 72, tabsY, 70).onUpdate(() -> {
scroll.clear();
drawItems(rectX, rectY, rectWidth, rectHeight);
})
.setHeight(15)
.setWidth(72)
.setAnimations(SaturnClientConfig.getAnimations()));
int tabSize = 9;
tabsX = (width - tabSize) / 2;
draw(
new SaturnClickableImage(Textures.SETTINGS, () -> {
client.setScreen(new SaturnConfigEditor());
})
.setX(tabsX)
.setY(tabsY + 3)
.setWidth(tabSize)
.setHeight(tabSize)
.setAnimations(SaturnClientConfig.getAnimations()));
draw(
new SaturnClickableImage(Textures.MODS_TAB, () -> {
})
.setSelected(true)
.setX(tabsX - 12)
.setY(tabsY + 3)
.setWidth(tabSize)
.setHeight(tabSize)
.setAnimations(SaturnClientConfig.getAnimations()));
draw(
new SaturnClickableImage(Textures.SEARCH, () -> {
System.out.println("Pressed");
})
.setX(tabsX + 12)
.setY(tabsY + 3)
.setWidth(tabSize)
.setHeight(tabSize)
.setAnimations(SaturnClientConfig.getAnimations()));
scroll = new SaturnScroll();
drawItems(rectX, rectY, rectWidth, rectHeight);
draw(scroll
.setX(rectX + 17)
.setY(rectY + 10)
.setWidth(rectWidth - 17)
.setHeight(rectHeight - 20)
.setAnimations(SaturnClientConfig.getAnimations()));
super.init();
}
@Override
public void close() {
ConfigManager.save();
super.close();
}
private void drawItems(int rectX, int rectY, int rectWidth, int rectHeight) {
int modX = 0;
int modY = 0;
int col = 0;
String[] searchTokens = search.value.toLowerCase().split("\\ ");
outer: for (Module mod : ModManager.MODS) {
String modName = mod.getName().toLowerCase();
for (String searchToken : searchTokens) {
if (!modName.contains(searchToken)) {
continue outer;
}
}
scroll.draw(
new SaturnModComp(mod)
.setX(modX)
.setY(modY)
.setWidth(86)
.setHeight(20));
col++;
if (col < 3) {
modX += 86 + 18;
} else {
modX = 0;
modY += 20 + 20;
col = 0;
}
}
}
}
@@ -1,64 +0,0 @@
package org.saturnclient.saturnclient.menus;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.ui.Textures;
import org.saturnclient.ui.widgets.SaturnClickableImage;
import org.saturnclient.ui.widgets.SaturnSprite;
public class SaturnConfigEditor extends ConfigEditor {
public SaturnConfigEditor() {
super(SaturnClientConfig.config);
}
@Override
protected void init() {
int rectHeight = 228;
int rectY = (height - rectHeight + 15) / 2;
int tabsX = (width - 43) / 2;
int tabsY = rectY - 17;
draw(
new SaturnSprite(Textures.RECT)
.setX(tabsX)
.setY(tabsY)
.setWidth(43)
.setHeight(15)
.setAnimations(SaturnClientConfig.getAnimations()));
int tabSize = 9;
tabsX = (width - tabSize) / 2;
draw(
new SaturnClickableImage(Textures.SETTINGS, () -> {
})
.setSelected(true)
.setX(tabsX)
.setY(tabsY + 3)
.setWidth(tabSize)
.setHeight(tabSize)
.setAnimations(SaturnClientConfig.getAnimations()));
draw(
new SaturnClickableImage(Textures.MODS_TAB, () -> {
client.setScreen(new ModMenu());
})
.setX(tabsX - 12)
.setY(tabsY + 3)
.setWidth(tabSize)
.setHeight(tabSize)
.setAnimations(SaturnClientConfig.getAnimations()));
draw(
new SaturnClickableImage(Textures.SEARCH, () -> {
System.out.println("Pressed");
})
.setX(tabsX + 12)
.setY(tabsY + 3)
.setWidth(tabSize)
.setHeight(tabSize)
.setAnimations(SaturnClientConfig.getAnimations()));
super.init();
}
}
@@ -1,13 +0,0 @@
package org.saturnclient.saturnclient.menus;
import org.saturnclient.ui2.SaturnScreen;
public class SaturnMenu extends SaturnScreen {
public SaturnMenu() {
super("Saturn Client");
}
@Override
public void ui() {
}
}
@@ -1,78 +0,0 @@
package org.saturnclient.saturnclient.menus;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui.Textures;
import org.saturnclient.ui.animations.FadeIn;
import org.saturnclient.ui.animations.Slide;
import org.saturnclient.ui.widgets.SaturnButton;
import org.saturnclient.ui.widgets.SaturnImage;
import org.saturnclient.ui2.screens.ShiftMenu;
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
import net.minecraft.client.gui.screen.option.OptionsScreen;
import net.minecraft.client.gui.screen.world.SelectWorldScreen;
import net.minecraft.text.Text;
public class SaturnTitleScreen extends SaturnUi {
public SaturnTitleScreen() {
super(Text.literal("Title Screen"));
}
@Override
protected void init() {
blur = false;
int logoSize = 49;
int bX = (width - 150) / 2;
int bY = height / 2 - logoSize - 27;
draw(
new SaturnImage(SaturnClientConfig.getLogo())
.setX((width - logoSize) / 2)
.setY(bY)
.setWidth(logoSize)
.setHeight(logoSize)
.setAnimations(new Slide(3, 14)));
bY += 44;
draw(
new SaturnImage(Textures.LOGO_TEXT)
.setX((width - logoSize) / 2)
.setY(bY)
.setWidth(logoSize)
.setHeight(8)
.setAnimations(new FadeIn(3)));
bY += 15;
draw(new SaturnButton("SINGLEPLAYER", () -> {
client.setScreen(new SelectWorldScreen(new SaturnTitleScreen()));
}).setBold(true).setWidth(210).setHeight(26).setX(bX).setY(bY).setScale(0.69f));
bY += 20;
draw(new SaturnButton("MULTIPLAYER", () -> {
client.setScreen(new MultiplayerScreen(new SaturnTitleScreen()));
}).setBold(true).setWidth(210).setHeight(26).setX(bX).setY(bY).setScale(0.69f));
bY += 20;
draw(new SaturnButton("OPTIONS", () -> {
client.setScreen(new OptionsScreen(new SaturnTitleScreen(), this.client.options));
}).setBold(true).setWidth(103).setHeight(26).setX(bX).setY(bY).setScale(0.69f));
draw(new SaturnButton("QUIT", () -> {
client.scheduleStop();
}).setBold(true).setWidth(103).setHeight(26).setX(bX + 74).setY(bY).setScale(0.69f));
bY += 20;
draw(new SaturnButton("SATURN OPTIONS", () -> {
client.setScreen(new ShiftMenu());
}).setBold(true).setWidth(210).setHeight(26).setX(bX).setY(bY).setScale(0.69f));
super.init();
}
}
@@ -0,0 +1,22 @@
package org.saturnclient.saturnclient.mixin;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.ui2.screens.TitleMenu;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.client.gui.screen.TitleScreen;
@Mixin(TitleScreen.class)
public class TitleScreenMixin {
@Inject(method = "init", at = @At("HEAD"), cancellable = true)
private void onInit(CallbackInfo ci) {
if (SaturnClientConfig.saturnTitleScreen.value) {
SaturnClient.client.setScreen(new TitleMenu());
ci.cancel();
}
}
}
@@ -1,13 +0,0 @@
package org.saturnclient.ui;
public class SaturnAnimation {
public int delay = 0;
public int lastTick = 0;
public void init(SaturnWidget widget) {}
public boolean run(SaturnWidget widget, int tick) {
return true;
}
}
@@ -1,322 +0,0 @@
package org.saturnclient.ui;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gl.PostEffectProcessor;
import net.minecraft.client.gui.CubeMapRenderer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.RotatingCubeMapRenderer;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.render.DefaultFramebufferSet;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.util.Pool;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.MutableText;
import net.minecraft.text.Style;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import org.lwjgl.glfw.GLFW;
public class SaturnUi extends Screen {
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
private final Pool pool = new Pool(3);
private float f = 0.0f;
public boolean blur = true;
public boolean titleBackground = false;
public List<SaturnWidget> widgets = new ArrayList<>();
private int tick = 0;
protected static final CubeMapRenderer PANORAMA_RENDERER = new CubeMapRenderer(
Identifier.of("saturnclient", "textures/gui/title/background/panorama"));
public static final RotatingCubeMapRenderer ROTATING_PANORAMA_RENDERER;
static {
ROTATING_PANORAMA_RENDERER = new RotatingCubeMapRenderer(PANORAMA_RENDERER);
}
public static MutableText text(String text) {
return Text.literal(text).setStyle(
Style.EMPTY.withFont(Identifier.of("saturnclient:panton")));
}
public static MutableText textBold(String text) {
return Text.literal(text).setStyle(
Style.EMPTY.withFont(Identifier.of("saturnclient:panton_bold")));
}
public static void drawHighResTexture(DrawContext context, Identifier t, int x, int y, int w, int h) {
MatrixStack matricies = context.getMatrices();
matricies.push();
matricies.translate(x, y, 0);
matricies.scale(.25f, .25f, 1.0f);
context.drawTexture(RenderLayer::getGuiTextured, t, 0, 0, 0, 0,
w * 4, h * 4, w * 4, h * 4);
matricies.pop();
}
public static void drawHighResTexture(DrawContext context, Identifier t, int x, int y, int w, int h, int c) {
MatrixStack matricies = context.getMatrices();
matricies.push();
matricies.translate(x, y, 0);
matricies.scale(.25f, .25f, 1.0f);
context.drawTexture(RenderLayer::getGuiTextured, t, 0, 0, 0, 0,
w * 4, h * 4, w * 4, h * 4, c);
matricies.pop();
}
public static void drawHighResGuiTexture(DrawContext context, Identifier t, int x, int y, int w, int h, int c) {
MatrixStack matricies = context.getMatrices();
matricies.push();
matricies.translate(x, y, 0);
matricies.scale(.25f, .25f, 1.0f);
context.drawGuiTexture(
RenderLayer::getGuiTextured,
t,
0,
0,
w * 4,
h * 4,
c);
matricies.pop();
}
public static int getAlpha(int color, float alpha) {
return ((int) (alpha * 255) << 24) |
(color & 0x00FFFFFF);
}
public SaturnUi(Text title) {
super(title);
}
@Override
protected void init() {
scheduler.scheduleAtFixedRate(
this::saturnTick,
0,
7,
TimeUnit.MILLISECONDS);
super.init();
}
public void draw(SaturnWidget widget) {
synchronized (widgets) {
widget.init();
widgets.add(widget);
}
}
public void refresh() {
synchronized (widgets) {
widgets.clear();
f = 0.0f;
tick = 0;
init();
}
}
@SuppressWarnings("deprecation")
@Override
public void render(
DrawContext context,
int mouseX,
int mouseY,
float delta) {
if (client.world == null && client.getCurrentServerEntry() == null) {
ROTATING_PANORAMA_RENDERER.render(context, this.width, this.height, 1.0F, delta);
}
// Blur
if (!(f < 1.0F) && blur) {
PostEffectProcessor postEffectProcessor = this.client.getShaderLoader().loadPostEffect(
Identifier.ofVanilla("blur"),
DefaultFramebufferSet.MAIN_ONLY);
if (postEffectProcessor != null) {
postEffectProcessor.setUniforms("Radius", f);
postEffectProcessor.render(this.client.getFramebuffer(), this.pool);
}
}
for (SaturnWidget widget : new ArrayList<>(widgets)) {
if (!widget.visible)
continue;
double adjustedMouseX = mouseX - widget.x;
double adjustedMouseY = mouseY - widget.y;
boolean isMouseInside = adjustedMouseX >= 0 &&
adjustedMouseX <= (widget.width * widget.scale) &&
adjustedMouseY >= 0 &&
adjustedMouseY <= (widget.height * widget.scale);
MatrixStack matrices = context.getMatrices();
matrices.push();
matrices.translate(widget.x, widget.y, 0);
matrices.scale(widget.scale, widget.scale, 1.0f);
widget.render(
context,
isMouseInside,
(int) (adjustedMouseX / widget.scale),
(int) (adjustedMouseY / widget.scale));
matrices.pop();
}
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button) {
if (button == 0) {
for (SaturnWidget widget : new ArrayList<>(widgets)) {
widget.focused = false;
if (!widget.visible)
continue;
double adjustedMouseX = mouseX - widget.x;
double adjustedMouseY = mouseY - widget.y;
boolean isMouseInside = adjustedMouseX >= 0 &&
adjustedMouseX <= (widget.width * widget.scale) &&
adjustedMouseY >= 0 &&
adjustedMouseY <= (widget.height * widget.scale);
if (isMouseInside) {
widget.focused = true;
widget.click(
(int) (adjustedMouseX / widget.scale),
(int) (adjustedMouseY / widget.scale));
}
}
}
return false;
}
@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
for (SaturnWidget widget : new ArrayList<>(widgets)) {
if (!widget.visible && !widget.focused)
continue;
widget.keyPressed(keyCode, scanCode, modifiers);
char typedChar = getCharFromKey(keyCode, modifiers);
if (typedChar != '\0') {
widget.charTyped(typedChar);
}
}
return super.keyPressed(keyCode, scanCode, modifiers);
}
@Override
public boolean mouseScrolled(
double mouseX,
double mouseY,
double horizontalAmount,
double verticalAmount) {
for (SaturnWidget widget : new ArrayList<>(widgets)) {
double adjustedMouseX = mouseX - widget.x;
double adjustedMouseY = mouseY - widget.y;
boolean isMouseInside = adjustedMouseX >= 0 &&
adjustedMouseX <= (widget.width * widget.scale) &&
adjustedMouseY >= 0 &&
adjustedMouseY <= (widget.height * widget.scale);
if (isMouseInside) {
widget.mouseScrolled(
(int) (adjustedMouseX / widget.scale),
(int) (adjustedMouseY / widget.scale),
horizontalAmount,
verticalAmount);
}
}
return super.mouseScrolled(
mouseX,
mouseY,
horizontalAmount,
verticalAmount);
}
private char getCharFromKey(int keyCode, int modifiers) {
boolean shift = (modifiers & GLFW.GLFW_MOD_SHIFT) != 0;
// A-Z
if (keyCode >= GLFW.GLFW_KEY_A && keyCode <= GLFW.GLFW_KEY_Z) {
return (char) (shift
? 'A' + (keyCode - GLFW.GLFW_KEY_A)
: 'a' + (keyCode - GLFW.GLFW_KEY_A));
}
// 0-9
if (keyCode >= GLFW.GLFW_KEY_0 && keyCode <= GLFW.GLFW_KEY_9) {
return shift
? ")!@#$%^&*(".charAt(keyCode - GLFW.GLFW_KEY_0)
: (char) ('0' + (keyCode - GLFW.GLFW_KEY_0));
}
// Special characters
return switch (keyCode) {
case GLFW.GLFW_KEY_SPACE -> ' ';
case GLFW.GLFW_KEY_PERIOD -> shift ? '>' : '.';
case GLFW.GLFW_KEY_COMMA -> shift ? '<' : ',';
case GLFW.GLFW_KEY_MINUS -> shift ? '_' : '-';
case GLFW.GLFW_KEY_EQUAL -> shift ? '+' : '=';
case GLFW.GLFW_KEY_SEMICOLON -> shift ? ':' : ';';
case GLFW.GLFW_KEY_APOSTROPHE -> shift ? '"' : '\'';
case GLFW.GLFW_KEY_SLASH -> shift ? '?' : '/';
case GLFW.GLFW_KEY_BACKSLASH -> shift ? '|' : '\\';
case GLFW.GLFW_KEY_LEFT_BRACKET -> shift ? '{' : '[';
case GLFW.GLFW_KEY_RIGHT_BRACKET -> shift ? '}' : ']';
case GLFW.GLFW_KEY_GRAVE_ACCENT -> shift ? '~' : '`';
default -> '\0';
};
}
public void saturnTick() {
synchronized (scheduler) {
if (f < 15.0f) {
f += 0.25f;
}
}
synchronized (widgets) {
for (SaturnWidget widget : widgets) {
if (widget.visible && widget.animations != null) {
for (SaturnAnimation animation : widget.animations) {
if (animation != null &&
tick - animation.lastTick == animation.delay) {
if (animation.run(widget, tick)) {
animation = null;
} else {
animation.lastTick = tick;
}
}
}
}
widget.tick();
}
tick++;
}
}
@Override
public void resize(MinecraftClient client, int width, int height) {
super.resize(client, width, height);
refresh();
}
}
@@ -1,88 +0,0 @@
package org.saturnclient.ui;
import net.minecraft.client.gui.DrawContext;
public class SaturnWidget {
public int x = 0;
public int y = 0;
public int width = 0;
public int height = 0;
public float alpha = 1.0f;
public float scale = 1.0f;
public SaturnAnimation[] animations = null;
public boolean visible = true;
public boolean focused = false;
public void init() {
}
public void render(
DrawContext context,
boolean hovering,
int mouseX,
int mouseY) {
}
public void click(int mouseX, int mouseY) {
}
public void keyPressed(int keyCode, int scanCode, int modifiers) {
}
public void charTyped(char typedChar) {
}
public void tick() {
}
public void mouseScrolled(
int mouseX,
int mouseY,
double horizontalAmount,
double verticalAmount) {
}
public SaturnWidget setX(int x) {
this.x = x;
return this;
}
public SaturnWidget setY(int y) {
this.y = y;
return this;
}
public SaturnWidget setWidth(int width) {
this.width = width;
return this;
}
public SaturnWidget setHeight(int height) {
this.height = height;
return this;
}
public SaturnWidget setAlpha(float alpha) {
this.alpha = alpha;
return this;
}
public SaturnWidget setAnimations(SaturnAnimation... animations) {
this.animations = animations;
for (SaturnAnimation anim : this.animations) {
anim.init(this);
}
return this;
}
public SaturnWidget setVisible(boolean visible) {
this.visible = visible;
return this;
}
public SaturnWidget setScale(float scale) {
this.scale = scale;
return this;
}
}
@@ -1,44 +0,0 @@
package org.saturnclient.ui;
import net.minecraft.util.Identifier;
public class Textures {
public static final Identifier COSMETICS = Identifier.of("saturnclient", "textures/gui/components/cosmetics.png");
public static final Identifier HUD_ICON = Identifier.of("saturnclient", "textures/gui/components/hud.png");
public static final Identifier SEARCH = Identifier.of("saturnclient", "textures/gui/components/search.png");
public static final Identifier CLOSE = Identifier.of("saturnclient", "textures/gui/components/close.png");
public static final Identifier MODS_TAB = Identifier.of("saturnclient", "textures/gui/components/mods_tab.png");
public static final Identifier SETTINGS = Identifier.of("saturnclient", "textures/gui/components/settings.png");
public static final Identifier CLOAK = Identifier.of("saturnclient", "textures/gui/components/cloak.png");
public static final Identifier HAT = Identifier.of("saturnclient", "textures/gui/components/hat.png");
public static final Identifier RESET = Identifier.of("saturnclient", "textures/gui/components/reset.png");
public static final Identifier TOGGLE_INDICATOR = Identifier.of("saturnclient",
"textures/gui/components/toggle_indicator.png");
public static final Identifier TOGGLE_BG = Identifier.of("saturnclient", "textures/gui/components/toggle_bg.png");
public static final Identifier LOGO = Identifier.of("saturnclient", "textures/logo/logo.png");
public static final Identifier REALISTIC_LOGO = Identifier.of("saturnclient", "textures/logo/realistic.png");
public static final Identifier LOGO_TEXT = Identifier.of("saturnclient", "textures/logo/text.png");
// Widgets
public static final Identifier BUTTON_BORDER = Identifier.of("saturnclient", "button_border");
public static final Identifier BUTTON = Identifier.of("saturnclient", "button");
public static final Identifier BUTTON_OP = Identifier.of("saturnclient", "button_op");
public static final Identifier SETTINGS_BG = Identifier.of("saturnclient", "settings_bg");
public static final Identifier RECT = Identifier.of("saturnclient", "rect");
public static final Identifier RECT_BORDER = Identifier.of("saturnclient", "rect_border");
public static final Identifier MOD = Identifier.of("saturnclient", "textures/gui/components/mod.png");
public static final Identifier MOD_BG = Identifier.of("saturnclient", "textures/gui/components/mod_bg.png");
public static Identifier getCloakPreview(String cloak) {
return Identifier.of("saturnclient", "textures/gui/cloak/" + (cloak.isEmpty() ? "none" : cloak) + ".png");
}
public static Identifier getHatPreview(String hat) {
return Identifier.of("saturnclient", "textures/gui/hat/" + (hat.isEmpty() ? "none" : hat) + ".png");
}
public static Identifier getModIcon(String modId) {
return Identifier.of("saturnclient", "textures/gui/mod/" + modId + ".png");
}
}
@@ -1,20 +0,0 @@
package org.saturnclient.ui.animations;
import org.saturnclient.ui.SaturnAnimation;
import org.saturnclient.ui.SaturnWidget;
public class FadeIn extends SaturnAnimation {
public FadeIn(int delay) {
this.delay = delay;
}
public void init(SaturnWidget widget) {
widget.alpha = 0.0f;
}
public boolean run(SaturnWidget widget, int tick) {
widget.alpha += 0.05f;
return widget.alpha > 0.9f;
}
}
@@ -1,24 +0,0 @@
package org.saturnclient.ui.animations;
import org.saturnclient.ui.SaturnAnimation;
import org.saturnclient.ui.SaturnWidget;
public class Slide extends SaturnAnimation {
private int offset;
public Slide(int delay, int offset) {
this.delay = delay;
this.offset = offset;
}
public void init(SaturnWidget widget) {
widget.y += offset;
}
public boolean run(SaturnWidget widget, int tick) {
widget.y--;
offset--;
return offset == 0;
}
}
@@ -1,179 +0,0 @@
package org.saturnclient.ui.components;
import org.saturnclient.saturnclient.SaturnClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import org.lwjgl.glfw.GLFW;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.saturnclient.config.ConfigManager;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui.SaturnWidget;
import org.saturnclient.ui.Textures;
public class SaturnFloat extends SaturnWidget {
String text = "";
public Property<Float> prop;
public int cursorPosition = 0;
private TextRenderer textRenderer = SaturnClient.client.textRenderer;
public SaturnFloat(Property<Float> prop, int x, int y, int width) {
this.x = x;
this.y = y;
this.width = width;
this.prop = prop;
this.text = String.valueOf(prop.value);
this.height = textRenderer.fontHeight + 4;
this.scale = 0.8f;
}
@Override
public void click(int mouseX, int mouseY) {
int scrollOffset = getScrollOffset();
String visibleText = text.substring(scrollOffset);
int newCursorPos = scrollOffset;
int textWidth = 0;
for (int i = 0; i < visibleText.length(); i++) {
textWidth = textRenderer.getWidth(visibleText.substring(0, i + 1));
if (textWidth > mouseX) {
break;
}
newCursorPos++;
}
cursorPosition = newCursorPos;
}
@Override
public void charTyped(char chr) {
if ((Character.isDigit(chr) || chr == '.') && text.length() < 10) {
if (text.equals("0") && cursorPosition == 1) {
text = "" + chr;
} else {
text = text.substring(0, cursorPosition) +
chr +
text.substring(cursorPosition);
prop.value = text.isEmpty() ? 0 : Float.parseFloat(text);
ConfigManager.save();
cursorPosition++;
}
}
}
@Override
public void keyPressed(int keyCode, int scanCode, int modifiers) {
if (keyCode == GLFW.GLFW_KEY_BACKSPACE) {
if (cursorPosition > 0) {
text = text.substring(0, cursorPosition - 1) +
text.substring(cursorPosition);
cursorPosition--;
if (text.length() == 0) {
text = "0";
cursorPosition = 1;
}
prop.value = Float.parseFloat(text);
ConfigManager.save();
}
} else if (keyCode == GLFW.GLFW_KEY_LEFT) {
if (cursorPosition > 0) {
cursorPosition--;
}
} else if (keyCode == GLFW.GLFW_KEY_RIGHT) {
if (cursorPosition < text.length()) {
cursorPosition++;
}
}
}
@Override
public void render(
DrawContext context,
boolean hovering,
int mouseX,
int mouseY) {
if (prop.isReset) {
this.text = String.valueOf(prop.value);
this.cursorPosition = 0;
prop.isReset = false;
}
SaturnUi.drawHighResGuiTexture(
context,
Textures.BUTTON_BORDER,
0,
0,
this.width,
this.height,
focused
? SaturnClientConfig.color.value
: SaturnClientConfig.getWhite(this.alpha));
int scrollOffset = getScrollOffset();
String visibleText = getVisibleText(scrollOffset);
int textColor = focused ? 0xFFFFFF : 0xAAAAAA;
context.drawText(
textRenderer,
SaturnUi.text(visibleText),
2,
2,
textColor,
false);
if (focused) {
int cursorX = 2 +
textRenderer.getWidth(
SaturnUi.text(
visibleText.substring(0, cursorPosition - scrollOffset)));
context.fill(
cursorX,
2,
cursorX + 1,
textRenderer.fontHeight + 4,
0xFFFFFFFF);
}
}
public void clearText() {
text = "0";
cursorPosition = 1;
prop.value = 0.0f;
}
private int getScrollOffset() {
if (text.isEmpty()) {
return 0;
}
int offset = 0;
int maxWidth = width - 4; // Available width for text
while (offset < cursorPosition) { // Ensure cursor remains visible
String visibleText = text.substring(offset, cursorPosition);
if (textRenderer.getWidth(SaturnUi.text(visibleText)) > maxWidth) {
offset++;
} else {
break;
}
}
return offset;
}
private String getVisibleText(int scrollOffset) {
String visibleText = text.substring(scrollOffset);
// Ensure text does not overflow past the available width
for (int i = 1; i <= visibleText.length(); i++) {
if (textRenderer.getWidth(
SaturnUi.text(visibleText.substring(0, i))) > width - 4) {
return visibleText.substring(0, i - 1); // Trim overflow
}
}
return visibleText;
}
}
@@ -1,140 +0,0 @@
package org.saturnclient.ui.components;
import org.saturnclient.saturnclient.SaturnClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import org.lwjgl.glfw.GLFW;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.saturnclient.config.ConfigManager;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui.SaturnWidget;
import org.saturnclient.ui.Textures;
public class SaturnHex extends SaturnWidget {
private String text = "#"; // Always starts with '#'
public Property<Integer> prop;
public int cursorPosition = 1; // After '#'
private final TextRenderer textRenderer = SaturnClient.client.textRenderer;
public SaturnHex(Property<Integer> prop, int x, int y, int width) {
this.x = x;
this.y = y;
this.width = width;
this.prop = prop;
this.text = intToHex(prop.value);
this.height = textRenderer.fontHeight + 4;
this.scale = 0.8f;
}
@Override
public void click(int mouseX, int mouseY) {
cursorPosition = Math.min(7, text.length()); // Keep cursor inside hex length
}
@Override
public void charTyped(char chr) {
if (isHexChar(chr) && text.length() < 7) { // Limit to 6 hex digits + '#'
text = text.substring(0, cursorPosition) +
chr +
text.substring(cursorPosition);
cursorPosition++;
if (text.length() == 7) { // Only update value when full hex is entered
prop.value = hexToInt(text);
ConfigManager.save();
}
}
}
@Override
public void keyPressed(int keyCode, int scanCode, int modifiers) {
if (keyCode == GLFW.GLFW_KEY_BACKSPACE && cursorPosition > 1) { // Prevent deleting '#'
text = text.substring(0, cursorPosition - 1) +
text.substring(cursorPosition);
cursorPosition--;
} else if (keyCode == GLFW.GLFW_KEY_LEFT && cursorPosition > 1) {
cursorPosition--;
} else if (keyCode == GLFW.GLFW_KEY_RIGHT && cursorPosition < text.length()) {
cursorPosition++;
}
if (text.length() == 1) { // Reset if empty (keep '#')
text = "#";
cursorPosition = 1;
}
if (text.length() == 7) { // Update only when valid hex
prop.value = hexToInt(text);
ConfigManager.save();
}
}
@Override
public void render(
DrawContext context,
boolean hovering,
int mouseX,
int mouseY) {
if (prop.isReset) {
this.text = intToHex(prop.value);
this.cursorPosition = 0;
prop.isReset = false;
}
SaturnUi.drawHighResGuiTexture(
context,
Textures.BUTTON_BORDER,
0,
0,
this.width,
this.height,
focused
? SaturnClientConfig.color.value
: SaturnClientConfig.getWhite(this.alpha));
int textColor = focused ? 0xFFFFFF : 0xAAAAAA;
context.drawText(
textRenderer,
SaturnUi.text(text),
2,
2,
textColor,
false);
if (focused) {
int cursorX = 2 +
textRenderer.getWidth(
SaturnUi.text(text.substring(0, cursorPosition)));
context.fill(
cursorX,
2,
cursorX + 1,
textRenderer.fontHeight + 4,
0xFFFFFFFF);
}
}
public void clearText() {
text = "#";
cursorPosition = 1;
prop.value = 0xFFFFFFFF; // Default white
}
private boolean isHexChar(char chr) {
return ((chr >= '0' && chr <= '9') ||
(chr >= 'A' && chr <= 'F') ||
(chr >= 'a' && chr <= 'f'));
}
public static int hexToInt(String hex) {
hex = hex.replace("#", "");
int rgb = Integer.parseInt(hex, 16);
return (0xFF << 24) | rgb;
}
public static String intToHex(int color) {
int rgb = color & 0xFFFFFF;
return String.format("#%06X", rgb).toLowerCase();
}
}
@@ -1,177 +0,0 @@
package org.saturnclient.ui.components;
import net.minecraft.client.gui.DrawContext;
import org.lwjgl.glfw.GLFW;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.saturnclient.config.ConfigManager;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui.SaturnWidget;
import org.saturnclient.ui.Textures;
public class SaturnInteger extends SaturnWidget {
String text = "";
public Property<Integer> prop;
public int cursorPosition = 0;
public SaturnInteger(Property<Integer> prop, int x, int y, int width) {
this.x = x;
this.y = y;
this.width = width;
this.prop = prop;
this.text = String.valueOf(prop.value);
this.height = SaturnClient.client.textRenderer.fontHeight + 4;
this.scale = 0.8f;
}
@Override
public void click(int mouseX, int mouseY) {
int scrollOffset = getScrollOffset();
String visibleText = text.substring(scrollOffset);
int newCursorPos = scrollOffset;
int textWidth = 0;
for (int i = 0; i < visibleText.length(); i++) {
textWidth = SaturnClient.client.textRenderer.getWidth(visibleText.substring(0, i + 1));
if (textWidth > mouseX) {
break;
}
newCursorPos++;
}
cursorPosition = newCursorPos;
}
@Override
public void charTyped(char chr) {
if (Character.isDigit(chr) && text.length() < 10) {
if (text.equals("0") && cursorPosition == 1) {
text = "" + chr;
} else {
text = text.substring(0, cursorPosition) +
chr +
text.substring(cursorPosition);
prop.value = text.isEmpty() ? 0 : Integer.parseInt(text);
ConfigManager.save();
cursorPosition++;
}
}
}
@Override
public void keyPressed(int keyCode, int scanCode, int modifiers) {
if (keyCode == GLFW.GLFW_KEY_BACKSPACE) {
if (cursorPosition > 0) {
text = text.substring(0, cursorPosition - 1) +
text.substring(cursorPosition);
cursorPosition--;
if (text.length() == 0) {
text = "0";
cursorPosition = 1;
}
prop.value = Integer.parseInt(text);
ConfigManager.save();
}
} else if (keyCode == GLFW.GLFW_KEY_LEFT) {
if (cursorPosition > 0) {
cursorPosition--;
}
} else if (keyCode == GLFW.GLFW_KEY_RIGHT) {
if (cursorPosition < text.length()) {
cursorPosition++;
}
}
}
@Override
public void render(
DrawContext context,
boolean hovering,
int mouseX,
int mouseY) {
if (prop.isReset) {
this.text = String.valueOf(prop.value);
this.cursorPosition = 0;
prop.isReset = false;
}
SaturnUi.drawHighResGuiTexture(
context,
Textures.BUTTON_BORDER,
0,
0,
this.width,
this.height,
focused
? SaturnClientConfig.color.value
: SaturnClientConfig.getWhite(this.alpha));
int scrollOffset = getScrollOffset();
String visibleText = getVisibleText(scrollOffset);
int textColor = focused ? 0xFFFFFF : 0xAAAAAA;
context.drawText(
SaturnClient.client.textRenderer,
SaturnUi.text(visibleText),
2,
2,
textColor,
false);
if (focused) {
int cursorX = 2 +
SaturnClient.client.textRenderer.getWidth(
SaturnUi.text(
visibleText.substring(0, cursorPosition - scrollOffset)));
context.fill(
cursorX,
2,
cursorX + 1,
SaturnClient.client.textRenderer.fontHeight + 4,
0xFFFFFFFF);
}
}
public void clearText() {
text = "0";
cursorPosition = 1;
prop.value = 0;
}
private int getScrollOffset() {
if (text.isEmpty()) {
return 0;
}
int offset = 0;
int maxWidth = width - 4; // Available width for text
while (offset < cursorPosition) { // Ensure cursor remains visible
String visibleText = text.substring(offset, cursorPosition);
if (SaturnClient.client.textRenderer.getWidth(SaturnUi.text(visibleText)) > maxWidth) {
offset++;
} else {
break;
}
}
return offset;
}
private String getVisibleText(int scrollOffset) {
String visibleText = text.substring(scrollOffset);
// Ensure text does not overflow past the available width
for (int i = 1; i <= visibleText.length(); i++) {
if (SaturnClient.client.textRenderer.getWidth(
SaturnUi.text(visibleText.substring(0, i))) > width - 4) {
return visibleText.substring(0, i - 1); // Trim overflow
}
}
return visibleText;
}
}
@@ -1,106 +0,0 @@
package org.saturnclient.ui.components;
import net.minecraft.client.gui.DrawContext;
import org.saturnclient.modules.Module;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.saturnclient.menus.ConfigEditor;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui.SaturnWidget;
import org.saturnclient.ui.Textures;
public class SaturnModComp extends SaturnWidget {
Module mod;
public SaturnModComp(Module mod) {
this.mod = mod;
}
@Override
public void render(
DrawContext context,
boolean hovering,
int mouseX,
int mouseY) {
boolean enabled = mod.isEnabled();
boolean hovering_settings = settingsHovering(mouseX, mouseY);
int color = !hovering_settings && (enabled || hovering)
? SaturnClientConfig.color.value
: SaturnClientConfig.getWhite(alpha);
int size = 12;
if (enabled) {
SaturnUi.drawHighResTexture(
context,
Textures.MOD_BG,
0,
0,
86,
20,
SaturnClientConfig.color.value);
}
SaturnUi.drawHighResTexture(
context,
Textures.MOD,
0,
0,
86,
20,
color);
SaturnUi.drawHighResTexture(
context,
mod.getIconTexture(),
4,
4,
size,
size,
color);
context.drawText(
SaturnClient.client.textRenderer,
SaturnUi.text(mod.getName()),
20,
(21 - SaturnClient.client.textRenderer.fontHeight) / 2,
color,
false);
SaturnUi.drawHighResTexture(
context,
Textures.SETTINGS,
77,
11,
7,
7,
hovering_settings
? SaturnClientConfig.color.value
: SaturnClientConfig.getWhite(alpha));
}
@Override
public void click(int mouseX, int mouseY) {
if (settingsHovering(mouseX, mouseY)) {
SaturnClient.client
.setScreen(new ConfigEditor(mod.getConfig()));
} else {
mod.setEnabled(!mod.isEnabled());
}
}
public boolean settingsHovering(int mouseX, int mouseY) {
int sX = 77;
int sY = 11;
int size = 7;
return (sX < mouseX &&
sX + size > mouseX &&
sY < mouseY &&
sY + size > mouseY);
}
}
@@ -1,155 +0,0 @@
package org.saturnclient.ui.components;
import org.saturnclient.saturnclient.SaturnClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import org.lwjgl.glfw.GLFW;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui.SaturnWidget;
import org.saturnclient.ui.Textures;
public class SaturnString extends SaturnWidget {
public Property<String> prop;
public int cursorPosition = 0;
private TextRenderer textRenderer = SaturnClient.client.textRenderer;
public SaturnString(Property<String> prop, int x, int y, int width) {
this.x = x;
this.y = y;
this.width = width;
this.prop = prop;
this.height = textRenderer.fontHeight + 4;
this.scale = 0.8f;
}
@Override
public void click(int mouseX, int mouseY) {
int scrollOffset = getScrollOffset();
String visibleText = prop.value.substring(scrollOffset);
int newCursorPos = scrollOffset;
int textWidth = 0;
for (int i = 0; i < visibleText.length(); i++) {
textWidth = textRenderer.getWidth(visibleText.substring(0, i + 1));
if (textWidth > mouseX) {
break;
}
newCursorPos++;
}
cursorPosition = newCursorPos;
}
@Override
public void charTyped(char chr) {
prop.value = prop.value.substring(0, cursorPosition) +
chr +
prop.value.substring(cursorPosition);
cursorPosition++;
}
@Override
public void keyPressed(int keyCode, int scanCode, int modifiers) {
if (keyCode == GLFW.GLFW_KEY_BACKSPACE) {
if (cursorPosition > 0) {
prop.value = prop.value.substring(0, cursorPosition - 1) +
prop.value.substring(cursorPosition);
cursorPosition--;
}
} else if (keyCode == GLFW.GLFW_KEY_LEFT) {
if (cursorPosition > 0) {
cursorPosition--;
}
} else if (keyCode == GLFW.GLFW_KEY_RIGHT) {
if (cursorPosition < prop.value.length()) {
cursorPosition++;
}
}
}
@Override
public void render(
DrawContext context,
boolean hovering,
int mouseX,
int mouseY) {
SaturnUi.drawHighResGuiTexture(
context,
Textures.BUTTON_BORDER,
0,
0,
this.width,
this.height,
focused
? SaturnClientConfig.color.value
: SaturnClientConfig.getWhite(this.alpha));
int scrollOffset = getScrollOffset();
String visibleText = getVisibleText(scrollOffset);
int textColor = focused ? 0xFFFFFF : 0xAAAAAA;
context.drawText(
textRenderer,
SaturnUi.text(visibleText),
2,
2,
textColor,
false);
if (focused) {
int cursorX = 2 +
textRenderer.getWidth(
SaturnUi.text(
visibleText.substring(0, cursorPosition - scrollOffset)));
context.fill(
cursorX,
2,
cursorX + 1,
textRenderer.fontHeight + 3,
0xFFFFFFFF);
}
}
public void clearText() {
prop.value = "";
cursorPosition = 1;
}
private int getScrollOffset() {
if (prop.value.isEmpty()) {
return 0;
}
int offset = 0;
int maxWidth = width - 4; // Available width for prop.value
while (offset < cursorPosition) { // Ensure cursor remains visible
String visibleText = prop.value.substring(offset, cursorPosition);
if (textRenderer.getWidth(SaturnUi.text(visibleText)) > maxWidth) {
offset++;
} else {
break;
}
}
return offset;
}
private String getVisibleText(int scrollOffset) {
String visibleText = prop.value.substring(scrollOffset);
// Ensure prop.value does not overflow past the available width
for (int i = 1; i <= visibleText.length(); i++) {
if (textRenderer.getWidth(
SaturnUi.text(visibleText.substring(0, i))) > width - 4) {
return visibleText.substring(0, i - 1); // Trim overflow
}
}
return visibleText;
}
}
@@ -1,66 +0,0 @@
package org.saturnclient.ui.components;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.render.RenderLayer;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.saturnclient.config.ConfigManager;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui.SaturnWidget;
import org.saturnclient.ui.Textures;
public class SaturnToggle extends SaturnWidget {
Property<Boolean> prop;
public SaturnToggle(Property<Boolean> prop) {
this.prop = prop;
width = 16;
height = 8;
}
@Override
public void render(
DrawContext context,
boolean hovering,
int mouseX,
int mouseY) {
int color = prop.value
? SaturnClientConfig.color.value
: SaturnClientConfig.getWhite(alpha);
int w = 13;
int h = 6;
int s = 8;
context.drawTexture(
RenderLayer::getGuiTextured,
Textures.TOGGLE_BG,
0,
1,
0,
0,
w,
h,
w,
h,
color);
context.drawTexture(
RenderLayer::getGuiTextured,
Textures.TOGGLE_INDICATOR,
prop.value ? 5 : 0,
0,
0,
0,
s,
s,
s,
s,
color);
}
@Override
public void click(int mouseX, int mouseY) {
prop.value = !prop.value;
ConfigManager.save();
}
}
@@ -1,106 +0,0 @@
package org.saturnclient.ui.widgets;
import com.mojang.blaze3d.systems.RenderSystem;
import java.util.function.Consumer;
import org.saturnclient.saturnclient.SaturnClient;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.text.Text;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui.SaturnWidget;
import org.saturnclient.ui.Textures;
import net.minecraft.client.MinecraftClient;
public class SaturnButton extends SaturnWidget {
public boolean active = true;
public String text;
public Consumer<SaturnButton> onPress;
public boolean background = true;
public boolean bold = false;
private float hoverAlpha = 0.0f;
public SaturnButton(String text, Consumer<SaturnButton> onPress) {
this.text = text;
this.onPress = onPress;
}
public SaturnButton(String text, Runnable onPress) {
this(text, b -> {
onPress.run();
});
}
@Override
public void render(
DrawContext context,
boolean hovering,
int mouseX,
int mouseY) {
MinecraftClient minecraftClient = SaturnClient.client;
if (background) {
RenderSystem.setShaderTexture(0, Textures.BUTTON);
SaturnUi.drawHighResGuiTexture(
context,
Textures.BUTTON,
0,
0,
this.width,
this.height,
SaturnClientConfig.getColor(hovering, alpha));
if (hovering) {
if (hoverAlpha == 0.0f)
hoverAlpha = 0.1f;
SaturnUi.drawHighResGuiTexture(
context,
Textures.BUTTON_BORDER,
0,
0,
this.width,
this.height,
SaturnClientConfig.getColor(hovering, alpha));
} else {
hoverAlpha = 0.0f;
}
}
if (alpha != 0.0f) {
Text t = bold ? SaturnUi.textBold(text) : SaturnUi.text(text);
context.drawText(
minecraftClient.textRenderer,
t,
((this.width -
minecraftClient.textRenderer.getWidth(t))
/
2),
((this.height - minecraftClient.textRenderer.fontHeight + 1) /
2),
SaturnClientConfig.getColor(hovering, alpha),
false);
}
}
@Override
public void click(int mouseX, int mouseY) {
this.onPress.accept(this);
}
@Override
public void tick() {
if (hoverAlpha > 0.0f && hoverAlpha < 0.9f)
hoverAlpha += 0.03f;
else if (hoverAlpha > 0.9f && hoverAlpha < 1.0f)
hoverAlpha = 1.0f;
}
public SaturnWidget setBold(boolean bold) {
this.bold = bold;
return this;
}
}
@@ -1,68 +0,0 @@
package org.saturnclient.ui.widgets;
import java.util.function.Consumer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.util.Identifier;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui.SaturnWidget;
public class SaturnClickableImage extends SaturnWidget {
public Identifier texture;
public boolean selected = false;
public Consumer<SaturnClickableImage> onPress;
private float hoverAlpha = 0.0f;
public SaturnClickableImage(
Identifier texture,
Consumer<SaturnClickableImage> onPress) {
this.texture = texture;
this.onPress = onPress;
}
public SaturnClickableImage(Identifier texture, Runnable onPress) {
this(texture, _o -> {
onPress.run();
});
}
@Override
public void render(
DrawContext context,
boolean hovering,
int mouseX,
int mouseY) {
if (hovering) {
if (hoverAlpha == 0.0f)
hoverAlpha = 0.1f;
}
SaturnUi.drawHighResTexture(
context,
texture,
0,
0,
width,
height,
SaturnClientConfig.getColor(hovering || selected, alpha));
}
@Override
public void click(int mouseX, int mouseY) {
this.onPress.accept(this);
}
public SaturnClickableImage setSelected(boolean selected) {
this.selected = selected;
return this;
}
@Override
public void tick() {
if (hoverAlpha > 0.0f && hoverAlpha < 0.9f)
hoverAlpha += 0.03f;
else if (hoverAlpha > 0.9f && hoverAlpha < 1.0f)
hoverAlpha = 1.0f;
}
}
@@ -1,54 +0,0 @@
package org.saturnclient.ui.widgets;
import java.util.function.Consumer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.util.Identifier;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui.SaturnWidget;
public class SaturnClickableSprite extends SaturnWidget {
public Identifier sprite;
public boolean selected = false;
public Consumer<SaturnClickableSprite> onPress;
public SaturnClickableSprite(
Identifier sprite,
Consumer<SaturnClickableSprite> onPress) {
this.sprite = sprite;
this.onPress = onPress;
}
public SaturnClickableSprite(Identifier sprite, Runnable onPress) {
this(sprite, _o -> {
onPress.run();
});
}
@Override
public void render(
DrawContext context,
boolean hovering,
int mouseX,
int mouseY) {
SaturnUi.drawHighResGuiTexture(
context,
sprite,
0,
0,
this.width,
this.height,
SaturnClientConfig.getColor(hovering, alpha));
}
@Override
public void click(int mouseX, int mouseY) {
this.onPress.accept(this);
}
public SaturnClickableSprite setSelected(boolean selected) {
this.selected = selected;
return this;
}
}
@@ -1,33 +0,0 @@
package org.saturnclient.ui.widgets;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.ColorHelper;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui.SaturnWidget;
public class SaturnImage extends SaturnWidget {
private final Identifier sprite;
public SaturnImage(Identifier sprite) {
this.sprite = sprite;
}
@Override
public void render(
DrawContext context,
boolean hovering,
int mouseX,
int mouseY) {
SaturnUi.drawHighResTexture(
context,
sprite,
0,
0,
width,
height,
ColorHelper.getWhite(alpha));
}
}
@@ -1,101 +0,0 @@
package org.saturnclient.ui.widgets;
import java.util.function.Consumer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.util.Identifier;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui.SaturnWidget;
import org.saturnclient.ui.Textures;
import com.mojang.blaze3d.systems.RenderSystem;
public class SaturnImageButton extends SaturnWidget {
public Identifier sprite;
public int imageWidth;
public int imageHeight;
public Consumer<SaturnImageButton> onPress;
private float hoverAlpha = 0.0f;
public SaturnImageButton(
Identifier sprite,
int imageWidth,
int imageHeight,
Consumer<SaturnImageButton> onPress) {
this.sprite = sprite;
this.imageWidth = imageWidth;
this.imageHeight = imageHeight;
this.onPress = onPress;
}
public SaturnImageButton(
Identifier sprite,
int imageWidth,
int imageHeight,
Runnable onPress) {
this(sprite, imageWidth, imageHeight, _o -> {
onPress.run();
});
}
@Override
public void render(
DrawContext context,
boolean hovering,
int mouseX,
int mouseY) {
if (hovering) {
if (hoverAlpha == 0.0f)
hoverAlpha = 0.1f;
}
RenderSystem.setShaderTexture(0, Textures.BUTTON);
SaturnUi.drawHighResGuiTexture(
context,
Textures.BUTTON,
0,
0,
this.width,
this.height,
SaturnClientConfig.getColor(hovering, alpha));
if (hovering) {
SaturnUi.drawHighResGuiTexture(
context,
Textures.BUTTON_BORDER,
0,
0,
this.width,
this.height,
SaturnClientConfig.getColor(hovering, alpha));
}
context.drawTexture(
RenderLayer::getGuiTextured,
sprite,
((width - imageWidth) / 2),
((height - imageHeight) / 2),
0,
0,
imageWidth,
imageHeight,
imageWidth,
imageHeight,
SaturnClientConfig.getColor(hovering, alpha));
}
@Override
public void click(int mouseX, int mouseY) {
this.onPress.accept(this);
}
@Override
public void tick() {
if (hoverAlpha > 0.0f && hoverAlpha < 0.9f)
hoverAlpha += 0.03f;
else if (hoverAlpha > 0.9f && hoverAlpha < 1.0f)
hoverAlpha = 1.0f;
}
}
@@ -1,230 +0,0 @@
package org.saturnclient.ui.widgets;
import org.saturnclient.ui.SaturnWidget;
import org.saturnclient.saturnclient.SaturnClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.util.math.MatrixStack;
import org.lwjgl.glfw.GLFW;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui.Textures;
public class SaturnInputBox extends SaturnWidget {
private TextRenderer textRenderer = SaturnClient.client.textRenderer;
private int tick = 0;
private boolean cursorVisible = true;
public Property<String> prop;
public int cursorPosition = 0;
public Runnable onUpdate;
public SaturnInputBox(Property<String> prop, int x, int y, int width) {
this.x = x;
this.y = y;
this.width = width;
this.prop = prop;
this.height = textRenderer.fontHeight + 4;
this.scale = 1.0f;
}
@Override
public void click(int mouseX, int mouseY) {
int scrollOffset = getScrollOffset();
String visibleText = prop.value.substring(scrollOffset);
int newCursorPos = scrollOffset;
int textWidth = 0;
for (int i = 0; i < visibleText.length(); i++) {
textWidth = textRenderer.getWidth(visibleText.substring(0, i + 1));
if (textWidth > mouseX) {
break;
}
newCursorPos++;
}
cursorPosition = newCursorPos;
}
@Override
public void charTyped(char chr) {
prop.value = prop.value.substring(0, cursorPosition) +
chr +
prop.value.substring(cursorPosition);
cursorPosition++;
onUpdate.run();
}
@Override
public void keyPressed(int keyCode, int scanCode, int modifiers) {
if (keyCode == GLFW.GLFW_KEY_BACKSPACE) {
if (cursorPosition > 0) {
prop.value = prop.value.substring(0, cursorPosition - 1) +
prop.value.substring(cursorPosition);
cursorPosition--;
}
onUpdate.run();
} else if (keyCode == GLFW.GLFW_KEY_LEFT) {
if (cursorPosition > 0) {
cursorPosition--;
}
} else if (keyCode == GLFW.GLFW_KEY_RIGHT) {
if (cursorPosition < prop.value.length()) {
cursorPosition++;
}
}
}
@Override
public void render(
DrawContext context,
boolean hovering,
int mouseX,
int mouseY) {
SaturnUi.drawHighResGuiTexture(
context,
Textures.BUTTON,
0,
0,
this.width,
this.height,
focused
? SaturnClientConfig.color.value
: SaturnClientConfig.getWhite(this.alpha));
if (hovering || focused) {
SaturnUi.drawHighResGuiTexture(
context,
Textures.BUTTON_BORDER,
0,
0,
this.width,
this.height,
hovering
? SaturnClientConfig.color.value
: SaturnClientConfig.getWhite(this.alpha));
}
MatrixStack matrices = context.getMatrices();
matrices.push();
if (prop.value.isEmpty() && !focused) {
SaturnUi.drawHighResTexture(
context,
Textures.SEARCH,
3,
3,
9,
9,
hovering
? SaturnClientConfig.color.value
: SaturnClientConfig.getWhite(this.alpha));
matrices.scale(0.9f, 0.9f, 1.0f);
context.drawText(
textRenderer,
SaturnUi.text("Search"),
14,
textRenderer.fontHeight / 2 + 1,
hovering
? SaturnClientConfig.color.value
: SaturnClientConfig.getWhite(this.alpha),
false);
}
matrices.pop();
matrices.push();
matrices.scale(0.9f, 0.9f, 1.0f);
int scrollOffset = getScrollOffset();
String visibleText = getVisibleText(scrollOffset);
int textColor = focused ? 0xFFFFFF : 0xAAAAAA;
context.drawText(
textRenderer,
SaturnUi.text(visibleText),
3,
textRenderer.fontHeight / 2,
textColor,
false);
if (focused && cursorVisible) {
int cursorX = 2 +
textRenderer.getWidth(
SaturnUi.text(
visibleText.substring(0, cursorPosition - scrollOffset)));
matrices.translate(cursorX, 0, 0);
context.fill(
1,
2,
2,
textRenderer.fontHeight + 3,
0xFFFFFFFF);
}
matrices.pop();
}
public void clearText() {
prop.value = "";
cursorPosition = 1;
}
private int getScrollOffset() {
if (prop.value.isEmpty()) {
return 0;
}
int offset = 0;
int maxWidth = width - 4; // Available width for prop.value
while (offset < cursorPosition) { // Ensure cursor remains visible
String visibleText = prop.value.substring(offset, cursorPosition);
if (textRenderer.getWidth(SaturnUi.text(visibleText)) > maxWidth) {
offset++;
} else {
break;
}
}
return offset;
}
private String getVisibleText(int scrollOffset) {
String visibleText = prop.value.substring(scrollOffset);
// Ensure prop.value does not overflow past the available width
for (int i = 1; i <= visibleText.length(); i++) {
if (textRenderer.getWidth(
SaturnUi.text(visibleText.substring(0, i))) > width - 4) {
return visibleText.substring(0, i - 1); // Trim overflow
}
}
return visibleText;
}
public SaturnInputBox onUpdate(Runnable onUpdate) {
this.onUpdate = onUpdate;
return this;
}
@Override
public void tick() {
if (focused) {
if (tick < 45 || tick < 60 && cursorVisible) {
tick++;
} else {
tick = 0;
cursorVisible = !cursorVisible;
}
}
}
}
@@ -1,150 +0,0 @@
package org.saturnclient.ui.widgets;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.util.math.MatrixStack;
import org.saturnclient.ui.SaturnWidget;
public class SaturnScroll extends SaturnWidget {
private int scroll = 0;
private int maxScroll = 0;
private List<SaturnWidget> children = new ArrayList<>();
@Override
public void mouseScrolled(
int mouseX,
int mouseY,
double horizontalAmount,
double verticalAmount
) {
verticalAmount *= 2;
if (scroll - verticalAmount <= 0) {
scroll = 0;
} else if (scroll - verticalAmount >= maxScroll) {
scroll = maxScroll;
} else {
scroll -= verticalAmount;
}
}
@Override
public void render(
DrawContext context,
boolean hovering,
int mouseX,
int mouseY
) {
context.enableScissor(0, 0, width, height);
for (SaturnWidget widget : children) {
if (!widget.visible) continue;
double adjustedMouseX = (mouseX - widget.x);
double adjustedMouseY = (mouseY - widget.y + scroll);
boolean isMouseInside =
adjustedMouseX >= 0 &&
adjustedMouseX <= (widget.width * widget.scale) &&
adjustedMouseY >= 0 &&
adjustedMouseY <= (widget.height * widget.scale);
if (
widget.y - scroll < height && widget.y + widget.height > scroll
) {
MatrixStack matrices = context.getMatrices();
matrices.push();
matrices.translate(widget.x, widget.y - scroll, 0);
matrices.scale(widget.scale, widget.scale, 1.0f);
widget.render(
context,
isMouseInside,
(int) (adjustedMouseX / widget.scale),
(int) (adjustedMouseY / widget.scale)
);
matrices.pop();
}
}
context.disableScissor();
}
@Override
public void init() {
maxScroll = 0;
for (SaturnWidget child : children) {
maxScroll = Math.max(maxScroll, child.y + child.height - height);
}
}
public void draw(SaturnWidget widget) {
synchronized (children) {
widget.init();
children.add(widget);
}
}
public boolean isScrollable() {
for (SaturnWidget widget : children) {
if (widget.y + widget.height > height) {
return true;
}
}
return false;
}
@Override
public void keyPressed(int keyCode, int scanCode, int modifiers) {
for (SaturnWidget widget : children) {
if (!widget.visible || !widget.focused) {
continue;
}
widget.keyPressed(keyCode, scanCode, modifiers);
break;
}
}
@Override
public void charTyped(char typedChar) {
for (SaturnWidget widget : children) {
if (!widget.visible || !widget.focused) {
continue;
}
widget.charTyped(typedChar);
break;
}
}
@Override
public void click(int mouseX, int mouseY) {
for (SaturnWidget widget : children) {
widget.focused = false;
if (!widget.visible) {
continue;
}
double adjustedMouseX = (mouseX - widget.x);
double adjustedMouseY = (mouseY - (widget.y - scroll));
boolean isMouseInside =
adjustedMouseX >= 0 &&
adjustedMouseX <= (widget.width * widget.scale) &&
adjustedMouseY >= 0 &&
adjustedMouseY <= (widget.height * widget.scale);
if (isMouseInside) {
widget.focused = true;
widget.click(
(int) (adjustedMouseX / widget.scale),
(int) (adjustedMouseY / widget.scale)
);
}
}
}
public void clear() {
children.clear();
}
}
@@ -1,32 +0,0 @@
package org.saturnclient.ui.widgets;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.ColorHelper;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui.SaturnWidget;
public class SaturnSprite extends SaturnWidget {
private final Identifier sprite;
public SaturnSprite(Identifier sprite) {
this.sprite = sprite;
}
@Override
public void render(
DrawContext context,
boolean hovering,
int mouseX,
int mouseY) {
SaturnUi.drawHighResGuiTexture(
context,
sprite,
0,
0,
this.width,
this.height,
ColorHelper.getWhite(this.alpha));
}
}
@@ -1,38 +0,0 @@
package org.saturnclient.ui.widgets;
import net.minecraft.client.gui.DrawContext;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.ui.SaturnUi;
import org.saturnclient.ui.SaturnWidget;
public class SaturnText extends SaturnWidget {
private String text;
public SaturnText(String text) {
this.text = text;
this.width = SaturnClient.client.textRenderer.getWidth(SaturnUi.text(text));
this.height = SaturnClient.client.textRenderer.fontHeight;
}
public SaturnText(String text, int color) {
this(text);
}
@Override
public void render(
DrawContext context,
boolean hovering,
int mouseX,
int mouseY) {
context.drawText(
SaturnClient.client.textRenderer,
SaturnUi.text(text),
0,
0,
SaturnClientConfig.getColor(hovering, alpha),
false);
}
}
@@ -16,12 +16,21 @@ public class Element {
public float scale = 1.0f;
public Function<Double, Double> curve = Curve::easeInOutCubic;
public void render(RenderScope renderScope, RenderContext ctx) {
public void render(RenderScope renderScope, ElementContext ctx) {
}
public void click(int mouseX, int mouseY) {
}
public void scroll(int mouseX, int mouseY, double horizontalAmount, double verticalAmount) {
}
public void keyPressed(int keyCode, int scanCode, int modifiers) {
}
public void charTyped(char typedChar) {
}
public final Element dimensions(int width, int height) {
this.width = width;
this.height = height;
@@ -0,0 +1,23 @@
package org.saturnclient.ui2;
public class ElementContext {
public int mouseX, mouseY;
public int elementWidth, elementHeight;
public float elementScale;
public ElementContext(int mouseX, int mouseY, Element e) {
this.mouseX = mouseX - e.x;
this.mouseY = mouseY - e.y;
this.elementWidth = e.width;
this.elementHeight = e.height;
this.elementScale = e.scale;
}
public boolean isHovering() {
return Utils.isHovering(mouseX, mouseY, elementWidth, elementHeight, elementScale);
}
public boolean isHovering(int x, int y, int width, int height) {
return Utils.isHovering(mouseX - x, mouseY - y, width, height, elementScale);
}
}
@@ -1,22 +0,0 @@
package org.saturnclient.ui2;
public class RenderContext {
public int mouseX, mouseY;
public int elementX, elementY;
public int elementWidth, elementHeight;
public float elementScale;
public RenderContext(int mouseX, int mouseY, Element e) {
this.mouseX = mouseX;
this.mouseY = mouseY;
this.elementX = e.x;
this.elementY = e.y;
this.elementWidth = e.width;
this.elementHeight = e.height;
this.elementScale = e.scale;
}
public boolean isHovering() {
return Utils.isHovering(mouseX - elementX, mouseY - elementY, elementWidth, elementHeight, elementScale);
}
}
@@ -1,7 +1,12 @@
package org.saturnclient.ui2;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
import org.saturnclient.ui2.resources.Fonts;
import com.mojang.blaze3d.systems.RenderSystem;
@@ -9,22 +14,38 @@ import com.mojang.blaze3d.systems.RenderSystem;
import org.saturnclient.saturnclient.SaturnClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.font.TextRenderer.TextLayerType;
import net.minecraft.client.gui.ScreenRect;
import net.minecraft.client.render.DiffuseLighting;
import net.minecraft.client.render.OverlayTexture;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.item.ItemRenderState;
import net.minecraft.client.util.Window;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ModelTransformationMode;
import net.minecraft.util.Identifier;
import net.minecraft.util.crash.CrashException;
import net.minecraft.util.crash.CrashReport;
import net.minecraft.util.crash.CrashReportSection;
import net.minecraft.util.math.RotationAxis;
import net.minecraft.world.World;
public class RenderScope {
public MatrixStack matrices;
public VertexConsumerProvider.Immediate vertexConsumers;
private Function<Identifier, RenderLayer> renderLayers;
private ScissorStack scissorStack = new ScissorStack();
private int opacity = 255 << 24;
private final ItemRenderState itemRenderState;
public RenderScope(MatrixStack matrices, VertexConsumerProvider.Immediate vertexConsumers) {
this.matrices = matrices;
this.vertexConsumers = vertexConsumers;
this.scissorStack = new ScissorStack();
this.itemRenderState = new ItemRenderState();
}
public void setOpacity(float alpha) {
@@ -71,21 +92,27 @@ public class RenderScope {
vertexConsumer.vertex(matrix4f, (float) x2, (float) y1, 0).color(color);
}
public void drawText(String text, int x, int y, boolean bold, int color) {
color = getColor(color);
public void drawText(String text, int x, int y, boolean bold, int color) {
drawText(1.0f, text, x, y, bold, color);
}
Identifier font = bold ? Fonts.PANTON_BOLD : Fonts.PANTON;
matrices.push();
matrices.translate(x, y, 0);
matrices.scale(2.0f, 2.0f, 1.0f);
TextRenderer textRenderer = SaturnClient.client.textRenderer;
textRenderer.draw(Fonts.setFont(text, font), 0, 0, color, false, this.matrices.peek().getPositionMatrix(),
this.vertexConsumers, TextLayerType.NORMAL, 0, 15728880);
matrices.pop();
public void drawText(float scale, String text, int x, int y, boolean bold, int color) {
int i = 0;
for (String line : text.split("\n")) {
color = getColor(color);
Identifier font = bold ? Fonts.INTER_BOLD : Fonts.INTER;
matrices.push();
matrices.translate(x, y + (i * Fonts.getHeight()), 0);
matrices.scale(scale, scale, 1.0f);
TextRenderer textRenderer = SaturnClient.client.textRenderer;
textRenderer.draw(Fonts.setFont(line, font), 0, 7, color, false, this.matrices.peek().getPositionMatrix(),
this.vertexConsumers, TextLayerType.NORMAL, 0, 15728880);
matrices.pop();
i++;
}
}
public void drawRoundedCorner(int width, int height, int radius, int color) {
private void drawRoundedCorner(int width, int height, int radius, int color) {
int w = width * 20;
int h = height * 20;
@@ -192,4 +219,139 @@ public class RenderScope {
vertexConsumer.vertex(matrix4f, (float)x2, (float)y1, 0.0F).texture(u2, v1).color(color);
matrices.pop();
}
public void enableScissor(int x1, int y1, int x2, int y2) {
ScreenRect screenRect = (new ScreenRect(x1, y1, x2 - x1, y2 - y1)).transform(this.matrices.peek().getPositionMatrix());
this.setScissor(this.scissorStack.push(screenRect));
}
public void disableScissor() {
this.setScissor(this.scissorStack.pop());
}
public boolean scissorContains(int x, int y) {
return this.scissorStack.containsPoint(x, y);
}
private void setScissor(@Nullable ScreenRect rect) {
this.draw();
if (rect != null) {
Window window = SaturnClient.client.getWindow();
int i = window.getFramebufferHeight();
double d = window.getScaleFactor();
double e = (double)rect.getLeft() * d;
double f = (double)i - (double)rect.getBottom() * d;
double g = (double)rect.width() * d;
double h = (double)rect.height() * d;
RenderSystem.enableScissor((int)e, (int)f, Math.max(0, (int)g), Math.max(0, (int)h));
} else {
RenderSystem.disableScissor();
}
}
public void draw() {
this.vertexConsumers.draw();
}
public void draw(Consumer<VertexConsumerProvider> drawer) {
drawer.accept(this.vertexConsumers);
this.vertexConsumers.draw();
}
static class ScissorStack {
private final Deque<ScreenRect> stack = new ArrayDeque<>();
public ScreenRect push(ScreenRect p_281812_) {
ScreenRect screenrectangle = this.stack.peekLast();
if (screenrectangle != null) {
ScreenRect screenrectangle1 = Objects.requireNonNullElse(p_281812_.intersection(screenrectangle), ScreenRect.empty());
this.stack.addLast(screenrectangle1);
return screenrectangle1;
} else {
this.stack.addLast(p_281812_);
return p_281812_;
}
}
@Nullable
public ScreenRect pop() {
if (this.stack.isEmpty()) {
throw new IllegalStateException("Scissor stack underflow");
} else {
this.stack.removeLast();
return this.stack.peekLast();
}
}
public boolean containsPoint(int p_329411_, int p_333404_) {
return this.stack.isEmpty() ? true : this.stack.peek().contains(p_329411_, p_333404_);
}
}
public void drawItem(ItemStack item, int x, int y) {
this.drawItem(SaturnClient.client.player, SaturnClient.client.world, item, x, y, 0);
}
public void drawItem(ItemStack stack, int x, int y, int seed) {
this.drawItem(SaturnClient.client.player, SaturnClient.client.world, stack, x, y, seed);
}
public void drawItem(ItemStack stack, int x, int y, int seed, int z) {
this.drawItem(SaturnClient.client.player, SaturnClient.client.world, stack, x, y, seed, z);
}
public void drawItemWithoutEntity(ItemStack stack, int x, int y) {
this.drawItemWithoutEntity(stack, x, y, 0);
}
public void drawItemWithoutEntity(ItemStack stack, int x, int y, int seed) {
this.drawItem((LivingEntity)null, SaturnClient.client.world, stack, x, y, seed);
}
public void drawItem(LivingEntity entity, ItemStack stack, int x, int y, int seed) {
this.drawItem(entity, entity.getWorld(), stack, x, y, seed);
}
private void drawItem(@Nullable LivingEntity entity, @Nullable World world, ItemStack stack, int x, int y, int seed) {
this.drawItem(entity, world, stack, x, y, seed, 0);
}
private void drawItem(@Nullable LivingEntity entity, @Nullable World world, ItemStack stack, int x, int y, int seed, int z) {
if (!stack.isEmpty()) {
SaturnClient.client.getItemModelManager().update(this.itemRenderState, stack, ModelTransformationMode.GUI, false, world, entity, seed);
this.matrices.push();
this.matrices.translate((float)(x + 8), (float)(y + 8), (float)(150 + (this.itemRenderState.hasDepth() ? z : 0)));
try {
this.matrices.scale(16.0F, -16.0F, 16.0F);
boolean bl = !this.itemRenderState.isSideLit();
if (bl) {
this.draw();
DiffuseLighting.disableGuiDepthLighting();
}
this.itemRenderState.render(this.matrices, this.vertexConsumers, 15728880, OverlayTexture.DEFAULT_UV);
this.draw();
if (bl) {
DiffuseLighting.enableGuiDepthLighting();
}
} catch (Throwable var11) {
CrashReport crashReport = CrashReport.create(var11, "Rendering item");
CrashReportSection crashReportSection = crashReport.addElement("Item being rendered");
crashReportSection.add("Item Type", () -> {
return String.valueOf(stack.getItem());
});
crashReportSection.add("Item Components", () -> {
return String.valueOf(stack.getComponents());
});
crashReportSection.add("Item Foil", () -> {
return String.valueOf(stack.hasGlint());
});
throw new CrashException(crashReport);
}
this.matrices.pop();
}
}
}
@@ -3,10 +3,11 @@ package org.saturnclient.ui2;
import java.util.ArrayList;
import java.util.List;
import org.saturnclient.saturnclient.config.ThemeManager;
import org.saturnclient.saturnclient.mixin.DrawContextAccessor;
import org.saturnclient.ui2.anim.Animation;
import org.saturnclient.ui2.components.ElementRenderer;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gl.PostEffectProcessor;
import net.minecraft.client.gui.CubeMapRenderer;
import net.minecraft.client.gui.DrawContext;
@@ -53,10 +54,10 @@ public abstract class SaturnScreen extends Screen {
@Override
protected void init() {
elements.clear();
width *= 2;
height *= 2;
ui(); // abstraction to render the saturn ui and also render extra stuff here
ThemeManager.load();
Animation.execute((Float progress) -> {
blurProgress = progress;
@@ -92,15 +93,7 @@ public abstract class SaturnScreen extends Screen {
renderScope.matrices.scale(0.5f, 0.5f, 0.5f);
for (Element element : elements) {
renderScope.matrices.push();
renderScope.setOpacity(element.opacity);
renderScope.matrices.translate(element.x, element.y, 0);
renderScope.matrices.scale(element.scale, element.scale, 1.0f);
element.render(renderScope, new RenderContext(mouseX, mouseY, element));
renderScope.matrices.pop();
renderScope.setRenderLayer(null);
}
ElementRenderer.render(elements, renderScope, mouseX, mouseY);
renderScope.matrices.pop();
}
@@ -109,20 +102,40 @@ public abstract class SaturnScreen extends Screen {
public boolean mouseClicked(double mouseX, double mouseY, int button) {
mouseX *= 2;
mouseY *= 2;
if (button == 0) {
for (Element element : new ArrayList<>(elements)) {
element.focused = false;
int adjustedMouseX = (int) mouseX - element.x;
int adjustedMouseY = (int) mouseY - element.y;
if (Utils.isHovering(adjustedMouseX, adjustedMouseY, element.width, element.height, element.scale)) {
element.focused = true;
element.click(adjustedMouseX, adjustedMouseY);
}
}
}
ElementRenderer.mouseClicked(elements, mouseX, mouseY, button);
return false;
}
@Override
public boolean mouseScrolled(
double mouseX,
double mouseY,
double horizontalAmount,
double verticalAmount) {
mouseX *= 2;
mouseY *= 2;
ElementRenderer.mouseScrolled(elements, mouseX, mouseY, horizontalAmount, verticalAmount);
return super.mouseScrolled(
mouseX,
mouseY,
horizontalAmount,
verticalAmount);
}
@Override
public void resize(MinecraftClient client, int width, int height) {
elements.clear();
super.resize(client, width, height);
}
@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
ElementRenderer.keyPressed(elements, keyCode, scanCode, modifiers);
return super.keyPressed(keyCode, scanCode, modifiers);
}
}
@@ -1,5 +1,7 @@
package org.saturnclient.ui2;
import org.lwjgl.glfw.GLFW;
public class Utils {
public static boolean isHovering(int mouseX, int mouseY, int elementWidth, int elementHeight, float elementScale) {
return mouseX >= 0 &&
@@ -7,4 +9,39 @@ public class Utils {
mouseY >= 0 &&
mouseY <= (elementHeight * elementScale);
}
public static char getCharFromKey(int keyCode, int modifiers) {
boolean shift = (modifiers & GLFW.GLFW_MOD_SHIFT) != 0;
// A-Z
if (keyCode >= GLFW.GLFW_KEY_A && keyCode <= GLFW.GLFW_KEY_Z) {
return (char) (shift
? 'A' + (keyCode - GLFW.GLFW_KEY_A)
: 'a' + (keyCode - GLFW.GLFW_KEY_A));
}
// 0-9
if (keyCode >= GLFW.GLFW_KEY_0 && keyCode <= GLFW.GLFW_KEY_9) {
return shift
? ")!@#$%^&*(".charAt(keyCode - GLFW.GLFW_KEY_0)
: (char) ('0' + (keyCode - GLFW.GLFW_KEY_0));
}
// Special characters
return switch (keyCode) {
case GLFW.GLFW_KEY_SPACE -> ' ';
case GLFW.GLFW_KEY_PERIOD -> shift ? '>' : '.';
case GLFW.GLFW_KEY_COMMA -> shift ? '<' : ',';
case GLFW.GLFW_KEY_MINUS -> shift ? '_' : '-';
case GLFW.GLFW_KEY_EQUAL -> shift ? '+' : '=';
case GLFW.GLFW_KEY_SEMICOLON -> shift ? ':' : ';';
case GLFW.GLFW_KEY_APOSTROPHE -> shift ? '"' : '\'';
case GLFW.GLFW_KEY_SLASH -> shift ? '?' : '/';
case GLFW.GLFW_KEY_BACKSLASH -> shift ? '|' : '\\';
case GLFW.GLFW_KEY_LEFT_BRACKET -> shift ? '{' : '[';
case GLFW.GLFW_KEY_RIGHT_BRACKET -> shift ? '}' : ']';
case GLFW.GLFW_KEY_GRAVE_ACCENT -> shift ? '~' : '`';
default -> '\0';
};
}
}
@@ -17,14 +17,10 @@ public abstract class Animation {
public static void execute(Consumer<Float> tick, int duration) {
new Thread(() -> {
long startTime = System.currentTimeMillis();
Function<Double, Double> curveFunction = Curve::easeInOutCubic;
float progress = 0.0f;
double incremental = (1000 - duration) / 10000.0;
System.out.println("Starting animation...");
for (int i = 0; i <= 100; i++) {
float newProgress = (float) (double) curveFunction.apply(i / 100.0);
@@ -46,8 +42,6 @@ public abstract class Animation {
}
}
}
System.out.println("Animation complete. " + (System.currentTimeMillis() - startTime) + "MS");
}).start();
}
}
@@ -0,0 +1,60 @@
package org.saturnclient.ui2.components;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.saturnclient.config.ThemeManager;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.util.Identifier;
public class CosmeticPreview extends Element {
private static ThemeManager theme = new ThemeManager("CosmeticPreview", "selected", "hovering");
private static Property<Integer> bgColor = theme.property("bg-color", new Property<Integer>(0xAA000000));
private static Property<Integer> fgColor = theme.property("fg-color", new Property<Integer>(0xFFFFFFFF));
private static Property<Integer> padding = theme.property("padding", new Property<Integer>(14));
private static Property<Integer> cornerRadius = theme.property("corner-radius", new Property<Integer>(10));
static {}
Identifier sprite;
private Runnable onClick;
private boolean isSelected;
public CosmeticPreview(boolean isSelected, Identifier sprite, Runnable onClick) {
this.sprite = sprite;
this.onClick = onClick;
this.isSelected = isSelected;
this.width = 50;
this.height = 111;
}
@Override
public void render(RenderScope renderScope, ElementContext ctx) {
if (ctx.isHovering()) {
theme.setState("hovering");
} else if (isSelected) {
theme.setState("selected");
}
renderScope.drawRoundedRectangle(0, 0, width, height, cornerRadius.value, bgColor.value);
renderScope.setRenderLayer(RenderLayer::getGuiTextured);
int texWidth = width - padding.value;
int texHeight = height - padding.value;
renderScope.drawTexture(sprite, padding.value / 2, padding.value / 2, 0, 0, texWidth, texHeight, fgColor.value);
theme.setState(null);
}
@Override
public void click(int mouseX, int mouseY) {
if (onClick != null) {
onClick.run();
}
}
}
@@ -0,0 +1,84 @@
package org.saturnclient.ui2.components;
import java.util.ArrayList;
import java.util.List;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.Utils;
import org.saturnclient.ui2.anim.Animation;
public class ElementRenderer {
public static void draw(List<Element> elements, Element element) {
synchronized (elements) {
elements.add(element);
}
if (element.animation != null) {
element.animation.init(element);
Animation.execute((Float progress) -> {
element.animation.tick(progress, element);
}, element.animation.duration);
}
}
public static void render(List<Element> elements, RenderScope renderScope, int mouseX, int mouseY) {
for (Element element : elements) {
renderScope.matrices.push();
renderScope.setOpacity(element.opacity);
renderScope.matrices.translate(element.x, element.y, 0);
renderScope.matrices.scale(element.scale, element.scale, 1.0f);
element.render(renderScope, new ElementContext(mouseX, mouseY, element));
renderScope.matrices.pop();
renderScope.setRenderLayer(null);
}
}
public static void mouseClicked(List<Element> elements, double mouseX, double mouseY, int button) {
if (button == 0) {
for (Element element : new ArrayList<>(elements)) {
element.focused = false;
int adjustedMouseX = (int) mouseX - element.x;
int adjustedMouseY = (int) mouseY - element.y;
if (element.opacity > 0 && Utils.isHovering(adjustedMouseX, adjustedMouseY, element.width, element.height, element.scale)) {
element.focused = true;
element.click((int) (adjustedMouseX * element.scale), (int) (adjustedMouseY * element.scale));
}
}
}
}
public static void mouseScrolled(
List<Element> elements,
double mouseX,
double mouseY,
double horizontalAmount,
double verticalAmount) {
for (Element element : new ArrayList<>(elements)) {
if (Utils.isHovering((int) mouseX - element.x, (int) mouseY - element.y, element.width, element.height, element.scale)) {
element.scroll(
(int) mouseX - element.x,
(int) mouseY - element.y,
horizontalAmount,
verticalAmount);
}
}
}
public static void keyPressed(List<Element> elements, int keyCode, int scanCode, int modifiers) {
for (Element element : new ArrayList<>(elements)) {
if (element.focused && element.opacity > 0) {
element.keyPressed(keyCode, scanCode, modifiers);
char typedChar = Utils.getCharFromKey(keyCode, modifiers);
if (typedChar != '\0') {
element.charTyped(typedChar);
}
}
}
}
}
@@ -0,0 +1,99 @@
package org.saturnclient.ui2.components;
import org.saturnclient.modules.Module;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.saturnclient.config.ThemeManager;
import org.saturnclient.ui2.resources.Fonts;
import org.saturnclient.ui2.resources.Textures;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.Utils;
import org.saturnclient.ui2.screens.ConfigEditor;
import net.minecraft.client.render.RenderLayer;
public class SaturnModule extends Element {
private static ThemeManager theme = new ThemeManager("Module", "enabled", "hovering");
private static Property<Integer> bgColor = theme.property("bg", new Property<>(0xFF1d202d));
private static Property<Integer> fgColor = theme.property("fg", new Property<>(0xFFA1A2B8));
private static Property<Integer> iconFg = theme.property("icon-fg", new Property<>(0xFFA1A2B8));
private static Property<Integer> iconBg = theme.property("icon-bg", new Property<>(0xFF2e3248));
private static Property<Integer> tagBg = theme.property("tag-bg", new Property<>(0xFF2e3248));
private static Property<Integer> iconRadius = theme.property("icon-radius", new Property<>(10));
private static Property<Integer> radius = theme.property("radius", new Property<>(10));
static {
theme.propertyStateDefault("enabled", "bg", 0xFF1d202d);
theme.propertyStateDefault("enabled", "icon-bg", 0xFF845eee);
theme.propertyStateDefault("hovering", "fg", 0xFF845eee);
}
private Module mod;
public SaturnModule(Module mod) {
this.mod = mod;
this.width = 160;
this.height = 50;
}
@Override
public void render(RenderScope renderScope, ElementContext ctx) {
int p = 10;
int s = 14;
boolean settingsHover = false;
renderScope.setRenderLayer(RenderLayer::getGuiTextured);
if (mod.isEnabled()) {
theme.setState("enabled");
}
if (ctx.isHovering(width - s - p - 5, height - s - p - 5, s + 10, s + 10)) {
settingsHover = true;
} else if (ctx.isHovering()) {
theme.applyState("hovering");
}
renderScope.drawRoundedRectangle(0, 0, width, height, radius.value, bgColor.value);
int h = height-(p * 2);
renderScope.drawRoundedRectangle(p, p, h, h, iconRadius.value, iconBg.value);
renderScope.drawTexture(mod.getIconTexture(), p + (p / 2), p + (p / 2), 0, 0, h - p, h - p, iconFg.value);
renderScope.drawText(0.6f, mod.getName(), p+h+4, p + 1, true, fgColor.value);
renderScope.drawText(0.35f, mod.getVersion(), width - p - (int) (Fonts.getWidth(mod.getVersion(), false) * 0.35f), p + 1, false, fgColor.value);
int xt = p + h + 4;
for (String tag : mod.getTags()) {
int xtb = (int) (Fonts.getWidth(tag, false) * 0.4f);
renderScope.drawRoundedRectangle(xt, p + (h/2), xtb + 6, 12, 5, tagBg.value);
renderScope.drawText(0.4f, tag, xt+2, p + (h/2) + 3, false, fgColor.value);
xt += xtb + 9;
}
if (settingsHover) {
theme.setState("hovering");
}
renderScope.drawTexture(Textures.SETTINGS, width - s - p, height - s - p, 0, 0, s, s, fgColor.value);
theme.setState(null);
}
@Override
public void click(int mouseX, int mouseY) {
int p = 10;
int s = 14;
if (Utils.isHovering(mouseX - (width - s - p - 5), mouseY - (height - s - p - 5), s + 10, s + 10, 1.0f)) {
SaturnClient.client.setScreen(new ConfigEditor(mod.getConfig()));
} else {
mod.setEnabled(!mod.isEnabled());
}
}
}
@@ -0,0 +1,143 @@
package org.saturnclient.ui2.components;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.saturnclient.config.ThemeManager;
import org.saturnclient.ui2.resources.Textures;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.Utils;
import org.saturnclient.ui2.screens.CloakMenu;
import org.saturnclient.ui2.screens.HatMenu;
import org.saturnclient.ui2.screens.ModMenu;
import org.saturnclient.ui2.screens.SaturnConfigEditor;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.util.Identifier;
public class Sidebar extends Element {
private static ThemeManager theme = new ThemeManager("SideBar", "hovering");
private static Property<Integer> bgColor = theme.property("bg-color", new Property<Integer>(0x90000000));
private static Property<Integer> iconFg = theme.property("icon-fg", new Property<Integer>(-1));
private static Property<Integer> iconBg = theme.property("icon-bg", new Property<Integer>(0x00000000));
private static Property<Integer> cornerRadius = theme.property("corner-radius", new Property<Integer>(10));
private static Property<Integer> iconRadius = theme.property("icon-radius", new Property<Integer>(10));
private static Property<Integer> padding = theme.property("padding", new Property<Integer>(10));
static {
theme.propertyStateDefault("hovering", "icon-bg", -7643914);
}
public static class SidebarComponent {
Runnable onClick;
boolean end;
Identifier sprite;
public SidebarComponent(Identifier sprite, Runnable onClick, boolean end) {
this.onClick = onClick;
this.end = end;
this.sprite = sprite;
}
}
Runnable onClose;
SidebarComponent[] components = {
new Sidebar.SidebarComponent(Textures.MODS_TAB, () -> {
SaturnClient.client.setScreen(new ModMenu());
}, false),
new Sidebar.SidebarComponent(Textures.SETTINGS, () -> {
SaturnClient.client.setScreen(new SaturnConfigEditor());
}, false),
new Sidebar.SidebarComponent(Textures.CLOAK, () -> {
SaturnClient.client.setScreen(new CloakMenu());
}, false),
new Sidebar.SidebarComponent(Textures.HAT, () -> {
SaturnClient.client.setScreen(new HatMenu());
}, false),
new Sidebar.SidebarComponent(Textures.CLOSE, () -> {
onClose.run();
}, true)
};
int active = 0;
public Sidebar(int active, Runnable onClose) {
this.width = 30;
this.height = 350;
this.active = active;
this.onClose = onClose;
}
@Override
public void render(RenderScope renderScope, ElementContext ctx) {
int topRow = 0;
int bottomRow = 0;
int sp = 30 - padding.value;
int s = 30 - (padding.value * 2);
int s2 = s + padding.value;
renderScope.setRenderLayer(RenderLayer::getGuiTextured);
renderScope.drawRoundedRectangle(0, 0, width, height, cornerRadius.value, bgColor.value);
int i = 0;
for (SidebarComponent component : components) {
if (component.end) {
int y = (height - (sp * bottomRow)) - (s * 2);
if (ctx.isHovering(0, y - (padding.value / 2), s2, s2) || active == i) {
theme.setState("hovering");
} else {
theme.setState(null);
}
renderScope.drawRoundedRectangle(padding.value / 2, y - (padding.value / 2), s + padding.value, s + padding.value, iconRadius.value, iconBg.value);
renderScope.drawTexture(component.sprite, padding.value, y, 0, 0, s, s, iconFg.value);
bottomRow += 1;
} else {
int y = padding.value + ((sp) * topRow);
if (ctx.isHovering(0, y - (padding.value / 2), s2, s2) || active == i) {
theme.setState("hovering");
} else {
theme.setState(null);
}
renderScope.drawRoundedRectangle(padding.value / 2, y - (padding.value / 2), s + padding.value, s + padding.value, iconRadius.value, iconBg.value);
renderScope.drawTexture(component.sprite, padding.value, y, 0, 0, s, s, iconFg.value);
topRow += 1;
}
i++;
}
}
@Override
public void click(int mouseX, int mouseY) {
int topRow = 0;
int bottomRow = 0;
int sp = 30 - padding.value;
int s = 30 - (padding.value * 2);
int s2 = s + padding.value;
for (SidebarComponent component : components) {
if (component.end) {
if (Utils.isHovering(mouseX, mouseY - (height - (sp * bottomRow) - (s * 2)), s2, s2, scale)) {
component.onClick.run();
break;
}
bottomRow += 1;
} else {
if (Utils.isHovering(mouseX, mouseY - (padding.value + ((sp) * topRow)), s2, s2, scale)) {
component.onClick.run();
break;
}
topRow += 1;
}
}
}
}
@@ -1,23 +1,31 @@
package org.saturnclient.ui.components;
package org.saturnclient.ui2.components;
import org.jetbrains.annotations.Nullable;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.saturnclient.ui.SaturnWidget;
import org.saturnclient.saturnclient.SaturnClient;
import net.minecraft.client.gui.DrawContext;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
import net.minecraft.client.render.DiffuseLighting;
import net.minecraft.client.render.entity.EntityRenderDispatcher;
import net.minecraft.entity.LivingEntity;
// If you think this code is bad, it's because it's written by Mojang
public class SkinPreview extends Element {
private boolean negativeAngle = false;
private float angle = 0.0f;
public class SkinPreview extends SaturnWidget {
public static void drawEntity(DrawContext context, int x1, int y1, int x2, int y2, int size, float f, float mouseX,
public SkinPreview(float angle, boolean negativeAngle) {
this.angle = angle;
this.negativeAngle = negativeAngle;
}
public static void drawEntity(RenderScope renderScope, int x1, int y1, int x2, int y2, int size, float f, float mouseX,
float mouseY, LivingEntity entity, float angle, boolean negativeAngle) {
float g = (float) (x1 + x2) / 2.0F;
float h = (float) (y1 + y2) / 2.0F;
context.enableScissor(0, 6, x2, y2);
renderScope.enableScissor(0, 6, x2, y2);
float i = (float) Math.atan((double) ((g - mouseX) / 40.0F));
float j = (float) Math.atan((double) ((h - mouseY) / 40.0F));
Quaternionf quaternionf = (new Quaternionf()).rotateZ(3.1415927F);
@@ -28,15 +36,15 @@ public class SkinPreview extends SaturnWidget {
float o = entity.headYaw;
entity.setYaw(angle);
entity.bodyYaw = angle;
entity.setPitch(-j * 20.0F);
entity.headYaw = negativeAngle ? -i * 40.0F : i * 40.0F;
entity.setPitch(-(j * 20.0F));
entity.headYaw = negativeAngle ? (i * 40.0F) + 180f : -(i * 40.0F);
entity.prevHeadYaw = entity.getHeadYaw();
entity.setCustomNameVisible(false);
float p = entity.getScale();
Vector3f vector3f = new Vector3f(0.0F, entity.getHeight() / 2.0F + f * p, 0.0F);
float q = (float) size / p;
drawEntity(context, g, h, q, vector3f, quaternionf, null, entity);
drawEntity(renderScope, g, h, q, vector3f, quaternionf, null, entity);
entity.setCustomNameVisible(true);
entity.bodyYaw = k;
@@ -44,36 +52,36 @@ public class SkinPreview extends SaturnWidget {
entity.setPitch(m);
entity.prevHeadYaw = n;
entity.headYaw = o;
context.disableScissor();
renderScope.disableScissor();
}
public static void drawEntity(DrawContext context, float x, float y, float size, Vector3f vector3f,
public static void drawEntity(RenderScope renderScope, float x, float y, float size, Vector3f vector3f,
Quaternionf quaternionf, @Nullable Quaternionf quaternionf2, LivingEntity entity) {
context.getMatrices().push();
context.getMatrices().translate((double) x, (double) y, 50.0);
context.getMatrices().scale(size, size, -size);
context.getMatrices().translate(vector3f.x, vector3f.y, vector3f.z);
context.getMatrices().multiply(quaternionf);
context.draw();
renderScope.matrices.push();
renderScope.matrices.translate((double) x, (double) y, 50.0);
renderScope.matrices.scale(size, size, -size);
renderScope.matrices.translate(vector3f.x, vector3f.y, vector3f.z);
renderScope.matrices.multiply(quaternionf);
renderScope.draw();
DiffuseLighting.method_34742();
EntityRenderDispatcher entityRenderDispatcher = SaturnClient.client.getEntityRenderDispatcher();
entityRenderDispatcher.setRenderShadows(false);
context.draw((vertexConsumers) -> {
entityRenderDispatcher.render(entity, 0.0, 0.0, 0.0, 1.0F, context.getMatrices(), vertexConsumers,
renderScope.draw((vertexConsumers) -> {
entityRenderDispatcher.render(entity, 0.0, 0.0, 0.0, 1.0F, renderScope.matrices, vertexConsumers,
15728880);
});
context.draw();
renderScope.draw();
entityRenderDispatcher.setRenderShadows(true);
context.getMatrices().pop();
renderScope.matrices.pop();
DiffuseLighting.enableGuiDepthLighting();
}
@Override
public void render(DrawContext context, boolean hovering, int mouseX, int mouseY) {
public void render(RenderScope renderScope, ElementContext ctx) {
LivingEntity entity = SaturnClient.client.player;
if (entity != null) {
drawEntity(context, 0, 0, 75, 78, 30, 0.0625F, mouseX, mouseY, entity, -30.0f, true);
drawEntity(renderScope, 0, 0, 75, 78, 30, 0.0625F, ctx.mouseX / scale, ctx.mouseY / scale, entity, angle, negativeAngle);
}
}
}
@@ -0,0 +1,246 @@
package org.saturnclient.ui2.components.dialog;
import java.awt.Color;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.saturnclient.mixin.DrawContextAccessor;
import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.SaturnScreen;
import net.minecraft.client.gui.DrawContext;
public class ColorDialog extends SaturnScreen {
private Property<Integer> prop;
private SaturnScreen parent;
private static final int PICKER_WIDTH = 200;
private static final int PICKER_HEIGHT = 200;
private static final int SLIDER_WIDTH = 200;
private static final int SLIDER_HEIGHT = 10;
private static final int HUE_SLIDER_HEIGHT = 10;
private float hue = 0.0f;
private int selectedX = 0;
private int selectedY = 0;
private float opacity = 1.0f;
private boolean dragging = false;
public ColorDialog(Property<Integer> prop , SaturnScreen parent) {
super("Color Dialog");
this.prop = prop;
this.parent = parent;
int alpha = (prop.value >> 24) & 0xFF;
if (alpha == 0) alpha = 255; // fallback if no alpha specified
this.opacity = alpha / 255.0f;
syncFromColor();
}
@Override
public void ui() {}
@Override
public void close() {
SaturnClient.client.setScreen(parent);
}
@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
super.render(context, mouseX, mouseY, delta);
RenderScope renderScope = new RenderScope(context.getMatrices(),
((DrawContextAccessor) context).getVertexConsumers());
renderScope.matrices.push();
renderScope.matrices.scale(0.5f, 0.5f, 0.5f);
int xStart = (width - PICKER_WIDTH) / 2;
int yStart = (height - PICKER_HEIGHT) / 2;
// Draw the HSV saturation/value square (with current hue)
for (int x = 0; x < PICKER_WIDTH; x++) {
for (int y = 0; y < PICKER_HEIGHT; y++) {
float saturation = x / (float) PICKER_WIDTH;
float value = 1.0f - y / (float) PICKER_HEIGHT;
int color = Color.HSBtoRGB(hue, saturation, value);
context.fill(xStart + x, yStart + y, xStart + x + 1, yStart + y + 1, 0xFF000000 | color);
}
}
int x = (xStart + selectedX) - 4;
int y = (yStart + selectedY) - 4;
context.fill(x, y, x+8, y+8, 0xFF000000 | prop.value);
context.drawBorder(x, y, 8, 8, 0xFFffffff);
renderSlider(context, mouseX, mouseY, delta);
renderHueSlider(context);
renderScope.matrices.pop();
}
public void renderSlider(DrawContext context, int mouseX, int mouseY, float delta) {
int xStart = (width - SLIDER_WIDTH) / 2;
int yStart = (height - SLIDER_HEIGHT - PICKER_HEIGHT) / 2 - 10;
// Draw slider background (left = transparent, right = white)
for (int x = 0; x < SLIDER_WIDTH; x++) {
float localOpacity = x / (float) SLIDER_WIDTH;
int alpha = (int)(localOpacity * 255) & 0xFF;
int color = (alpha << 24) | (prop.value & 0xFFFFFF);
context.fill(xStart + x, yStart, xStart + x + 1, yStart + SLIDER_HEIGHT, color);
}
// Draw current value as a marker (thin black line)
int knobX = xStart + (int)(opacity * SLIDER_WIDTH);
context.fill(knobX - 1, yStart - 2, knobX + 1, yStart + SLIDER_HEIGHT + 2, 0xFF000000);
// Draw opacity text
// context.drawText(textRenderer, String.format("Opacity: %.2f", opacity), xStart, yStart - 15, 0xFFFFFF, false);
}
private void renderHueSlider(DrawContext context) {
int xStart = (width - SLIDER_WIDTH) / 2;
int yStart = (height + PICKER_HEIGHT) / 2 + 10;
for (int x = 0; x < SLIDER_WIDTH; x++) {
float localHue = x / (float) SLIDER_WIDTH;
int color = Color.HSBtoRGB(localHue, 1.0f, 1.0f);
context.fill(xStart + x, yStart, xStart + x + 1, yStart + HUE_SLIDER_HEIGHT, 0xFF000000 | color);
}
int knobX = xStart + (int)(hue * SLIDER_WIDTH);
context.fill(knobX - 1, yStart - 2, knobX + 1, yStart + HUE_SLIDER_HEIGHT + 2, 0xFF000000);
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button) {
mouseX *= 2;
mouseY *= 2;
int xStart = (width - PICKER_WIDTH) / 2;
int yStart = (height - PICKER_HEIGHT) / 2;
int relX = (int) mouseX - xStart;
int relY = (int) mouseY - yStart;
if (relX >= 0 && relX < PICKER_WIDTH && relY >= 0 && relY < PICKER_HEIGHT) {
float saturation = relX / (float) PICKER_WIDTH;
float value = 1.0f - relY / (float) PICKER_HEIGHT;
prop.value = Color.HSBtoRGB(hue, saturation, value);
int alpha = (int)(opacity * 255) & 0xFF;
prop.value = (alpha << 24) | (prop.value & 0xFFFFFF);
selectedX = relX;
selectedY = relY;
return true;
} else if (isInSlider(mouseX, mouseY)) {
updateOpacity(mouseX);
dragging = true;
return true;
} else if (isInHueSlider(mouseX, mouseY)) {
updateHue(mouseX);
return true;
}
return super.mouseClicked(mouseX, mouseY, button);
}
@Override
public boolean mouseReleased(double mouseX, double mouseY, int button) {
dragging = false;
return super.mouseReleased(mouseX, mouseY, button);
}
@Override
public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
mouseX *= 2;
mouseY *= 2;
if (isInHueSlider(mouseX, mouseY)) {
updateHue(mouseX);
return true;
} else if (dragging) {
updateOpacity(mouseX);
return true;
} else {
int xStart = (width - PICKER_WIDTH) / 2;
int yStart = (height - PICKER_HEIGHT) / 2;
int relX = (int) mouseX - xStart;
int relY = (int) mouseY - yStart;
if (relX >= 0 && relX < PICKER_WIDTH && relY >= 0 && relY < PICKER_HEIGHT) {
float saturation = relX / (float) PICKER_WIDTH;
float value = 1.0f - relY / (float) PICKER_HEIGHT;
prop.value = Color.HSBtoRGB(hue, saturation, value);
int alpha = (int)(opacity * 255) & 0xFF;
prop.value = (alpha << 24) | (prop.value & 0xFFFFFF);
selectedX = relX;
selectedY = relY;
return true;
}
}
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
}
private boolean isInSlider(double mouseX, double mouseY) {
int xStart = (width - SLIDER_WIDTH) / 2;
int yStart = (height - SLIDER_HEIGHT - PICKER_HEIGHT) / 2 - 10;
return mouseX >= xStart && mouseX <= xStart + SLIDER_WIDTH &&
mouseY >= yStart && mouseY <= yStart + SLIDER_HEIGHT;
}
private boolean isInHueSlider(double mouseX, double mouseY) {
int xStart = (width - SLIDER_WIDTH) / 2;
int yStart = (height + PICKER_HEIGHT) / 2 + 10;
return mouseX >= xStart && mouseX <= xStart + SLIDER_WIDTH &&
mouseY >= yStart && mouseY <= yStart + HUE_SLIDER_HEIGHT;
}
private void updateOpacity(double mouseX) {
int xStart = (width - SLIDER_WIDTH) / 2;
float newOpacity = (float)((mouseX - xStart) / SLIDER_WIDTH);
opacity = Math.max(0.0f, Math.min(1.0f, newOpacity));
int alpha = (int)(opacity * 255) & 0xFF;
prop.value = (alpha << 24) | (prop.value & 0xFFFFFF);
}
private void updateHue(double mouseX) {
int xStart = (width - SLIDER_WIDTH) / 2;
float newHue = (float)((mouseX - xStart) / SLIDER_WIDTH);
hue = Math.max(0.0f, Math.min(1.0f, newHue));
float saturation = selectedX / (float) PICKER_WIDTH;
float value = 1.0f - selectedY / (float) PICKER_HEIGHT;
prop.value = Color.HSBtoRGB(hue, saturation, value);
int alpha = (int)(opacity * 255) & 0xFF;
prop.value = (alpha << 24) | (prop.value & 0xFFFFFF);
}
private void syncFromColor() {
int rgb = prop.value & 0xFFFFFF;
float[] hsb = Color.RGBtoHSB((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF, null);
this.hue = hsb[0];
float saturation = hsb[1];
float value = hsb[2];
this.selectedX = (int)(saturation * PICKER_WIDTH);
this.selectedY = (int)((1.0f - value) * PICKER_HEIGHT);
// Extract alpha and convert to opacity float
int alpha = (prop.value >> 24) & 0xFF;
if (alpha == 0) alpha = 255;
this.opacity = alpha / 255.0f;
}
}
@@ -0,0 +1,59 @@
package org.saturnclient.ui2.components.inputs;
import org.saturnclient.saturnclient.config.ConfigManager;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui2.resources.Fonts;
public class FloatInput extends Input {
public Property<Float> prop;
public FloatInput(Property<Float> prop) {
this.width = 120;
this.height = Fonts.getHeight();
this.prop = prop;
this.text = String.valueOf(prop.value);
}
@Override
public void charTyped(char chr) {
if ((Character.isDigit(chr) || chr == '.' || (chr == '-' && cursorPosition == 0)) && text.length() < 10) {
if (text.equals("0") && cursorPosition == 1) {
text = "" + chr;
} else {
text = text.substring(0, cursorPosition) +
chr +
text.substring(cursorPosition);
try {
prop.value = text.isEmpty() ? 0 : Float.parseFloat(text);
cursorPosition++;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@Override
public void backspace() {
try {
if (text.length() == 0) {
text = "0";
cursorPosition = 1;
}
prop.value = Float.parseFloat(text);
ConfigManager.save();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void checkReset() {
if (prop.isReset) {
this.text = String.valueOf(prop.value);
this.cursorPosition = 0;
prop.isReset = false;
}
}
}
@@ -0,0 +1,32 @@
package org.saturnclient.ui2.components.inputs;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.SaturnScreen;
import org.saturnclient.ui2.components.dialog.ColorDialog;
public class HexInput extends Element {
public Property<Integer> prop;
public SaturnScreen screen;
public HexInput(Property<Integer> prop, SaturnScreen screen) {
this.width = 58;
this.height = 20;
this.prop = prop;
this.scale = 0.8f;
this.screen = screen;
}
@Override
public void click(int mouseX, int mouseY) {
SaturnClient.client.setScreen(new ColorDialog(prop, screen));
}
@Override
public void render(RenderScope renderScope, ElementContext ctx) {
renderScope.drawRoundedRectangle(0, 0, width, height, 17, prop.value);
}
}
@@ -0,0 +1,110 @@
package org.saturnclient.ui2.components.inputs;
import org.lwjgl.glfw.GLFW;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.resources.Fonts;
public abstract class Input extends Element {
String text = "";
public int cursorPosition = 0;
public abstract void checkReset();
public abstract void backspace();
public boolean validateBackspace() {
return true;
}
@Override
public void keyPressed(int keyCode, int scanCode, int modifiers) {
if (keyCode == GLFW.GLFW_KEY_BACKSPACE) {
if (cursorPosition > 0 && validateBackspace()) {
text = text.substring(0, cursorPosition - 1) +
text.substring(cursorPosition);
cursorPosition--;
backspace();
}
} else if (keyCode == GLFW.GLFW_KEY_LEFT) {
if (cursorPosition > 0) {
cursorPosition--;
}
} else if (keyCode == GLFW.GLFW_KEY_RIGHT) {
if (cursorPosition < text.length()) {
cursorPosition++;
}
}
}
@Override
public void click(int mouseX, int mouseY) {
int scrollOffset = getScrollOffset();
String visibleText = text.substring(scrollOffset);
int newCursorPos = scrollOffset;
float textWidth = 0;
for (int i = 0; i < visibleText.length(); i++) {
textWidth = SaturnClient.client.textRenderer.getWidth(visibleText.substring(0, i + 1)) * 0.6f;
if (textWidth > mouseX) {
break;
}
newCursorPos++;
}
cursorPosition = newCursorPos;
}
@Override
public void render(RenderScope renderScope, ElementContext ctx) {
checkReset();
renderScope.drawRoundedRectangle(0, 0, width, height, 10, 0xFF000000);
int scrollOffset = getScrollOffset();
String visibleText = getVisibleText(scrollOffset);
int textColor = focused ? 0xFFFFFF : 0xAAAAAA;
renderScope.drawText(0.6f, visibleText, 4, 4, false, textColor);
if (focused) {
int cursorX = 4 +
(int) (SaturnClient.client.textRenderer.getWidth(
Fonts.setFont(visibleText.substring(0, cursorPosition - scrollOffset))) * 0.6f);
renderScope.drawRect(cursorX, 2, 1, height - 4, 0xFFFFFFFF);
}
}
protected int getScrollOffset() {
if (text.isEmpty()) {
return 0;
}
int offset = 0;
int maxWidth = width - 4; // Available width for text
while (offset < cursorPosition) { // Ensure cursor remains visible
String visibleText = text.substring(offset, cursorPosition);
if (SaturnClient.client.textRenderer.getWidth(Fonts.setFont(visibleText)) > maxWidth) {
offset++;
} else {
break;
}
}
return offset;
}
protected String getVisibleText(int scrollOffset) {
String visibleText = text.substring(scrollOffset);
// Ensure text does not overflow past the available width
for (int i = 1; i <= visibleText.length(); i++) {
if (SaturnClient.client.textRenderer.getWidth(
Fonts.setFont(visibleText.substring(0, i))) > width - 4) {
return visibleText.substring(0, i - 1); // Trim overflow
}
}
return visibleText;
}
}
@@ -0,0 +1,59 @@
package org.saturnclient.ui2.components.inputs;
import org.saturnclient.saturnclient.config.ConfigManager;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui2.resources.Fonts;
public class IntInput extends Input {
public Property<Integer> prop;
public IntInput(Property<Integer> prop) {
this.width = 120;
this.height = Fonts.getHeight();
this.prop = prop;
this.text = String.valueOf(prop.value);
}
@Override
public void charTyped(char chr) {
if ((Character.isDigit(chr) || chr == '.' || (chr == '-' && cursorPosition == 0)) && text.length() < 10) {
if (text.equals("0") && cursorPosition == 1) {
text = "" + chr;
} else {
text = text.substring(0, cursorPosition) +
chr +
text.substring(cursorPosition);
try {
prop.value = text.isEmpty() ? 0 : Integer.parseInt(text);
cursorPosition++;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@Override
public void backspace() {
try {
if (text.length() == 0) {
text = "0";
cursorPosition = 1;
}
prop.value = Integer.parseInt(text);
ConfigManager.save();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void checkReset() {
if (prop.isReset) {
this.text = String.valueOf(prop.value);
this.cursorPosition = 0;
prop.isReset = false;
}
}
}
@@ -0,0 +1,49 @@
package org.saturnclient.ui2.components.inputs;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.saturnclient.config.ThemeManager;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
public class Toggle extends Element {
private static ThemeManager theme = new ThemeManager("Toggle", "hovering", "enabled");
private static Property<Integer> bgColor = theme.property("bg-color", new Property<Integer>(0xFF808080));
private static Property<Integer> fgColor = theme.property("fg-color", new Property<Integer>(0xFF909090));
private static Property<Integer> cornerRadius = theme.property("corner-radius", new Property<Integer>(30));
static {
theme.propertyStateDefault("enabled", "bg-color", 0xaf8B5CF6);
theme.propertyStateDefault("enabled", "fg-color", 0xff8B5CF6);
}
private Property<Boolean> prop;
public Toggle(Property<Boolean> prop) {
this.prop = prop;
this.width = 60;
this.height = 30;
}
@Override
public void render(RenderScope renderScope, ElementContext ctx) {
if (prop.value) {
theme.setState("enabled");
}
if (ctx.isHovering()) {
theme.applyState("hovering");
}
renderScope.drawRoundedRectangle(0, 0, width, height, cornerRadius.value, bgColor.value);
renderScope.drawRoundedRectangle(prop.value ? 30 : 0, 0, 30, 30, 30, fgColor.value);
theme.setState(null);
}
@Override
public void click(int mouseX, int mouseY) {
prop.value = !prop.value;
}
}
@@ -3,12 +3,10 @@ package org.saturnclient.ui2.elements;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.saturnclient.config.ThemeManager;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.RenderContext;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.resources.Fonts;
import net.minecraft.util.Identifier;
public class Button extends Element {
private static ThemeManager theme = new ThemeManager("Button", "hovering");
private static Property<Integer> bgColor = theme.property("bg-color", new Property<Integer>(0xFF000000));
@@ -17,22 +15,20 @@ public class Button extends Element {
private static Property<Boolean> bold = theme.property("fg-bold", new Property<Boolean>(false));
static {
theme.propertyStateDefault("hovering", "fg-color", 0xFFFF0000);
theme.propertyStateDefault("hovering", "fg-color", 0xFF845eee);
}
private String text;
private Identifier font;
private Runnable onClick;
public Button(String text, Runnable onClick) {
this.text = text;
this.font = Fonts.getFont(bold.value);
this.onClick = onClick;
this.dimensions(Fonts.getWidth(text, font) + 50, Fonts.getHeight() + 20);
this.dimensions(Fonts.getWidth(text, bold.value) + 50, 38);
}
@Override
public void render(RenderScope renderScope, RenderContext ctx) {
public void render(RenderScope renderScope, ElementContext ctx) {
if (ctx.isHovering()) {
theme.setState("hovering");
} else {
@@ -40,7 +36,8 @@ public class Button extends Element {
}
renderScope.drawRoundedRectangle(0, 0, width, height, cornerRadius.value, bgColor.value);
renderScope.drawText(text, (width - Fonts.getWidth(text, font)) / 2, (height - Fonts.getHeight()) / 2, bold.value, fgColor.value);
// renderScope.drawText(text, (width - Fonts.getWidth(text, font)) / 2, (height - Fonts.getHeight()) / 2, bold.value, fgColor.value);
renderScope.drawText(text, Fonts.centerX(width, text, bold.value), Fonts.centerY(height), bold.value, fgColor.value);
}
@Override
@@ -3,7 +3,7 @@ package org.saturnclient.ui2.elements;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.saturnclient.config.ThemeManager;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.RenderContext;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
import net.minecraft.client.render.RenderLayer;
@@ -22,7 +22,7 @@ public class ClickableTexture extends Element {
}
@Override
public void render(RenderScope renderScope, RenderContext ctx) {
public void render(RenderScope renderScope, ElementContext ctx) {
if (ctx.isHovering()) {
theme.setState("hovering");
} else {
@@ -1,7 +1,7 @@
package org.saturnclient.ui2.elements;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.RenderContext;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
import net.minecraft.client.render.RenderLayer;
@@ -15,7 +15,7 @@ public class ImageTexture extends Element {
}
@Override
public void render(RenderScope renderScope, RenderContext ctx) {
public void render(RenderScope renderScope, ElementContext ctx) {
renderScope.setRenderLayer(RenderLayer::getGuiTextured);
renderScope.drawTexture(sprite, 0, 0, 0, 0, width, height);
}
@@ -0,0 +1,91 @@
package org.saturnclient.ui2.elements;
import java.util.ArrayList;
import java.util.List;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.saturnclient.config.ThemeManager;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
import org.saturnclient.ui2.components.ElementRenderer;
public class Scroll extends Element {
private static ThemeManager theme = new ThemeManager("Scroll");
private static Property<Integer> bgColor = theme.property("bg-color", new Property<Integer>(0x90000000));
private static Property<Integer> scrollBarColor = theme.property("scrollbar-color", new Property<Integer>(-7643914));
private static Property<Integer> scrollBarRadius = theme.property("scrollbar-radius", new Property<Integer>(10));
private static Property<Integer> scrollBarWidth = theme.property("scrollbar-width", new Property<Integer>(5));
private static Property<Integer> scrollBarPadding = theme.property("scrollbar-padding", new Property<Integer>(5));
private static Property<Integer> cornerRadius = theme.property("corner-radius", new Property<Integer>(10));
int padding = 0;
protected List<Element> children = new ArrayList<>();
int scroll = 0;
int maxScroll = 0;
public Scroll(int padding) {
this.padding = padding;
}
@Override
public void render(RenderScope renderScope, ElementContext ctx) {
renderScope.drawRoundedRectangle(0, 0, width, height, cornerRadius.value, bgColor.value);
renderScope.enableScissor(padding, padding, width - padding, height - padding);
renderScope.matrices.push();
renderScope.matrices.translate(padding, (-scroll) + padding, 0);
ElementRenderer.render(children, renderScope, ctx.mouseX - padding, ctx.mouseY - padding + scroll);
renderScope.matrices.pop();
renderScope.disableScissor();
renderScope.drawRoundedRectangle(width - scrollBarWidth.value - scrollBarPadding.value, calculateScrollBarY(), scrollBarWidth.value, calculateScrollBarHeight(), scrollBarRadius.value, scrollBarColor.value);
}
@Override
public void scroll(int mouseX, int mouseY, double horizontalAmount, double verticalAmount) {
scroll -= verticalAmount;
if (scroll < 0) {
scroll = 0;
} else if (scroll > maxScroll) {
scroll = maxScroll;
}
}
@Override
public void click(int mouseX, int mouseY) {
ElementRenderer.mouseClicked(children, mouseX - padding, mouseY - padding + scroll, 0);
}
public void draw(Element element) {
children.add(element);
if (element.width > width) {
width = element.width;
}
if (element.height > height) {
height = element.height;
}
maxScroll = Math.max(maxScroll, element.y - maxScroll);
}
int calculateScrollBarHeight() {
if (maxScroll <= 0) return height - (scrollBarPadding.value * 2); // No scrolling needed
return Math.max(20, (height * height) / (height + maxScroll)) - (scrollBarPadding.value * 2); // At least 20px tall
}
int calculateScrollBarY() {
int scrollBarHeight = calculateScrollBarHeight();
if (maxScroll <= 0) return scrollBarPadding.value;
return (scroll * (height - scrollBarHeight)) / maxScroll + scrollBarPadding.value;
}
@Override
public void keyPressed(int keyCode, int scanCode, int modifiers) {
ElementRenderer.keyPressed(children, keyCode, scanCode, modifiers);
}
}
@@ -3,7 +3,7 @@ package org.saturnclient.ui2.elements;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.saturnclient.config.ThemeManager;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.RenderContext;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
public class Text extends Element {
@@ -17,7 +17,7 @@ public class Text extends Element {
}
@Override
public void render(RenderScope renderScope, RenderContext ctx) {
renderScope.drawText(this.text, this.x, this.y, false, fgColor.value);
public void render(RenderScope renderScope, ElementContext ctx) {
renderScope.drawText(this.text, 0, 0, false, fgColor.value);
}
}
@@ -3,7 +3,7 @@ package org.saturnclient.ui2.elements;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.saturnclient.config.ThemeManager;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.RenderContext;
import org.saturnclient.ui2.ElementContext;
import org.saturnclient.ui2.RenderScope;
import net.minecraft.client.render.RenderLayer;
@@ -18,7 +18,7 @@ public class TextureButton extends Element {
static {
theme.propertyStateDefault("hovering", "fg-color", 0xFFFF0000);
theme.propertyStateDefault("hovering", "fg-color", 0xFF845eee);
}
Identifier sprite;
@@ -30,7 +30,7 @@ public class TextureButton extends Element {
}
@Override
public void render(RenderScope renderScope, RenderContext ctx) {
public void render(RenderScope renderScope, ElementContext ctx) {
if (ctx.isHovering()) {
theme.setState("hovering");
} else {
@@ -6,14 +6,14 @@ import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
public class Fonts {
public static final Identifier PANTON = Identifier.of("saturnclient", "panton");
public static final Identifier PANTON_BOLD = Identifier.of("saturnclient", "panton_bold");
public static final Identifier INTER = Identifier.of("saturnclient", "inter");
public static final Identifier INTER_BOLD = Identifier.of("saturnclient", "inter_bold");
public static Identifier getFont(boolean bold) {
if (bold) {
return PANTON_BOLD;
return INTER_BOLD;
} else {
return PANTON;
return INTER;
}
}
@@ -22,6 +22,16 @@ public class Fonts {
Style.EMPTY.withFont(font));
}
public static Text setFont(String text, boolean bold) {
return Text.literal(text).setStyle(
Style.EMPTY.withFont(bold ? INTER_BOLD : INTER));
}
public static Text setFont(String text) {
return Text.literal(text).setStyle(
Style.EMPTY.withFont(INTER));
}
// public static int getWidth(String text, Identifier font) {
// return SaturnClient.client.textRenderer.getWidth(Text.literal(text).setStyle(
// Style.EMPTY.withFont(font)));
@@ -31,12 +41,19 @@ public class Fonts {
// return SaturnClient.client.textRenderer.fontHeight;
// }
public static int getWidth(String text, Identifier font) {
return SaturnClient.client.textRenderer.getWidth(Text.literal(text).setStyle(
Style.EMPTY.withFont(font))) * 2;
public static int getWidth(String text, boolean bold) {
return SaturnClient.client.textRenderer.getWidth(setFont(text, getFont(bold)));
}
public static int getHeight() {
return SaturnClient.client.textRenderer.fontHeight * 2;
return 18;
}
public static int centerX(int w, String text, boolean bold) {
return (w - Fonts.getWidth(text, bold)) / 2;
}
public static int centerY(int h) {
return (h - 18) / 2;
}
}
@@ -4,4 +4,42 @@ import net.minecraft.util.Identifier;
public class Textures {
public static final Identifier CROSSHAIR_RANGE = Identifier.of("saturnclient", "textures/gui/hud/crosshair_range.png");
}
public static final Identifier COSMETICS = Identifier.of("saturnclient", "textures/gui/components/cosmetics.png");
public static final Identifier HUD_ICON = Identifier.of("saturnclient", "textures/gui/components/hud.png");
public static final Identifier SEARCH = Identifier.of("saturnclient", "textures/gui/components/search.png");
public static final Identifier CLOSE = Identifier.of("saturnclient", "textures/gui/components/close.png");
public static final Identifier MODS_TAB = Identifier.of("saturnclient", "textures/gui/components/mods_tab.png");
public static final Identifier SETTINGS = Identifier.of("saturnclient", "textures/gui/components/settings.png");
public static final Identifier CLOAK = Identifier.of("saturnclient", "textures/gui/components/cloak.png");
public static final Identifier HAT = Identifier.of("saturnclient", "textures/gui/components/hat.png");
public static final Identifier RESET = Identifier.of("saturnclient", "textures/gui/components/reset.png");
public static final Identifier TOGGLE_INDICATOR = Identifier.of("saturnclient",
"textures/gui/components/toggle_indicator.png");
public static final Identifier TOGGLE_BG = Identifier.of("saturnclient", "textures/gui/components/toggle_bg.png");
public static final Identifier LOGO = Identifier.of("saturnclient", "textures/logo/logo.png");
public static final Identifier REALISTIC_LOGO = Identifier.of("saturnclient", "textures/logo/realistic.png");
public static final Identifier LOGO_TEXT = Identifier.of("saturnclient", "textures/logo/text.png");
// Widgets
public static final Identifier BUTTON_BORDER = Identifier.of("saturnclient", "button_border");
public static final Identifier BUTTON = Identifier.of("saturnclient", "button");
public static final Identifier BUTTON_OP = Identifier.of("saturnclient", "button_op");
public static final Identifier SETTINGS_BG = Identifier.of("saturnclient", "settings_bg");
public static final Identifier RECT = Identifier.of("saturnclient", "rect");
public static final Identifier RECT_BORDER = Identifier.of("saturnclient", "rect_border");
public static final Identifier MOD = Identifier.of("saturnclient", "textures/gui/components/mod.png");
public static final Identifier MOD_BG = Identifier.of("saturnclient", "textures/gui/components/mod_bg.png");
public static Identifier getCloakPreview(String cloak) {
return Identifier.of("saturnclient", "textures/gui/cloak/" + (cloak.isEmpty() ? "none" : cloak) + ".png");
}
public static Identifier getHatPreview(String hat) {
return Identifier.of("saturnclient", "textures/gui/hat/" + (hat.isEmpty() ? "none" : hat) + ".png");
}
public static Identifier getModIcon(String modId) {
return Identifier.of("saturnclient", "textures/gui/mod/" + modId + ".png");
}
}
@@ -0,0 +1,53 @@
package org.saturnclient.ui2.screens;
import org.saturnclient.saturnclient.auth.Auth;
import org.saturnclient.saturnclient.auth.SaturnPlayer;
import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks;
import org.saturnclient.ui2.resources.Textures;
import org.saturnclient.ui2.SaturnScreen;
import org.saturnclient.ui2.components.CosmeticPreview;
import org.saturnclient.ui2.components.Sidebar;
import org.saturnclient.ui2.components.SkinPreview;
import org.saturnclient.ui2.elements.Scroll;
public class CloakMenu extends SaturnScreen {
public CloakMenu() {
super("Cloaks Menu");
}
@Override
public void ui() {
int p = 10;
int g = 10;
Scroll scroll = new Scroll(p);
int row = 0;
int col = 0;
SaturnPlayer player = Auth.players.get(Auth.uuid);
if (player != null) {
for (String cloak : Cloaks.availableCloaks) {
scroll.draw(new CosmeticPreview(cloak == player.cloak, Textures.getCloakPreview(cloak), () -> {
Cloaks.setCloak(Auth.uuid, cloak);
}).position((50 + g) * col, (111 + g) * row));
if (col == 5) {
col = 0;
row++;
} else {
col++;
}
}
}
int scrollWidth = 480 + 10 + (g * 2) + (p * 2);
draw(scroll.dimensions(scrollWidth, 350).center(width, height));
draw(new SkinPreview(-30.0f, false).scale(3.5f).position(scroll.x + (scrollWidth - 220), scroll.y+40));
draw(new Sidebar(2, this::close).centerOffset(width, height, -(scrollWidth / 2 + 20), 0));
}
}
@@ -0,0 +1,120 @@
package org.saturnclient.ui2.screens;
import java.util.Map;
import org.saturnclient.saturnclient.config.ConfigManager;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui2.SaturnScreen;
import org.saturnclient.ui2.components.Sidebar;
import org.saturnclient.ui2.components.inputs.FloatInput;
import org.saturnclient.ui2.components.inputs.HexInput;
import org.saturnclient.ui2.components.inputs.IntInput;
import org.saturnclient.ui2.components.inputs.Toggle;
import org.saturnclient.ui2.elements.Scroll;
import org.saturnclient.ui2.elements.Text;
import org.saturnclient.ui2.resources.Fonts;
public class ConfigEditor extends SaturnScreen {
private ConfigManager config;
public ConfigEditor(ConfigManager config) {
super("Config Editor");
this.config = config;
}
@Override
public void ui() {
int p = 10;
int g = 10;
Scroll scroll = new Scroll(p);
drawProperties(scroll, config.getProperties(), 0, 0, 480 + 10 + (g * 2));
int scrollWidth = 480 + 10 + (g * 2) + (p * 2);
draw(scroll.dimensions(scrollWidth, 350).center(width, height));
draw(new Sidebar(0, this::close).centerOffset(width, height, -(scrollWidth / 2 + 20), 0));
}
@SuppressWarnings("unchecked")
private int drawProperties(Scroll configScroll, Map<String, Property<?>> properties, int row, int col, int w) {
for (Map.Entry<String, Property<?>> propEntry : properties.entrySet()) {
Property<?> prop = propEntry.getValue();
String propName = propEntry.getKey();
boolean full = isFull(prop);
// Always reset to col 0 if full-width component needs to be drawn mid-row
if (full && col != 0) {
col = 0;
row++;
}
int modX = (w / 2) * col; // two-column layout
int modY = 25 * row;
if (prop.getType() == Property.PropertyType.NAMESPACE) {
configScroll.draw(
new Text(
propName
).position(Fonts.centerX(520, propName, false), modY + 1).scale(0.7f));
} else {
configScroll.draw(
new Text(
propName
).position(modX, modY + 1).scale(0.7f));
}
switch (prop.getType()) {
case BOOLEAN:
configScroll.draw(
new Toggle((Property<Boolean>) prop)
.position(modX + (w / 2) - 40, modY)
.scale(0.5f));
break;
case HEX:
configScroll.draw(new HexInput((Property<Integer>) prop, this).position(w / 2, modY));
break;
case INTEGER:
configScroll.draw(new IntInput((Property<Integer>) prop).position(w / 2, modY));
break;
case FLOAT:
configScroll.draw(new FloatInput((Property<Float>) prop).position(w / 2, modY));
break;
case NAMESPACE:
Map<String, Property<?>> nestedProperties = (Map<String, Property<?>>) prop.value;
row = drawProperties(configScroll, nestedProperties, row + 1, col, w);
break;
case STRING:
}
if (full) {
row++; // full-width takes a whole row
col = 0;
} else {
col++;
if (col > 1) { // max 2 columns
col = 0;
row++;
}
}
}
return row;
}
public static boolean isFull(Property<?> prop) {
switch (prop.getType()) {
case BOOLEAN:
return false;
default:
return true;
}
}
}
@@ -0,0 +1,53 @@
package org.saturnclient.ui2.screens;
import org.saturnclient.saturnclient.auth.Auth;
import org.saturnclient.saturnclient.auth.SaturnPlayer;
import org.saturnclient.saturnclient.cosmetics.Hats;
import org.saturnclient.ui2.resources.Textures;
import org.saturnclient.ui2.SaturnScreen;
import org.saturnclient.ui2.components.CosmeticPreview;
import org.saturnclient.ui2.components.Sidebar;
import org.saturnclient.ui2.components.SkinPreview;
import org.saturnclient.ui2.elements.Scroll;
public class HatMenu extends SaturnScreen {
public HatMenu() {
super("Hats Menu");
}
@Override
public void ui() {
int p = 10;
int g = 10;
Scroll scroll = new Scroll(p);
int row = 0;
int col = 0;
SaturnPlayer player = Auth.players.get(Auth.uuid);
if (player != null) {
for (String hat : Hats.availableHats) {
scroll.draw(new CosmeticPreview(hat == player.hat, Textures.getHatPreview(hat), () -> {
Hats.setHat(Auth.uuid, hat);
}).dimensions(50, 50).position((50 + g) * col, (50 + g) * row));
if (col == 5) {
col = 0;
row++;
} else {
col++;
}
}
}
int scrollWidth = 480 + 10 + (g * 2) + (p * 2);
draw(scroll.dimensions(scrollWidth, 350).center(width, height));
draw(new SkinPreview(170f, true).scale(3.5f).position(scroll.x + (scrollWidth - 220), scroll.y+40));
draw(new Sidebar(3, this::close).centerOffset(width, height, -(scrollWidth / 2 + 20), 0));
}
}
@@ -0,0 +1,42 @@
package org.saturnclient.ui2.screens;
import org.saturnclient.modules.ModManager;
import org.saturnclient.modules.Module;
import org.saturnclient.ui2.SaturnScreen;
import org.saturnclient.ui2.components.SaturnModule;
import org.saturnclient.ui2.components.Sidebar;
import org.saturnclient.ui2.elements.Scroll;
public class ModMenu extends SaturnScreen {
public ModMenu() {
super("Mod Menu");
}
@Override
public void ui() {
int p = 10;
int g = 10;
Scroll scroll = new Scroll(p);
int row = 0;
int col = 0;
for (Module mod : ModManager.MODS) {
scroll.draw(new SaturnModule(mod).position((160 + g) * col, (50 + g) * row));
if (col == 2) {
col = 0;
row++;
} else {
col++;
}
}
int scrollWidth = 480 + 10 + (g * 2) + (p * 2);
draw(scroll.dimensions(scrollWidth, 350).center(width, height));
draw(new Sidebar(0, this::close).centerOffset(width, height, -(scrollWidth / 2 + 20), 0));
}
}
@@ -0,0 +1,117 @@
package org.saturnclient.ui2.screens;
import java.util.Map;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.saturnclient.config.Property;
import org.saturnclient.ui2.SaturnScreen;
import org.saturnclient.ui2.components.Sidebar;
import org.saturnclient.ui2.components.inputs.FloatInput;
import org.saturnclient.ui2.components.inputs.HexInput;
import org.saturnclient.ui2.components.inputs.IntInput;
import org.saturnclient.ui2.components.inputs.Toggle;
import org.saturnclient.ui2.elements.Scroll;
import org.saturnclient.ui2.elements.Text;
import org.saturnclient.ui2.resources.Fonts;
public class SaturnConfigEditor extends SaturnScreen {
public SaturnConfigEditor() {
super("Saturn Config Editor");
}
@Override
public void ui() {
int p = 10;
int g = 10;
Scroll scroll = new Scroll(p);
drawProperties(scroll, SaturnClientConfig.config.getProperties(), 0, 0, 480 + 10 + (g * 2));
int scrollWidth = 480 + 10 + (g * 2) + (p * 2);
draw(scroll.dimensions(scrollWidth, 350).center(width, height));
draw(new Sidebar(1, this::close).centerOffset(width, height, -(scrollWidth / 2 + 20), 0));
}
@SuppressWarnings("unchecked")
private int drawProperties(Scroll configScroll, Map<String, Property<?>> properties, int row, int col, int w) {
for (Map.Entry<String, Property<?>> propEntry : properties.entrySet()) {
Property<?> prop = propEntry.getValue();
String propName = propEntry.getKey();
boolean full = isFull(prop);
// Always reset to col 0 if full-width component needs to be drawn mid-row
if (full && col != 0) {
col = 0;
row++;
}
int modX = (w / 2) * col; // two-column layout
int modY = 25 * row;
if (prop.getType() == Property.PropertyType.NAMESPACE) {
configScroll.draw(
new Text(
propName
).position(Fonts.centerX(520, propName, false), modY + 1).scale(0.7f));
} else {
configScroll.draw(
new Text(
propName
).position(modX, modY + 1).scale(0.7f));
}
switch (prop.getType()) {
case BOOLEAN:
configScroll.draw(
new Toggle((Property<Boolean>) prop)
.position(modX + (w / 2) - 40, modY)
.scale(0.5f));
break;
case HEX:
configScroll.draw(new HexInput((Property<Integer>) prop, this).position(w / 2, modY));
break;
case INTEGER:
configScroll.draw(new IntInput((Property<Integer>) prop).position(w / 2, modY));
break;
case FLOAT:
configScroll.draw(new FloatInput((Property<Float>) prop).position(w / 2, modY));
break;
case NAMESPACE:
Map<String, Property<?>> nestedProperties = (Map<String, Property<?>>) prop.value;
row = drawProperties(configScroll, nestedProperties, row + 1, col, w);
break;
case STRING:
}
if (full) {
row++; // full-width takes a whole row
col = 0;
} else {
col++;
if (col > 1) { // max 2 columns
col = 0;
row++;
}
}
}
return row;
}
public static boolean isFull(Property<?> prop) {
switch (prop.getType()) {
case BOOLEAN:
return false;
default:
return true;
}
}
}
@@ -2,10 +2,8 @@ package org.saturnclient.ui2.screens;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.saturnclient.menus.CloaksMenu;
import org.saturnclient.saturnclient.menus.HudEditor;
import org.saturnclient.saturnclient.menus.ModMenu;
import org.saturnclient.ui.Textures;
import org.saturnclient.ui2.resources.Textures;
import org.saturnclient.ui2.Element;
import org.saturnclient.ui2.SaturnScreen;
import org.saturnclient.ui2.elements.Button;
@@ -21,17 +19,17 @@ public class ShiftMenu extends SaturnScreen {
@Override
public void ui() {
draw(new ImageTexture(Textures.LOGO_TEXT).dimensions(98, 16).centerOffset(width, height, 0, -36).animation(new Fade(700)));
draw(new ImageTexture(SaturnClientConfig.getLogo()).dimensions(98, 98).centerOffset(width, height, 0, -80).animation(new SlideY(700, -40)));
draw(new ImageTexture(Textures.LOGO_TEXT).dimensions(98, 10).centerOffset(width, height, 0, -36).animation(new Fade(700)));
draw(new ImageTexture(SaturnClientConfig.getLogo()).dimensions(98, 98).centerOffset(width, height, 0, -80).animation(new SlideY(700, -20)));
Element button = new Button("Settings", () -> {
SaturnClient.client.setScreen(new ModMenu());
}).center(width, height);
}).center(width, height);
draw(button);
draw(new TextureButton(Textures.COSMETICS, () -> {
client.setScreen(new CloaksMenu());
client.setScreen(new CloakMenu());
}).dimensions(button.height, button.height).centerOffset(width, height, (button.width / 2) + (button.height / 2) + 4, 0));
draw(new TextureButton(Textures.HUD_ICON, () -> {
@@ -2,10 +2,8 @@ package org.saturnclient.ui2.screens;
import org.saturnclient.saturnclient.SaturnClient;
import org.saturnclient.saturnclient.SaturnClientConfig;
import org.saturnclient.saturnclient.menus.CloaksMenu;
import org.saturnclient.saturnclient.menus.HudEditor;
import org.saturnclient.saturnclient.menus.ModMenu;
import org.saturnclient.ui.Textures;
import org.saturnclient.ui2.resources.Textures;
import org.saturnclient.ui2.SaturnScreen;
import org.saturnclient.ui2.anim.Fade;
import org.saturnclient.ui2.anim.SlideY;
@@ -27,8 +25,8 @@ public class TitleMenu extends SaturnScreen {
public void ui() {
backgroundBlur = 0;
draw(new ImageTexture(Textures.LOGO_TEXT).dimensions(98, 16).centerOffset(width, height, 0, -40).animation(new Fade(700)));
draw(new ImageTexture(SaturnClientConfig.getLogo()).dimensions(98, 98).centerOffset(width, height, 0, -82).animation(new SlideY(700, -40)));
draw(new ImageTexture(Textures.LOGO_TEXT).dimensions(98, 10).centerOffset(width, height, 0, -36).animation(new Fade(700)));
draw(new ImageTexture(SaturnClientConfig.getLogo()).dimensions(98, 98).centerOffset(width, height, 0, -82).animation(new SlideY(700, -20)));
draw(new Button("SINGLEPLAYER", () -> {
client.setScreen(new SelectWorldScreen(new TitleMenu()));
@@ -57,7 +55,7 @@ public class TitleMenu extends SaturnScreen {
}).dimensions(s, s).centerHorizontal(width, height, 0, 8).animation(new SlideY(700, s + 8)));
draw(new TextureButton(Textures.CLOAK, () -> {
client.setScreen(new CloaksMenu());
client.setScreen(new CloakMenu());
}).dimensions(s, s).centerHorizontal(width, height, s + 2, 8).animation(new SlideY(700, s + 8)));
}
}
@@ -2,11 +2,11 @@
"providers": [
{
"type": "reference",
"id": "saturnclient:panton"
"id": "saturnclient:inter"
},
{
"type": "reference",
"id": "saturnclient:panton_bold"
"id": "saturnclient:inter_bold"
}
]
}
@@ -1,3 +1 @@
This font was designed by Ivan Petrov and published by Fontfabric.
The panton font is the regular version of: https://www.dafont.com/panton.font
Here is the font download: https://fonts.google.com/specimen/Inter
@@ -2,10 +2,10 @@
"providers": [
{
"type": "ttf",
"file": "saturnclient:panton.ttf",
"file": "saturnclient:inter.ttf",
"shift": [0, 0],
"size": 9,
"oversample": 5.0,
"size": 18,
"oversample": 12.0,
"skip_missing": true
}
]
@@ -2,10 +2,10 @@
"providers": [
{
"type": "ttf",
"file": "saturnclient:panton_bold.ttf",
"file": "saturnclient:inter_bold.ttf",
"shift": [0, 0],
"size": 9,
"oversample": 5.0,
"size": 18,
"oversample": 8.0,
"skip_missing": true
}
]
@@ -1,13 +1,13 @@
{
"parent": "special-model-loader:builtin/obj",
"model": "saturnclient:models/item/horns/horns.obj",
"mtl_override": "saturnclient:models/item/black.mtl",
"flip_v": true,
"display": {
"thirdperson_righthand": {
"rotation": [0, 0, 0],
"translation": [-5.08, 8.3, -0.1],
"scale": [0.065, 0.065, 0.065]
}
}
}
{
"parent": "special-model-loader:builtin/obj",
"model": "saturnclient:models/item/horns/horns.obj",
"mtl_override": "saturnclient:models/item/black.mtl",
"flip_v": true,
"display": {
"thirdperson_righthand": {
"rotation": [0, 0, 0],
"translation": [2, 6, 2],
"scale": [0.25, 0.25, 0.25]
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,13 +1,13 @@
{
"parent": "special-model-loader:builtin/obj",
"model": "saturnclient:models/item/horns/horns.obj",
"mtl_override": "saturnclient:models/item/white.mtl",
"flip_v": true,
"display": {
"thirdperson_righthand": {
"rotation": [0, 0, 0],
"translation": [-5.08, 8.3, -0.1],
"scale": [0.065, 0.065, 0.065]
}
}
}
{
"parent": "special-model-loader:builtin/obj",
"model": "saturnclient:models/item/horns/horns.obj",
"mtl_override": "saturnclient:models/item/white.mtl",
"flip_v": true,
"display": {
"thirdperson_righthand": {
"rotation": [0, 0, 0],
"translation": [2, 6, 2],
"scale": [0.25, 0.25, 0.25]
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

+2 -1
View File
@@ -9,7 +9,8 @@
"PlayerEntityRendererMixin",
"WhoAmI",
"SaturnReload",
"DrawContextAccessor"
"DrawContextAccessor",
"TitleScreenMixin"
],
"injectors": {
"defaultRequire": 1