diff --git a/src/main/java/org/saturnclient/saturnclient/SaturnClient.java b/src/main/java/org/saturnclient/saturnclient/SaturnClient.java index c14fb4b..2ec685a 100644 --- a/src/main/java/org/saturnclient/saturnclient/SaturnClient.java +++ b/src/main/java/org/saturnclient/saturnclient/SaturnClient.java @@ -5,7 +5,7 @@ import net.minecraft.util.math.ColorHelper; import org.saturnclient.saturnclient.cloaks.Cloaks; import org.saturnclient.saturnclient.event.KeyInputHandler; -import org.saturnclient.saturnclient.auth.SaturnApi; +import org.saturnclient.saturnclient.auth.SaturnSocket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,7 +23,7 @@ public class SaturnClient implements ModInitializer { LOGGER.info("Initializing " + MOD_ID); KeyInputHandler.register(); - if (SaturnApi.authenticate()) { + if (SaturnSocket.authenticate()) { Cloaks.initialize(); LOGGER.info(MOD_ID + " initialization complete"); } else { diff --git a/src/main/java/org/saturnclient/saturnclient/auth/SaturnApi.java b/src/main/java/org/saturnclient/saturnclient/auth/SaturnApi.java deleted file mode 100644 index e84c43e..0000000 --- a/src/main/java/org/saturnclient/saturnclient/auth/SaturnApi.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.saturnclient.saturnclient.auth; - -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; -import net.minecraft.client.MinecraftClient; -import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.cloaks.Cloaks; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.net.Socket; -import java.util.HashMap; -import java.util.Map; - -public class SaturnApi { - private static final String server = "127.0.0.1"; - private static final int port = 8080; - - public static Map players = new HashMap<>(); - public static Map playerNames = new HashMap<>(); - private static Socket socket; - private static BufferedReader reader; - private static PrintWriter writer; - - public static boolean authenticate() { - // Register shutdown hook ONCE - ClientLifecycleEvents.CLIENT_STOPPING.register(c -> close()); - - try { - MinecraftClient client = MinecraftClient.getInstance(); - if (client.getSession() == null) { - SaturnClient.LOGGER.error("No active Minecraft session found"); - return false; - } - - String accessToken = client.getSession().getAccessToken(); - SaturnClient.LOGGER.info("Authenticating"); - - // Use try-with-resources to ensure proper cleanup - try (Socket tempSocket = new Socket(server, port); - BufferedReader tempReader = new BufferedReader(new InputStreamReader(tempSocket.getInputStream())); - PrintWriter tempWriter = new PrintWriter(tempSocket.getOutputStream(), true)) { - - // Assign to class fields - socket = tempSocket; - reader = tempReader; - writer = tempWriter; - - writer.println(accessToken); - String response = reader.readLine(); - SaturnParser parser = new SaturnParser(response); - - String uuid = parser.getString("uuid"); - String cloak = parser.getString("cloak"); - - if (cloak != null) { - SaturnClient.LOGGER.info("Setting cloak to " + cloak + " for " + uuid); - MinecraftClient.getInstance().execute(() -> Cloaks.setCloak(uuid, cloak)); - } - - return true; - } - - } catch (IOException e) { - SaturnClient.LOGGER.error("Authentication failed", e); - return false; - } - } - - public static void close() { - try { - if (writer != null) { - writer.close(); - } - if (reader != null) { - reader.close(); - } - if (socket != null) { - socket.close(); - } - SaturnClient.LOGGER.info("SaturnApi connection closed."); - } catch (IOException e) { - SaturnClient.LOGGER.error("Failed to close resources", e); - } - } - - public static void setCloak(String cloakName) { - try { - - writer.println("set_cloak@cloak=" + cloakName); - String response = reader.readLine(); - new SaturnParser(response); - } catch (IOException e) { - SaturnClient.LOGGER.error("Request failed", e); - } - } -} diff --git a/src/main/java/org/saturnclient/saturnclient/auth/SaturnParser.java b/src/main/java/org/saturnclient/saturnclient/auth/SaturnParser.java index bfbe6c7..2000c26 100644 --- a/src/main/java/org/saturnclient/saturnclient/auth/SaturnParser.java +++ b/src/main/java/org/saturnclient/saturnclient/auth/SaturnParser.java @@ -22,6 +22,8 @@ public class SaturnParser { 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]); } @@ -36,4 +38,16 @@ public class SaturnParser { 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 index f8ae0fc..586af6b 100644 --- a/src/main/java/org/saturnclient/saturnclient/auth/SaturnPlayer.java +++ b/src/main/java/org/saturnclient/saturnclient/auth/SaturnPlayer.java @@ -2,4 +2,8 @@ package org.saturnclient.saturnclient.auth; public class SaturnPlayer { public String cloak = ""; + + public SaturnPlayer(String cloak) { + this.cloak = cloak; + } } diff --git a/src/main/java/org/saturnclient/saturnclient/auth/SaturnSocket.java b/src/main/java/org/saturnclient/saturnclient/auth/SaturnSocket.java new file mode 100644 index 0000000..a9be6ed --- /dev/null +++ b/src/main/java/org/saturnclient/saturnclient/auth/SaturnSocket.java @@ -0,0 +1,134 @@ +package org.saturnclient.saturnclient.auth; + +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; +import net.minecraft.client.MinecraftClient; +import org.saturnclient.saturnclient.SaturnClient; +import org.saturnclient.saturnclient.cloaks.Cloaks; +import java.io.*; +import java.net.Socket; +import java.util.HashMap; +import java.util.Map; + +public class SaturnSocket { + private static final String server = "127.0.0.1"; + private static final int port = 8080; + + public static Map players = new HashMap<>(); + public static Map playerNames = new HashMap<>(); + public static String uuid; + + private static Socket socket; + private static BufferedReader reader; + private static PrintWriter writer; + private static Thread listenerThread; + private static volatile boolean running = false; + + @SuppressWarnings("resource") + public static boolean authenticate() { + // Register shutdown hook ONCE + ClientLifecycleEvents.CLIENT_STOPPING.register(c -> close()); + + try { + MinecraftClient client = MinecraftClient.getInstance(); + if (client.getSession() == null) { + SaturnClient.LOGGER.error("No active Minecraft session found"); + return false; + } + + String accessToken = client.getSession().getAccessToken(); + SaturnClient.LOGGER.info("Authenticating"); + + // Establish a persistent connection + socket = new Socket(server, port); + reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); + writer = new PrintWriter(socket.getOutputStream(), true); + + // Send authentication request + writer.println(accessToken); + String response = reader.readLine(); + + SaturnClient.LOGGER.info(response); + + SaturnParser parser = new SaturnParser(response); + + uuid = parser.getString("uuid"); + String cloak = parser.getString("cloak"); + + for (String availableCloak : parser.getArray("cloaks")) { + SaturnClient.LOGGER.info("Available cloak: " + availableCloak); + Cloaks.availableCloaks.add(availableCloak); + } + + players.put(uuid, new SaturnPlayer(cloak)); + + if (cloak != null) { + SaturnClient.LOGGER.info("Setting cloak to " + cloak + " for " + uuid); + MinecraftClient.getInstance().execute(() -> Cloaks.setCloak(uuid, cloak)); + } + + playerNames.put(client.getSession().getUsername(), uuid); + + // Start listening for server messages + startListenerThread(); + + return true; + + } catch (IOException e) { + SaturnClient.LOGGER.error("Authentication failed", e); + return false; + } + } + + private static void startListenerThread() { + running = true; + listenerThread = new Thread(() -> { + try { + while (running) { + String message = reader.readLine(); + if (message == null) { + running = false; + break; + } + + SaturnClient.LOGGER.info("Received: " + message); + + // TODO: make a server response/request handler + + } + } catch (IOException e) { + SaturnClient.LOGGER.error("Error reading from server", e); + } finally { + close(); + } + }); + + listenerThread.setDaemon(true); + listenerThread.start(); + } + + public static void close() { + running = false; + try { + if (writer != null) { + writer.close(); + } + if (reader != null) { + reader.close(); + } + if (socket != null) { + socket.close(); + } + SaturnClient.LOGGER.info("SaturnApi connection closed."); + } catch (IOException e) { + SaturnClient.LOGGER.error("Failed to close resources", e); + } + } + + public static void setCloak(String cloakName) { + try { + writer.println("set_cloak@cloak=" + cloakName); + } catch (Exception e) { + SaturnClient.LOGGER.error("Request failed", e); + } + } +} diff --git a/src/main/java/org/saturnclient/saturnclient/cloaks/Cloaks.java b/src/main/java/org/saturnclient/saturnclient/cloaks/Cloaks.java index 7a3d677..0988011 100644 --- a/src/main/java/org/saturnclient/saturnclient/cloaks/Cloaks.java +++ b/src/main/java/org/saturnclient/saturnclient/cloaks/Cloaks.java @@ -2,7 +2,7 @@ package org.saturnclient.saturnclient.cloaks; import net.minecraft.util.Identifier; import org.saturnclient.saturnclient.SaturnClient; -import org.saturnclient.saturnclient.auth.SaturnApi; +import org.saturnclient.saturnclient.auth.SaturnSocket; import org.saturnclient.saturnclient.auth.SaturnPlayer; import org.saturnclient.saturnclient.cloaks.utils.AnimatedCloakData; import org.saturnclient.saturnclient.cloaks.utils.IdentifierUtils; @@ -41,13 +41,20 @@ public class Cloaks { * @param cloakName Name of the cloak file to load */ public static void setCloak(String uuid, String cloakName) { - SaturnApi.setCloak(cloakName); + SaturnSocket.setCloak(cloakName); + setCloakSilent(uuid, cloakName); + } - SaturnPlayer player = SaturnApi.players.get(uuid); + /** + * Handles loading and caching of a new cloak texture, without connecting to the + * server. + * + * @param cloakName Name of the cloak file to load + */ + public static void setCloakSilent(String uuid, String cloakName) { + SaturnPlayer player = SaturnSocket.players.get(uuid); if (player == null) { - SaturnPlayer newPlayer = new SaturnPlayer(); - newPlayer.cloak = cloakName; - SaturnApi.players.put(uuid, newPlayer); + SaturnSocket.players.put(uuid, new SaturnPlayer(cloakName)); } else { player.cloak = cloakName; } @@ -59,7 +66,6 @@ public class Cloaks { loadStaticCloak(cloakName + ".png"); } } - } /** @@ -128,11 +134,11 @@ public class Cloaks { } public static Identifier getCurrentCloakTexture(String uuid) { - if (!SaturnApi.players.containsKey(uuid)) { + if (!SaturnSocket.players.containsKey(uuid)) { return null; } - String cloakName = SaturnApi.players.get(uuid).cloak; + String cloakName = SaturnSocket.players.get(uuid).cloak; if (cloakName.isEmpty()) { return null; diff --git a/src/main/java/org/saturnclient/saturnclient/menus/CloaksMenu.java b/src/main/java/org/saturnclient/saturnclient/menus/CloaksMenu.java index 8fc2549..c1f4b60 100644 --- a/src/main/java/org/saturnclient/saturnclient/menus/CloaksMenu.java +++ b/src/main/java/org/saturnclient/saturnclient/menus/CloaksMenu.java @@ -1,6 +1,6 @@ package org.saturnclient.saturnclient.menus; -import org.saturnclient.saturnclient.auth.SaturnApi; +import org.saturnclient.saturnclient.auth.SaturnSocket; import org.saturnclient.saturnclient.cloaks.Cloaks; import org.saturnclient.ui.SaturnUi; import org.saturnclient.ui.Textures; @@ -55,7 +55,7 @@ public class CloaksMenu extends SaturnUi { .setHeight(cloakHeight)); draw(new SaturnClickableSprite(Textures.BUTTON_BORDER, () -> { - SaturnApi.setCloak(cloak); + Cloaks.setCloak(SaturnSocket.uuid, cloak); }) .setColor(10526880) .setX(modX - 3) diff --git a/src/main/java/org/saturnclient/saturnclient/menus/MainMenu.java b/src/main/java/org/saturnclient/saturnclient/menus/MainMenu.java index d34e274..02f4acb 100644 --- a/src/main/java/org/saturnclient/saturnclient/menus/MainMenu.java +++ b/src/main/java/org/saturnclient/saturnclient/menus/MainMenu.java @@ -26,7 +26,7 @@ public class MainMenu extends SaturnUi { }).setX((width - buttonWidth) / 2).setY((height - buttonHeight) / 2).setWidth(buttonWidth) .setHeight(buttonHeight) - .setAnimations(new FadeIn(3))); + .setAnimations(new FadeIn(1))); draw( new SaturnImageButton(Textures.EMOTE, 14, 14, @@ -37,7 +37,7 @@ public class MainMenu extends SaturnUi { .setY((height - buttonHeight) / 2) .setWidth(buttonHeight) .setHeight(buttonHeight) - .setAnimations(new FadeIn(3))); + .setAnimations(new FadeIn(1))); draw( new SaturnImageButton(Textures.COSMETICS, 14, 14, @@ -48,7 +48,7 @@ public class MainMenu extends SaturnUi { .setY((height - buttonHeight) / 2) .setWidth(buttonHeight) .setHeight(buttonHeight) - .setAnimations(new FadeIn(3))); + .setAnimations(new FadeIn(1))); int logoSize = 49; @@ -58,7 +58,7 @@ public class MainMenu extends SaturnUi { .setY((height - 8) / 2 - 23) .setWidth(logoSize) .setHeight(8) - .setAnimations(new FadeIn(3))); + .setAnimations(new FadeIn(1))); draw( new SaturnImage(Textures.LOGO) @@ -66,6 +66,6 @@ public class MainMenu extends SaturnUi { .setY(height / 2 - logoSize - 24) .setWidth(logoSize) .setHeight(logoSize) - .setAnimations(new Slide(2, 14))); + .setAnimations(new Slide(1, 14))); } } \ No newline at end of file diff --git a/src/main/java/org/saturnclient/saturnclient/mixin/NameTagMixin.java b/src/main/java/org/saturnclient/saturnclient/mixin/NameTagMixin.java index f39cfbe..30a1b2e 100644 --- a/src/main/java/org/saturnclient/saturnclient/mixin/NameTagMixin.java +++ b/src/main/java/org/saturnclient/saturnclient/mixin/NameTagMixin.java @@ -13,7 +13,7 @@ import net.minecraft.text.Text; import net.minecraft.util.math.Vec3d; import net.minecraft.client.render.LightmapTextureManager; -import org.saturnclient.saturnclient.auth.SaturnApi; +import org.saturnclient.saturnclient.auth.SaturnSocket; import org.joml.Matrix4f; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; @@ -60,7 +60,7 @@ public abstract class NameTagMixin { private boolean isSaturn(S state) { if (state instanceof PlayerEntityRenderState) { String name = ((PlayerEntityRenderState) state).name; - return SaturnApi.playerNames.containsKey(name); + return SaturnSocket.playerNames.containsKey(name); } return false; } diff --git a/src/main/java/org/saturnclient/saturnclient/mixin/TabListMixin.java b/src/main/java/org/saturnclient/saturnclient/mixin/TabListMixin.java index 67ca770..4135746 100644 --- a/src/main/java/org/saturnclient/saturnclient/mixin/TabListMixin.java +++ b/src/main/java/org/saturnclient/saturnclient/mixin/TabListMixin.java @@ -1,6 +1,6 @@ package org.saturnclient.saturnclient.mixin; -import org.saturnclient.saturnclient.auth.SaturnApi; +import org.saturnclient.saturnclient.auth.SaturnSocket; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; @@ -22,6 +22,6 @@ public abstract class TabListMixin { @Nullable public Text getDisplayName() { String name = displayName.getString(); - return Text.literal(SaturnApi.playerNames.containsKey(name) ? "" + name : name); + return Text.literal(SaturnSocket.playerNames.containsKey(name) ? "" + name : name); } } diff --git a/src/main/java/org/saturnclient/ui/widgets/SaturnClickableImage.java b/src/main/java/org/saturnclient/ui/widgets/SaturnClickableImage.java index 6fbcfa2..339aa75 100644 --- a/src/main/java/org/saturnclient/ui/widgets/SaturnClickableImage.java +++ b/src/main/java/org/saturnclient/ui/widgets/SaturnClickableImage.java @@ -12,26 +12,26 @@ import net.minecraft.util.math.ColorHelper; import net.minecraft.util.math.MathHelper; public class SaturnClickableImage extends SaturnWidget { - public Identifier sprite; + public Identifier texture; public boolean selected = false; public Consumer onPress; public int color = ColorHelper.getWhite(1.0f); public int hoverColor = SaturnClient.COLOR; - public SaturnClickableImage(Identifier sprite, Consumer onPress) { - this.sprite = sprite; + public SaturnClickableImage(Identifier texture, Consumer onPress) { + this.texture = texture; this.onPress = onPress; } - public SaturnClickableImage(Identifier sprite, Runnable onPress) { - this(sprite, (m) -> { + public SaturnClickableImage(Identifier texture, Runnable onPress) { + this(texture, (m) -> { onPress.run(); }); } @Override public void render(DrawContext context, boolean hovering, int mouseX, int mouseY) { - context.drawTexture(RenderLayer::getGuiTextured, sprite, x, y, 0, 0, width, height, width, + context.drawTexture(RenderLayer::getGuiTextured, texture, x, y, 0, 0, width, height, width, height, (hovering || selected ? hoverColor : color) | MathHelper.ceil(this.alpha * 255.0F) << 24); }