working ish

This commit is contained in:
2025-02-28 18:21:04 +01:00
parent 9928854f88
commit ff78d68e98
2 changed files with 107 additions and 6 deletions
@@ -3,13 +3,17 @@ package org.auraclient.auraclient.cloaks;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import org.auraclient.auraclient.AuraClient; import org.auraclient.auraclient.AuraClient;
import org.auraclient.auraclient.auth.AuraApi; import org.auraclient.auraclient.auth.AuraApi;
import org.auraclient.auraclient.cloaks.utils.AnimatedCapeData;
import org.auraclient.auraclient.cloaks.utils.IdentifierUtils; import org.auraclient.auraclient.cloaks.utils.IdentifierUtils;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* Manages the cloak/cape system for Aura Client. * Manages the cloak/cape system for Aura Client.
@@ -20,6 +24,8 @@ public class Cloaks {
public static final List<String> availableCloaks = new ArrayList<>(); public static final List<String> availableCloaks = new ArrayList<>();
public static Identifier capeCacheIdentifier = null; public static Identifier capeCacheIdentifier = null;
public static final Map<String, String> playerCapes = new HashMap<>(); public static final Map<String, String> playerCapes = new HashMap<>();
public static final Map<String, List<AnimatedCapeData>> animatedCapes = new ConcurrentHashMap<>();
private static final Map<String, Long> lastFrameTime = new ConcurrentHashMap<>();
/** /**
* Initializes the cloak system. * Initializes the cloak system.
@@ -39,9 +45,13 @@ public class Cloaks {
Cloaks.playerCapes.put(uuid, capeName); Cloaks.playerCapes.put(uuid, capeName);
if (!capeName.isEmpty()) { if (!capeName.isEmpty()) {
if (capeName.endsWith(".gif")) {
loadAnimatedCape(uuid, capeName);
} else {
loadStaticCape(capeName); loadStaticCape(capeName);
} }
} }
}
/** /**
* Loads and processes a static cape from a PNG file in resources. * Loads and processes a static cape from a PNG file in resources.
@@ -68,4 +78,97 @@ public class Cloaks {
AuraClient.LOGGER.error("Failed to load static cape from resources: " + fileName, e); AuraClient.LOGGER.error("Failed to load static cape from resources: " + fileName, e);
} }
} }
private static void loadAnimatedCape(String uuid, String fileName) {
try {
String resourcePath = CAPES_RESOURCE_PATH + fileName;
InputStream inputStream = Cloaks.class.getClassLoader().getResourceAsStream(resourcePath);
if (inputStream != null) {
ImageInputStream stream = ImageIO.createImageInputStream(inputStream);
ImageReader reader = ImageIO.getImageReadersByFormatName("gif").next();
reader.setInput(stream);
List<AnimatedCapeData> frames = new ArrayList<>();
int frameCount = reader.getNumImages(true);
for (int i = 0; i < frameCount; i++) {
BufferedImage frame = reader.read(i);
String frameId = fileName.replace(".gif", "") + "_frame_" + i;
Identifier frameIdentifier = Identifier.of(AuraClient.MOD_ID, "capes_" + frameId);
IdentifierUtils.registerBufferedImageTexture(frameIdentifier, frame);
// Get frame delay in milliseconds (default to 100ms if not specified)
int delay = 100;
try {
javax.imageio.metadata.IIOMetadata metadata = reader.getImageMetadata(i);
String metaFormatName = metadata.getNativeMetadataFormatName();
org.w3c.dom.Node root = metadata.getAsTree(metaFormatName);
org.w3c.dom.NodeList children = root.getChildNodes();
for (int j = 0; j < children.getLength(); j++) {
org.w3c.dom.Node node = children.item(j);
if (node.getNodeName().equals("GraphicControlExtension")) {
org.w3c.dom.NamedNodeMap attrs = node.getAttributes();
org.w3c.dom.Node delayNode = attrs.getNamedItem("delayTime");
if (delayNode != null) {
delay = Integer.parseInt(delayNode.getNodeValue()) * 10; // Convert centiseconds to
// milliseconds
}
break;
}
}
} catch (Exception e) {
AuraClient.LOGGER.warn("Could not read frame delay for " + fileName + " frame " + i);
}
frames.add(new AnimatedCapeData(frameIdentifier, delay));
}
animatedCapes.put(uuid, frames);
lastFrameTime.put(uuid, System.currentTimeMillis());
}
} catch (IOException e) {
AuraClient.LOGGER.error("Failed to load animated cape from resources: " + fileName, e);
}
}
public static Identifier getCurrentCapeTexture(String uuid) {
if (!playerCapes.containsKey(uuid)) {
return null;
}
String capeName = playerCapes.get(uuid);
if (capeName.endsWith(".gif")) {
List<AnimatedCapeData> frames = animatedCapes.get(uuid);
if (frames == null || frames.isEmpty()) {
return null;
}
long currentTime = System.currentTimeMillis();
long lastTime = lastFrameTime.getOrDefault(uuid, currentTime);
int currentFrame = 0;
// Find the current frame based on elapsed time
long elapsedTime = currentTime - lastTime;
long totalTime = 0;
for (int i = 0; i < frames.size(); i++) {
totalTime += frames.get(i).getDelayMs();
if (elapsedTime < totalTime) {
currentFrame = i;
break;
}
}
// Reset animation if we've gone through all frames
if (elapsedTime >= totalTime) {
lastFrameTime.put(uuid, currentTime);
currentFrame = 0;
}
return frames.get(currentFrame).getTextureId();
} else {
return Identifier.of(AuraClient.MOD_ID, "textures/capes/" + capeName + ".png");
}
}
} }
@@ -27,18 +27,16 @@ public class AbstractClientPlayerEntityMixin {
@Inject(method = "getSkinTextures", at = @At("RETURN"), cancellable = true) @Inject(method = "getSkinTextures", at = @At("RETURN"), cancellable = true)
private void getSkinTextures(CallbackInfoReturnable<SkinTextures> cir) { private void getSkinTextures(CallbackInfoReturnable<SkinTextures> cir) {
AbstractClientPlayerEntity player = (AbstractClientPlayerEntity) (Object) this; AbstractClientPlayerEntity player = (AbstractClientPlayerEntity) (Object) this;
String uuid = player.getUuidAsString().replace("-", ""); String uuid = player.getUuidAsString().replace("-", "");
if (Cloaks.playerCapes.containsKey(uuid)) { if (Cloaks.playerCapes.containsKey(uuid)) {
String cloak = Cloaks.playerCapes.get(uuid); Identifier capeTexture = Cloaks.getCurrentCapeTexture(uuid);
if (capeTexture != null) {
if (!cloak.isEmpty()) {
SkinTextures textures = cir.getReturnValue(); SkinTextures textures = cir.getReturnValue();
cir.setReturnValue(new SkinTextures( cir.setReturnValue(new SkinTextures(
textures.texture(), textures.texture(),
textures.textureUrl(), textures.textureUrl(),
Identifier.of("auraclient", "textures/capes/" + cloak + ".png"), capeTexture,
textures.elytraTexture(), textures.elytraTexture(),
textures.model(), textures.model(),
textures.secure())); textures.secure()));