diff --git a/build.gradle b/build.gradle index 3fcc938..0d0efed 100644 --- a/build.gradle +++ b/build.gradle @@ -1,41 +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" - implementation 'com.github.selimaj-dev:session-java:0.1.4' + // SVG Rendering Library + implementation "com.formdev:svgSalamander:1.1.4" - 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}") + + // ───────────────────────────────────────────── + // 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.fabricmc.net/' } // Fabric's official repo - maven { url 'https://jitpack.io' } - maven { url "https://maven.parchmentmc.org" } - maven { name = "FelNull Maven"; url = "https://maven.felnull.dev" } - maven { name = "KosmX 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 @@ -43,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) { @@ -82,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/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/client/ServiceClient.java b/src/main/java/org/saturnclient/saturnclient/client/ServiceClient.java index 8876664..442f7d9 100644 --- a/src/main/java/org/saturnclient/saturnclient/client/ServiceClient.java +++ b/src/main/java/org/saturnclient/saturnclient/client/ServiceClient.java @@ -8,8 +8,13 @@ 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; @@ -17,7 +22,7 @@ public class ServiceClient { public static boolean connectTimeout() { try { - session = Session.connect("ws://127.0.0.1:8080", 10, TimeUnit.SECONDS); + session = Session.connect("wss://saturn-server.selimaj.dev", 10, TimeUnit.SECONDS); return true; } catch (Exception e) { return false; @@ -46,14 +51,15 @@ public class ServiceClient { uuid = mcSession.getUuidOrNull(); String username = mcSession.getUsername(); - SaturnClient.LOGGER.info("Authenticating with UUID: " + accessToken); + SaturnClient.LOGGER.info("Authenticating with UUID: " + uuid); if (!connectTimeout()) { SaturnClient.LOGGER.error("Unable to authenticate: Session Server Timeout"); return false; } - ServiceMethods.AuthResponse response = session.request(ServiceMethods.Authenticate, accessToken).get(); + ServiceMethods.Types.Player response = session.request(ServiceMethods.Authenticate, accessToken) + .get(); for (String availableCloak : response.cloaks()) { Cloaks.availableCloaks.add(availableCloak); @@ -63,7 +69,9 @@ public class ServiceClient { Hats.availableHats.add(availableHat); } - SaturnPlayer.set(uuid, username, new SaturnPlayer(uuid, username, response.cloak(), response.hat())); + eventHandlers(); + + SaturnPlayer.set(new SaturnPlayer(uuid, username, response.cloak(), response.hat())); Cloaks.loadCloak(uuid); @@ -74,33 +82,67 @@ public class ServiceClient { } } - public static void setCloak(String cloak) { + public static void setCloak(String itemId) { try { - session.request(ServiceMethods.SetCloak, cloak).get(); + 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 hat) { + public static void setHat(String itemId) { try { - session.request(ServiceMethods.SetHat, hat).get(); + 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 cloak) { + public static void buyCloak(String itemId) { try { - session.request(ServiceMethods.BuyCloak, cloak).get(); + 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 hat) { + public static void buyHat(String itemId) { try { - session.request(ServiceMethods.BuyHat, hat).get(); + 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); } @@ -108,9 +150,56 @@ public class ServiceClient { public static void emote(String emote) { try { - session.request(ServiceMethods.Emote, emote).get(); + 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 index 7eb9dea..0a09c53 100644 --- a/src/main/java/org/saturnclient/saturnclient/client/ServiceMethods.java +++ b/src/main/java/org/saturnclient/saturnclient/client/ServiceMethods.java @@ -1,27 +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 { - public record AuthResponse(String cloak, String hat, String[] cloaks, String[] hats) { + + // ========================= + // 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) { + } } - public static final Method Authenticate = new Method<>("auth", - String.class, AuthResponse.class, String.class); + // ========================= + // AUTH + // ========================= + public static final Method Authenticate = new Method<>("auth", + String.class, + Types.Player.class, + String.class); - // Equip + // ========================= + // EQUIP + // ========================= public static final Method SetCloak = new Method<>("set_cloak", - String.class, String.class, String.class); + String.class, + String.class, + String.class); + public static final Method SetHat = new Method<>("set_hat", - String.class, String.class, String.class); + String.class, + String.class, + String.class); - // Buy + // ========================= + // 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); + String.class, + String.class, + String.class); - // Emote - public static final Method Emote = new Method<>("emote", - 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/client/player/PlayerTracker.java b/src/main/java/org/saturnclient/saturnclient/client/player/PlayerTracker.java index 2a27c6b..f43347f 100644 --- a/src/main/java/org/saturnclient/saturnclient/client/player/PlayerTracker.java +++ b/src/main/java/org/saturnclient/saturnclient/client/player/PlayerTracker.java @@ -3,6 +3,7 @@ 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; @@ -46,7 +47,6 @@ public class PlayerTracker { private static void onPlayerJoin(MinecraftClient client, PlayerListEntry player) { GameProfile profile = player.getProfile(); - UUID uuid = profile.getId(); - SaturnPlayer.player(uuid); + ServiceClient.player(profile.getId(), profile.getName()); } } diff --git a/src/main/java/org/saturnclient/saturnclient/client/player/SaturnPlayer.java b/src/main/java/org/saturnclient/saturnclient/client/player/SaturnPlayer.java index a6caf95..f4c935e 100644 --- a/src/main/java/org/saturnclient/saturnclient/client/player/SaturnPlayer.java +++ b/src/main/java/org/saturnclient/saturnclient/client/player/SaturnPlayer.java @@ -41,18 +41,14 @@ public class SaturnPlayer { return PLAYERS.get(uuid); } - public static void set(UUID uuid, String name, SaturnPlayer player) { - PLAYER_NAMES.put(name, uuid); - PLAYERS.put(uuid, player); + public static void set(SaturnPlayer player) { + PLAYER_NAMES.put(player.name, player.uuid); + PLAYERS.put(player.uuid, player); } - public static void player(UUID uuid) { - if (PLAYERS.containsKey(uuid)) { - return; - } - - // If offline then leave - - PLAYERS.put(uuid, null); + 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/cosmetics/HatFeatureRenderer.java b/src/main/java/org/saturnclient/saturnclient/cosmetics/HatFeatureRenderer.java index 2f7e061..cabc440 100644 --- a/src/main/java/org/saturnclient/saturnclient/cosmetics/HatFeatureRenderer.java +++ b/src/main/java/org/saturnclient/saturnclient/cosmetics/HatFeatureRenderer.java @@ -28,7 +28,8 @@ public class HatFeatureRenderer extends FeatureRenderer 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/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/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 cdaac79..35a238c 100644 --- a/src/main/java/org/saturnclient/ui2/resources/Textures.java +++ b/src/main/java/org/saturnclient/ui2/resources/Textures.java @@ -53,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/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