diff --git a/build.gradle b/build.gradle index d99ed5d..0d0efed 100644 --- a/build.gradle +++ b/build.gradle @@ -1,44 +1,126 @@ +/* + * ================================================================ + * Saturn Client - Fabric Mod Build Configuration + * ================================================================ + * + * This build file configures: + * - Fabric Loom (Minecraft mod development) + * - Dependency management + * - Resource processing + * - Java toolchain (Java 21) + * - Publishing setup + * + * All version values are defined in gradle.properties. + * ================================================================ + */ + plugins { + // Fabric mod development plugin id 'fabric-loom' version '1.9-SNAPSHOT' + + // Maven publishing support id 'maven-publish' } +/* + * ================================================================ + * Project Metadata + * ================================================================ + */ + version = project.mod_version -group = project.maven_group +group = project.maven_group -repositories {} +/* + * ================================================================ + * Repositories + * ================================================================ + * All dependency sources. + */ +repositories { + // Fabric + maven { url 'https://maven.fabricmc.net/' } + // JitPack (GitHub releases) + maven { url 'https://jitpack.io' } + + // Parchment mappings (if needed later) + maven { url 'https://maven.parchmentmc.org' } + + // Special Model Loader + maven { name = "FelNull Maven"; url = "https://maven.felnull.dev" } + + // Player Animation Library + maven { name = "KosmX Maven"; url = 'https://maven.kosmx.dev/' } + + // Central repository + mavenCentral() +} + +/* + * ================================================================ + * Dependencies + * ================================================================ + */ dependencies { + + // ───────────────────────────────────────────── + // Minecraft Core + // ───────────────────────────────────────────── minecraft "com.mojang:minecraft:${project.minecraft_version}" - - // Switch back to Yarn + + // Yarn mappings (named mappings for dev environment) mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" - + + // Fabric Loader modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + + // Fabric API modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + + // ───────────────────────────────────────────── + // Rendering / Model Libraries + // ───────────────────────────────────────────── + + // Special Model Loader (included inside your mod jar) modApi "dev.felnull:special-model-loader:1.4.0+pre.1" include "dev.felnull:special-model-loader:1.4.0+pre.1" - include modImplementation("dev.kosmx.player-anim:player-animation-lib-fabric:${project.player_anim}") - //You might want bendy-lib. playerAnimator will wrap it. - // include modRuntimeOnly("io.github.kosmx.bendy-lib:bendy-lib-fabric:${project.bendylib_version}") + // SVG Rendering Library + implementation "com.formdev:svgSalamander:1.1.4" + + + // ───────────────────────────────────────────── + // Animation + // ───────────────────────────────────────────── + + // Player Animation Library (bundled into your mod) + include modImplementation( + "dev.kosmx.player-anim:player-animation-lib-fabric:${project.player_anim}" + ) + + // Optional: BendyLib (only if you directly use it) + // include modRuntimeOnly( + // "io.github.kosmx.bendy-lib:bendy-lib-fabric:${project.bendylib_version}" + // ) + + + // ───────────────────────────────────────────── + // External Libraries + // ───────────────────────────────────────────── + + // Session Java (auth/session handling) + implementation "com.github.selimaj-dev:session-java:0.1.6" } -repositories { - maven { url "https://maven.parchmentmc.org" } - maven { - name = "FelNull Maven" - url = "https://maven.felnull.dev" - } - - maven { - name "KosmX's maven" - url 'https://maven.kosmx.dev/' - } -} - +/* + * ================================================================ + * Resource Processing + * ================================================================ + * Injects version values into fabric.mod.json. + */ processResources { inputs.property "version", project.version inputs.property "minecraft_version", project.minecraft_version @@ -46,38 +128,58 @@ processResources { filteringCharset "UTF-8" filesMatching("fabric.mod.json") { - expand "version": project.version, + expand( + "version": project.version, "minecraft_version": project.minecraft_version, "loader_version": project.loader_version + ) } } + +/* + * ================================================================ + * Java Configuration + * ================================================================ + * Targeting Java 21. + */ def targetJavaVersion = 21 + tasks.withType(JavaCompile).configureEach { - it.options.encoding = "UTF-8" - if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) { - it.options.release.set(targetJavaVersion) - } + options.encoding = "UTF-8" + options.release.set(targetJavaVersion) } java { - def javaVersion = JavaVersion.toVersion(targetJavaVersion) - if (JavaVersion.current() < javaVersion) { - toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion) - } + toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion) + archivesBaseName = project.archives_base_name withSourcesJar() } + +/* + * ================================================================ + * Jar Packaging + * ================================================================ + * Includes LICENSE and NOTICE inside the final jar. + */ jar { from("LICENSE") { - rename { "${it}_${project.archivesBaseName}"} + rename { "${it}_${project.archivesBaseName}" } } from("NOTICE") { - rename { "${it}_${project.archivesBaseName}"} + rename { "${it}_${project.archivesBaseName}" } } } + +/* + * ================================================================ + * Publishing + * ================================================================ + * Configured but no remote repository defined yet. + */ publishing { publications { mavenJava(MavenPublication) { @@ -85,5 +187,7 @@ publishing { } } - repositories {} + repositories { + // Add publishing repository here when needed + } } \ No newline at end of file diff --git a/src/main/java/org/saturnclient/modules/ModDimensions.java b/src/main/java/org/saturnclient/modules/ModDimensions.java index b0bdb4f..c09b096 100644 --- a/src/main/java/org/saturnclient/modules/ModDimensions.java +++ b/src/main/java/org/saturnclient/modules/ModDimensions.java @@ -2,7 +2,7 @@ package org.saturnclient.modules; import java.util.Map; -import org.saturnclient.saturnclient.config.NamedProperty; +import org.saturnclient.saturnclient.config.Property.NamedProperty; import org.saturnclient.saturnclient.config.Property; public class ModDimensions { @@ -20,17 +20,17 @@ public class ModDimensions { public NamedProperty>> prop() { return Property.namespace(Map.of( - "X", x, - "Y", y, - "Scale", scale, - "Background Color", bgColor, - "Foreground Color", fgColor, - "Corner Radius", radius, - "Font", font - )).named("In-Game Display"); + "X", x, + "Y", y, + "Scale", scale, + "Background Color", bgColor, + "Foreground Color", fgColor, + "Corner Radius", radius, + "Font", font)).named("In-Game Display"); } - public ModDimensions() {} + public ModDimensions() { + } public ModDimensions(int width, int height) { this.width = width; diff --git a/src/main/java/org/saturnclient/modules/Module.java b/src/main/java/org/saturnclient/modules/Module.java index 87527e4..bedc306 100644 --- a/src/main/java/org/saturnclient/modules/Module.java +++ b/src/main/java/org/saturnclient/modules/Module.java @@ -1,9 +1,9 @@ package org.saturnclient.modules; import org.saturnclient.saturnclient.config.ConfigManager; -import org.saturnclient.saturnclient.config.NamedProperty; import org.saturnclient.ui2.resources.Textures; import org.saturnclient.ui2.RenderScope; +import org.saturnclient.saturnclient.config.Property.NamedProperty; import net.minecraft.util.Identifier; @@ -19,8 +19,11 @@ public abstract class Module { } } - public void render(RenderScope scope) {} - public void tick() {} + public void render(RenderScope scope) { + } + + public void tick() { + } public abstract boolean isEnabled(); @@ -34,7 +37,7 @@ public abstract class Module { public final String getName() { return details.name; } - + public Identifier getIconTexture() { return Textures.getModIcon(details.namespace); } @@ -46,11 +49,11 @@ public abstract class Module { public String getDescription() { return details.description; } - + public String[] getTags() { return details.tags; } - + public String getVersion() { return details.version; } diff --git a/src/main/java/org/saturnclient/modules/mods/Keystrokes.java b/src/main/java/org/saturnclient/modules/mods/Keystrokes.java index 5cdef8f..7b356ea 100644 --- a/src/main/java/org/saturnclient/modules/mods/Keystrokes.java +++ b/src/main/java/org/saturnclient/modules/mods/Keystrokes.java @@ -9,46 +9,45 @@ import org.saturnclient.ui2.RenderScope; import org.saturnclient.modules.ModuleDetails; public class Keystrokes extends Module implements HudMod { - public static Property enabled = Property.bool(false); - public static Property showMouse = Property.bool(true); - public static Property showSpace = Property.bool(false); - public static ModDimensions dimensions = new ModDimensions(78, 46); - // Cache key states to avoid repeated calls - private boolean w = false; - private boolean a = false; - private boolean s = false; - private boolean d = false; - private boolean lmb = false; - private boolean rmb = false; - private boolean space = false; + private static final Property enabled = Property.bool(false); + private static final Property showMouse = Property.bool(true); + private static final Property showSpace = Property.bool(false); - // Cache dimensions to avoid recalculation - private int cachedHeight = 54; - private boolean dimensionsDirty = true; + private static final Property clickBg = Property.color(0xFFCCCCCC); + private static final Property clickFg = Property.color(0xFFFFFFFF); - private static Property clickBg = Property.color(0xFFCCCCCC); - private static Property clickFg = Property.color(0xFFFFFFFF); + private static final ModDimensions dimensions = new ModDimensions(78, 54); + + // Key states + private boolean w, a, s, d, lmb, rmb, space; + + // Layout constants + private static final int KEY_SIZE = 24; + private static final int KEY_SPACING = 3; + private static final int MOUSE_WIDTH = 38; + private static final int MOUSE_HEIGHT = 24; + private static final int SPACE_HEIGHT = 19; public Keystrokes() { super(new ModuleDetails("Keystrokes", "keystrokes") - .description("Displays the keystrokes for movement") - .version("v0.1.0") + .description("Displays movement keystrokes") + .version("v0.2.0") .tags("Utility"), enabled.named("Enabled"), showMouse.named("Show mouse clicks"), - showSpace.named("Show space clicks"), + showSpace.named("Show space"), dimensions.prop(), clickFg.named("Clicked fg"), - clickBg.named("Clicked bg")); + clickBg.named("Clicked bg") + ); dimensions.renderBackground = false; } @Override public void tick() { - // Cache key states to reduce method calls w = SaturnClient.client.options.forwardKey.isPressed(); a = SaturnClient.client.options.leftKey.isPressed(); s = SaturnClient.client.options.backKey.isPressed(); @@ -57,103 +56,84 @@ public class Keystrokes extends Module implements HudMod { rmb = SaturnClient.client.options.useKey.isPressed(); space = SaturnClient.client.options.jumpKey.isPressed(); - // Mark dimensions as dirty if mouse or space visibility changed - if (dimensionsDirty) { - updateDimensions(); - dimensionsDirty = false; - } + updateHeight(); } - private void updateDimensions() { - cachedHeight = 54; // base height with padding considered + private void updateHeight() { + int height = KEY_SIZE * 2 + KEY_SPACING; - if (showMouse.value) { - cachedHeight += 27; - } + if (showSpace.value) + height += SPACE_HEIGHT + KEY_SPACING; - if (showSpace.value) { - cachedHeight += 22; - } + if (showMouse.value) + height += MOUSE_HEIGHT + KEY_SPACING; - dimensions.height = cachedHeight; + dimensions.height = height; } @Override public void renderDummy(RenderScope scope) { - // Use cached dimensions - dimensions.height = cachedHeight; - - // WASD keys (3px padding between each key) - renderKey(scope, false, 'W', 27, 0); // Top center - renderKey(scope, false, 'A', 0, 27); // Bottom left - renderKey(scope, false, 'S', 27, 27); // Bottom center - renderKey(scope, false, 'D', 54, 27); // Bottom right - - if (showMouse.value) { - renderKeyM(scope, false, "LMB", 0, 54); // Below A/S/D - renderKeyM(scope, false, "RMB", 40, 54); // With 3px between - } - - if (showSpace.value) { - renderKeySpace(scope, false, 0, cachedHeight - (showSpace.value ? 22 : 0)); - } + render(scope, false); } @Override public void renderHud(RenderScope scope) { - // Use cached dimensions - dimensions.height = cachedHeight; + render(scope, true); + } - // WASD keys (3px padding between each key) - renderKey(scope, w, 'W', 27, 0); // Top center - renderKey(scope, a, 'A', 0, 27); // Bottom left - renderKey(scope, s, 'S', 27, 27); // Bottom center - renderKey(scope, d, 'D', 54, 27); // Bottom right + private void render(RenderScope scope, boolean live) { - if (showMouse.value) { - renderKeyM(scope, lmb, "LMB", 0, 54); // Below A/S/D - renderKeyM(scope, rmb, "RMB", 40, 54); // With 3px between - } + int yOffset = 0; + // --- W --- + renderKey(scope, live && w, 'W', KEY_SIZE + KEY_SPACING, yOffset); + + // --- A S D --- + yOffset += KEY_SIZE + KEY_SPACING; + + renderKey(scope, live && a, 'A', 0, yOffset); + renderKey(scope, live && s, 'S', KEY_SIZE + KEY_SPACING, yOffset); + renderKey(scope, live && d, 'D', (KEY_SIZE + KEY_SPACING) * 2, yOffset); + + yOffset += KEY_SIZE + KEY_SPACING; + + // --- SPACE --- if (showSpace.value) { - renderKeySpace(scope, space, 0, cachedHeight - (showSpace.value ? 22 : 0)); + renderKeySpace(scope, live && space, 0, yOffset); + yOffset += SPACE_HEIGHT + KEY_SPACING; + } + + // --- MOUSE --- + if (showMouse.value) { + renderKeyMouse(scope, live && lmb, "LMB", 0, yOffset); + renderKeyMouse(scope, live && rmb, "RMB", MOUSE_WIDTH + KEY_SPACING, yOffset); } } - // Consistent 3px padding applied below: + private void renderKey(RenderScope scope, boolean pressed, char c, int x, int y) { + int bg = pressed ? clickBg.value : dimensions.bgColor.value; + int fg = pressed ? clickFg.value : dimensions.fgColor.value; - private void renderKeySpace(RenderScope scope, boolean isPressed, int x, int y) { - int height = 19; - int bgColor = isPressed ? clickBg.value : dimensions.bgColor.value; - int fgColor = isPressed ? clickFg.value : dimensions.fgColor.value; - - scope.drawRoundedRectangle(x, y, dimensions.width, height, dimensions.radius.value, bgColor); - - // A 30-pixel line centered vertically with 3px top padding - int lineY = y + (height - 1) / 2; - scope.drawRect(x + (dimensions.width - 30) / 2, lineY, 30, 1, fgColor); + scope.drawRoundedRectangle(x, y, KEY_SIZE, KEY_SIZE, dimensions.radius.value, bg); + scope.drawText(0.6f, String.valueOf(c), x + 9, y + 7, dimensions.font.value, fg); } - private void renderKeyM(RenderScope scope, boolean isPressed, String c, int x, int y) { - int width = 38, height = 24; - int bgColor = isPressed ? clickBg.value : dimensions.bgColor.value; - int fgColor = isPressed ? clickFg.value : dimensions.fgColor.value; + private void renderKeyMouse(RenderScope scope, boolean pressed, String text, int x, int y) { + int bg = pressed ? clickBg.value : dimensions.bgColor.value; + int fg = pressed ? clickFg.value : dimensions.fgColor.value; - scope.drawRoundedRectangle(x, y, width, height, dimensions.radius.value, bgColor); - - // Apply padding: 3px top and left -> add slight offset to x/y - scope.drawText(0.6f, c, x + 9, y + 7, dimensions.font.value, fgColor); + scope.drawRoundedRectangle(x, y, MOUSE_WIDTH, MOUSE_HEIGHT, dimensions.radius.value, bg); + scope.drawText(0.6f, text, x + 9, y + 7, dimensions.font.value, fg); } - private void renderKey(RenderScope scope, boolean isPressed, char c, int x, int y) { - int size = 24; - int bgColor = isPressed ? clickBg.value : dimensions.bgColor.value; - int fgColor = isPressed ? clickFg.value : dimensions.fgColor.value; + private void renderKeySpace(RenderScope scope, boolean pressed, int x, int y) { + int bg = pressed ? clickBg.value : dimensions.bgColor.value; + int fg = pressed ? clickFg.value : dimensions.fgColor.value; - scope.drawRoundedRectangle(x, y, size, size, dimensions.radius.value, bgColor); + scope.drawRoundedRectangle(x, y, dimensions.width, SPACE_HEIGHT, dimensions.radius.value, bg); - // Center the character with 3px top padding - scope.drawText(0.6f, String.valueOf(c), x + 9, y + 7, dimensions.font.value, fgColor); + int lineY = y + SPACE_HEIGHT / 2; + scope.drawRect(x + (dimensions.width - 30) / 2, lineY, 30, 1, fg); } @Override @@ -169,6 +149,5 @@ public class Keystrokes extends Module implements HudMod { @Override public void onEnabled(boolean e) { enabled.value = e; - dimensionsDirty = true; } } \ No newline at end of file diff --git a/src/main/java/org/saturnclient/saturnclient/SaturnClient.java b/src/main/java/org/saturnclient/saturnclient/SaturnClient.java index 0b9d836..1894a58 100644 --- a/src/main/java/org/saturnclient/saturnclient/SaturnClient.java +++ b/src/main/java/org/saturnclient/saturnclient/SaturnClient.java @@ -7,8 +7,9 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.util.math.MatrixStack; import org.saturnclient.modules.ModManager; -import org.saturnclient.saturnclient.auth.Auth; +import org.saturnclient.saturnclient.client.ServiceClient; import org.saturnclient.saturnclient.config.ConfigManager; +import org.saturnclient.saturnclient.config.SaturnClientConfig; import org.saturnclient.saturnclient.cosmetics.Emotes; import org.saturnclient.saturnclient.cosmetics.Hats; import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks; @@ -40,6 +41,10 @@ public class SaturnClient implements ModInitializer { SaturnClientConfig.init(); ModManager.init(); + client.execute(() -> { + SaturnScreen.preload(client); + }); + ClientLifecycleEvents.CLIENT_STOPPING.register(_o -> ConfigManager.save()); SpecialModelLoaderEvents.LOAD_SCOPE.register(() -> { @@ -75,7 +80,7 @@ public class SaturnClient implements ModInitializer { KeyInputHandler.register(); Emotes.initialize(); - if (Auth.authenticate()) { + if (ServiceClient.authenticate()) { Cloaks.initialize(); Hats.initialize(); LOGGER.info(MOD_ID + " initialization complete"); diff --git a/src/main/java/org/saturnclient/saturnclient/auth/Auth.java b/src/main/java/org/saturnclient/saturnclient/auth/Auth.java deleted file mode 100644 index 3bcd7af..0000000 --- a/src/main/java/org/saturnclient/saturnclient/auth/Auth.java +++ /dev/null @@ -1,283 +0,0 @@ -package org.saturnclient.saturnclient.auth; - -import java.util.HashMap; -import java.util.Map; -import java.util.stream.Collectors; - -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; -import net.minecraft.client.network.AbstractClientPlayerEntity; -import net.minecraft.util.Identifier; - -import org.saturnclient.saturnclient.cosmetics.Hats; -import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks; -import org.saturnclient.ui2.Utils; -import org.saturnclient.ui2.elements.Notification.NotificationKind; - -import dev.kosmx.playerAnim.api.layered.AnimationStack; -import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess; -import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationRegistry; - -import org.saturnclient.saturnclient.SaturnClient; - -public class Auth { - public static Map players = new HashMap<>(); - public static Map playerNames = new HashMap<>(); - public static String uuid; - private static Thread listenerThread; - private static Thread pingThread; - private static volatile boolean running = false; - - public static boolean authenticate() { - // Register shutdown hook ONCE - ClientLifecycleEvents.CLIENT_STOPPING.register(_o -> close()); - - try { - if (SaturnClient.client.getSession() == null) { - SaturnClient.LOGGER.error("No active Minecraft session found"); - return false; - } - - String accessToken = SaturnClient.client.getSession().getAccessToken(); - SaturnClient.LOGGER.info("Authenticating"); - - Network.init(); - - Network.write(accessToken); - - String response = Network.read(); - - SaturnParser parser = new SaturnParser(response); - - uuid = parser.getString("uuid"); - String cloak = parser.getString("cloak"); - String hat = parser.getString("hat"); - - for (String availableCloak : parser.getArray("cloaks")) { - Cloaks.availableCloaks.add(availableCloak); - } - - for (String availableHat : parser.getArray("hats")) { - Hats.availableHats.add(availableHat); - } - - players.put(uuid, new SaturnPlayer(cloak, hat)); - - Cloaks.loadCloak(uuid); - - playerNames.put(SaturnClient.client.getSession().getUsername(), uuid); - - afterAuth(); - - startListenerThread(); - startPingThread(); - - return true; - } catch (Exception e) { - SaturnClient.LOGGER.error("Authentication failed", e); - return false; - } - } - - private static void startListenerThread() { - running = true; - listenerThread = new Thread(() -> { - try { - while (running) { - String message = Network.read(); - if (message == null) { - SaturnClient.LOGGER.error("Connection closed"); - running = false; - break; - } - - SaturnClient.LOGGER.info("Received: " + message); - - SaturnParser parser = new SaturnParser(message); - - switch (parser.method) { - case "player": - String uuid = parser.getString("uuid"); - if (parser.getBool("saturn")) { - String cloak = parser.getString("cloak"); - String hat = parser.getString("hat"); - players.put(uuid, new SaturnPlayer(cloak, hat)); - Cloaks.loadCloak(uuid); - } else { - playerNames.entrySet().removeIf(entry -> entry.getValue().equals(uuid)); - } - break; - - case "successful_transaction": - String cloak = parser.getStringOrNull("cloak"); - String hat = parser.getStringOrNull("hat"); - if (cloak != null) { - Cloaks.availableCloaks.add(cloak); - - } - if (hat != null) { - Hats.availableHats.add(hat); - } - - case "update_cloak": - String targetUuid = parser.getStringOrNull("uuid"); - String targetCloak = parser.getStringOrNull("cloak"); - if (targetUuid != null && targetCloak != null) { - SaturnPlayer player = players.get(targetUuid); - if (player != null) { - player.cloak = targetCloak; - } - } - break; - - case "update_hat": - targetUuid = parser.getStringOrNull("uuid"); - String targetHat = parser.getStringOrNull("hat"); - if (targetUuid != null && targetHat != null) { - SaturnPlayer player = players.get(targetUuid); - if (player != null) { - player.hat = targetHat; - } - } - break; - - case "emote": - targetUuid = parser.getStringOrNull("uuid"); - String emote = parser.getStringOrNull("name"); - - for (AbstractClientPlayerEntity player : SaturnClient.client.world.getPlayers()) { - if (player.getUuidAsString().replace("-", "").equals(targetUuid)) { - AnimationStack animationStack = PlayerAnimationAccess.getPlayerAnimLayer(player); - if (emote != null && !emote.isEmpty()) { - if (animationStack.isActive() && animationStack.getPriority() == 1000) { - animationStack.removeLayer(1000); - } - animationStack.addAnimLayer(1000, - PlayerAnimationRegistry - .getAnimation(Identifier.of("saturnclient", emote)) - .playAnimation()); - } else { - animationStack.removeLayer(1000); - } - } - } - break; - - default: - if (parser.error != null) { - String[] a = parser.error.replace("!", "").split(": "); - Utils.notify(NotificationKind.Error, a[0], a[1]); - } - break; - } - } - } catch (Exception e) { - SaturnClient.LOGGER.error("Error reading from server", e); - } finally { - close(); - } - }); - - listenerThread.setDaemon(true); - listenerThread.start(); - } - - private static void startPingThread() { - pingThread = new Thread(() -> { - try { - while (running && !Thread.currentThread().isInterrupted()) { - try { - Thread.sleep(25000); // 25 seconds - if (running) { - Network.write("ping"); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); // Restore interrupt status - break; // Exit the loop on interruption - } - } - } catch (Exception e) { - if (!(e instanceof InterruptedException)) { - SaturnClient.LOGGER.error("Error in ping thread", e); - } - } - }); - - pingThread.setDaemon(true); - pingThread.start(); - } - - public static void close() { - running = false; - if (pingThread != null) { - pingThread.interrupt(); - } - if (listenerThread != null) { - listenerThread.interrupt(); - } - try { - close(); - SaturnClient.LOGGER.info("SaturnApi connection closed."); - } catch (Exception e) { - SaturnClient.LOGGER.error("Failed to close resources", e); - } - } - - public static void afterAuth() { - PlayerTracker.initialize(); - } - - public static void setCloak(String cloakName) { - try { - Network.write("set_cloak@cloak=" + cloakName + "@notify=" + stringifyPlayers()); - } catch (Exception e) { - SaturnClient.LOGGER.error("Request failed", e); - } - } - - public static void setHat(String hatName) { - try { - Network.write("set_hat@hat=" + hatName + "@notify=" + stringifyPlayers()); - } catch (Exception e) { - SaturnClient.LOGGER.error("Request failed", e); - } - } - - public static void emote(String name) { - try { - Network.write("emote@name=" + name + "@notify=" + stringifyPlayers()); - } catch (Exception e) { - SaturnClient.LOGGER.error("Request failed", e); - } - } - - public static String stringifyPlayers() { - return players.keySet().stream() - .filter(key -> key != uuid) - .collect(Collectors.joining("$")); - } - - public static void player(String name, String uuid) { - try { - playerNames.put(name, uuid.replaceAll("-", "")); - Network.write("player@uuid=" + uuid.replaceAll("-", "")); - } catch (Exception e) { - SaturnClient.LOGGER.error("Request failed", e); - } - } - - public static void buyCloak(String name) { - try { - Network.write("buy_cloak@cloak=" + name); - } catch (Exception e) { - SaturnClient.LOGGER.error("Request failed", e); - } - } - - public static void buyHat(String name) { - try { - Network.write("buy_hat@hat=" + name); - } catch (Exception e) { - SaturnClient.LOGGER.error("Request failed", e); - } - } -} diff --git a/src/main/java/org/saturnclient/saturnclient/auth/Network.java b/src/main/java/org/saturnclient/saturnclient/auth/Network.java deleted file mode 100644 index 507f857..0000000 --- a/src/main/java/org/saturnclient/saturnclient/auth/Network.java +++ /dev/null @@ -1,105 +0,0 @@ -package org.saturnclient.saturnclient.auth; - -import java.io.*; -import java.net.*; -import java.security.*; -import java.util.Base64; -import javax.crypto.*; -import javax.crypto.spec.*; -import java.security.interfaces.*; -import java.security.spec.X509EncodedKeySpec; - -public class Network { - static Socket socket; - static PrintWriter out; - static BufferedReader in; - static byte[] key = new byte[32]; - - private static final int CONNECTION_TIMEOUT = 5000; - private static final int READ_TIMEOUT = 5000; - - public static class AES { - public static byte[] encryptAES256(String message, byte[] key) throws Exception { - Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); - SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES"); - cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); - byte[] encryptedMessage = cipher.doFinal(message.getBytes()); - return encryptedMessage; - } - - public static String decryptAES256(byte[] encryptedMessage, byte[] key) throws Exception { - Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); - SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES"); - cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); - byte[] decryptedMessage = cipher.doFinal(encryptedMessage); - return new String(decryptedMessage); - } - } - - public static void init() throws Exception { - // Generate AES key - new SecureRandom().nextBytes(key); - - socket = new Socket(); - socket.connect(new InetSocketAddress("77.247.92.168", 8080), CONNECTION_TIMEOUT); - - socket.setSoTimeout(READ_TIMEOUT); - - // out = new DataOutputStream(socket.getOutputStream()); - out = new PrintWriter(socket.getOutputStream(), true); - in = new BufferedReader(new InputStreamReader(socket.getInputStream())); - - StringBuilder publicKeyBuilder = new StringBuilder(); - String line; - while (!(line = in.readLine()).contains("-----END PUBLIC KEY-----")) { - publicKeyBuilder.append(line).append("\n"); - } - publicKeyBuilder.append(line); - - String publicKeyPem = publicKeyBuilder.toString(); - - String publicKeyBase64 = publicKeyPem.replace("-----BEGIN PUBLIC KEY-----", "") - .replace("-----END PUBLIC KEY-----", "").replace("\n", "").replace("\r", ""); - byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyBase64); - - X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes); - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec); - - Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); - rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey); - byte[] encryptedKey = rsaCipher.doFinal(key); - - out.println(Base64.getEncoder().encodeToString(encryptedKey)); - } - - public static void write(String message) { - try { - out.println(Base64.getEncoder().encodeToString(AES.encryptAES256(message, key))); - } catch (Exception e) { - throw new RuntimeException("Failed to write to server: " + e.getMessage()); - } - } - - public static String read() { - try { - String msg = in.readLine(); - if (msg != null) { - return AES.decryptAES256(Base64.getDecoder().decode(msg), key); - } else { - return ""; - } - } catch (Exception e) { - return ""; - } - } - - public static void close() { - try { - socket.close(); - out.close(); - in.close(); - } catch (Exception e) { - } - } -} \ No newline at end of file diff --git a/src/main/java/org/saturnclient/saturnclient/auth/SaturnParser.java b/src/main/java/org/saturnclient/saturnclient/auth/SaturnParser.java deleted file mode 100644 index 60d1c31..0000000 --- a/src/main/java/org/saturnclient/saturnclient/auth/SaturnParser.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.saturnclient.saturnclient.auth; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -public class SaturnParser { - public String method = ""; - public String error; - private Map params = new HashMap<>(); - - public SaturnParser(String input) throws IOException { - String[] parts = input.split("@"); - - if (parts.length == 0) { - throw new IOException("Invalid input string"); - } - - if (parts[0].startsWith("!")) { - error = input; - } - - method = parts[0]; - - for (int i = 1; i < parts.length; i++) { - String[] keyValue = parts[i].split("="); - if (keyValue.length == 2) { - params.put(keyValue[0].trim(), keyValue[1].trim()); - } else if (keyValue.length == 1) { - params.put(keyValue[0].trim(), ""); - } else { - throw new IOException("Invalid parameter format: " + parts[i]); - } - } - } - - public String getString(String i) throws IOException { - String val = params.get(i); - if (val != null) { - return val; - } else { - throw new IOException("Parameter not found " + i); - } - } - - public String getStringOrNull(String i) throws IOException { - String val = params.get(i); - return val; - } - - public boolean getBool(String i) throws IOException { - String val = params.get(i); - if (val != null) { - return val.equals("true"); - } else { - throw new IOException("Parameter not found " + i); - } - } - - public String[] getArray(String i) throws IOException { - String val = params.get(i); - if (val != null) { - if (val.isEmpty()) { - return new String[] {}; - } - return val.split("\\$"); - } else { - throw new IOException("Parameter not found " + i); - } - } -} diff --git a/src/main/java/org/saturnclient/saturnclient/auth/SaturnPlayer.java b/src/main/java/org/saturnclient/saturnclient/auth/SaturnPlayer.java deleted file mode 100644 index 8ffe19e..0000000 --- a/src/main/java/org/saturnclient/saturnclient/auth/SaturnPlayer.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.saturnclient.saturnclient.auth; - -public class SaturnPlayer { - public String cloak = ""; - public String hat = ""; - - public SaturnPlayer(String cloak, String hat) { - this.cloak = cloak; - this.hat = hat; - } -} diff --git a/src/main/java/org/saturnclient/saturnclient/client/ServiceClient.java b/src/main/java/org/saturnclient/saturnclient/client/ServiceClient.java new file mode 100644 index 0000000..442f7d9 --- /dev/null +++ b/src/main/java/org/saturnclient/saturnclient/client/ServiceClient.java @@ -0,0 +1,205 @@ +package org.saturnclient.saturnclient.client; + +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import org.saturnclient.saturnclient.SaturnClient; +import org.saturnclient.saturnclient.client.player.SaturnPlayer; +import org.saturnclient.saturnclient.cosmetics.Hats; +import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks; + +import dev.kosmx.playerAnim.api.layered.AnimationStack; +import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess; +import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationRegistry; +import dev.selimaj.session.Session; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; +import net.minecraft.client.network.AbstractClientPlayerEntity; +import net.minecraft.util.Identifier; + +public class ServiceClient { + private static Session session; + public static UUID uuid; + + public static boolean connectTimeout() { + try { + session = Session.connect("wss://saturn-server.selimaj.dev", 10, TimeUnit.SECONDS); + return true; + } catch (Exception e) { + return false; + } + } + + public static boolean authenticate() { + ClientLifecycleEvents.CLIENT_STOPPING.register(_o -> { + if (session != null) + try { + session.close(); + } catch (Exception e) { + SaturnClient.LOGGER.error("Unable to close Saturn session"); + + } + }); + + try { + var mcSession = SaturnClient.client.getSession(); + if (mcSession == null) { + SaturnClient.LOGGER.error("No active Minecraft session found"); + return false; + } + + String accessToken = mcSession.getAccessToken(); + uuid = mcSession.getUuidOrNull(); + String username = mcSession.getUsername(); + + SaturnClient.LOGGER.info("Authenticating with UUID: " + uuid); + + if (!connectTimeout()) { + SaturnClient.LOGGER.error("Unable to authenticate: Session Server Timeout"); + return false; + } + + ServiceMethods.Types.Player response = session.request(ServiceMethods.Authenticate, accessToken) + .get(); + + for (String availableCloak : response.cloaks()) { + Cloaks.availableCloaks.add(availableCloak); + } + + for (String availableHat : response.hats()) { + Hats.availableHats.add(availableHat); + } + + eventHandlers(); + + SaturnPlayer.set(new SaturnPlayer(uuid, username, response.cloak(), response.hat())); + + Cloaks.loadCloak(uuid); + + return true; + } catch (Exception e) { + SaturnClient.LOGGER.error("Authentication failed", e); + return false; + } + } + + public static void setCloak(String itemId) { + try { + session.request(ServiceMethods.SetCloak, itemId).whenComplete((msg, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + } else { + try { + session.request(ServiceMethods.SendPlayer, + new ServiceMethods.Types.SendPlayerRequest(SaturnPlayer.getExternalUUIDAsString())); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } catch (Exception e) { + SaturnClient.LOGGER.error("Failed to set cloak (service): ", e); + } + } + + public static void setHat(String itemId) { + try { + session.request(ServiceMethods.SetHat, itemId).whenComplete((msg, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + } else { + try { + session.request(ServiceMethods.SendPlayer, + new ServiceMethods.Types.SendPlayerRequest(SaturnPlayer.getExternalUUIDAsString())); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } catch (Exception e) { + SaturnClient.LOGGER.error("Failed to set hat (service): ", e); + } + } + + public static void buyCloak(String itemId) { + try { + session.request(ServiceMethods.BuyCloak, itemId).whenComplete((msg, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + } else { + Cloaks.availableCloaks.add(itemId); + } + }); + } catch (Exception e) { + SaturnClient.LOGGER.error("Failed to buy cloak (service): ", e); + } + } + + public static void buyHat(String itemId) { + try { + session.request(ServiceMethods.BuyHat, itemId).whenComplete((msg, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + } else { + Hats.availableHats.add(itemId); + } + }); + } catch (Exception e) { + SaturnClient.LOGGER.error("Failed to buy hat (service): ", e); + } + } + + public static void emote(String emote) { + try { + session.request(ServiceMethods.Emote, + new ServiceMethods.Types.EmoteRequest(emote, SaturnPlayer.getExternalUUIDAsString())) + .whenComplete((msg, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + } + }); + } catch (Exception e) { + SaturnClient.LOGGER.error("Failed to emote (service): ", e); + } + } + + public static void eventHandlers() { + session.onNotification(ServiceMethods.EmoteEvent, (data) -> { + for (AbstractClientPlayerEntity player : SaturnClient.client.world.getPlayers()) { + if (player.getUuidAsString().equals(data.from())) { + AnimationStack animationStack = PlayerAnimationAccess.getPlayerAnimLayer(player); + if (data.emote() != null && !data.emote().isEmpty()) { + if (animationStack.isActive() && animationStack.getPriority() == 1000) { + animationStack.removeLayer(1000); + } + animationStack.addAnimLayer(1000, + PlayerAnimationRegistry + .getAnimation(Identifier.of("saturnclient", data.emote())) + .playAnimation()); + } else { + animationStack.removeLayer(1000); + } + } + } + }); + + session.onNotification(ServiceMethods.Player, (player) -> { + System.out.println(player); + SaturnPlayer.set(player.toSaturnPlayer()); + }); + } + + public static void player(UUID uuid, String name) { + try { + session.request(ServiceMethods.GetPlayer, uuid.toString()) + .whenComplete((user, throwable) -> { + if (throwable != null) { + throwable.printStackTrace(); + } else if (user != null) { + SaturnPlayer.set(user.toSaturnPlayer(uuid, name)); + } + }); + } catch (Exception e) { + SaturnClient.LOGGER.error("Failed to get player", e); + } + } +} diff --git a/src/main/java/org/saturnclient/saturnclient/client/ServiceMethods.java b/src/main/java/org/saturnclient/saturnclient/client/ServiceMethods.java new file mode 100644 index 0000000..0a09c53 --- /dev/null +++ b/src/main/java/org/saturnclient/saturnclient/client/ServiceMethods.java @@ -0,0 +1,113 @@ +package org.saturnclient.saturnclient.client; + +import java.util.UUID; + +import org.saturnclient.saturnclient.client.ServiceMethods.Types.SendPlayerRequest; +import org.saturnclient.saturnclient.client.player.SaturnPlayer; + +import dev.selimaj.session.types.Method; + +public class ServiceMethods { + + // ========================= + // Types (Rust structs) + // ========================= + public static class Types { + + public record EmoteRequest(String emote, String[] targets) { + } + + public record EmoteEvent(String emote, String from) { + } + + public record Player( + String cloak, + String hat, + String[] cloaks, + String[] hats) { + public SaturnPlayer toSaturnPlayer(UUID uuid, String name) { + return new SaturnPlayer(uuid, name, cloak, hat); + } + } + + public record PlayerStream(Player player, String name, String uuid) { + public SaturnPlayer toSaturnPlayer() { + return new SaturnPlayer(UUID.fromString(uuid), name, this.player.cloak, this.player.hat); + } + } + + public record SendPlayerRequest(String[] targets) { + } + } + + // ========================= + // AUTH + // ========================= + public static final Method Authenticate = new Method<>("auth", + String.class, + Types.Player.class, + String.class); + + // ========================= + // EQUIP + // ========================= + public static final Method SetCloak = new Method<>("set_cloak", + String.class, + String.class, + String.class); + + public static final Method SetHat = new Method<>("set_hat", + String.class, + String.class, + String.class); + + // ========================= + // BUY + // ========================= + public static final Method BuyCloak = new Method<>("buy_cloak", + String.class, + String.class, + String.class); + + public static final Method BuyHat = new Method<>("buy_hat", + String.class, + String.class, + String.class); + + // ========================= + // EMOTE + // ========================= + public static final Method Emote = new Method<>("emote", + Types.EmoteRequest.class, + Void.class, + String.class); + + public static final Method EmoteEvent = new Method<>("emote_event", + Types.EmoteEvent.class, + Void.class, + Void.class); + + // ========================= + // GET PLAYER + // ========================= + public static final Method GetPlayer = new Method<>("get_player", + String.class, + Types.Player.class, + String.class); + + // ========================= + // PLAYER (Server Notification) + // ========================= + public static final Method Player = new Method<>("player", + Types.PlayerStream.class, + Void.class, + Void.class); + + // ========================= + // SEND PLAYER + // ========================= + public static final Method SendPlayer = new Method<>("send_player", + SendPlayerRequest.class, + Void.class, + String.class); +} \ No newline at end of file diff --git a/src/main/java/org/saturnclient/saturnclient/auth/PlayerTracker.java b/src/main/java/org/saturnclient/saturnclient/client/player/PlayerTracker.java similarity index 90% rename from src/main/java/org/saturnclient/saturnclient/auth/PlayerTracker.java rename to src/main/java/org/saturnclient/saturnclient/client/player/PlayerTracker.java index a6aff97..f43347f 100644 --- a/src/main/java/org/saturnclient/saturnclient/auth/PlayerTracker.java +++ b/src/main/java/org/saturnclient/saturnclient/client/player/PlayerTracker.java @@ -1,8 +1,10 @@ -package org.saturnclient.saturnclient.auth; +package org.saturnclient.saturnclient.client.player; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import org.saturnclient.saturnclient.SaturnClient; +import org.saturnclient.saturnclient.client.ServiceClient; + import net.minecraft.client.network.PlayerListEntry; import net.minecraft.client.MinecraftClient; @@ -45,8 +47,6 @@ public class PlayerTracker { private static void onPlayerJoin(MinecraftClient client, PlayerListEntry player) { GameProfile profile = player.getProfile(); - String uuid = profile.getId().toString(); - if (uuid != Auth.uuid) - Auth.player(profile.getName(), uuid); + ServiceClient.player(profile.getId(), profile.getName()); } } diff --git a/src/main/java/org/saturnclient/saturnclient/client/player/Roles.java b/src/main/java/org/saturnclient/saturnclient/client/player/Roles.java new file mode 100644 index 0000000..8771960 --- /dev/null +++ b/src/main/java/org/saturnclient/saturnclient/client/player/Roles.java @@ -0,0 +1,59 @@ +package org.saturnclient.saturnclient.client.player; + +import java.util.Map; +import java.util.UUID; + +import org.saturnclient.saturnclient.config.SaturnClientConfig; + +import net.minecraft.util.Formatting; + +public class Roles { + static enum Role { + OWNER, + ADMIN, + PARTNER, + CONTRIBUTOR + } + + private static final Map ROLES = Map.of( + UUID.fromString("d362a042-28bd-49e1-a807-ae74dbe8aba9"), + Role.OWNER); + + /* + * Gets the icon color of a specific individual, here are the different colors + * + * - Owner: Dark Red + * - Admin: Red + * - Partners: Gold + * - Contributor: Aqua + * - Other/player: White + */ + public static Formatting getIconColor(UUID uuid) { + Role role = ROLES.get(uuid); + + if (role == null) { + return Formatting.WHITE; + } + + switch (role) { + case OWNER: + return Formatting.DARK_RED; + + case ADMIN: + return Formatting.RED; + + case PARTNER: + return Formatting.GOLD; + + case CONTRIBUTOR: + return Formatting.AQUA; + + default: + return Formatting.WHITE; + } + } + + public static String getSaturnIndicator() { + return SaturnClientConfig.realisticLogo.value ? "" : ""; + } +} diff --git a/src/main/java/org/saturnclient/saturnclient/client/player/SaturnPlayer.java b/src/main/java/org/saturnclient/saturnclient/client/player/SaturnPlayer.java new file mode 100644 index 0000000..f4c935e --- /dev/null +++ b/src/main/java/org/saturnclient/saturnclient/client/player/SaturnPlayer.java @@ -0,0 +1,54 @@ +package org.saturnclient.saturnclient.client.player; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.jetbrains.annotations.Nullable; +import org.saturnclient.saturnclient.client.ServiceClient; + +public class SaturnPlayer { + private static Map PLAYERS = new HashMap<>(); + private static Map PLAYER_NAMES = new HashMap<>(); + + public String cloak = ""; + public String hat = ""; + public final UUID uuid; + public final String name; + + public SaturnPlayer(UUID uuid, String name, String cloak, String hat) { + this.cloak = cloak; + this.hat = hat; + this.uuid = uuid; + this.name = name; + } + + @Nullable + public static SaturnPlayer get() { + return PLAYERS.get(ServiceClient.uuid); + } + + @Nullable + public static SaturnPlayer get(UUID uuid) { + return PLAYERS.get(uuid); + } + + @Nullable + public static SaturnPlayer get(String name) { + UUID uuid = PLAYER_NAMES.get(name); + if (uuid == null) + return null; + return PLAYERS.get(uuid); + } + + public static void set(SaturnPlayer player) { + PLAYER_NAMES.put(player.name, player.uuid); + PLAYERS.put(player.uuid, player); + } + + public static String[] getExternalUUIDAsString() { + return PLAYERS.keySet().stream().filter(id -> !id.equals(ServiceClient.uuid)).map(UUID::toString) + .toArray(String[]::new); + } + +} diff --git a/src/main/java/org/saturnclient/saturnclient/config/ConfigManager.java b/src/main/java/org/saturnclient/saturnclient/config/ConfigManager.java index 4123bbf..bc628b1 100644 --- a/src/main/java/org/saturnclient/saturnclient/config/ConfigManager.java +++ b/src/main/java/org/saturnclient/saturnclient/config/ConfigManager.java @@ -1,107 +1,94 @@ package org.saturnclient.saturnclient.config; import com.google.gson.*; +import org.saturnclient.saturnclient.SaturnClient; + import java.io.File; import java.io.IOException; import java.nio.file.Files; -import java.util.*; -import org.saturnclient.saturnclient.SaturnClient; +import java.util.LinkedHashMap; +import java.util.Map; public class ConfigManager { + private static final File configFile = new File(SaturnClient.client.runDirectory, "saturn.json"); - private static final Map>> properties = new HashMap<>(); - private static JsonObject cachedThemeJson = null; + + // SINGLE ROOT TREE + private static final Map> ROOT = new LinkedHashMap<>(); + + private static JsonObject cachedJson = null; private final Map> currentMap; - private final String namespace; + private final String[] path; + + /** + * Creates a root namespace + */ public ConfigManager(String namespace) { - this.namespace = namespace; this.currentMap = new LinkedHashMap<>(); - properties.put(namespace, currentMap); - System.out.println("Created namespace: " + namespace); + this.path = new String[] { namespace }; // Path is just ["namespace"] + ROOT.put(namespace, Property.namespace(currentMap)); } + /** + * Creates a sub-namespace inside a parent + */ public ConfigManager(ConfigManager parent, String namespace) { - this.namespace = namespace; this.currentMap = new LinkedHashMap<>(); - Property>> nsProp = Property.namespace(currentMap); - parent.property(namespace, nsProp); - System.out.println("Created sub-namespace: " + namespace); - } - public void sub(String name) { - property(name, Property.namespace(new LinkedHashMap<>())); + // Build new path: parent path + current namespace + this.path = new String[parent.path.length + 1]; + System.arraycopy(parent.path, 0, this.path, 0, parent.path.length); + this.path[this.path.length - 1] = namespace; + + parent.property(namespace, Property.namespace(currentMap)); } + /** + * Add a property + */ public Property property(String name, Property value) { currentMap.put(name, value); - loadProp(name, value); + loadSingleProperty(name, value); return value; } - private void loadProp(String name, Property prop) { - JsonObject source = cachedThemeJson != null ? cachedThemeJson : loadAndCache(); - if (source == null) - return; - - JsonElement namespaceJson = source.get(namespace); - if (namespaceJson == null || !namespaceJson.isJsonObject()) - return; - - JsonElement value = namespaceJson.getAsJsonObject().get(name); - if (value != null) - prop.loadFromJson(value); - } - - private static JsonObject loadAndCache() { - try { - if (!configFile.exists()) { - Files.writeString(configFile.toPath(), "{}"); - return new JsonObject(); - } - String json = Files.readString(configFile.toPath()); - cachedThemeJson = JsonParser.parseString(json).getAsJsonObject(); - return cachedThemeJson; - } catch (IOException e) { - SaturnClient.LOGGER.error("Error reading config file", e); - return null; - } + /** + * Add empty namespace + */ + public ConfigManager sub(String name) { + return new ConfigManager(this, name); } + /** + * Load entire config + */ public static void load() { SaturnClient.LOGGER.info("Loading config..."); + JsonObject json = loadAndCache(); if (json == null) return; - properties.forEach((namespace, map) -> { - JsonElement nsElement = json.get(namespace); - if (nsElement != null && nsElement.isJsonObject()) { - loadProperties(nsElement.getAsJsonObject(), map); - } - }); - } - - private static void loadProperties(JsonObject json, Map> props) { - props.forEach((name, prop) -> { - JsonElement el = json.get(name); - if (el != null) - prop.loadFromJson(el); - }); + loadRecursive(json, ROOT); } + /** + * Save entire config + */ public static void save() { SaturnClient.LOGGER.info("Saving config..."); - JsonObject root = new JsonObject(); - properties.forEach((namespace, map) -> { - JsonObject nsJson = new JsonObject(); - saveProperties(nsJson, map); - root.add(namespace, nsJson); - }); + + JsonObject rootJson = new JsonObject(); + saveRecursive(rootJson, ROOT); try { - String formatted = new GsonBuilder().setPrettyPrinting().create().toJson(root); + String formatted = new GsonBuilder() + .setPrettyPrinting() + .create() + .toJson(rootJson); + Files.writeString(configFile.toPath(), formatted); SaturnClient.LOGGER.info("Config saved successfully."); } catch (IOException e) { @@ -109,11 +96,86 @@ public class ConfigManager { } } - private static void saveProperties(JsonObject json, Map> props) { - props.forEach((name, prop) -> json.add(name, prop.toJson())); + /** + * Recursive save + */ + private static void saveRecursive(JsonObject json, Map> map) { + map.forEach((name, prop) -> { + if (prop.isNamespace()) { + JsonObject child = new JsonObject(); + saveRecursive(child, prop.getNamespaceMap()); + json.add(name, child); + } else { + json.add(name, prop.toJson()); + } + }); + } + + /** + * Recursive load + */ + private static void loadRecursive(JsonObject json, Map> map) { + map.forEach((name, prop) -> { + JsonElement element = json.get(name); + if (element == null) + return; + + if (prop.isNamespace() && element.isJsonObject()) { + loadRecursive(element.getAsJsonObject(), prop.getNamespaceMap()); + } else { + prop.loadFromJson(element); + } + }); + } + + /** + * Load only a single property immediately after creation, + * traversing the JSON tree based on this manager's path. + */ + private void loadSingleProperty(String name, Property prop) { + JsonObject source = cachedJson != null ? cachedJson : loadAndCache(); + if (source == null) + return; + + // Traverse the tree to the correct namespace + JsonObject currentScope = source; + for (String segment : path) { + JsonElement next = currentScope.get(segment); + if (next != null && next.isJsonObject()) { + currentScope = next.getAsJsonObject(); + } else { + return; // Path doesn't exist in config yet + } + } + + // Now look for the property inside the correctly nested object + JsonElement element = currentScope.get(name); + if (element != null) { + prop.loadFromJson(element); + } + } + + /** + * Reads file and caches json + */ + private static JsonObject loadAndCache() { + try { + if (!configFile.exists()) { + Files.writeString(configFile.toPath(), "{}"); + return new JsonObject(); + } + + String json = Files.readString(configFile.toPath()); + cachedJson = JsonParser.parseString(json).getAsJsonObject(); + return cachedJson; + + } catch (IOException e) { + SaturnClient.LOGGER.error("Error reading config file", e); + return null; + } } public Map> getProperties() { return currentMap; } -} +} \ No newline at end of file diff --git a/src/main/java/org/saturnclient/saturnclient/config/NamedProperty.java b/src/main/java/org/saturnclient/saturnclient/config/NamedProperty.java deleted file mode 100644 index 3e63c31..0000000 --- a/src/main/java/org/saturnclient/saturnclient/config/NamedProperty.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.saturnclient.saturnclient.config; - -public class NamedProperty { - public String name; - public Property prop; - - public NamedProperty(String name, Property value) { - this.name = name; - this.prop = value; - } -} diff --git a/src/main/java/org/saturnclient/saturnclient/config/Property.java b/src/main/java/org/saturnclient/saturnclient/config/Property.java index 0a8aa01..2d7dd2e 100644 --- a/src/main/java/org/saturnclient/saturnclient/config/Property.java +++ b/src/main/java/org/saturnclient/saturnclient/config/Property.java @@ -10,6 +10,15 @@ import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; public class Property { + public static class NamedProperty { + public String name; + public Property prop; + + public NamedProperty(String name, Property value) { + this.name = name; + this.prop = value; + } + } public enum PropertyType { BOOLEAN, @@ -277,4 +286,13 @@ public class Property { if (value != null) this.loadFromJson(value); } + + public boolean isNamespace() { + return type == PropertyType.NAMESPACE; + } + + @SuppressWarnings("unchecked") + public Map> getNamespaceMap() { + return isNamespace() ? (Map>) (Object) value : null; + } } diff --git a/src/main/java/org/saturnclient/saturnclient/SaturnClientConfig.java b/src/main/java/org/saturnclient/saturnclient/config/SaturnClientConfig.java similarity index 56% rename from src/main/java/org/saturnclient/saturnclient/SaturnClientConfig.java rename to src/main/java/org/saturnclient/saturnclient/config/SaturnClientConfig.java index db45255..0b9a628 100644 --- a/src/main/java/org/saturnclient/saturnclient/SaturnClientConfig.java +++ b/src/main/java/org/saturnclient/saturnclient/config/SaturnClientConfig.java @@ -1,11 +1,8 @@ -package org.saturnclient.saturnclient; +package org.saturnclient.saturnclient.config; -import org.saturnclient.saturnclient.config.Property; import org.lwjgl.glfw.GLFW; -import org.saturnclient.saturnclient.config.ConfigManager; import org.saturnclient.ui2.resources.Textures; -import net.minecraft.util.Formatting; import net.minecraft.util.Identifier; public class SaturnClientConfig { @@ -15,37 +12,21 @@ public class SaturnClientConfig { public static Property saturnTitleScreen = Property.bool(true); public static Property bendyCloaks = Property.bool(true); public static Property openEmoteWheel = Property.keybinding(GLFW.GLFW_KEY_B); + public static Property stagger = Property.bool(true); public static Identifier getLogo() { return realisticLogo.value ? Textures.REALISTIC_LOGO : Textures.LOGO; } - public static String getSaturnIndicator() { - return realisticLogo.value ? "" : ""; - } - - /* - * Gets the icon color of a specific individual, here are the different colors - * - * - Owner: Dark Red - * - Admin: Red - * - Partners: Gold - * - Contributor: Aqua - * - Other/player: White - */ - public static Formatting getIconColor(String uuid) { - if (uuid.equals("d362a04228bd49e1a807ae74dbe8aba9")) { - return Formatting.DARK_RED; // Owner - } - - return Formatting.WHITE; - } - public static void init() { config = new ConfigManager("Saturn Client"); config.property("Realistic logo", realisticLogo); config.property("Saturn client title screen", saturnTitleScreen); config.property("Open Emote Wheel", openEmoteWheel); config.property("Bendy Cloaks", bendyCloaks); + config.property("Stagger Animations", stagger); + + // Initialize a sub namespace for theme + Theme.init(config); } } diff --git a/src/main/java/org/saturnclient/saturnclient/config/Theme.java b/src/main/java/org/saturnclient/saturnclient/config/Theme.java new file mode 100644 index 0000000..29cb887 --- /dev/null +++ b/src/main/java/org/saturnclient/saturnclient/config/Theme.java @@ -0,0 +1,88 @@ +package org.saturnclient.saturnclient.config; + +public class Theme { + // Main UI background (slightly warm dark to match Saturn tone) + public static final Property BACKGROUND = Property.color(0xFF12100D); + + // Default text color + public static final Property FOREGROUND = Property.color(0xFFF2E6D2); + + // Widget default background (normal state) + public static final Property PRIMARY = Property.color(0xFF1C1915); + + // Widget text color + public static final Property PRIMARY_FG = Property.color(0xFFEAD9B8); + + // Saturn brand color (hovered / enabled / selected) + public static final Property ACCENT = Property.color(0xFFE2BF7D); + + // Text/icons shown on accent background + public static final Property ACCENT_FG = Property.color(0xFF1A140A); + + // Misc colors + public static final Property SCROLL = Property.color(0xFFE2BF7D); + + // UI metrics + public static final Property BG_RADIUS = Property.integer(12); + public static final Property WIDGET_RADIUS = Property.integer(10); + + // Font (keeping your current system) + public static Property FONT = Property.font(1); + + public static void init(ConfigManager parent) { + ConfigManager config = new ConfigManager(parent, "UI Style"); + config.property("Background", BACKGROUND); + config.property("Foreground", FOREGROUND); + config.property("Primary", PRIMARY); + config.property("Primary Foreground", PRIMARY_FG); + config.property("Accent", ACCENT); + config.property("Accent Foreground", ACCENT_FG); + config.property("Scrollbar Color", SCROLL); + + config.property("Background Radius", BG_RADIUS); + config.property("Widget Radius", WIDGET_RADIUS); + + config.property("Font", FONT); + } + + /** + * primary by default, accent if true + */ + public static int getBg(boolean hover) { + return hover ? ACCENT.value : PRIMARY.value; + } + + /** + * (Foreground) primary by default, accent if true + */ + public static int getFg(boolean hover) { + return hover ? ACCENT_FG.value : PRIMARY_FG.value; + } + + /** + * Multiplies existing alpha with 0–255 alpha. + */ + public static int withAlpha(int alpha, int color) { + alpha = Math.max(0, Math.min(255, alpha)); + + int originalAlpha = (color >>> 24) & 0xFF; + + // Merge (multiply) alphas + int merged = (originalAlpha * alpha) / 255; + + return (color & 0x00FFFFFF) | (merged << 24); + } + + /** + * Multiplies existing alpha with 0.0–1.0 alpha. + */ + public static int withAlpha(float alpha, int color) { + alpha = Math.max(0f, Math.min(1f, alpha)); + + int originalAlpha = (color >>> 24) & 0xFF; + + int merged = (int) (originalAlpha * alpha); + + return (color & 0x00FFFFFF) | (merged << 24); + } +} diff --git a/src/main/java/org/saturnclient/saturnclient/config/ThemeManager.java b/src/main/java/org/saturnclient/saturnclient/config/ThemeManager.java deleted file mode 100644 index 0bcc14b..0000000 --- a/src/main/java/org/saturnclient/saturnclient/config/ThemeManager.java +++ /dev/null @@ -1,93 +0,0 @@ -package org.saturnclient.saturnclient.config; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import org.saturnclient.saturnclient.SaturnClient; - -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - -public class ThemeManager { - private static File themeFile = new File( - SaturnClient.client.runDirectory, - "saturn.theme.json"); - private static List theme = new ArrayList<>(); - private static JsonObject cachedThemeJson = null; - - private Map> states; - private Map> currentStyling; - private String namespace; - - public ThemeManager(String namespace, String... states) { - this.namespace = namespace; - this.states = new LinkedHashMap<>(); - this.currentStyling = new LinkedHashMap<>(); - this.states.put(null, new LinkedHashMap<>()); - for (String s : states) { - this.states.put(s, new LinkedHashMap<>()); - } - theme.add(this); - } - - public void setState(String state) { - for (Map.Entry tProp : states.get(state).entrySet()) { - currentStyling.get(tProp.getKey()).setValue(tProp.getValue()); - } - } - - public void applyState(String state) { - for (Map.Entry tProp : states.get(state).entrySet()) { - if (!states.get(null).get(tProp.getKey()).equals(tProp.getValue())) - currentStyling.get(tProp.getKey()).setValue(tProp.getValue()); - } - } - - public Property property(String name, Property prop) { - for (Map.Entry> state : this.states.entrySet()) { - Property property = prop.copy(); - if (cachedThemeJson == null) { - load(); - } - String stateName = state.getKey(); - property.load(name, cachedThemeJson.get(stateName != null ? namespace + "@" + stateName : namespace)); - state.getValue().put(name, property.value); - } - - currentStyling.put(name, prop); - - return prop; - } - - public void propertyStateDefault(String state, String name, T value) { - Property prop = currentStyling.get(name).copy(); - prop.setValue(value, value); - if (cachedThemeJson == null) { - load(); - } - prop.load(name, cachedThemeJson.get(state != null ? namespace + "@" + state : namespace)); - states.get(state).put(name, prop.value); - } - - public static void load() { - try { - SaturnClient.LOGGER.info("Starting to load theme..."); - if (!themeFile.exists()) { - themeFile.createNewFile(); - Files.write(themeFile.toPath(), "{}".getBytes()); - } - - cachedThemeJson = JsonParser.parseString( - new String(Files.readAllBytes(themeFile.toPath()))).getAsJsonObject(); - - SaturnClient.LOGGER.info("Theme loaded"); - } catch (IOException e) { - SaturnClient.LOGGER.error("Error reading the theme file", e); - } - } -} diff --git a/src/main/java/org/saturnclient/saturnclient/cosmetics/CloakFeatureRenderer.java b/src/main/java/org/saturnclient/saturnclient/cosmetics/CloakFeatureRenderer.java index 6ce1401..bafc998 100644 --- a/src/main/java/org/saturnclient/saturnclient/cosmetics/CloakFeatureRenderer.java +++ b/src/main/java/org/saturnclient/saturnclient/cosmetics/CloakFeatureRenderer.java @@ -1,7 +1,7 @@ package org.saturnclient.saturnclient.cosmetics; -import org.saturnclient.saturnclient.SaturnClientConfig; -import org.saturnclient.saturnclient.auth.Auth; +import org.saturnclient.saturnclient.client.player.SaturnPlayer; +import org.saturnclient.saturnclient.config.SaturnClientConfig; import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks; import net.minecraft.client.render.OverlayTexture; @@ -283,20 +283,18 @@ public class CloakFeatureRenderer extends FeatureRenderer availableCloaks = new ArrayList<>(); public static Identifier cloakCacheIdentifier = null; - public static final Map> animatedCloaks = new ConcurrentHashMap<>(); - private static final Map lastFrameTime = new ConcurrentHashMap<>(); + public static final Map> animatedCloaks = new ConcurrentHashMap<>(); + private static final Map lastFrameTime = new ConcurrentHashMap<>(); private static final ExecutorService CLOAK_LOADER_EXECUTOR = Executors.newFixedThreadPool( Math.min(4, Runtime.getRuntime().availableProcessors()), @@ -54,17 +55,6 @@ public class Cloaks { availableCloaks.add(0, ""); } - /** - * Handles loading and caching of a new cloak texture. - * - * @param cloakName Name of the cloak file to load - */ - public static void setCloak(String uuid, String cloakName) { - Auth.setCloak(cloakName); - setCloakSilent(uuid, cloakName); - SaturnClient.LOGGER.info("Cloak set to " + cloakName); - } - /** * Sets cloak of the current player * @@ -72,7 +62,8 @@ public class Cloaks { */ public static void setCloak(String cloakName) { if (availableCloaks.contains(cloakName)) { - setCloak(Auth.uuid, cloakName); + setCloak(ServiceClient.uuid, cloakName); + ServiceClient.setCloak(cloakName); } } @@ -82,11 +73,10 @@ public class Cloaks { * * @param cloakName Name of the cloak file to load */ - public static void setCloakSilent(String uuid, String cloakName) { - SaturnPlayer player = Auth.players.get(uuid); - if (player == null) { - Auth.players.put(uuid, new SaturnPlayer(cloakName, null)); - } else { + public static void setCloak(UUID uuid, String cloakName) { + SaturnPlayer player = SaturnPlayer.get(uuid); + + if (player != null) { player.cloak = cloakName; } @@ -99,8 +89,9 @@ public class Cloaks { * * @param cloakName Name of the cloak file to load */ - public static void loadCloak(String uuid) { - SaturnPlayer player = Auth.players.get(uuid); + public static void loadCloak(UUID uuid) { + SaturnPlayer player = SaturnPlayer.get(uuid); + if (player != null && player.cloak != null) { if (!player.cloak.isEmpty()) { if (Arrays.asList(ANIMATED_CLOAKS).contains(player.cloak)) { @@ -146,7 +137,7 @@ public class Cloaks { } } - public static CompletableFuture loadAnimatedCloakAsync(String uuid, String cloakName) { + public static CompletableFuture loadAnimatedCloakAsync(UUID uuid, String cloakName) { return CompletableFuture.runAsync(() -> { String fileName = cloakName + ".gif"; @@ -196,7 +187,7 @@ public class Cloaks { } else { // Queue for main thread execution // SaturnClient.client.execute( - // () -> IdentifierUtils.registerBufferedImageTexture(frameIdentifier, frame)); + // () -> IdentifierUtils.registerBufferedImageTexture(frameIdentifier, frame)); } animatedFrames.add(new AnimatedCloakData(frameIdentifier, delay)); @@ -226,16 +217,14 @@ public class Cloaks { }, CLOAK_LOADER_EXECUTOR); } - public static Identifier getCurrentCloakTexture(String uuid) { - if (!Auth.players.containsKey(uuid)) { + public static Identifier getCurrentCloakTexture(UUID uuid) { + SaturnPlayer player = SaturnPlayer.get(uuid); + + if (player == null || player.cloak.isEmpty()) { return null; } - String cloakName = Auth.players.get(uuid).cloak; - - if (cloakName.isEmpty()) { - return null; - } + String cloakName = player.cloak; if (Arrays.asList(ANIMATED_CLOAKS).contains(cloakName)) { List frames = animatedCloaks.get(uuid); diff --git a/src/main/java/org/saturnclient/saturnclient/event/KeyInputHandler.java b/src/main/java/org/saturnclient/saturnclient/event/KeyInputHandler.java index 87e1ea1..b2231a1 100644 --- a/src/main/java/org/saturnclient/saturnclient/event/KeyInputHandler.java +++ b/src/main/java/org/saturnclient/saturnclient/event/KeyInputHandler.java @@ -6,8 +6,8 @@ import net.minecraft.client.option.KeyBinding; import net.minecraft.client.util.InputUtil; import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.SaturnClientConfig; -import org.saturnclient.saturnclient.auth.Auth; +import org.saturnclient.saturnclient.client.ServiceClient; +import org.saturnclient.saturnclient.config.SaturnClientConfig; import org.saturnclient.ui2.screens.EmoteWheel; import org.saturnclient.ui2.screens.ShiftMenu; @@ -47,7 +47,7 @@ public class KeyInputHandler { AnimationStack animationStack = PlayerAnimationAccess.getPlayerAnimLayer(SaturnClient.client.player); if (animationStack.isActive() && animationStack.getPriority() == 1000) { animationStack.removeLayer(1000); - Auth.emote(""); + ServiceClient.emote(""); } } }); diff --git a/src/main/java/org/saturnclient/saturnclient/mixin/NameTagMixin.java b/src/main/java/org/saturnclient/saturnclient/mixin/NameTagMixin.java index defa7f5..6cb2d0b 100644 --- a/src/main/java/org/saturnclient/saturnclient/mixin/NameTagMixin.java +++ b/src/main/java/org/saturnclient/saturnclient/mixin/NameTagMixin.java @@ -14,8 +14,11 @@ import net.minecraft.text.Text; import net.minecraft.util.Formatting; import net.minecraft.util.math.Vec3d; -import org.saturnclient.saturnclient.SaturnClientConfig; -import org.saturnclient.saturnclient.auth.Auth; +import org.saturnclient.saturnclient.client.player.Roles; +import org.saturnclient.saturnclient.client.player.SaturnPlayer; + +import java.util.UUID; + import org.joml.Matrix4f; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.Inject; @@ -37,12 +40,12 @@ public abstract class NameTagMixin { private void onRenderLabelIfPresent(S state, Text text, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, CallbackInfo ci) { - String uuid = isSaturn(state); + UUID uuid = isSaturn(state); if (uuid != null) { - MutableText iconText = Text.literal(SaturnClientConfig.getSaturnIndicator()) - .styled(style -> style.withColor(SaturnClientConfig.getIconColor(uuid))); - + MutableText iconText = Text.literal(Roles.getSaturnIndicator()) + .styled(style -> style.withColor(Roles.getIconColor(uuid))); + Text nameText = text.copy().styled(style -> style.withColor(Formatting.WHITE)); renderLabel(state, iconText.append(nameText), matrices, @@ -52,12 +55,12 @@ public abstract class NameTagMixin { } } - private String isSaturn(S state) { + private UUID isSaturn(S state) { if (state instanceof PlayerEntityRenderState) { String name = ((PlayerEntityRenderState) state).name; - String uuid = Auth.playerNames.get(name); - if (Auth.players.containsKey(uuid)) { - return uuid; + SaturnPlayer player = SaturnPlayer.get(name); + if (player != null) { + return player.uuid; } } diff --git a/src/main/java/org/saturnclient/saturnclient/mixin/SetScreenMixin.java b/src/main/java/org/saturnclient/saturnclient/mixin/SetScreenMixin.java new file mode 100644 index 0000000..4a398a5 --- /dev/null +++ b/src/main/java/org/saturnclient/saturnclient/mixin/SetScreenMixin.java @@ -0,0 +1,26 @@ +package org.saturnclient.saturnclient.mixin; + +import org.saturnclient.saturnclient.config.SaturnClientConfig; +import org.saturnclient.ui2.screens.TitleMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.TitleScreen; + +@Mixin(MinecraftClient.class) +public class SetScreenMixin { + @ModifyVariable(method = "setScreen", at = @At("HEAD"), argsOnly = true) + private Screen replaceTitleScreen(Screen screen) { + if (SaturnClientConfig.saturnTitleScreen.value) { + if (screen instanceof TitleScreen) + return new TitleMenu(); + if (screen == null && ((MinecraftClient) (Object) this).world == null) + return new TitleMenu(); + } + + return screen; + } +} \ No newline at end of file diff --git a/src/main/java/org/saturnclient/saturnclient/mixin/SplashOverlayMixin.java b/src/main/java/org/saturnclient/saturnclient/mixin/SplashOverlayMixin.java new file mode 100644 index 0000000..b5c0c3b --- /dev/null +++ b/src/main/java/org/saturnclient/saturnclient/mixin/SplashOverlayMixin.java @@ -0,0 +1,159 @@ +package org.saturnclient.saturnclient.mixin; + +import java.util.Optional; +import java.util.function.Consumer; + +import org.saturnclient.saturnclient.config.Theme; +import org.saturnclient.ui2.RenderScope; +import org.saturnclient.ui2.resources.Textures; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.SplashOverlay; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.resource.ResourceReload; +import net.minecraft.util.Util; +import net.minecraft.util.math.MathHelper; + +@Mixin(SplashOverlay.class) +public abstract class SplashOverlayMixin { + + @Shadow + private MinecraftClient client; + @Shadow + private ResourceReload reload; + + @Shadow(remap = false) + private long reloadCompleteTime; + + @Shadow(remap = false) + private long reloadStartTime; + + @Shadow(remap = false) + private boolean reloading; + + @Shadow(remap = false) + private Consumer> exceptionHandler; + + @Shadow(remap = false) + private float progress; + + /** + * @author SaturnClient + * @reason Replace vanilla splash rendering completely but keep exit logic + */ + @Overwrite + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + int screenWidth = context.getScaledWindowWidth(); + int screenHeight = context.getScaledWindowHeight(); + long currentTime = Util.getMeasuringTimeMs(); + + // Initialize reload start time if not set + if (reloadStartTime == -1L) { + reloadStartTime = currentTime; + } + + // Compute fade-out progress after reload completes + float fadeOutProgress = reloadCompleteTime > -1L + ? (float) (currentTime - reloadCompleteTime) / 1000f + : -1f; + + int alpha = fadeOutProgress >= 0f + ? MathHelper.ceil((1.0f - MathHelper.clamp(fadeOutProgress - 1f, 0f, 1f)) * 255f) + : 255; + + // Compute fade-in progress while reloading + float reloadProgress = reloadStartTime > -1L + ? (float) (currentTime - reloadStartTime) / 500f + : -1f; + + // Get render scope for better UI + RenderScope scope = new RenderScope(context); + scope.setRenderLayer(RenderLayer::getGuiTextured); + + // Draw background overlay + if (fadeOutProgress >= 1.0F) { + renderCurrentScreen(context, mouseX, mouseY, delta); + int overlayAlpha = computeOverlayAlpha(fadeOutProgress - 1f); + scope.drawTexture(Textures.SPLASH, 0, 0, 0, 0, screenWidth, screenHeight, + Theme.withAlpha(overlayAlpha, 0xFFFFFFFF)); + } else if (reloading) { + if (reloadProgress < 1.0F) { + renderCurrentScreen(context, mouseX, mouseY, delta); + } + scope.drawTexture(Textures.SPLASH, 0, 0, 0, 0, screenWidth, screenHeight, + Theme.withAlpha(alpha, 0xFFFFFFFF)); + } else { + scope.drawTexture(Textures.SPLASH, 0, 0, 0, 0, screenWidth, screenHeight, + Theme.withAlpha(alpha, 0xFFFFFFFF)); + } + + float u = this.reload.getProgress(); + this.progress = MathHelper.clamp(this.progress * 0.95F + u * 0.050000012F, 0.0F, 1.0F); + + // Draw central logo + drawLogo(scope, screenWidth, screenHeight, alpha); + renderProgressBar(scope, context, screenWidth, screenHeight, alpha); + + // Remove overlay after fade-out completes + if (fadeOutProgress >= 2.0F) { + client.setOverlay(null); + } + + // Handle reload completion and exceptions + handleReloadCompletion(context); + } + + private void renderCurrentScreen(DrawContext context, int mouseX, int mouseY, float delta) { + if (client.currentScreen != null) { + client.currentScreen.render(context, mouseX, mouseY, delta); + } + } + + /** Draw the main logo centered */ + private void drawLogo(RenderScope scope, int screenWidth, int screenHeight, int alpha) { + scope.drawTexture(Textures.LOGO, (screenWidth - 60) / 2, ((screenHeight - 60) / 2) - 20, 0, 0, 60, 60, + Theme.withAlpha(alpha, 0xFFFFFFFF)); + } + + private void renderProgressBar(RenderScope scope, DrawContext context, int screenWidth, int screenHeight, + int alpha) { + int progressY = ((screenHeight - 5) / 2) + 25; + context.drawBorder((screenWidth - 120) / 2, progressY, 120, 5, Theme.withAlpha(alpha, 0xFFFFFFFF)); + + int progressWidth = Math.min((int) (progress * 120), 120); + int progressX = (screenWidth - 120) / 2; + + context.fill(progressX, progressY, progressX + progressWidth, progressY + 5, + Theme.withAlpha(alpha, 0xFFFFFFFF)); + } + + /** Compute overlay alpha from fade progress */ + private int computeOverlayAlpha(float progress) { + return MathHelper.ceil((1.0F - MathHelper.clamp(progress, 0.0F, 1.0F)) * 255.0F); + } + + /** Handle reload completion logic */ + private void handleReloadCompletion(DrawContext context) { + float reloadProgress = reloadStartTime > -1L ? (float) (Util.getMeasuringTimeMs() - reloadStartTime) / 500f + : -1f; + + if (reloadCompleteTime == -1L && reload.isComplete() && (!reloading || reloadProgress >= 2.0F)) { + try { + reload.throwException(); + exceptionHandler.accept(Optional.empty()); + } catch (Throwable ex) { + exceptionHandler.accept(Optional.of(ex)); + } + + reloadCompleteTime = Util.getMeasuringTimeMs(); + + if (client.currentScreen != null) { + client.currentScreen.init(client, context.getScaledWindowWidth(), context.getScaledWindowHeight()); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/org/saturnclient/saturnclient/mixin/TabListMixin.java b/src/main/java/org/saturnclient/saturnclient/mixin/TabListMixin.java index 058ec46..e830a3e 100644 --- a/src/main/java/org/saturnclient/saturnclient/mixin/TabListMixin.java +++ b/src/main/java/org/saturnclient/saturnclient/mixin/TabListMixin.java @@ -1,13 +1,14 @@ package org.saturnclient.saturnclient.mixin; import net.minecraft.client.network.PlayerListEntry; -import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Formatting; +import java.util.UUID; + import org.jetbrains.annotations.Nullable; -import org.saturnclient.saturnclient.SaturnClientConfig; -import org.saturnclient.saturnclient.auth.Auth; +import org.saturnclient.saturnclient.client.player.Roles; +import org.saturnclient.saturnclient.client.player.SaturnPlayer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; @@ -30,13 +31,13 @@ public abstract class TabListMixin { public Text getDisplayName() { GameProfile profile = ((PlayerListEntry) (Object) this).getProfile(); String name = profile.getName(); - String uuid = profile.getId().toString().replaceAll("-", ""); + UUID uuid = profile.getId(); - MutableText iconText = Text.literal(SaturnClientConfig.getSaturnIndicator()) - .styled(style -> style.withColor(SaturnClientConfig.getIconColor(uuid))); - - Text nameText = Text.literal(name).styled(style -> style.withColor(Formatting.WHITE)); - - return Auth.players.containsKey(uuid) ? iconText.append(nameText) : Text.literal(name); + if (SaturnPlayer.get(uuid) != null) { + return Text.literal(Roles.getSaturnIndicator()) + .styled(style -> style.withColor(Roles.getIconColor(uuid))) + .append(Text.literal(name).styled(style -> style.withColor(Formatting.WHITE))); + } + return Text.literal(name); } } diff --git a/src/main/java/org/saturnclient/saturnclient/mixin/TitleScreenMixin.java b/src/main/java/org/saturnclient/saturnclient/mixin/TitleScreenMixin.java deleted file mode 100644 index 44151c1..0000000 --- a/src/main/java/org/saturnclient/saturnclient/mixin/TitleScreenMixin.java +++ /dev/null @@ -1,22 +0,0 @@ -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(); - } - } -} diff --git a/src/main/java/org/saturnclient/ui2/Element.java b/src/main/java/org/saturnclient/ui2/Element.java index 4e4e00c..d00b80f 100644 --- a/src/main/java/org/saturnclient/ui2/Element.java +++ b/src/main/java/org/saturnclient/ui2/Element.java @@ -32,6 +32,22 @@ public class Element { public void charTyped(char typedChar) { } + public void mouseClicked(double mouseX, double mouseY, int button) { + } + + public void mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + } + + public void mouseReleased(double mouseX, double mouseY, int button) { + } + + public void playAnimationFrame(long elapsed) { + if (this.animation != null && elapsed >= this.animation.delay) { + this.animation.tick(this.curve + .apply(Math.min(1.0, (double) (elapsed - this.animation.delay) / this.animation.duration)), this); + } + } + public Element dimensions(int width, int height) { this.width = width; this.height = height; diff --git a/src/main/java/org/saturnclient/ui2/ElementContext.java b/src/main/java/org/saturnclient/ui2/ElementContext.java index 8f3f898..def84dd 100644 --- a/src/main/java/org/saturnclient/ui2/ElementContext.java +++ b/src/main/java/org/saturnclient/ui2/ElementContext.java @@ -4,13 +4,15 @@ public class ElementContext { public int mouseX, mouseY; public int elementWidth, elementHeight; public float elementScale; + public long elapsed; - public ElementContext(int mouseX, int mouseY, Element e) { + public ElementContext(long elapsed, 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; + this.elapsed = elapsed; } public boolean isHovering() { diff --git a/src/main/java/org/saturnclient/ui2/RenderScope.java b/src/main/java/org/saturnclient/ui2/RenderScope.java index 8954e05..1f846e6 100644 --- a/src/main/java/org/saturnclient/ui2/RenderScope.java +++ b/src/main/java/org/saturnclient/ui2/RenderScope.java @@ -9,11 +9,17 @@ import java.util.function.Function; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import org.saturnclient.ui2.resources.Fonts; +import org.saturnclient.ui2.resources.SvgTexture; + import com.mojang.blaze3d.systems.RenderSystem; import org.saturnclient.saturnclient.SaturnClient; +import org.saturnclient.saturnclient.mixin.DrawContextAccessor; + +import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.font.TextRenderer.TextLayerType; +import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.ScreenRect; import net.minecraft.client.render.DiffuseLighting; import net.minecraft.client.render.OverlayTexture; @@ -42,6 +48,10 @@ public class RenderScope { private int opacity = 255 << 24; private final ItemRenderState itemRenderState; + public RenderScope(DrawContext context) { + this(context.getMatrices(), ((DrawContextAccessor) context).getVertexConsumers()); + } + public RenderScope(MatrixStack matrices, VertexConsumerProvider.Immediate vertexConsumers) { this.matrices = matrices; this.vertexConsumers = vertexConsumers; @@ -217,6 +227,11 @@ public class RenderScope { private void drawTexturedQuad(Identifier sprite, int x1, int x2, int y1, int y2, float u1, float u2, float v1, float v2, int color) { + + if (sprite.toString().endsWith(".svg")) { + sprite = SvgTexture.getSvg(MinecraftClient.getInstance(), sprite, (x2 - x1) * 2, (y2 - y1) * 2); + } + if (color == 0) return; x1 *= 4; @@ -391,4 +406,45 @@ public class RenderScope { sprite.getMinV(), sprite.getMaxV(), color); } } + + public void fill(int x1, int y1, int x2, int y2, int color) { + this.fill(x1, y1, x2, y2, 0, color); + } + + public void fill(int x1, int y1, int x2, int y2, int z, int color) { + this.fill(RenderLayer.getGui(), x1, y1, x2, y2, z, color); + } + + public void fill(RenderLayer layer, int x1, int y1, int x2, int y2, int color) { + this.fill(layer, x1, y1, x2, y2, 0, color); + } + + public void fill(RenderLayer layer, int x1, int y1, int x2, int y2, int z, int color) { + Matrix4f matrix4f = this.matrices.peek().getPositionMatrix(); + int i; + if (x1 < x2) { + i = x1; + x1 = x2; + x2 = i; + } + + if (y1 < y2) { + i = y1; + y1 = y2; + y2 = i; + } + + VertexConsumer vertexConsumer = this.vertexConsumers.getBuffer(layer); + vertexConsumer.vertex(matrix4f, (float) x1, (float) y1, (float) z).color(color); + vertexConsumer.vertex(matrix4f, (float) x1, (float) y2, (float) z).color(color); + vertexConsumer.vertex(matrix4f, (float) x2, (float) y2, (float) z).color(color); + vertexConsumer.vertex(matrix4f, (float) x2, (float) y1, (float) z).color(color); + } + + public void drawBorder(int x, int y, int width, int height, int color) { + this.fill(x, y, x + width, y + 1, color); + this.fill(x, y + height - 1, x + width, y + height, color); + this.fill(x, y + 1, x + 1, y + height - 1, color); + this.fill(x + width - 1, y + 1, x + width, y + height - 1, color); + } } diff --git a/src/main/java/org/saturnclient/ui2/SaturnScreen.java b/src/main/java/org/saturnclient/ui2/SaturnScreen.java index d69b579..29651de 100644 --- a/src/main/java/org/saturnclient/ui2/SaturnScreen.java +++ b/src/main/java/org/saturnclient/ui2/SaturnScreen.java @@ -1,11 +1,11 @@ package org.saturnclient.ui2; +import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; import java.util.List; import org.saturnclient.saturnclient.mixin.DrawContextAccessor; -import org.saturnclient.ui2.anim.Animation; -import org.saturnclient.ui2.anim.SlideXAbsolute; import org.saturnclient.ui2.components.ElementRenderer; import net.minecraft.client.MinecraftClient; @@ -15,6 +15,8 @@ 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.texture.ResourceTexture; +import net.minecraft.client.texture.TextureManager; import net.minecraft.client.util.Pool; import net.minecraft.text.Text; import net.minecraft.util.Identifier; @@ -22,12 +24,13 @@ import net.minecraft.util.Identifier; public abstract class SaturnScreen extends Screen { private final Pool pool = new Pool(3); protected List elements = new ArrayList<>(); - public int blurDuration = 700; - public float blurProgress = 0.0f; + protected float backgroundOpacity = 1.0f; + protected Instant start = null; public int backgroundBlur = 10; - protected static final CubeMapRenderer PANORAMA_RENDERER = new CubeMapRenderer( - Identifier.of("saturnclient", "textures/gui/title/background/panorama")); + protected static final Identifier PANORAMA = Identifier.of("saturnclient", + "textures/gui/title/background/panorama"); + protected static final CubeMapRenderer PANORAMA_RENDERER = new CubeMapRenderer(PANORAMA); public static final RotatingCubeMapRenderer ROTATING_PANORAMA_RENDERER; @@ -35,41 +38,24 @@ public abstract class SaturnScreen extends Screen { ROTATING_PANORAMA_RENDERER = new RotatingCubeMapRenderer(PANORAMA_RENDERER); } + public static void preload(MinecraftClient client) { + TextureManager textureManager = client.getTextureManager(); + + // Force upload each texture to GPU + for (int i = 0; i < 6; i++) { + String var10001 = PANORAMA.getPath(); + Identifier tex = PANORAMA.withPath(var10001 + "_" + i + ".png"); + ResourceTexture resourceTexture = new ResourceTexture(tex); + textureManager.registerTexture(tex, resourceTexture); + } + } + public SaturnScreen(String title) { super(Text.literal(title)); } public void draw(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); - } - - if (element.duration != null) { - new Thread(() -> { - try { - Animation fadeOut = new SlideXAbsolute(700, -(width - element.x)); - Thread.sleep(element.duration); - fadeOut.init(element); - Animation.executeSync((Float progress) -> { - fadeOut.tick(progress, element); - }, fadeOut.duration); - synchronized (elements) { - elements.remove(element); - } - - } catch (InterruptedException e) { - e.printStackTrace(); - } - }).start(); - } + ElementRenderer.draw(elements, element); } @Override @@ -78,10 +64,6 @@ public abstract class SaturnScreen extends Screen { width *= 2; height *= 2; ui(); // abstraction to render the saturn ui and also render extra stuff here - - Animation.execute((Float progress) -> { - blurProgress = progress; - }, blurDuration); } public abstract void ui(); @@ -89,20 +71,26 @@ public abstract class SaturnScreen extends Screen { @SuppressWarnings("deprecation") @Override public void render(DrawContext context, int mouseX, int mouseY, float delta) { + if (start == null) { + start = Instant.now(); + } + long elapsed = Duration.between(start, Instant.now()).toMillis(); + mouseX *= 2; mouseY *= 2; if (client.world == null && client.getCurrentServerEntry() == null) { - ROTATING_PANORAMA_RENDERER.render(context, this.width, this.height, 1.0F, delta); + ROTATING_PANORAMA_RENDERER.render(context, this.width, this.height, backgroundOpacity, delta); } PostEffectProcessor postEffectProcessor = this.client.getShaderLoader().loadPostEffect( - Identifier.ofVanilla("blur"), - DefaultFramebufferSet.MAIN_ONLY); - if (postEffectProcessor != null) { - postEffectProcessor.setUniforms("Radius", backgroundBlur * blurProgress); - postEffectProcessor.render(this.client.getFramebuffer(), this.pool); - } + Identifier.ofVanilla("blur"), + DefaultFramebufferSet.MAIN_ONLY); + + if (postEffectProcessor != null) { + postEffectProcessor.setUniforms("Radius", backgroundBlur * Math.min((float) elapsed / 700, 1.0f)); + postEffectProcessor.render(this.client.getFramebuffer(), this.pool); + } // We are using a Abstracted RenderScope because older minecraft versions don't // use DrawContext @@ -113,7 +101,7 @@ public abstract class SaturnScreen extends Screen { renderScope.matrices.scale(0.5f, 0.5f, 0.5f); - ElementRenderer.render(new ArrayList<>(elements), renderScope, mouseX, mouseY); + ElementRenderer.render(new ArrayList<>(elements), elapsed, renderScope, mouseX, mouseY); renderScope.matrices.pop(); } @@ -128,6 +116,26 @@ public abstract class SaturnScreen extends Screen { return false; } + @Override + public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + mouseX *= 2; + mouseY *= 2; + + ElementRenderer.mouseDragged(elements, mouseX, mouseY, button, deltaX, deltaY); + + return super.mouseReleased(mouseX, mouseY, button); + } + + @Override + public boolean mouseReleased(double mouseX, double mouseY, int button) { + mouseX *= 2; + mouseY *= 2; + + ElementRenderer.mouseReleased(elements, mouseX, mouseY, button); + + return super.mouseReleased(mouseX, mouseY, button); + } + @Override public boolean mouseScrolled( double mouseX, diff --git a/src/main/java/org/saturnclient/ui2/Utils.java b/src/main/java/org/saturnclient/ui2/Utils.java index 98dcc27..6e3efb2 100644 --- a/src/main/java/org/saturnclient/ui2/Utils.java +++ b/src/main/java/org/saturnclient/ui2/Utils.java @@ -51,7 +51,6 @@ public class Utils { } public static T getOrNull(List list, int index) { - SaturnClient.LOGGER.info("Accessing index {} in list of size {}", index, list.size()); return (index >= 0 && index < list.size()) ? list.get(index) : null; } diff --git a/src/main/java/org/saturnclient/ui2/anim/Animation.java b/src/main/java/org/saturnclient/ui2/anim/Animation.java index d1ed85d..5fa328b 100644 --- a/src/main/java/org/saturnclient/ui2/anim/Animation.java +++ b/src/main/java/org/saturnclient/ui2/anim/Animation.java @@ -1,75 +1,16 @@ package org.saturnclient.ui2.anim; -import java.util.function.Consumer; -import java.util.function.Function; - import org.saturnclient.ui2.Element; public abstract class Animation { public int duration; + public int delay = 0; Animation(int duration) { this.duration = duration; } - public abstract void tick(float progress, Element element); + public abstract void tick(double progress, Element element); + public abstract void init(Element element); - - public static void execute(Consumer tick, int duration) { - new Thread(() -> { - Function curveFunction = Curve::easeInOutCubic; - float progress = 0.0f; - double incremental = (1000 - duration) / 10000.0; - - for (int i = 0; i <= 100; i++) { - float newProgress = (float) (double) curveFunction.apply(i / 100.0); - - while (Math.abs(newProgress - progress) > 1e-6) { - if (progress < newProgress) { - progress += incremental; - if (progress > newProgress) progress = newProgress; - } else { - progress -= incremental; - if (progress < newProgress) progress = newProgress; - } - - tick.accept(newProgress); - - try { - Thread.sleep(duration / 100); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - }).start(); - } - - public static void executeSync(Consumer tick, int duration) { - Function curveFunction = Curve::easeInOutCubic; - float progress = 0.0f; - double incremental = (1000 - duration) / 10000.0; - - for (int i = 0; i <= 100; i++) { - float newProgress = (float) (double) curveFunction.apply(i / 100.0); - - while (Math.abs(newProgress - progress) > 1e-6) { - if (progress < newProgress) { - progress += incremental; - if (progress > newProgress) progress = newProgress; - } else { - progress -= incremental; - if (progress < newProgress) progress = newProgress; - } - - tick.accept(newProgress); - - try { - Thread.sleep(duration / 100); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } } diff --git a/src/main/java/org/saturnclient/ui2/anim/Fade.java b/src/main/java/org/saturnclient/ui2/anim/Fade.java index 47dfd65..db75ae6 100644 --- a/src/main/java/org/saturnclient/ui2/anim/Fade.java +++ b/src/main/java/org/saturnclient/ui2/anim/Fade.java @@ -10,13 +10,13 @@ public class Fade extends Animation { } @Override - public void tick(float progress, Element element) { - element.opacity = targetOpacity * progress; + public void tick(double progress, Element element) { + element.opacity = Math.max(0.1f, targetOpacity * (float) progress); } @Override public void init(Element element) { targetOpacity = element.opacity; - element.opacity = 0; + element.opacity = 0.1f; } } diff --git a/src/main/java/org/saturnclient/ui2/anim/FadeOut.java b/src/main/java/org/saturnclient/ui2/anim/FadeOut.java index a1fb42a..77d93f6 100644 --- a/src/main/java/org/saturnclient/ui2/anim/FadeOut.java +++ b/src/main/java/org/saturnclient/ui2/anim/FadeOut.java @@ -10,8 +10,8 @@ public class FadeOut extends Animation { } @Override - public void tick(float progress, Element element) { - element.opacity = targetOpacity - progress; + public void tick(double progress, Element element) { + element.opacity = targetOpacity - (float) progress; } @Override diff --git a/src/main/java/org/saturnclient/ui2/anim/SlideFade.java b/src/main/java/org/saturnclient/ui2/anim/SlideFade.java new file mode 100644 index 0000000..c407cc0 --- /dev/null +++ b/src/main/java/org/saturnclient/ui2/anim/SlideFade.java @@ -0,0 +1,32 @@ +package org.saturnclient.ui2.anim; + +import org.saturnclient.ui2.Element; + +public class SlideFade extends Animation { + public Fade fade; + public SlideY slideY; + + public SlideFade(int duration, int offset) { + super(duration); + this.fade = new Fade(duration); + this.slideY = new SlideY(duration, offset); + } + + @Override + public void tick(double progress, Element element) { + fade.delay = this.delay; + fade.duration = this.duration; + + slideY.delay = this.delay; + slideY.duration = this.duration; + + fade.tick(progress, element); + slideY.tick(progress, element); + } + + @Override + public void init(Element element) { + fade.init(element); + slideY.init(element); + } +} diff --git a/src/main/java/org/saturnclient/ui2/anim/SlideX.java b/src/main/java/org/saturnclient/ui2/anim/SlideX.java index 595c412..58d5e8c 100644 --- a/src/main/java/org/saturnclient/ui2/anim/SlideX.java +++ b/src/main/java/org/saturnclient/ui2/anim/SlideX.java @@ -24,7 +24,7 @@ public class SlideX extends Animation { } @Override - public void tick(float progress, Element element) { + public void tick(double progress, Element element) { element.x = elementX + (int) (offset * progress); } diff --git a/src/main/java/org/saturnclient/ui2/anim/SlideXAbsolute.java b/src/main/java/org/saturnclient/ui2/anim/SlideXAbsolute.java index ace746f..75a3121 100644 --- a/src/main/java/org/saturnclient/ui2/anim/SlideXAbsolute.java +++ b/src/main/java/org/saturnclient/ui2/anim/SlideXAbsolute.java @@ -24,7 +24,7 @@ public class SlideXAbsolute extends Animation { } @Override - public void tick(float progress, Element element) { + public void tick(double progress, Element element) { element.x = elementX + (int) (offset * progress); } diff --git a/src/main/java/org/saturnclient/ui2/anim/SlideY.java b/src/main/java/org/saturnclient/ui2/anim/SlideY.java index 48ca61b..5ca5a97 100644 --- a/src/main/java/org/saturnclient/ui2/anim/SlideY.java +++ b/src/main/java/org/saturnclient/ui2/anim/SlideY.java @@ -5,7 +5,7 @@ import org.saturnclient.ui2.Element; public class SlideY extends Animation { int offset = 20; int maxOffset = 20; - int elementY; + double startY; public SlideY(int duration) { super(duration); @@ -24,15 +24,16 @@ public class SlideY extends Animation { this.offset = offset; this.maxOffset = offset; } - - @Override - public void tick(float progress, Element element) { - element.y = elementY + (int) (offset * progress); - } @Override public void init(Element element) { - element.y -= offset; - elementY = element.y; + startY = element.y - offset; + element.y = (int) startY; + } + + @Override + public void tick(double progress, Element element) { + double currentY = startY + offset * progress; + element.y = (int) currentY; } } diff --git a/src/main/java/org/saturnclient/ui2/components/CosmeticPreview.java b/src/main/java/org/saturnclient/ui2/components/CosmeticPreview.java index 55d9e99..49ace16 100644 --- a/src/main/java/org/saturnclient/ui2/components/CosmeticPreview.java +++ b/src/main/java/org/saturnclient/ui2/components/CosmeticPreview.java @@ -1,7 +1,6 @@ package org.saturnclient.ui2.components; -import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; @@ -10,13 +9,7 @@ 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 bgColor = theme.property("bg-color", Property.color(0x89000000)); - private static Property fgColor = theme.property("fg-color", Property.color(0xFFFFFFFF)); - private static Property padding = theme.property("padding", Property.integer(14)); - private static Property cornerRadius = theme.property("corner-radius", Property.integer(10)); - - static {} + static int padding = 14; Identifier sprite; private Runnable onClick; @@ -30,25 +23,19 @@ public class CosmeticPreview extends Element { 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, Theme.WIDGET_RADIUS.value, + isSelected ? Theme.ACCENT.value : Theme.PRIMARY.value); - 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); + int texWidth = width - padding; + int texHeight = height - padding; - theme.setState(null); + renderScope.drawTexture(sprite, padding / 2, padding / 2, 0, 0, texWidth, texHeight, + Theme.FOREGROUND.value); } @Override diff --git a/src/main/java/org/saturnclient/ui2/components/ElementRenderer.java b/src/main/java/org/saturnclient/ui2/components/ElementRenderer.java index d7b9a02..30842a1 100644 --- a/src/main/java/org/saturnclient/ui2/components/ElementRenderer.java +++ b/src/main/java/org/saturnclient/ui2/components/ElementRenderer.java @@ -7,30 +7,27 @@ 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 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 elements, RenderScope renderScope, int mouseX, int mouseY) { + public static void render(List elements, long elapsed, RenderScope renderScope, int mouseX, int mouseY) { for (Element element : elements) { + element.playAnimationFrame(elapsed); + 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)); + element.render(renderScope, new ElementContext(elapsed, mouseX, mouseY, element)); renderScope.matrices.pop(); renderScope.setRenderLayer(null); } @@ -44,7 +41,10 @@ public class ElementRenderer { 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.mouseClicked(adjustedMouseX * element.scale, adjustedMouseY * element.scale, button); + + 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)); } @@ -58,16 +58,17 @@ public class ElementRenderer { 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); - } - } + 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 elements, int keyCode, int scanCode, int modifiers) { for (Element element : new ArrayList<>(elements)) { @@ -81,4 +82,17 @@ public class ElementRenderer { } } } + + public static void mouseDragged(List elements, double mouseX, double mouseY, int button, double deltaX, + double deltaY) { + for (Element element : new ArrayList<>(elements)) { + element.mouseDragged(mouseX - element.x, mouseY - element.y, button, deltaX, deltaY); + } + } + + public static void mouseReleased(List elements, double mouseX, double mouseY, int button) { + for (Element element : new ArrayList<>(elements)) { + element.mouseReleased(mouseX - element.x, mouseY - element.y, button); + } + } } diff --git a/src/main/java/org/saturnclient/ui2/components/SaturnModule.java b/src/main/java/org/saturnclient/ui2/components/SaturnModule.java index a9c0059..21c8b1c 100644 --- a/src/main/java/org/saturnclient/ui2/components/SaturnModule.java +++ b/src/main/java/org/saturnclient/ui2/components/SaturnModule.java @@ -2,8 +2,7 @@ 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.saturnclient.config.Theme; import org.saturnclient.ui2.resources.Fonts; import org.saturnclient.ui2.resources.Textures; import org.saturnclient.ui2.Element; @@ -15,23 +14,12 @@ 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 bgColor = theme.property("bg", Property.color(0xFF1d202d)); - private static Property fgColor = theme.property("fg", Property.color(0xFFA1A2B8)); - private static Property iconFg = theme.property("icon-fg", Property.color(0xFFA1A2B8)); - private static Property iconBg = theme.property("icon-bg", Property.color(0xFF2e3248)); - private static Property tagBg = theme.property("tag-bg", Property.color(0xFF2e3248)); - private static Property iconRadius = theme.property("icon-radius", Property.color(10)); - private static Property font = theme.property("font", Property.font(1)); - private static Property radius = theme.property("radius", Property.color(10)); - static { - theme.propertyStateDefault("enabled", "bg", 0xFF1d202d); - theme.propertyStateDefault("enabled", "icon-bg", 0xFF845eee); - theme.propertyStateDefault("hovering", "fg", 0xFF845eee); - } + private final Module mod; - private Module mod; + static int p = 10; // padding + static int s = 14; // settings icon size + static int expand = 5; // settings icon click area public SaturnModule(Module mod) { this.mod = mod; @@ -41,60 +29,137 @@ public class SaturnModule extends Element { @Override public void render(RenderScope renderScope, ElementContext ctx) { - int p = 10; - int s = 14; - boolean settingsHover = false; + boolean hovered = ctx.isHovering(); + boolean enabled = mod.isEnabled(); + + int iconX = width - s - p; + int iconY = height - s - p; + + boolean settingsHover = ctx.isHovering( + getSettingsX(), + getSettingsY(), + getSettingsHitBox(), + getSettingsHitBox()); renderScope.setRenderLayer(RenderLayer::getGuiTextured); - if (mod.isEnabled()) { - theme.setState("enabled"); - } + // Resolve theme colors + int bgColor = Theme.PRIMARY.value; + int fgColor = hovered && !settingsHover ? Theme.ACCENT.value : Theme.PRIMARY_FG.value; - if (ctx.isHovering(width - s - p - 5, height - s - p - 5, s + 10, s + 10)) { - settingsHover = true; - } else if (ctx.isHovering()) { - theme.applyState("hovering"); - } + int iconBg = enabled ? Theme.ACCENT.value : Theme.PRIMARY.value; + int iconFg = enabled ? Theme.ACCENT_FG.value : fgColor; - renderScope.drawRoundedRectangle(0, 0, width, height, radius.value, bgColor.value); + int settingsColor = settingsHover + ? Theme.ACCENT.value + : Theme.withAlpha(160, fgColor); - int h = height-(p * 2); + int h = height - (p * 2); - renderScope.drawRoundedRectangle(p, p, h, h, iconRadius.value, iconBg.value); + // Main background + renderScope.drawRoundedRectangle( + 0, 0, + width, height, + Theme.WIDGET_RADIUS.value, + bgColor); - renderScope.drawTexture(mod.getIconTexture(), p + (p / 2), p + (p / 2), 0, 0, h - p, h - p, iconFg.value); + // Icon background + renderScope.drawRoundedRectangle( + p, p, + h, h, + Theme.WIDGET_RADIUS.value, + iconBg); - renderScope.drawText(0.6f, mod.getName(), p+h+4, p + 1, font.value, fgColor.value); + // Icon + renderScope.drawTexture( + mod.getIconTexture(), + p + (p / 2), + p + (p / 2), + 0, 0, + h - p, + h - p, + iconFg); - renderScope.drawText(0.35f, mod.getVersion(), width - p - (int) (Fonts.getWidth(mod.getVersion(), font.value) * 0.35f), p + 1, font.value, fgColor.value); + // Module name + renderScope.drawText( + 0.6f, + mod.getName(), + p + h + 4, + p + 1, + Theme.FONT.value, + fgColor); + // Version (right aligned) + String version = mod.getVersion(); + int versionWidth = (int) (Fonts.getWidth(version, Theme.FONT.value) * 0.35f); + + renderScope.drawText( + 0.35f, + version, + width - p - versionWidth, + p + 1, + Theme.FONT.value, + fgColor); + + // Tags int xt = p + h + 4; for (String tag : mod.getTags()) { - int xtb = (int) (Fonts.getWidth(tag, font.value) * 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, font.value, fgColor.value); - xt += xtb + 9; + int tagWidth = (int) (Fonts.getWidth(tag, Theme.FONT.value) * 0.4f); + + renderScope.drawRoundedRectangle( + xt, + p + (h / 2), + tagWidth + 6, + 12, + 5, + Theme.ACCENT.value); + + renderScope.drawText( + 0.4f, + tag, + xt + 2, + p + (h / 2) + 3, + Theme.FONT.value, + Theme.ACCENT_FG.value); + + xt += tagWidth + 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); + // Settings icon + renderScope.drawTexture( + Textures.SETTINGS, + iconX, + iconY, + 0, 0, + s, s, + settingsColor); } @Override public void click(int mouseX, int mouseY) { - int p = 10; - int s = 14; + boolean settingsHover = Utils.isHovering( + mouseX - getSettingsX(), + mouseY - getSettingsY(), + getSettingsHitBox(), + getSettingsHitBox(), + 1.0f); - if (Utils.isHovering(mouseX - (width - s - p - 5), mouseY - (height - s - p - 5), s + 10, s + 10, 1.0f)) { + if (settingsHover) { SaturnClient.client.setScreen(new ConfigEditor(mod.getConfig())); } else { mod.setEnabled(!mod.isEnabled()); } } -} + + private int getSettingsX() { + return width - s - p - expand; + } + + private int getSettingsY() { + return height - s - p - expand; + } + + private int getSettingsHitBox() { + return s + expand * 2; + } +} \ No newline at end of file diff --git a/src/main/java/org/saturnclient/ui2/components/Sidebar.java b/src/main/java/org/saturnclient/ui2/components/Sidebar.java index 0a93dff..7d6e002 100644 --- a/src/main/java/org/saturnclient/ui2/components/Sidebar.java +++ b/src/main/java/org/saturnclient/ui2/components/Sidebar.java @@ -1,9 +1,8 @@ package org.saturnclient.ui2.components; import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.SaturnClientConfig; -import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.SaturnClientConfig; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.resources.Textures; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; @@ -18,19 +17,6 @@ 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 bgColor = theme.property("bg-color", Property.color(0x90000000)); - private static Property iconFg = theme.property("icon-fg", Property.color(0xFFFFFFFF)); - private static Property iconBg = theme.property("icon-bg", Property.color(0x00000000)); - - private static Property cornerRadius = theme.property("corner-radius", Property.integer(10)); - private static Property iconRadius = theme.property("icon-radius", Property.integer(10)); - private static Property padding = theme.property("padding", Property.integer(10)); - - static { - theme.propertyStateDefault("hovering", "icon-bg", -7643914); - } - public static class SidebarComponent { Runnable onClick; boolean end; @@ -45,7 +31,7 @@ public class Sidebar extends Element { Runnable onClose; SidebarComponent[] components = { - new Sidebar.SidebarComponent(Textures.MODS_TAB, () -> { + new Sidebar.SidebarComponent(Textures.MODS_TAB, () -> { SaturnClient.client.setScreen(new ModMenu()); }, false), new Sidebar.SidebarComponent(Textures.SETTINGS, () -> { @@ -79,36 +65,29 @@ public class Sidebar extends Element { int bottomRow = 0; int gap = 5; // 5px gap between icons - int sp = 30 - padding.value + gap; - int s = 30 - (padding.value * 2); - int s2 = s + padding.value; + int padding = 10; + int sp = 30 - padding + gap; + int s = 30 - (padding * 2); + int s2 = s + padding; renderScope.setRenderLayer(RenderLayer::getGuiTextured); - renderScope.drawRoundedRectangle(0, 0, width, height, cornerRadius.value, bgColor.value); + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.BG_RADIUS.value, Theme.BACKGROUND.value); int i = 0; for (SidebarComponent component : components) { + int y = component.end ? ((height - (sp * bottomRow)) - (s * 2)) : (padding + (sp * topRow)); + boolean selected = ctx.isHovering(0, y - (padding / 2), s2, s2) || active == i; + + renderScope.drawRoundedRectangle(padding / 2, y - (padding / 2), s + padding, + s + padding, Theme.WIDGET_RADIUS.value, Theme.getBg(selected)); + + renderScope.drawTexture(component.sprite, padding, y, 0, 0, s, s, Theme.getFg(selected)); + 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; } @@ -121,25 +100,24 @@ public class Sidebar extends Element { int topRow = 0; int bottomRow = 0; - int gap = 5; // same 5px gap here - int sp = 30 - padding.value + gap; - int s = 30 - (padding.value * 2); - int s2 = s + padding.value; + int gap = 5; + int padding = 10; + int sp = 30 - padding + gap; + int s = 30 - (padding * 2); + int s2 = s + padding; for (SidebarComponent component : components) { + int y = component.end ? ((height - (sp * bottomRow)) - (s * 2)) : (padding + (sp * topRow)); + boolean hovering = Utils.isHovering(mouseX - (padding / 2), mouseY - (y - (padding / 2)), s2, s2, scale); + + if (hovering) { + component.onClick.run(); + break; + } + if (component.end) { - int y = (height - (sp * bottomRow)) - (s * 2); - if (Utils.isHovering(mouseX - (padding.value / 2), mouseY - (y - (padding.value / 2)), s2, s2, scale)) { - component.onClick.run(); - break; - } bottomRow += 1; } else { - int y = padding.value + (sp * topRow); - if (Utils.isHovering(mouseX - (padding.value / 2), mouseY - (y - (padding.value / 2)), s2, s2, scale)) { - component.onClick.run(); - break; - } topRow += 1; } } diff --git a/src/main/java/org/saturnclient/ui2/components/dialog/ColorDialog.java b/src/main/java/org/saturnclient/ui2/components/dialog/ColorDialog.java deleted file mode 100644 index 9567218..0000000 --- a/src/main/java/org/saturnclient/ui2/components/dialog/ColorDialog.java +++ /dev/null @@ -1,246 +0,0 @@ -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 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 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; - } -} diff --git a/src/main/java/org/saturnclient/ui2/components/inputs/HexInput.java b/src/main/java/org/saturnclient/ui2/components/inputs/HexInput.java index 025bfd9..aa49018 100644 --- a/src/main/java/org/saturnclient/ui2/components/inputs/HexInput.java +++ b/src/main/java/org/saturnclient/ui2/components/inputs/HexInput.java @@ -1,32 +1,183 @@ package org.saturnclient.ui2.components.inputs; -import org.saturnclient.saturnclient.SaturnClient; +import java.awt.Color; + 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 prop; - public SaturnScreen screen; - public HexInput(Property prop, SaturnScreen screen) { + // Picker state + private boolean open = false; + private float hue = 0f; + private float opacity = 1f; + private int selectedX = 0; + private int selectedY = 0; + + private boolean draggingOpacity = false; + + // Dimensions + private static final int PICKER_WIDTH = 100; + private static final int PICKER_HEIGHT = 100; + private static final int SLIDER_WIDTH = 100; + private static final int SLIDER_HEIGHT = 10; + private static final int HUE_SLIDER_HEIGHT = 10; + + public HexInput(Property prop) { + this.prop = prop; this.width = 58; this.height = 20; - this.prop = prop; - this.scale = 0.8f; - this.screen = screen; + syncFromColor(); } @Override public void click(int mouseX, int mouseY) { - SaturnClient.client.setScreen(new ColorDialog(prop, screen)); + open = !open; + } + + @Override + public void mouseClicked(double mouseX, double mouseY, int button) { + if (open) { + handlePickerClick(mouseX - width - 8, mouseY); + } + } + + @Override + public void mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + if (open) { + handlePickerDrag(mouseX - width - 8, mouseY); + } + } + + @Override + public void mouseReleased(double mouseX, double mouseY, int button) { + draggingOpacity = false; } @Override public void render(RenderScope renderScope, ElementContext ctx) { - renderScope.drawRoundedRectangle(0, 0, width, height, 17, prop.value); + // Draw the main color rectangle + renderScope.drawRoundedRectangle(0, 0, width, height, 6, prop.value); + + if (!open) + return; + + // Draw the picker relative to (width + 8, 0) + int pickerX = width + 8; + int pickerY = 0; + + renderColorSquare(renderScope, pickerX, pickerY); + renderOpacitySlider(renderScope, pickerX, pickerY - SLIDER_HEIGHT - 10); + renderHueSlider(renderScope, pickerX, pickerY + PICKER_HEIGHT + 10); } -} + + private void renderColorSquare(RenderScope renderScope, int xStart, int yStart) { + for (int x = 0; x < PICKER_WIDTH; x++) { + for (int y = 0; y < PICKER_HEIGHT; y++) { + float saturation = x / (float) PICKER_WIDTH; + float value = 1f - y / (float) PICKER_HEIGHT; + int color = Color.HSBtoRGB(hue, saturation, value); + int alpha = (int) (opacity * 255) & 0xFF; + color = (alpha << 24) | (color & 0xFFFFFF); + renderScope.fill(xStart + x, yStart + y, xStart + x + 1, yStart + y + 1, color); + } + } + + // Draw selection square + int selX = xStart + selectedX - 4; + int selY = yStart + selectedY - 4; + renderScope.fill(selX, selY, selX + 8, selY + 8, 0xFF000000 | prop.value); + renderScope.drawBorder(selX, selY, 8, 8, 0xFFFFFFFF); + } + + private void renderOpacitySlider(RenderScope renderScope, int xStart, int yStart) { + 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); + renderScope.fill(xStart + x, yStart, xStart + x + 1, yStart + SLIDER_HEIGHT, color); + } + + int knobX = xStart + (int) (opacity * SLIDER_WIDTH); + renderScope.fill(knobX - 1, yStart - 2, knobX + 1, yStart + SLIDER_HEIGHT + 2, 0xFF000000); + } + + private void renderHueSlider(RenderScope renderScope, int xStart, int yStart) { + for (int x = 0; x < SLIDER_WIDTH; x++) { + float localHue = x / (float) SLIDER_WIDTH; + int color = Color.HSBtoRGB(localHue, 1f, 1f); + renderScope.fill(xStart + x, yStart, xStart + x + 1, yStart + HUE_SLIDER_HEIGHT, 0xFF000000 | color); + } + + int knobX = xStart + (int) (hue * SLIDER_WIDTH); + renderScope.fill(knobX - 1, yStart - 2, knobX + 1, yStart + HUE_SLIDER_HEIGHT + 2, 0xFF000000); + } + + private void handlePickerClick(double mouseX, double mouseY) { + // Color square + if (mouseX >= 0 && mouseX < PICKER_WIDTH && mouseY >= 0 && mouseY < PICKER_HEIGHT) { + selectedX = (int) mouseX; + selectedY = (int) mouseY; + updateColorFromSelection(); + } + + // Opacity slider + int opY = -SLIDER_HEIGHT - 10; + if (mouseX >= 0 && mouseX < SLIDER_WIDTH && mouseY >= opY && mouseY <= opY + SLIDER_HEIGHT) { + updateOpacity(mouseX); + draggingOpacity = true; + } + + // Hue slider + int hueY = PICKER_HEIGHT + 10; + if (mouseX >= 0 && mouseX < SLIDER_WIDTH && mouseY >= hueY && mouseY <= hueY + HUE_SLIDER_HEIGHT) { + updateHue(mouseX); + } + } + + private void handlePickerDrag(double mouseX, double mouseY) { + // Opacity + if (draggingOpacity) + updateOpacity(mouseX); + + // Color square + if (mouseX >= 0 && mouseX < PICKER_WIDTH && mouseY >= 0 && mouseY < PICKER_HEIGHT) { + selectedX = (int) mouseX; + selectedY = (int) mouseY; + updateColorFromSelection(); + } + } + + private void updateColorFromSelection() { + float saturation = selectedX / (float) PICKER_WIDTH; + float value = 1f - selectedY / (float) PICKER_HEIGHT; + int color = Color.HSBtoRGB(hue, saturation, value); + int alpha = (int) (opacity * 255) & 0xFF; + prop.value = (alpha << 24) | (color & 0xFFFFFF); + } + + private void updateHue(double mouseX) { + hue = (float) Math.max(0, Math.min(1, mouseX / SLIDER_WIDTH)); + updateColorFromSelection(); + } + + private void updateOpacity(double mouseX) { + opacity = (float) Math.max(0, Math.min(1, mouseX / SLIDER_WIDTH)); + updateColorFromSelection(); + } + + private void syncFromColor() { + int rgb = prop.value & 0xFFFFFF; + float[] hsb = Color.RGBtoHSB((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF, null); + hue = hsb[0]; + selectedX = (int) (hsb[1] * PICKER_WIDTH); + selectedY = (int) ((1f - hsb[2]) * PICKER_HEIGHT); + int alpha = (prop.value >> 24) & 0xFF; + if (alpha == 0) + alpha = 255; + opacity = alpha / 255f; + } +} \ No newline at end of file diff --git a/src/main/java/org/saturnclient/ui2/components/inputs/Input.java b/src/main/java/org/saturnclient/ui2/components/inputs/Input.java index 99997e4..fbd48d9 100644 --- a/src/main/java/org/saturnclient/ui2/components/inputs/Input.java +++ b/src/main/java/org/saturnclient/ui2/components/inputs/Input.java @@ -2,21 +2,20 @@ package org.saturnclient.ui2.components.inputs; import org.lwjgl.glfw.GLFW; import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; 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 { - private static ThemeManager theme = new ThemeManager("Input"); - private static Property font = theme.property("font", Property.font(1)); - String text = ""; public int cursorPosition = 0; + public abstract void checkReset(); + public abstract void backspace(); + public boolean validateBackspace() { return true; } @@ -71,11 +70,12 @@ public abstract class Input extends Element { int scrollOffset = getScrollOffset(); String visibleText = getVisibleText(scrollOffset); int textColor = focused ? 0xFFFFFF : 0xAAAAAA; - renderScope.drawText(0.6f, visibleText, 4, 4, font.value, textColor); + renderScope.drawText(0.6f, visibleText, 4, 4, Theme.FONT.value, textColor); if (focused) { int cursorX = 4 + - (int) (Fonts.getWidth(visibleText.substring(0, cursorPosition - scrollOffset), font.value) * 0.6f); + (int) (Fonts.getWidth(visibleText.substring(0, cursorPosition - scrollOffset), Theme.FONT.value) + * 0.6f); renderScope.drawRect(cursorX, 2, 1, height - 4, 0xFFFFFFFF); } @@ -90,7 +90,7 @@ public abstract class Input extends Element { int maxWidth = width - 4; // Available width for text while (offset < cursorPosition) { // Ensure cursor remains visible String visibleText = text.substring(offset, cursorPosition); - if (Fonts.getWidth(visibleText, font.value) > maxWidth) { + if (Fonts.getWidth(visibleText, Theme.FONT.value) > maxWidth) { offset++; } else { break; @@ -104,7 +104,7 @@ public abstract class Input extends Element { // Ensure text does not overflow past the available width for (int i = 1; i <= visibleText.length(); i++) { - if (Fonts.getWidth(visibleText.substring(0, i), font.value) > width - 4) { + if (Fonts.getWidth(visibleText.substring(0, i), Theme.FONT.value) > width - 4) { return visibleText.substring(0, i - 1); // Trim overflow } } diff --git a/src/main/java/org/saturnclient/ui2/components/inputs/KeybindingSelector.java b/src/main/java/org/saturnclient/ui2/components/inputs/KeybindingSelector.java index c4f07ad..f85d76e 100644 --- a/src/main/java/org/saturnclient/ui2/components/inputs/KeybindingSelector.java +++ b/src/main/java/org/saturnclient/ui2/components/inputs/KeybindingSelector.java @@ -2,15 +2,13 @@ package org.saturnclient.ui2.components.inputs; import org.lwjgl.glfw.GLFW; import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; import org.saturnclient.ui2.resources.Fonts; public class KeybindingSelector extends Element { - private static ThemeManager theme = new ThemeManager("Input"); - private static Property font = theme.property("font", Property.font(1)); Property prop; public KeybindingSelector(Property prop) { @@ -23,9 +21,12 @@ public class KeybindingSelector extends Element { public void render(RenderScope renderScope, ElementContext ctx) { int textColor = focused ? 0xFFFFFF : 0xAAAAAA; renderScope.drawRoundedRectangle(0, 0, width, height, 10, 0xFF000000); - renderScope.drawText(0.6f, prop.value == -1 ? "" : - GLFW.glfwGetKeyName(prop.value, GLFW.glfwGetKeyScancode(prop.value)).toUpperCase(), - 4, 4, font.value, textColor); + String name = GLFW.glfwGetKeyName(prop.value, GLFW.glfwGetKeyScancode(prop.value)); + + renderScope.drawText(0.6f, + prop.value == -1 ? "" + : name != null ? name.toUpperCase() : "", + 4, 4, Theme.FONT.value, textColor); } @Override diff --git a/src/main/java/org/saturnclient/ui2/components/inputs/Select.java b/src/main/java/org/saturnclient/ui2/components/inputs/Select.java index c4d207c..31aeedf 100644 --- a/src/main/java/org/saturnclient/ui2/components/inputs/Select.java +++ b/src/main/java/org/saturnclient/ui2/components/inputs/Select.java @@ -1,7 +1,7 @@ package org.saturnclient.ui2.components.inputs; import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; @@ -10,11 +10,6 @@ import org.saturnclient.ui2.resources.Fonts; import net.minecraft.client.render.RenderLayer; public class Select extends Element { - private static ThemeManager theme = new ThemeManager("Toggle"); - private static Property fgColor = theme.property("fg-color", Property.color(0xAAAAAA)); - private static Property arrowColor = theme.property("arrow-color", Property.color(0xff8B5CF6)); - private static Property font = theme.property("font", Property.font(1)); - private Property prop; public Select(Property prop) { @@ -27,15 +22,14 @@ public class Select extends Element { public void render(RenderScope renderScope, ElementContext ctx) { renderScope.setRenderLayer(RenderLayer::getGuiTextured); - renderScope.drawText(0.8f, "<", 0, 0, font.value, arrowColor.value); + renderScope.drawText(0.8f, "<", 0, 0, Theme.FONT.value, Theme.FOREGROUND.value); String text = prop.getSelection(); - renderScope.drawText(0.6f, text, (int) (width - ((float) Fonts.getWidth(text, font.value) * 0.6f)) / 2, 1, font.value, fgColor.value); + renderScope.drawText(0.6f, text, (int) (width - ((float) Fonts.getWidth(text, Theme.FONT.value) * 0.6f)) / 2, 1, + Theme.FONT.value, Theme.FOREGROUND.value); - renderScope.drawText(0.8f, ">", width - 10, 0, font.value, arrowColor.value); - - theme.setState(null); + renderScope.drawText(0.8f, ">", width - 10, 0, Theme.FONT.value, Theme.FOREGROUND.value); } @Override diff --git a/src/main/java/org/saturnclient/ui2/components/inputs/Toggle.java b/src/main/java/org/saturnclient/ui2/components/inputs/Toggle.java index 5436d42..e692ad9 100644 --- a/src/main/java/org/saturnclient/ui2/components/inputs/Toggle.java +++ b/src/main/java/org/saturnclient/ui2/components/inputs/Toggle.java @@ -1,22 +1,12 @@ package org.saturnclient.ui2.components.inputs; import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; 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 bgColor = theme.property("bg-color", Property.color(0xFF808080)); - private static Property fgColor = theme.property("fg-color", Property.color(0xFF909090)); - private static Property cornerRadius = theme.property("corner-radius", Property.integer(30)); - - static { - theme.propertyStateDefault("enabled", "bg-color", 0xaf8B5CF6); - theme.propertyStateDefault("enabled", "fg-color", 0xff8B5CF6); - } - private Property prop; public Toggle(Property prop) { @@ -27,19 +17,10 @@ public class Toggle extends Element { @Override public void render(RenderScope renderScope, ElementContext ctx) { - theme.setState(null); - - 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); + renderScope.drawRoundedRectangle(0, 0, width, height, height, + Theme.withAlpha(0.5f, prop.value ? Theme.ACCENT.value : Theme.PRIMARY.value)); + renderScope.drawRoundedRectangle(prop.value ? 30 : 0, 0, 30, 30, 30, + prop.value ? Theme.ACCENT.value : Theme.PRIMARY.value); } @Override diff --git a/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java b/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java new file mode 100644 index 0000000..3865481 --- /dev/null +++ b/src/main/java/org/saturnclient/ui2/elements/AnimationStagger.java @@ -0,0 +1,58 @@ +package org.saturnclient.ui2.elements; + +import java.util.ArrayList; +import java.util.List; + +import org.saturnclient.saturnclient.config.SaturnClientConfig; +import org.saturnclient.ui2.Element; +import org.saturnclient.ui2.ElementContext; +import org.saturnclient.ui2.RenderScope; +import org.saturnclient.ui2.components.ElementRenderer; + +public class AnimationStagger extends Element { + protected List children = new ArrayList<>(); + public int delay; + + public AnimationStagger(int delay) { + this.delay = delay; + } + + public void draw(Element element) { + if (!SaturnClientConfig.stagger.value) { + element.animation = null; + } + + if (element.animation != null) { + element.animation.delay = delay * children.size(); + } + + ElementRenderer.draw(children, element); + } + + @Override + public void render(RenderScope renderScope, ElementContext ctx) { + ElementRenderer.render(children, ctx.elapsed, renderScope, + ctx.mouseX, + ctx.mouseY); + } + + @Override + public void mouseClicked(double mouseX, double mouseY, int button) { + ElementRenderer.mouseClicked(children, mouseX, mouseY, button); + } + + @Override + public void keyPressed(int keyCode, int scanCode, int modifiers) { + ElementRenderer.keyPressed(children, keyCode, scanCode, modifiers); + } + + @Override + public void mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + ElementRenderer.mouseDragged(children, mouseX, mouseY, button, deltaX, deltaY); + } + + @Override + public void mouseReleased(double mouseX, double mouseY, int button) { + ElementRenderer.mouseReleased(children, mouseX, mouseY, button); + } +} diff --git a/src/main/java/org/saturnclient/ui2/elements/Button.java b/src/main/java/org/saturnclient/ui2/elements/Button.java index 0b74643..4774f11 100644 --- a/src/main/java/org/saturnclient/ui2/elements/Button.java +++ b/src/main/java/org/saturnclient/ui2/elements/Button.java @@ -1,43 +1,29 @@ package org.saturnclient.ui2.elements; -import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; import org.saturnclient.ui2.resources.Fonts; public class Button extends Element { - private static ThemeManager theme = new ThemeManager("Button", "hovering"); - private static Property bgColor = theme.property("bg-color", Property.color(0xFF000000)); - private static Property fgColor = theme.property("fg-color", Property.color(0xFFFFFFFF)); - private static Property cornerRadius = theme.property("corner-radius", Property.integer(10)); - private static Property font = theme.property("font", Property.font(1)); - - static { - theme.propertyStateDefault("hovering", "fg-color", 0xFF845eee); - } - private String text; private Runnable onClick; public Button(String text, Runnable onClick) { this.text = text; this.onClick = onClick; - this.dimensions(Fonts.getWidth(text, font.value) + 50, 38); + this.dimensions(Fonts.getWidth(text, Theme.FONT.value) + 50, 38); } @Override public void render(RenderScope renderScope, ElementContext ctx) { - if (ctx.isHovering()) { - theme.setState("hovering"); - } else { - theme.setState(null); - } - renderScope.drawRoundedRectangle(0, 0, width, height, cornerRadius.value, bgColor.value); + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, + ctx.isHovering() ? Theme.ACCENT.value : Theme.PRIMARY.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, font.value), Fonts.centerY(height), font.value, fgColor.value); + renderScope.drawText(text, Fonts.centerX(width, text, Theme.FONT.value), Fonts.centerY(height), + Theme.FONT.value, + ctx.isHovering() ? Theme.ACCENT_FG.value : Theme.PRIMARY_FG.value); } @Override diff --git a/src/main/java/org/saturnclient/ui2/elements/ClickableTexture.java b/src/main/java/org/saturnclient/ui2/elements/ClickableTexture.java index 0a8aff1..877eeea 100644 --- a/src/main/java/org/saturnclient/ui2/elements/ClickableTexture.java +++ b/src/main/java/org/saturnclient/ui2/elements/ClickableTexture.java @@ -1,7 +1,6 @@ package org.saturnclient.ui2.elements; -import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; @@ -10,9 +9,6 @@ import net.minecraft.client.render.RenderLayer; import net.minecraft.util.Identifier; public class ClickableTexture extends Element { - private static ThemeManager theme = new ThemeManager("ClickableTexture", "hovering"); - private static Property fgColor = theme.property("fg-color", Property.color(0xFFFFFFFF)); - Identifier sprite; private Runnable onClick; @@ -20,17 +16,12 @@ public class ClickableTexture extends Element { this.sprite = sprite; this.onClick = onClick; } - + @Override public void render(RenderScope renderScope, ElementContext ctx) { - if (ctx.isHovering()) { - theme.setState("hovering"); - } else { - theme.setState(null); - } - renderScope.setRenderLayer(RenderLayer::getGuiTextured); - renderScope.drawTexture(sprite, 0, 0, 0, 0, width, height, fgColor.value); + renderScope.drawTexture(sprite, 0, 0, 0, 0, width, height, + ctx.isHovering() ? Theme.ACCENT.value : Theme.PRIMARY.value); } @Override diff --git a/src/main/java/org/saturnclient/ui2/elements/ImageTexture.java b/src/main/java/org/saturnclient/ui2/elements/ImageTexture.java index b5d9426..037ef31 100644 --- a/src/main/java/org/saturnclient/ui2/elements/ImageTexture.java +++ b/src/main/java/org/saturnclient/ui2/elements/ImageTexture.java @@ -3,8 +3,9 @@ package org.saturnclient.ui2.elements; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; +import org.saturnclient.ui2.resources.SvgTexture; -import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.MinecraftClient; import net.minecraft.util.Identifier; public class ImageTexture extends Element { @@ -16,7 +17,16 @@ public class ImageTexture extends Element { @Override public void render(RenderScope renderScope, ElementContext ctx) { - renderScope.setRenderLayer(RenderLayer::getGuiTextured); + if (sprite.toString().endsWith(".svg")) { + MinecraftClient client = MinecraftClient.getInstance(); + + // Get the actual window pixel dimensions for the image + int renderWidth = (int) (width * client.getWindow().getFramebufferWidth() / client.getWindow().getWidth()); + int renderHeight = (int) (height * client.getWindow().getFramebufferHeight() / client.getWindow().getHeight()); + + sprite = SvgTexture.getSvg(client, sprite, renderWidth * 2, renderHeight * 2); + } + renderScope.drawTexture(sprite, 0, 0, 0, 0, width, height); } } diff --git a/src/main/java/org/saturnclient/ui2/elements/Notification.java b/src/main/java/org/saturnclient/ui2/elements/Notification.java index 61916d0..0da60c7 100644 --- a/src/main/java/org/saturnclient/ui2/elements/Notification.java +++ b/src/main/java/org/saturnclient/ui2/elements/Notification.java @@ -1,7 +1,7 @@ package org.saturnclient.ui2.elements; import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; @@ -10,11 +10,9 @@ import org.saturnclient.ui2.resources.Fonts; import org.saturnclient.ui2.resources.Textures; public class Notification extends Element { - private static ThemeManager theme = new ThemeManager("Notification"); - private static Property bgColor = theme.property("bg-color", Property.color(0xFF000000)); - private static Property error = theme.property("error", Property.color(0xFFbf212f)); - private static Property info = theme.property("info", Property.color(0xFF264b96)); - private static Property success = theme.property("success", Property.color(0xFF27b376)); + private static Property error = Property.color(0xFFbf212f); + private static Property info = Property.color(0xFF264b96); + private static Property success = Property.color(0xFF27b376); public static enum NotificationKind { Error, @@ -40,7 +38,7 @@ public class Notification extends Element { @Override public void render(RenderScope renderScope, ElementContext ctx) { - renderScope.drawRoundedRectangle(0, 0, width, height, 10, bgColor.value); + renderScope.drawRoundedRectangle(0, 0, width, height, 10, Theme.PRIMARY.value); switch (kind) { case Error: renderScope.drawTexture(Textures.CIRCLE_X, 9, 9, 0, 0, 15, 15, error.value); diff --git a/src/main/java/org/saturnclient/ui2/elements/Scroll.java b/src/main/java/org/saturnclient/ui2/elements/Scroll.java index 2ba9295..b9c8848 100644 --- a/src/main/java/org/saturnclient/ui2/elements/Scroll.java +++ b/src/main/java/org/saturnclient/ui2/elements/Scroll.java @@ -4,22 +4,17 @@ import java.util.ArrayList; import java.util.List; import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; 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 bgColor = theme.property("bg-color", Property.color(0x90000000)); - private static Property scrollBarColor = theme.property("scrollbar-color", Property.color(-7643914)); + private static Property scrollBarRadius = Property.integer(10); + private static Property scrollBarWidth = Property.integer(5); + private static Property scrollBarPadding = Property.integer(5); - private static Property scrollBarRadius = theme.property("scrollbar-radius", Property.integer(10)); - private static Property scrollBarWidth = theme.property("scrollbar-width", Property.integer(5)); - private static Property scrollBarPadding = theme.property("scrollbar-padding", Property.integer(5)); - private static Property cornerRadius = theme.property("corner-radius", Property.integer(10)); - int padding = 0; protected List children = new ArrayList<>(); @@ -30,18 +25,37 @@ public class Scroll extends Element { this.padding = padding; } + public void draw(Element element) { + ElementRenderer.draw(children, element); + } + @Override public void render(RenderScope renderScope, ElementContext ctx) { - renderScope.drawRoundedRectangle(0, 0, width, height, cornerRadius.value, bgColor.value); + calculateMaxScroll(); + + renderScope.drawRoundedRectangle(0, 0, width, height, + Theme.BG_RADIUS.value, Theme.BACKGROUND.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.translate(padding, -scroll + padding, 0); + + ElementRenderer.render(children, ctx.elapsed, 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); + if (maxScroll > 0) { + renderScope.drawRoundedRectangle( + width - scrollBarWidth.value - scrollBarPadding.value, + calculateScrollBarY(), + scrollBarWidth.value, + calculateScrollBarHeight(), + scrollBarRadius.value, + Theme.SCROLL.value); + } } @Override @@ -54,15 +68,6 @@ public class Scroll extends Element { } } - @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); - } - @Override public Element dimensions(int width, int height) { super.dimensions(width, height); @@ -76,8 +81,9 @@ public class Scroll extends Element { } 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 + if (maxScroll <= 0) + return height - (scrollBarPadding.value * 2); + return Math.max(20, (height * height) / (height + maxScroll + 10)) - (scrollBarPadding.value * 2); } int calculateScrollBarY() { @@ -87,8 +93,38 @@ public class Scroll extends Element { return Math.min(y, height - scrollBarHeight - scrollBarPadding.value); } + private void calculateMaxScroll() { + maxScroll = 0; + + for (Element element : children) { + int bottom = element.y + element.height; + maxScroll = Math.max(maxScroll, bottom - height + padding); + } + + if (maxScroll > 0) { + maxScroll = maxScroll + 10; + } else { + maxScroll = 0; + } + } + @Override public void keyPressed(int keyCode, int scanCode, int modifiers) { ElementRenderer.keyPressed(children, keyCode, scanCode, modifiers); } + + @Override + public void mouseClicked(double mouseX, double mouseY, int button) { + ElementRenderer.mouseClicked(children, mouseX - padding, mouseY - padding + scroll, button); + } + + @Override + public void mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + ElementRenderer.mouseDragged(children, mouseX - padding, mouseY - padding + scroll, button, deltaX, deltaY); + } + + @Override + public void mouseReleased(double mouseX, double mouseY, int button) { + ElementRenderer.mouseReleased(children, mouseX - padding, mouseY - padding + scroll, button); + } } diff --git a/src/main/java/org/saturnclient/ui2/elements/TabMenu.java b/src/main/java/org/saturnclient/ui2/elements/TabMenu.java index e640106..b41757b 100644 --- a/src/main/java/org/saturnclient/ui2/elements/TabMenu.java +++ b/src/main/java/org/saturnclient/ui2/elements/TabMenu.java @@ -1,7 +1,6 @@ package org.saturnclient.ui2.elements; -import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; @@ -10,16 +9,6 @@ import org.saturnclient.ui2.Utils; import net.minecraft.util.Identifier; public class TabMenu extends Element { - private static ThemeManager theme = new ThemeManager("TabMenu", "hovering", "selected"); - private static Property bgColor = theme.property("bg-color", Property.color(0x90000000)); - private static Property iconFg = theme.property("icon-fg", Property.color(0xFFFFFFFF)); - private static Property iconBg = theme.property("icon-bg", Property.color(0x00000000)); - private static Property cornerRadius = theme.property("corner-radius", Property.integer(10)); - - static { - theme.propertyStateDefault("hovering", "icon-bg", -7643914); - } - public static class TabMenuComponent { Runnable onClick; Identifier sprite; @@ -29,7 +18,7 @@ public class TabMenu extends Element { this.sprite = sprite; } } - + TabMenuComponent[] components; public int selectedScreen = 0; @@ -42,19 +31,21 @@ public class TabMenu extends Element { @Override public void render(RenderScope renderScope, ElementContext ctx) { - renderScope.drawRoundedRectangle(0, 0, width, height, cornerRadius.value, bgColor.value); + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, Theme.PRIMARY.value); int col = 0; for (TabMenuComponent component : components) { int x = 25 * col + 5; - if (ctx.isHovering(x, 5, 20, 20) || selectedScreen == col) { - theme.setState("hovering"); + + boolean hovering = ctx.isHovering(x, 5, 20, 20) || selectedScreen == col; + + if (hovering) { + renderScope.drawRoundedRectangle(x, 5, 20, 20, Theme.WIDGET_RADIUS.value, Theme.ACCENT.value); } - renderScope.drawRoundedRectangle(x, 5, 20, 20, cornerRadius.value, iconBg.value); - renderScope.drawTexture(component.sprite, x + 5, 10, 0, 0, 10, 10, iconFg.value); + renderScope.drawTexture(component.sprite, x + 5, 10, 0, 0, 10, 10, + hovering ? Theme.ACCENT_FG.value : Theme.PRIMARY_FG.value); - theme.setState(null); col++; } } diff --git a/src/main/java/org/saturnclient/ui2/elements/Text.java b/src/main/java/org/saturnclient/ui2/elements/Text.java index 8465021..285433d 100644 --- a/src/main/java/org/saturnclient/ui2/elements/Text.java +++ b/src/main/java/org/saturnclient/ui2/elements/Text.java @@ -1,27 +1,22 @@ package org.saturnclient.ui2.elements; -import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; import org.saturnclient.ui2.resources.Fonts; public class Text extends Element { - private static ThemeManager theme = new ThemeManager("Text"); - private static Property fgColor = theme.property("fg-color", Property.color(0xFFFFFFFF)); - public static Property font = theme.property("font", Property.font(1)); - private String text; public Text(String text) { this.text = text; - width = Fonts.getWidth(text, font.value); + width = Fonts.getWidth(text, Theme.FONT.value); height = Fonts.getHeight(); } @Override public void render(RenderScope renderScope, ElementContext ctx) { - renderScope.drawText(this.text, 0, 0, font.value, fgColor.value); + renderScope.drawText(this.text, 0, 0, Theme.FONT.value, Theme.FOREGROUND.value); } } diff --git a/src/main/java/org/saturnclient/ui2/elements/TextureButton.java b/src/main/java/org/saturnclient/ui2/elements/TextureButton.java index d345bf3..ccbf1ba 100644 --- a/src/main/java/org/saturnclient/ui2/elements/TextureButton.java +++ b/src/main/java/org/saturnclient/ui2/elements/TextureButton.java @@ -1,7 +1,6 @@ package org.saturnclient.ui2.elements; -import org.saturnclient.saturnclient.config.Property; -import org.saturnclient.saturnclient.config.ThemeManager; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.Element; import org.saturnclient.ui2.ElementContext; import org.saturnclient.ui2.RenderScope; @@ -10,41 +9,27 @@ import net.minecraft.client.render.RenderLayer; import net.minecraft.util.Identifier; public class TextureButton extends Element { - private static ThemeManager theme = new ThemeManager("TextureButton", "hovering"); - private static Property bgColor = theme.property("bg-color", Property.color(0xFF000000)); - private static Property fgColor = theme.property("fg-color", Property.color(0xFFFFFFFF)); - private static Property padding = theme.property("padding", Property.integer(14)); - private static Property cornerRadius = theme.property("corner-radius", Property.integer(10)); - - - static { - theme.propertyStateDefault("hovering", "fg-color", 0xFF845eee); - } - Identifier sprite; private Runnable onClick; + static int padding = 14; public TextureButton(Identifier sprite, Runnable onClick) { this.sprite = sprite; this.onClick = onClick; } - + @Override public void render(RenderScope renderScope, ElementContext ctx) { - if (ctx.isHovering()) { - theme.setState("hovering"); - } else { - theme.setState(null); - } + renderScope.drawRoundedRectangle(0, 0, width, height, Theme.WIDGET_RADIUS.value, + ctx.isHovering() ? Theme.ACCENT.value : Theme.PRIMARY.value); - 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); + int texWidth = width - padding; + int texHeight = height - padding; + + renderScope.drawTexture(sprite, padding / 2, padding / 2, 0, 0, texWidth, texHeight, + ctx.isHovering() ? Theme.ACCENT_FG.value : Theme.PRIMARY_FG.value); } @Override diff --git a/src/main/java/org/saturnclient/ui2/resources/SvgTexture.java b/src/main/java/org/saturnclient/ui2/resources/SvgTexture.java new file mode 100644 index 0000000..0bcd0f8 --- /dev/null +++ b/src/main/java/org/saturnclient/ui2/resources/SvgTexture.java @@ -0,0 +1,80 @@ +package org.saturnclient.ui2.resources; + +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import com.kitfox.svg.SVGDiagram; +import com.kitfox.svg.SVGUniverse; + +import org.jetbrains.annotations.Nullable; +import org.saturnclient.saturnclient.cosmetics.cloaks.utils.IdentifierUtils; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.util.Identifier; + +public class SvgTexture { + + private static List svgCache = new ArrayList<>(); + + private static BufferedImage renderSvg(InputStream svgStream, int width, int height) throws Exception { + // Load SVG + SVGUniverse universe = new SVGUniverse(); + java.net.URI uri = universe.loadSVG(svgStream, "tempSvg"); + SVGDiagram diagram = universe.getDiagram(uri); + + // Get intrinsic size of SVG + float svgWidth = (float) diagram.getWidth(); + float svgHeight = (float) diagram.getHeight(); + + // Compute scale factors + float scaleX = width / svgWidth; + float scaleY = height / svgHeight; + + // Create output image + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + Graphics2D g = image.createGraphics(); + + // Enable anti-aliasing for smooth scaling + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); + + // Apply scaling transform + g.scale(scaleX, scaleY); + + // Render SVG + diagram.render(g); + + g.dispose(); + return image; + } + + @Nullable + public static Identifier getSvg(MinecraftClient client, Identifier svgImage, int width, int height) { + Identifier id = Identifier + .of(svgImage.toString().replaceAll("\\.svg$", (width + "_" + height).toString() + ".png")); + + if (svgCache.contains(id)) { + return id; + } + + try (InputStream svgStream = client + .getResourceManager() + .getResource(svgImage).get() + .getInputStream()) { + + BufferedImage image = renderSvg(svgStream, width, height); + + IdentifierUtils.registerBufferedImageTexture(id, image); + + return id; + + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/saturnclient/ui2/resources/Textures.java b/src/main/java/org/saturnclient/ui2/resources/Textures.java index 1e29bdd..35a238c 100644 --- a/src/main/java/org/saturnclient/ui2/resources/Textures.java +++ b/src/main/java/org/saturnclient/ui2/resources/Textures.java @@ -28,6 +28,7 @@ public class Textures { 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"); public static final Identifier LOGO_TEXT_BIG = Identifier.of("saturnclient", "textures/logo/text_big.png"); + public static final Identifier SPLASH = Identifier.of("saturnclient", "textures/gui/splash.png"); // Widgets public static final Identifier BUTTON_BORDER = Identifier.of("saturnclient", "button_border"); @@ -52,7 +53,7 @@ public class Textures { } public static Identifier getModIcon(String modId) { - return Identifier.of("saturnclient", "textures/gui/mod/" + modId + ".png"); + return Identifier.of("saturnclient", "textures/gui/mod/" + modId + ".svg"); } } diff --git a/src/main/java/org/saturnclient/ui2/screens/ConfigEditor.java b/src/main/java/org/saturnclient/ui2/screens/ConfigEditor.java index e46fcb6..c56ed4a 100644 --- a/src/main/java/org/saturnclient/ui2/screens/ConfigEditor.java +++ b/src/main/java/org/saturnclient/ui2/screens/ConfigEditor.java @@ -4,6 +4,7 @@ import java.util.Map; import org.saturnclient.saturnclient.config.ConfigManager; import org.saturnclient.saturnclient.config.Property; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.ui2.SaturnScreen; import org.saturnclient.ui2.components.Sidebar; import org.saturnclient.ui2.components.inputs.FloatInput; @@ -59,14 +60,13 @@ public class ConfigEditor extends SaturnScreen { if (prop.getType() == Property.PropertyType.NAMESPACE) { configScroll.draw( - new Text( - propName - ).position(Fonts.centerX(520, propName, Text.font.value), modY + 1).scale(0.7f)); + new Text( + propName).position(Fonts.centerX(520, propName, Theme.FONT.value), modY + 1) + .scale(0.7f)); } else { configScroll.draw( - new Text( - propName - ).position(modX, modY + 1).scale(0.7f)); + new Text( + propName).position(modX, modY + 1).scale(0.7f)); } switch (prop.getType()) { @@ -76,9 +76,9 @@ public class ConfigEditor extends SaturnScreen { .position(modX + (w / 2) - 40, modY) .scale(0.5f)); break; - + case HEX: - configScroll.draw(new HexInput((Property) prop, this).position(w / 2, modY)); + configScroll.draw(new HexInput((Property) prop).position(w / 2, modY)); break; case INTEGER: diff --git a/src/main/java/org/saturnclient/ui2/screens/EmoteWheel.java b/src/main/java/org/saturnclient/ui2/screens/EmoteWheel.java index 73ba8d4..55d6fe1 100644 --- a/src/main/java/org/saturnclient/ui2/screens/EmoteWheel.java +++ b/src/main/java/org/saturnclient/ui2/screens/EmoteWheel.java @@ -1,9 +1,8 @@ package org.saturnclient.ui2.screens; import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.SaturnClientConfig; -import org.saturnclient.saturnclient.auth.Auth; -// import org.saturnclient.saturnclient.auth.Auth; +import org.saturnclient.saturnclient.client.ServiceClient; +import org.saturnclient.saturnclient.config.SaturnClientConfig; import org.saturnclient.saturnclient.cosmetics.Emotes; import org.saturnclient.ui2.SaturnScreen; import org.saturnclient.ui2.Utils; @@ -71,7 +70,7 @@ public class EmoteWheel extends SaturnScreen { animationStack.addAnimLayer(1000, PlayerAnimationRegistry.getAnimation(Identifier.of("saturnclient", emote)).playAnimation()); - Auth.emote(emote); + ServiceClient.emote(emote); close(); }).dimensions(70, 70).centerOffset(width, height, -80 + (col * 80), -35 + (row * 80)) .animation(new Fade(700))); diff --git a/src/main/java/org/saturnclient/ui2/screens/ModMenu.java b/src/main/java/org/saturnclient/ui2/screens/ModMenu.java index 8b414a6..83041b1 100644 --- a/src/main/java/org/saturnclient/ui2/screens/ModMenu.java +++ b/src/main/java/org/saturnclient/ui2/screens/ModMenu.java @@ -3,8 +3,10 @@ package org.saturnclient.ui2.screens; import org.saturnclient.modules.ModManager; import org.saturnclient.modules.Module; import org.saturnclient.ui2.SaturnScreen; +import org.saturnclient.ui2.anim.SlideFade; import org.saturnclient.ui2.components.SaturnModule; import org.saturnclient.ui2.components.Sidebar; +import org.saturnclient.ui2.elements.AnimationStagger; import org.saturnclient.ui2.elements.ImageTexture; import org.saturnclient.ui2.elements.Scroll; import org.saturnclient.ui2.resources.Textures; @@ -24,8 +26,11 @@ public class ModMenu extends SaturnScreen { int row = 0; int col = 0; + AnimationStagger moduleStagger = new AnimationStagger(80); + for (Module mod : ModManager.ALL_MODS) { - scroll.draw(new SaturnModule(mod).position((160 + g) * col, (50 + g) * row)); + moduleStagger.draw( + new SaturnModule(mod).position((160 + g) * col, (50 + g) * row).animation(new SlideFade(600, -12))); if (col == 2) { col = 0; @@ -35,6 +40,8 @@ public class ModMenu extends SaturnScreen { } } + scroll.draw(moduleStagger); + int scrollWidth = 480 + 10 + (g * 2) + (p * 2); draw(scroll.dimensions(scrollWidth, 350).center(width, height)); diff --git a/src/main/java/org/saturnclient/ui2/screens/ShiftMenu.java b/src/main/java/org/saturnclient/ui2/screens/ShiftMenu.java index 004308e..350a6a1 100644 --- a/src/main/java/org/saturnclient/ui2/screens/ShiftMenu.java +++ b/src/main/java/org/saturnclient/ui2/screens/ShiftMenu.java @@ -1,12 +1,12 @@ package org.saturnclient.ui2.screens; import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.SaturnClientConfig; +import org.saturnclient.saturnclient.config.SaturnClientConfig; import org.saturnclient.saturnclient.menus.HudEditor; import org.saturnclient.ui2.resources.Textures; import org.saturnclient.ui2.screens.cosmetics.CloakMenu; -import org.saturnclient.ui2.Element; import org.saturnclient.ui2.SaturnScreen; +import org.saturnclient.ui2.elements.AnimationStagger; import org.saturnclient.ui2.elements.Button; import org.saturnclient.ui2.elements.ImageTexture; import org.saturnclient.ui2.elements.TextureButton; @@ -20,21 +20,42 @@ public class ShiftMenu extends SaturnScreen { @Override public void ui() { - 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))); + // Logo animations (unchanged) + draw(new ImageTexture(Textures.LOGO_TEXT) + .dimensions(98, 10) + .centerOffset(width, height, 0, -36) + .animation(new Fade(700))); - Element button = new Button("Settings", () -> { - SaturnClient.client.setScreen(new ModMenu()); - }).center(width, height); + draw(new ImageTexture(SaturnClientConfig.getLogo()) + .dimensions(98, 98) + .centerOffset(width, height, 0, -80) + .animation(new SlideY(700, -20))); - draw(button); + // Spacing and sizes + int btnWidth = 120; + int btnHeight = 40; + int spacing = 4; - draw(new TextureButton(Textures.COSMETICS, () -> { - client.setScreen(new CloakMenu()); - }).dimensions(button.height, button.height).centerOffset(width, height, (button.width / 2) + (button.height / 2) + 4, 0)); + // Create stagger + AnimationStagger stagger = new AnimationStagger(120); - draw(new TextureButton(Textures.HUD_ICON, () -> { + stagger.draw(new TextureButton(Textures.HUD_ICON, () -> { client.setScreen(new HudEditor()); - }).dimensions(button.height, button.height).centerOffset(width, height, -((button.width / 2) + (button.height / 2) + 4), 0)); + }).dimensions(btnHeight, btnHeight).position(0, 0) + .animation(new Fade(300))); + + stagger.draw(new Button("Settings", () -> { + SaturnClient.client.setScreen(new ModMenu()); + }).dimensions(btnWidth, btnHeight).position(btnHeight + spacing, 0) + .animation(new Fade(300))); + + stagger.draw(new TextureButton(Textures.COSMETICS, () -> { + client.setScreen(new CloakMenu()); + }).dimensions(btnHeight, btnHeight).position(btnWidth + btnHeight + (spacing * 2), 0) + .animation(new Fade(300))); + + // Draw the stagger at the absolute center of the screen + draw(stagger.dimensions(btnWidth + (btnHeight * 2) + (spacing * 2), btnHeight).centerOffset(width, height, 0, + 0)); } } diff --git a/src/main/java/org/saturnclient/ui2/screens/TitleMenu.java b/src/main/java/org/saturnclient/ui2/screens/TitleMenu.java index 8bcde8e..ebffa12 100644 --- a/src/main/java/org/saturnclient/ui2/screens/TitleMenu.java +++ b/src/main/java/org/saturnclient/ui2/screens/TitleMenu.java @@ -1,13 +1,15 @@ package org.saturnclient.ui2.screens; import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.SaturnClientConfig; +import org.saturnclient.saturnclient.config.SaturnClientConfig; import org.saturnclient.saturnclient.menus.HudEditor; import org.saturnclient.ui2.resources.Textures; import org.saturnclient.ui2.screens.cosmetics.CloakMenu; import org.saturnclient.ui2.SaturnScreen; import org.saturnclient.ui2.anim.Fade; +import org.saturnclient.ui2.anim.SlideFade; import org.saturnclient.ui2.anim.SlideY; +import org.saturnclient.ui2.elements.AnimationStagger; import org.saturnclient.ui2.elements.Button; import org.saturnclient.ui2.elements.ImageTexture; import org.saturnclient.ui2.elements.TextureButton; @@ -19,44 +21,54 @@ import net.minecraft.client.gui.screen.world.SelectWorldScreen; public class TitleMenu extends SaturnScreen { public TitleMenu() { - super("Tile Menu"); + super("Title Menu"); } @Override public void ui() { backgroundBlur = 0; - 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 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", () -> { + AnimationStagger mainButtonStagger = new AnimationStagger(120); + + mainButtonStagger.draw(new Button("SINGLEPLAYER", () -> { client.setScreen(new SelectWorldScreen(new TitleMenu())); - }).scale(0.69f).dimensions(420, 52).centerOffset(width, height, 0, 0)); + }).scale(0.69f).dimensions(420, 52).position(0, 0).animation(new SlideFade(1000, -10))); - draw(new Button("MULTIPLAYER", () -> { + mainButtonStagger.draw(new Button("MULTIPLAYER", () -> { client.setScreen(new MultiplayerScreen(new TitleMenu())); - }).scale(0.69f).dimensions(420, 52).centerOffset(width, height, 0, 40)); + }).scale(0.69f).dimensions(420, 52).position(0, 40).animation(new SlideFade(1000, -10))); - draw(new Button("OPTIONS", () -> { + mainButtonStagger.draw(new Button("OPTIONS", () -> { client.setScreen(new OptionsScreen(new TitleMenu(), SaturnClient.client.options)); - }).scale(0.69f).dimensions(206, 52).centerOffset(width, height, -73, 80)); + }).scale(0.69f).dimensions(206, 52).position(0, 80).animation(new SlideFade(1000, -10))); - draw(new Button("QUIT", () -> { + mainButtonStagger.draw(new Button("QUIT", () -> { client.scheduleStop(); - }).scale(0.69f).dimensions(206, 52).centerOffset(width, height, 73, 80)); + }).scale(0.69f).dimensions(206, 52).position(146, 80).animation(new SlideFade(1000, -10))); + + draw(mainButtonStagger.dimensions(289, 143).centerOffset(width, height, 0, 60)); int s = Fonts.getHeight() + 20; - draw(new TextureButton(Textures.HUD_ICON, () -> { + AnimationStagger saturnStagger = new AnimationStagger(180); + + saturnStagger.draw(new TextureButton(Textures.HUD_ICON, () -> { client.setScreen(new HudEditor()); - }).dimensions(s, s).centerHorizontal(width, height, -(s + 2), 8).animation(new SlideY(700, s + 8))); + }).dimensions(s, s).position(0, 0).animation(new SlideFade(1000, s + 8))); - draw(new TextureButton(Textures.SETTINGS, () -> { + saturnStagger.draw(new TextureButton(Textures.SETTINGS, () -> { SaturnClient.client.setScreen(new ModMenu()); - }).dimensions(s, s).centerHorizontal(width, height, 0, 8).animation(new SlideY(700, s + 8))); + }).dimensions(s, s).position(s + 2, 0).animation(new SlideFade(1000, s + 8))); - draw(new TextureButton(Textures.CLOAK, () -> { + saturnStagger.draw(new TextureButton(Textures.CLOAK, () -> { client.setScreen(new CloakMenu()); - }).dimensions(s, s).centerHorizontal(width, height, s + 2, 8).animation(new SlideY(700, s + 8))); + }).dimensions(s, s).position((s + 2) * 2, 0).animation(new SlideFade(1000, s + 8))); + + draw(saturnStagger.dimensions(((s + 2) * 2) + s, s).centerHorizontal(width, height, 0, 8)); } } diff --git a/src/main/java/org/saturnclient/ui2/screens/cosmetics/CloakMenu.java b/src/main/java/org/saturnclient/ui2/screens/cosmetics/CloakMenu.java index aae0b06..2abb28d 100644 --- a/src/main/java/org/saturnclient/ui2/screens/cosmetics/CloakMenu.java +++ b/src/main/java/org/saturnclient/ui2/screens/cosmetics/CloakMenu.java @@ -1,8 +1,7 @@ package org.saturnclient.ui2.screens.cosmetics; import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.auth.Auth; -import org.saturnclient.saturnclient.auth.SaturnPlayer; +import org.saturnclient.saturnclient.client.player.SaturnPlayer; import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks; import org.saturnclient.ui2.resources.Textures; import org.saturnclient.ui2.SaturnScreen; @@ -27,15 +26,15 @@ public class CloakMenu extends SaturnScreen { int row = 0; int col = 0; - - SaturnPlayer player = Auth.players.get(Auth.uuid); + + SaturnPlayer player = SaturnPlayer.get(); if (player != null) { for (String cloak : Cloaks.availableCloaks) { scroll.draw(new CosmeticPreview(cloak == player.cloak, Textures.getCloakPreview(cloak), () -> { Cloaks.setCloak(cloak); }).position((50 + g) * col, (111 + g) * row)); - + if (col == 5) { col = 0; row++; @@ -46,18 +45,18 @@ public class CloakMenu extends SaturnScreen { } 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 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)); draw(new TabMenu(0, - new TabMenuComponent(Textures.CLOAK, () -> {}), - new TabMenuComponent(Textures.HAT, () -> { - SaturnClient.client.setScreen(new HatMenu()); - }) - ).centerOffset(width, height, 0, -195)); + new TabMenuComponent(Textures.CLOAK, () -> { + }), + new TabMenuComponent(Textures.HAT, () -> { + SaturnClient.client.setScreen(new HatMenu()); + })).centerOffset(width, height, 0, -195)); } } diff --git a/src/main/java/org/saturnclient/ui2/screens/cosmetics/HatMenu.java b/src/main/java/org/saturnclient/ui2/screens/cosmetics/HatMenu.java index d81a9cb..06deb3c 100644 --- a/src/main/java/org/saturnclient/ui2/screens/cosmetics/HatMenu.java +++ b/src/main/java/org/saturnclient/ui2/screens/cosmetics/HatMenu.java @@ -1,8 +1,7 @@ package org.saturnclient.ui2.screens.cosmetics; import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.auth.Auth; -import org.saturnclient.saturnclient.auth.SaturnPlayer; +import org.saturnclient.saturnclient.client.player.SaturnPlayer; import org.saturnclient.saturnclient.cosmetics.Hats; import org.saturnclient.ui2.resources.Textures; import org.saturnclient.ui2.SaturnScreen; @@ -27,15 +26,15 @@ public class HatMenu extends SaturnScreen { int row = 0; int col = 0; - - SaturnPlayer player = Auth.players.get(Auth.uuid); + + SaturnPlayer player = SaturnPlayer.get(); if (player != null) { for (String hat : Hats.availableHats) { scroll.draw(new CosmeticPreview(hat == player.hat, Textures.getHatPreview(hat), () -> { - Hats.setHat(Auth.uuid, hat); + Hats.setHat(hat); }).dimensions(50, 50).position((50 + g) * col, (50 + g) * row)); - + if (col == 5) { col = 0; row++; @@ -46,18 +45,18 @@ public class HatMenu extends SaturnScreen { } 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 SkinPreview(170f, true).scale(3.5f).position(scroll.x + (scrollWidth - 220), scroll.y + 40)); draw(new Sidebar(2, this::close).centerOffset(width, height, -(scrollWidth / 2 + 20), 0)); draw(new TabMenu(1, - new TabMenuComponent(Textures.CLOAK, () -> { - SaturnClient.client.setScreen(new CloakMenu()); - }), - new TabMenuComponent(Textures.HAT, () -> {}) - ).centerOffset(width, height, 0, -195)); + new TabMenuComponent(Textures.CLOAK, () -> { + SaturnClient.client.setScreen(new CloakMenu()); + }), + new TabMenuComponent(Textures.HAT, () -> { + })).centerOffset(width, height, 0, -195)); } } diff --git a/src/main/java/org/saturnclient/ui2/screens/store/CloakStore.java b/src/main/java/org/saturnclient/ui2/screens/store/CloakStore.java index e400320..d13b099 100644 --- a/src/main/java/org/saturnclient/ui2/screens/store/CloakStore.java +++ b/src/main/java/org/saturnclient/ui2/screens/store/CloakStore.java @@ -1,8 +1,9 @@ package org.saturnclient.ui2.screens.store; import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.auth.Auth; -import org.saturnclient.saturnclient.auth.SaturnPlayer; +import org.saturnclient.saturnclient.client.ServiceClient; +import org.saturnclient.saturnclient.client.player.SaturnPlayer; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.saturnclient.cosmetics.cloaks.Cloaks; import org.saturnclient.ui2.SaturnScreen; import org.saturnclient.ui2.Utils; @@ -42,7 +43,7 @@ public class CloakStore extends SaturnScreen { int row = 0; int col = 0; - SaturnPlayer player = Auth.players.get(Auth.uuid); + SaturnPlayer player = SaturnPlayer.get(); if (player != null) { for (String cloak : Cloaks.ALL_CLOAKS) { @@ -54,7 +55,7 @@ public class CloakStore extends SaturnScreen { long now = System.currentTimeMillis(); if (now - lastPurchaseTime >= 3000) { Utils.notify(NotificationKind.Info, "Purchase processing", "Please wait"); - Auth.buyCloak(cloak); + ServiceClient.buyCloak(cloak); lastPurchaseTime = now; new Thread(() -> { try { @@ -75,10 +76,10 @@ public class CloakStore extends SaturnScreen { String t = "100"; - scroll.draw(new Text(t).position(x + Fonts.centerX(50, t, Text.font.value), y + 113).scale(0.5f)); + scroll.draw(new Text(t).position(x + Fonts.centerX(50, t, Theme.FONT.value), y + 113).scale(0.5f)); scroll.draw(new ImageTexture(Textures.COINS).dimensions(16, 16) - .position(x + Fonts.getWidth(t, Text.font.value) - 1, y + 112).scale(0.5f)); + .position(x + Fonts.getWidth(t, Theme.FONT.value) - 1, y + 112).scale(0.5f)); if (col == 8) { col = 0; diff --git a/src/main/java/org/saturnclient/ui2/screens/store/HatStore.java b/src/main/java/org/saturnclient/ui2/screens/store/HatStore.java index 579ffa5..7a3de0a 100644 --- a/src/main/java/org/saturnclient/ui2/screens/store/HatStore.java +++ b/src/main/java/org/saturnclient/ui2/screens/store/HatStore.java @@ -1,8 +1,9 @@ package org.saturnclient.ui2.screens.store; import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.auth.Auth; -import org.saturnclient.saturnclient.auth.SaturnPlayer; +import org.saturnclient.saturnclient.client.ServiceClient; +import org.saturnclient.saturnclient.client.player.SaturnPlayer; +import org.saturnclient.saturnclient.config.Theme; import org.saturnclient.saturnclient.cosmetics.Hats; import org.saturnclient.ui2.SaturnScreen; import org.saturnclient.ui2.Utils; @@ -42,7 +43,7 @@ public class HatStore extends SaturnScreen { int row = 0; int col = 0; - SaturnPlayer player = Auth.players.get(Auth.uuid); + SaturnPlayer player = SaturnPlayer.get(); if (player != null) { for (String hat : Hats.ALL_HATS) { @@ -54,7 +55,7 @@ public class HatStore extends SaturnScreen { long now = System.currentTimeMillis(); if (now - lastPurchaseTime >= 3000) { Utils.notify(NotificationKind.Info, "Purchase processing", "Please wait"); - Auth.buyHat(hat); + ServiceClient.buyHat(hat); lastPurchaseTime = now; new Thread(() -> { try { @@ -75,10 +76,10 @@ public class HatStore extends SaturnScreen { String t = "50"; - scroll.draw(new Text(t).position(x + Fonts.centerX(50, t, Text.font.value), y + 53).scale(0.5f)); + scroll.draw(new Text(t).position(x + Fonts.centerX(50, t, Theme.FONT.value), y + 53).scale(0.5f)); scroll.draw(new ImageTexture(Textures.COINS).dimensions(16, 16) - .position(x + Fonts.getWidth(t, Text.font.value) + 4, y + 52).scale(0.5f)); + .position(x + Fonts.getWidth(t, Theme.FONT.value) + 4, y + 52).scale(0.5f)); if (col == 8) { col = 0; diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/armor.png b/src/main/resources/assets/saturnclient/textures/gui/mod/armor.png deleted file mode 100644 index 3d1c75e..0000000 Binary files a/src/main/resources/assets/saturnclient/textures/gui/mod/armor.png and /dev/null differ diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/armor.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/armor.svg new file mode 100644 index 0000000..c5995e0 --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/armor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/coords.png b/src/main/resources/assets/saturnclient/textures/gui/mod/coords.png deleted file mode 100644 index 5af14bf..0000000 Binary files a/src/main/resources/assets/saturnclient/textures/gui/mod/coords.png and /dev/null differ diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/coords.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/coords.svg new file mode 100644 index 0000000..317f49b --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/coords.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/crosshair.png b/src/main/resources/assets/saturnclient/textures/gui/mod/crosshair.png deleted file mode 100644 index cd208a3..0000000 Binary files a/src/main/resources/assets/saturnclient/textures/gui/mod/crosshair.png and /dev/null differ diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/crosshair.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/crosshair.svg new file mode 100644 index 0000000..bb0cb50 --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/crosshair.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/day.png b/src/main/resources/assets/saturnclient/textures/gui/mod/day.png deleted file mode 100644 index 5fb3352..0000000 Binary files a/src/main/resources/assets/saturnclient/textures/gui/mod/day.png and /dev/null differ diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/day.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/day.svg new file mode 100644 index 0000000..9432885 --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/day.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/effect.png b/src/main/resources/assets/saturnclient/textures/gui/mod/effect.png deleted file mode 100644 index ad39774..0000000 Binary files a/src/main/resources/assets/saturnclient/textures/gui/mod/effect.png and /dev/null differ diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/effect.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/effect.svg new file mode 100644 index 0000000..0e61d06 --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/effect.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/fps.png b/src/main/resources/assets/saturnclient/textures/gui/mod/fps.png deleted file mode 100644 index 0daed16..0000000 Binary files a/src/main/resources/assets/saturnclient/textures/gui/mod/fps.png and /dev/null differ diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/fps.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/fps.svg new file mode 100644 index 0000000..6e76d84 --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/fps.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/freelook.png b/src/main/resources/assets/saturnclient/textures/gui/mod/freelook.png deleted file mode 100644 index 9418d12..0000000 Binary files a/src/main/resources/assets/saturnclient/textures/gui/mod/freelook.png and /dev/null differ diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/freelook.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/freelook.svg new file mode 100644 index 0000000..199e319 --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/freelook.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/fullbright.png b/src/main/resources/assets/saturnclient/textures/gui/mod/fullbright.png deleted file mode 100644 index dfa9f7a..0000000 Binary files a/src/main/resources/assets/saturnclient/textures/gui/mod/fullbright.png and /dev/null differ diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/fullbright.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/fullbright.svg new file mode 100644 index 0000000..3e8360d --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/fullbright.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/health.png b/src/main/resources/assets/saturnclient/textures/gui/mod/health.png deleted file mode 100644 index dcca15c..0000000 Binary files a/src/main/resources/assets/saturnclient/textures/gui/mod/health.png and /dev/null differ diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/health.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/health.svg new file mode 100644 index 0000000..491bbd7 --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/health.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/keystrokes.png b/src/main/resources/assets/saturnclient/textures/gui/mod/keystrokes.png deleted file mode 100644 index da20fcd..0000000 Binary files a/src/main/resources/assets/saturnclient/textures/gui/mod/keystrokes.png and /dev/null differ diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/keystrokes.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/keystrokes.svg new file mode 100644 index 0000000..f7e19c9 --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/keystrokes.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/nofog.png b/src/main/resources/assets/saturnclient/textures/gui/mod/nofog.png deleted file mode 100644 index d7dc168..0000000 Binary files a/src/main/resources/assets/saturnclient/textures/gui/mod/nofog.png and /dev/null differ diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/nofog.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/nofog.svg new file mode 100644 index 0000000..63a48cc --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/nofog.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/particles.png b/src/main/resources/assets/saturnclient/textures/gui/mod/particles.png deleted file mode 100644 index 3709190..0000000 Binary files a/src/main/resources/assets/saturnclient/textures/gui/mod/particles.png and /dev/null differ diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/particles.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/particles.svg new file mode 100644 index 0000000..f4addd6 --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/particles.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/speed.png b/src/main/resources/assets/saturnclient/textures/gui/mod/speed.png deleted file mode 100644 index 8ad03eb..0000000 Binary files a/src/main/resources/assets/saturnclient/textures/gui/mod/speed.png and /dev/null differ diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/speed.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/speed.svg new file mode 100644 index 0000000..e8ff01c --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/speed.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/sprint.png b/src/main/resources/assets/saturnclient/textures/gui/mod/sprint.png deleted file mode 100644 index c1c507c..0000000 Binary files a/src/main/resources/assets/saturnclient/textures/gui/mod/sprint.png and /dev/null differ diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/sprint.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/sprint.svg new file mode 100644 index 0000000..35e91e7 --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/sprint.svg @@ -0,0 +1,35 @@ + + + + +Created by potrace 1.15, written by Peter Selinger 2001-2017 + + + + + + diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/zoom.png b/src/main/resources/assets/saturnclient/textures/gui/mod/zoom.png deleted file mode 100644 index c6969ae..0000000 Binary files a/src/main/resources/assets/saturnclient/textures/gui/mod/zoom.png and /dev/null differ diff --git a/src/main/resources/assets/saturnclient/textures/gui/mod/zoom.svg b/src/main/resources/assets/saturnclient/textures/gui/mod/zoom.svg new file mode 100644 index 0000000..320a59d --- /dev/null +++ b/src/main/resources/assets/saturnclient/textures/gui/mod/zoom.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/resources/assets/saturnclient/textures/gui/splash.png b/src/main/resources/assets/saturnclient/textures/gui/splash.png new file mode 100644 index 0000000..84f2988 Binary files /dev/null and b/src/main/resources/assets/saturnclient/textures/gui/splash.png differ diff --git a/src/main/resources/saturnclient.mixins.json b/src/main/resources/saturnclient.mixins.json index 8327a69..3bc9ccc 100644 --- a/src/main/resources/saturnclient.mixins.json +++ b/src/main/resources/saturnclient.mixins.json @@ -9,7 +9,8 @@ "PlayerEntityRendererMixin", "WhoAmI", "DrawContextAccessor", - "TitleScreenMixin" + "SplashOverlayMixin", + "SetScreenMixin" ], "injectors": { "defaultRequire": 1