Moving cloaks to common
This commit is contained in:
+1
-1
Submodule common updated: a54aa9eaba...5b34d3eb37
+1
-1
@@ -282,7 +282,7 @@ public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderStat
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Identifier customCape = Cloaks.getCurrentCloakTexture(player.uuid);
|
Identifier customCape = (Identifier) (Object) Cloaks.getCurrentCloakTexture(player.uuid);
|
||||||
if (customCape == null
|
if (customCape == null
|
||||||
|| this.hasCustomModelForLayer(playerEntityRenderState.equippedChestStack, LayerType.WINGS)) {
|
|| this.hasCustomModelForLayer(playerEntityRenderState.equippedChestStack, LayerType.WINGS)) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
package org.saturnclient.cosmetics.cloak;
|
package org.saturnclient.cosmetics.cloak;
|
||||||
|
|
||||||
import net.minecraft.util.Identifier;
|
|
||||||
|
|
||||||
import org.saturnclient.client.ServiceClient;
|
import org.saturnclient.client.ServiceClient;
|
||||||
import org.saturnclient.client.player.SaturnPlayer;
|
import org.saturnclient.client.player.SaturnPlayer;
|
||||||
|
import org.saturnclient.common.ref.asset.IdentifierRef;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
@@ -15,7 +14,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
import org.saturnclient.cosmetics.cloak.utils.AnimatedCloakData;
|
import org.saturnclient.cosmetics.utils.AnimatedCloakData;
|
||||||
import org.saturnclient.cosmetics.cloak.utils.IdentifierUtils;
|
import org.saturnclient.cosmetics.cloak.utils.IdentifierUtils;
|
||||||
import org.saturnclient.saturnclient.SaturnClient;
|
import org.saturnclient.saturnclient.SaturnClient;
|
||||||
|
|
||||||
@@ -32,7 +31,7 @@ public class Cloaks {
|
|||||||
|
|
||||||
private static final String CLOAKS_RESOURCE_PATH = "assets/saturnclient/textures/cloaks/";
|
private static final String CLOAKS_RESOURCE_PATH = "assets/saturnclient/textures/cloaks/";
|
||||||
public static final List<String> availableCloaks = new ArrayList<>();
|
public static final List<String> availableCloaks = new ArrayList<>();
|
||||||
public static Identifier cloakCacheIdentifier = null;
|
public static IdentifierRef cloakCacheIdentifier = null;
|
||||||
public static final Map<UUID, List<AnimatedCloakData>> animatedCloaks = new ConcurrentHashMap<>();
|
public static final Map<UUID, List<AnimatedCloakData>> animatedCloaks = new ConcurrentHashMap<>();
|
||||||
private static final Map<UUID, Long> lastFrameTime = new ConcurrentHashMap<>();
|
private static final Map<UUID, Long> lastFrameTime = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@@ -129,8 +128,8 @@ public class Cloaks {
|
|||||||
.replace(' ', '_')
|
.replace(' ', '_')
|
||||||
.replaceAll("[^a-z0-9/._-]", "");
|
.replaceAll("[^a-z0-9/._-]", "");
|
||||||
|
|
||||||
cloakCacheIdentifier = Identifier.of(SaturnClient.MOD_ID, "cloaks_" + safeFileName);
|
cloakCacheIdentifier = IdentifierRef.of(SaturnClient.MOD_ID, "cloaks_" + safeFileName);
|
||||||
IdentifierUtils.registerBufferedImageTexture(cloakCacheIdentifier, image);
|
IdentifierUtils.registerBufferedImageTextureFast(cloakCacheIdentifier, image);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
SaturnClient.LOGGER.error("Failed to load static cloak from resources: " + fileName, e);
|
SaturnClient.LOGGER.error("Failed to load static cloak from resources: " + fileName, e);
|
||||||
@@ -177,7 +176,7 @@ public class Cloaks {
|
|||||||
int delay = Math.max(gif.getDelay(i) * 10, 50); // Minimum 50ms delay
|
int delay = Math.max(gif.getDelay(i) * 10, 50); // Minimum 50ms delay
|
||||||
|
|
||||||
String frameId = baseFrameId + "_frame_" + i;
|
String frameId = baseFrameId + "_frame_" + i;
|
||||||
Identifier frameIdentifier = Identifier.of(SaturnClient.MOD_ID, "cloaks_" + frameId);
|
IdentifierRef frameIdentifier = IdentifierRef.of(SaturnClient.MOD_ID, "cloaks_" + frameId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
IdentifierUtils.registerBufferedImageTextureFast(frameIdentifier, frame);
|
IdentifierUtils.registerBufferedImageTextureFast(frameIdentifier, frame);
|
||||||
@@ -217,7 +216,7 @@ public class Cloaks {
|
|||||||
}, CLOAK_LOADER_EXECUTOR);
|
}, CLOAK_LOADER_EXECUTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Identifier getCurrentCloakTexture(UUID uuid) {
|
public static IdentifierRef getCurrentCloakTexture(UUID uuid) {
|
||||||
SaturnPlayer player = SaturnPlayer.get(uuid);
|
SaturnPlayer player = SaturnPlayer.get(uuid);
|
||||||
|
|
||||||
if (player == null || player.cloak.isEmpty()) {
|
if (player == null || player.cloak.isEmpty()) {
|
||||||
@@ -251,15 +250,15 @@ public class Cloaks {
|
|||||||
currentFrame = 0;
|
currentFrame = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Identifier identifier = frames.get(currentFrame).getTextureId();
|
IdentifierRef identifier = frames.get(currentFrame).getTextureId();
|
||||||
|
|
||||||
if (identifier == null) {
|
if (identifier == null) {
|
||||||
return Identifier.of(SaturnClient.MOD_ID, "textures/cloaks/" + cloakName + ".png");
|
return IdentifierRef.of(SaturnClient.MOD_ID, "textures/cloaks/" + cloakName + ".png");
|
||||||
}
|
}
|
||||||
|
|
||||||
return identifier;
|
return identifier;
|
||||||
} else {
|
} else {
|
||||||
return Identifier.of(SaturnClient.MOD_ID, "textures/cloaks/" + cloakName + ".png");
|
return IdentifierRef.of(SaturnClient.MOD_ID, "textures/cloaks/" + cloakName + ".png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
-36
@@ -1,36 +0,0 @@
|
|||||||
package org.saturnclient.cosmetics.cloak.utils;
|
|
||||||
|
|
||||||
import net.minecraft.util.Identifier;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a single frame of an animated cloak.
|
|
||||||
*/
|
|
||||||
public class AnimatedCloakData {
|
|
||||||
private final Identifier textureId;
|
|
||||||
private final int delayMs;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new animated cloak frame.
|
|
||||||
*
|
|
||||||
* @param textureId The texture identifier for this frame
|
|
||||||
* @param delayMs The delay in milliseconds before the next frame
|
|
||||||
*/
|
|
||||||
public AnimatedCloakData(Identifier textureId, int delayMs) {
|
|
||||||
this.textureId = textureId;
|
|
||||||
this.delayMs = delayMs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The texture identifier for this frame
|
|
||||||
*/
|
|
||||||
public Identifier getTextureId() {
|
|
||||||
return textureId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The delay in milliseconds before the next frame
|
|
||||||
*/
|
|
||||||
public int getDelayMs() {
|
|
||||||
return delayMs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+34
-62
@@ -1,98 +1,70 @@
|
|||||||
package org.saturnclient.cosmetics.cloak.utils;
|
package org.saturnclient.cosmetics.cloak.utils;
|
||||||
|
|
||||||
|
import org.saturnclient.common.ref.asset.IdentifierRef;
|
||||||
import org.saturnclient.saturnclient.SaturnClient;
|
import org.saturnclient.saturnclient.SaturnClient;
|
||||||
|
|
||||||
import net.minecraft.client.texture.NativeImage;
|
import net.minecraft.client.texture.NativeImage;
|
||||||
import net.minecraft.client.texture.NativeImageBackedTexture;
|
import net.minecraft.client.texture.NativeImageBackedTexture;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.DataBufferInt;
|
import java.awt.image.DataBufferInt;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class IdentifierUtils {
|
public class IdentifierUtils {
|
||||||
|
|
||||||
/**
|
public static void registerBufferedImageTextureFast(IdentifierRef identifierRef, BufferedImage bufferedImage) {
|
||||||
* ORIGINAL METHOD - EXTREMELY SLOW - causes 10-20 second freezes
|
|
||||||
* This converts BufferedImage -> PNG bytes -> ByteBuffer -> NativeImage ->
|
|
||||||
* Texture
|
|
||||||
* This is completely unnecessary and wastes massive amounts of CPU time!
|
|
||||||
*/
|
|
||||||
public static void registerBufferedImageTexture(Identifier i, BufferedImage bi) {
|
|
||||||
try {
|
try {
|
||||||
// This is the performance killer:
|
Identifier identifier = (Identifier) (Object) identifierRef;
|
||||||
// 1. Converts BufferedImage to PNG (expensive compression)
|
|
||||||
// 2. Creates ByteBuffer copy (memory allocation)
|
|
||||||
// 3. NativeImage.read() parses PNG back to raw pixels (expensive decompression)
|
|
||||||
// This is doing compression -> decompression for no reason!
|
|
||||||
|
|
||||||
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
|
|
||||||
javax.imageio.ImageIO.write(bi, "png", baos);
|
|
||||||
byte[] bytes = baos.toByteArray();
|
|
||||||
java.nio.ByteBuffer bb = org.lwjgl.BufferUtils.createByteBuffer(bytes.length).put(bytes);
|
|
||||||
bb.flip();
|
|
||||||
NativeImageBackedTexture nibt = new NativeImageBackedTexture(NativeImage.read(bb));
|
|
||||||
SaturnClient.client.getTextureManager().registerTexture(i, nibt);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OPTIMIZED METHOD - Direct pixel conversion without unnecessary PNG
|
|
||||||
* encoding/decoding
|
|
||||||
* This should reduce loading time from 10-20 seconds to under 1 second
|
|
||||||
*/
|
|
||||||
public static void registerBufferedImageTextureFast(Identifier identifier, BufferedImage bufferedImage) {
|
|
||||||
try {
|
|
||||||
int width = bufferedImage.getWidth();
|
int width = bufferedImage.getWidth();
|
||||||
int height = bufferedImage.getHeight();
|
int height = bufferedImage.getHeight();
|
||||||
|
|
||||||
// Create NativeImage directly with the correct format
|
|
||||||
NativeImage nativeImage = new NativeImage(NativeImage.Format.RGBA, width, height, false);
|
NativeImage nativeImage = new NativeImage(NativeImage.Format.RGBA, width, height, false);
|
||||||
|
|
||||||
// Direct pixel copy - much faster than PNG conversion
|
|
||||||
if (bufferedImage.getType() == BufferedImage.TYPE_INT_ARGB) {
|
if (bufferedImage.getType() == BufferedImage.TYPE_INT_ARGB) {
|
||||||
// Fast path for ARGB images - direct memory access
|
|
||||||
int[] pixels = ((DataBufferInt) bufferedImage.getRaster().getDataBuffer()).getData();
|
int[] pixels = ((DataBufferInt) bufferedImage.getRaster().getDataBuffer()).getData();
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
int pixel = pixels[y * width + x];
|
nativeImage.setColorArgb(x, y, pixels[index++]);
|
||||||
nativeImage.setColorArgb(x, y, pixel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Fallback for other image types - still faster than PNG conversion
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
int rgb = bufferedImage.getRGB(x, y);
|
|
||||||
nativeImage.setColorArgb(x, y, rgb);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the texture
|
} else {
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
nativeImage.setColorArgb(x, y, bufferedImage.getRGB(x, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
NativeImageBackedTexture texture = new NativeImageBackedTexture(nativeImage);
|
NativeImageBackedTexture texture = new NativeImageBackedTexture(nativeImage);
|
||||||
SaturnClient.client.execute(
|
|
||||||
() -> SaturnClient.client.getTextureManager().registerTexture(identifier, texture));
|
SaturnClient.client.execute(() ->
|
||||||
|
SaturnClient.client.getTextureManager().registerTexture(identifier, texture)
|
||||||
|
);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
SaturnClient.LOGGER.error("Failed to register texture: " + identifier, e);
|
SaturnClient.LOGGER.error("Failed to register texture: {}", identifierRef, e);
|
||||||
// Fallback to slow method if fast method fails
|
|
||||||
registerBufferedImageTexture(identifier, bufferedImage);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static void registerBufferedImageTexturesBulk(Map<IdentifierRef, BufferedImage> textures) {
|
||||||
* EVEN FASTER VERSION - Bulk texture registration
|
|
||||||
* Use this when registering many textures at once (like animated cloak frames)
|
|
||||||
*/
|
|
||||||
public static void registerBufferedImageTexturesBulk(java.util.Map<Identifier, BufferedImage> textures) {
|
|
||||||
long startTime = System.currentTimeMillis();
|
|
||||||
|
|
||||||
for (java.util.Map.Entry<Identifier, BufferedImage> entry : textures.entrySet()) {
|
long start = System.currentTimeMillis();
|
||||||
registerBufferedImageTextureFast(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
long endTime = System.currentTimeMillis();
|
textures.forEach(IdentifierUtils::registerBufferedImageTextureFast);
|
||||||
SaturnClient.LOGGER.info("Registered {} textures in {}ms", textures.size(), (endTime - startTime));
|
|
||||||
|
long end = System.currentTimeMillis();
|
||||||
|
|
||||||
|
SaturnClient.LOGGER.info(
|
||||||
|
"Registered {} textures in {}ms",
|
||||||
|
textures.size(),
|
||||||
|
(end - start)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
package org.saturnclient.cosmetics.cloak.utils;
|
|
||||||
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility class for generating random strings and numbers.
|
|
||||||
*/
|
|
||||||
public final class RandomUtils {
|
|
||||||
private static final String ALPHANUMERIC = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
||||||
private static final String ALPHANUMERIC_LOWERCASE = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
||||||
private static final Random RANDOM = new Random();
|
|
||||||
|
|
||||||
private RandomUtils() {
|
|
||||||
// Prevent instantiation
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a random string of specified length using given characters.
|
|
||||||
*/
|
|
||||||
private static String random(final int length, final char[] chars) {
|
|
||||||
StringBuilder sb = new StringBuilder(length);
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
sb.append(chars[RANDOM.nextInt(chars.length)]);
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a random string of specified length using alphanumeric characters.
|
|
||||||
*/
|
|
||||||
public static String randomString(final int length) {
|
|
||||||
return random(length, ALPHANUMERIC.toCharArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a random lowercase string of specified length.
|
|
||||||
*/
|
|
||||||
public static String randomStringLowercase(final int length) {
|
|
||||||
return random(length, ALPHANUMERIC_LOWERCASE.toCharArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a random integer between min and max (inclusive).
|
|
||||||
*/
|
|
||||||
public static int randBetween(int min, int max) {
|
|
||||||
return RANDOM.nextInt(max - min + 1) + min;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
-1
@@ -67,6 +67,6 @@ public class SaturnProviderImpl implements SaturnProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerBufferedImageTexture(IdentifierRef i, BufferedImage bi) {
|
public void registerBufferedImageTexture(IdentifierRef i, BufferedImage bi) {
|
||||||
IdentifierUtils.registerBufferedImageTextureFast((Identifier) (Object) i, bi);
|
IdentifierUtils.registerBufferedImageTextureFast(i, bi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user