From 9f2406abdb8f66fbf39ccda91784417ee373a5a1 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Fri, 20 Mar 2026 23:06:01 +0100 Subject: [PATCH] Cloak loading --- .../saturnclient/client/ServiceClient.java | 2 + .../org/saturnclient/cosmetics/Cloaks.java | 180 +++++++----------- 2 files changed, 76 insertions(+), 106 deletions(-) diff --git a/src/main/java/org/saturnclient/client/ServiceClient.java b/src/main/java/org/saturnclient/client/ServiceClient.java index 8b68069..e9fb1e6 100644 --- a/src/main/java/org/saturnclient/client/ServiceClient.java +++ b/src/main/java/org/saturnclient/client/ServiceClient.java @@ -69,6 +69,8 @@ public class ServiceClient { SaturnPlayer.set(new SaturnPlayer(uuid, username, response.cloak(), response.hat())); + Cloaks.loadCloak(response.cloak()); + return true; } catch (Exception e) { Providers.saturn.logError("Authentication failed", e); diff --git a/src/main/java/org/saturnclient/cosmetics/Cloaks.java b/src/main/java/org/saturnclient/cosmetics/Cloaks.java index 905d61a..48a5cd6 100644 --- a/src/main/java/org/saturnclient/cosmetics/Cloaks.java +++ b/src/main/java/org/saturnclient/cosmetics/Cloaks.java @@ -10,10 +10,7 @@ import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.util.*; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import org.saturnclient.cosmetics.utils.AnimatedCloakData; import org.saturnclient.cosmetics.utils.GifDecoder; @@ -33,17 +30,8 @@ public class Cloaks { private static final String CLOAKS_RESOURCE_PATH = "assets/saturnclient/textures/cloaks/"; public static final List availableCloaks = new ArrayList<>(); public static IdentifierRef cloakCacheIdentifier = null; - 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()), - r -> { - Thread t = new Thread(r, "cloak-loader"); - t.setDaemon(true); - t.setPriority(Thread.NORM_PRIORITY - 1); - return t; - }); + public static final Map> animatedCloaks = new ConcurrentHashMap<>(); + private static final Map lastFrameTime = new ConcurrentHashMap<>(); private static final ConcurrentHashMap> CLOAK_CACHE = new ConcurrentHashMap<>(); @@ -80,7 +68,7 @@ public class Cloaks { player.cloak = cloakName; } - loadCloak(uuid); + loadCloak(cloakName); } /** @@ -89,22 +77,12 @@ public class Cloaks { * * @param cloakName Name of the cloak file to load */ - 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)) { - loadAnimatedCloakAsync(uuid, player.cloak) - .exceptionally(throwable -> { - Providers.saturn.logError("Failed to load animated cloak for player: " + player.cloak, - throwable); - return null; - }); - - } else { - Providers.saturn.getClient().executeOnThread(() -> loadStaticCloak(player.cloak + ".png")); - } + public static void loadCloak(String cloakName) { + if (cloakName != null && !cloakName.isEmpty()) { + if (Arrays.asList(ANIMATED_CLOAKS).contains(cloakName)) { + Providers.saturn.getClient().executeOnThread(() -> loadAnimatedCloak(cloakName)); + } else { + Providers.saturn.getClient().executeOnThread(() -> loadStaticCloak(cloakName + ".png")); } } } @@ -137,94 +115,84 @@ public class Cloaks { } } - public static CompletableFuture loadAnimatedCloakAsync(UUID uuid, String cloakName) { - return CompletableFuture.runAsync(() -> { - String fileName = cloakName + ".gif"; + public static void loadAnimatedCloak(String cloakName) { + String fileName = cloakName + ".gif"; - // Check cache first - List cached = CLOAK_CACHE.get(fileName); - if (cached != null) { - animatedCloaks.put(uuid, cached); - lastFrameTime.put(uuid, System.currentTimeMillis()); + // Check cache first + List cached = CLOAK_CACHE.get(fileName); + if (cached != null) { + animatedCloaks.put(cloakName, cached); + lastFrameTime.put(cloakName, System.currentTimeMillis()); + return; + } + + String resourcePath = CLOAKS_RESOURCE_PATH + fileName; + + try (InputStream inputStream = Cloaks.class.getClassLoader().getResourceAsStream(resourcePath)) { + if (inputStream == null) { + Providers.saturn.logError("Cloak resource not found: " + resourcePath); return; } - String resourcePath = CLOAKS_RESOURCE_PATH + fileName; + // Read all bytes at once - more efficient than multiple reads + byte[] data = inputStream.readAllBytes(); + GifDecoder.GifImage gif = GifDecoder.read(data); - try (InputStream inputStream = Cloaks.class.getClassLoader().getResourceAsStream(resourcePath)) { - if (inputStream == null) { - Providers.saturn.logError("Cloak resource not found: " + resourcePath); - return; - } - - // Read all bytes at once - more efficient than multiple reads - byte[] data = inputStream.readAllBytes(); - GifDecoder.GifImage gif = GifDecoder.read(data); - - int frameCount = gif.getFrameCount(); - if (frameCount == 0) { - Providers.saturn.logError("No frames found in animated cloak: " + fileName); - return; - } - - // Pre-allocate collections with known size - List animatedFrames = new ArrayList<>(frameCount); - String baseFrameId = fileName.replace(".gif", ""); - - // Process frames in batch - for (int i = 0; i < frameCount; i++) { - BufferedImage frame = gif.getFrame(i); - int delay = Math.max(gif.getDelay(i) * 10, 50); // Minimum 50ms delay - - String frameId = baseFrameId + "_frame_" + i; - IdentifierRef frameIdentifier = IdentifierRef.ofSaturn("cloaks_" + frameId); - - try { - Providers.saturn.registerBufferedImageTexture(frameIdentifier, frame); - animatedFrames.add(new AnimatedCloakData(frameIdentifier, delay)); - } catch (Exception e) { - Providers.saturn.logError("Failed to register frame " + i + " for cloak: " + fileName, e); - // Continue with other frames instead of failing completely - } - } - - if (!animatedFrames.isEmpty()) { - // Cache the result for future use - CLOAK_CACHE.put(fileName, animatedFrames); - animatedCloaks.put(uuid, animatedFrames); - lastFrameTime.put(uuid, System.currentTimeMillis()); - - Providers.saturn.logInfo("Loaded " + animatedFrames.size() + " frames for animated cloak: " - + fileName + " (cached)"); - } else { - Providers.saturn.logError("No valid frames could be loaded for cloak: " + fileName); - } - - } catch (IOException e) { - Providers.saturn.logError("Failed to load animated cloak from resources: " + fileName, e); - } catch (Exception e) { - Providers.saturn.logError("Unexpected error loading animated cloak: " + fileName, e); + int frameCount = gif.getFrameCount(); + if (frameCount == 0) { + Providers.saturn.logError("No frames found in animated cloak: " + fileName); + return; } - }, CLOAK_LOADER_EXECUTOR); + + // Pre-allocate collections with known size + List animatedFrames = new ArrayList<>(frameCount); + String baseFrameId = fileName.replace(".gif", ""); + + // Process frames in batch + for (int i = 0; i < frameCount; i++) { + BufferedImage frame = gif.getFrame(i); + int delay = Math.max(gif.getDelay(i) * 10, 50); // Minimum 50ms delay + + String frameId = baseFrameId + "_frame_" + i; + IdentifierRef frameIdentifier = IdentifierRef.ofSaturn("cloaks_" + frameId); + + try { + Providers.saturn.registerBufferedImageTexture(frameIdentifier, frame); + animatedFrames.add(new AnimatedCloakData(frameIdentifier, delay)); + } catch (Exception e) { + Providers.saturn.logError("Failed to register frame " + i + " for cloak: " + fileName, e); + // Continue with other frames instead of failing completely + } + } + + if (!animatedFrames.isEmpty()) { + // Cache the result for future use + CLOAK_CACHE.put(fileName, animatedFrames); + animatedCloaks.put(cloakName, animatedFrames); + lastFrameTime.put(cloakName, System.currentTimeMillis()); + + Providers.saturn.logInfo("Loaded " + animatedFrames.size() + " frames for animated cloak: " + + fileName + " (cached)"); + } else { + Providers.saturn.logError("No valid frames could be loaded for cloak: " + fileName); + } + + } catch (IOException e) { + Providers.saturn.logError("Failed to load animated cloak from resources: " + fileName, e); + } catch (Exception e) { + Providers.saturn.logError("Unexpected error loading animated cloak: " + fileName, e); + } } - public static IdentifierRef getCurrentCloakTexture(UUID uuid) { - SaturnPlayer player = SaturnPlayer.get(uuid); - - if (player == null || player.cloak.isEmpty()) { - return null; - } - - String cloakName = player.cloak; - + public static IdentifierRef getCurrentCloakTexture(String cloakName) { if (Arrays.asList(ANIMATED_CLOAKS).contains(cloakName)) { - List frames = animatedCloaks.get(uuid); + List frames = animatedCloaks.get(cloakName); if (frames == null || frames.isEmpty()) { return null; } long currentTime = System.currentTimeMillis(); - long lastTime = lastFrameTime.getOrDefault(uuid, currentTime); + long lastTime = lastFrameTime.getOrDefault(cloakName, currentTime); int currentFrame = 0; long elapsedTime = currentTime - lastTime; @@ -238,7 +206,7 @@ public class Cloaks { } if (elapsedTime >= totalTime) { - lastFrameTime.put(uuid, currentTime); + lastFrameTime.put(cloakName, currentTime); currentFrame = 0; }