working ish
This commit is contained in:
@@ -3,6 +3,7 @@ package org.auraclient.auraclient;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import org.auraclient.auraclient.cloaks.Cloaks;
|
||||
import org.auraclient.auraclient.event.KeyInputHandler;
|
||||
import org.auraclient.auraclient.auth.AuraApi;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -17,8 +18,14 @@ public class AuraClient implements ModInitializer {
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
LOGGER.info("Initializing " + MOD_ID);
|
||||
KeyInputHandler.register();
|
||||
Cloaks.initialize();
|
||||
LOGGER.info(MOD_ID + " initialization complete");
|
||||
|
||||
// Attempt authentication before initializing other features
|
||||
if (AuraApi.authenticate()) {
|
||||
KeyInputHandler.register();
|
||||
Cloaks.initialize();
|
||||
LOGGER.info(MOD_ID + " initialization complete");
|
||||
} else {
|
||||
LOGGER.error("Failed to authenticate with the server");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
package org.auraclient.auraclient.auth;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import org.auraclient.auraclient.AuraClient;
|
||||
import org.auraclient.auraclient.cloaks.Cloaks;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class AuraApi {
|
||||
private static final String URL = "http://localhost:3000";
|
||||
|
||||
private static String token = null;
|
||||
private static String uuid = null;
|
||||
|
||||
public static boolean authenticate() {
|
||||
try {
|
||||
MinecraftClient client = MinecraftClient.getInstance();
|
||||
if (client.getSession() == null) {
|
||||
AuraClient.LOGGER.error("No active Minecraft session found");
|
||||
return false;
|
||||
}
|
||||
|
||||
String accessToken = client.getSession().getAccessToken();
|
||||
|
||||
token = URLEncoder.encode(accessToken, StandardCharsets.UTF_8);
|
||||
|
||||
String authUrl = String.format("%s/auth?token=%s", URL, token);
|
||||
|
||||
AuraClient.LOGGER.info("Authenticating with URL: " + authUrl);
|
||||
|
||||
URL url = URI.create(authUrl).toURL();
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setRequestMethod("GET");
|
||||
|
||||
BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(conn.getInputStream()));
|
||||
StringBuilder response = new StringBuilder();
|
||||
String line;
|
||||
|
||||
while ((line = reader.readLine()) != null) {
|
||||
response.append(line);
|
||||
}
|
||||
reader.close();
|
||||
|
||||
JsonObject jsonResponse = JsonParser.parseString(response.toString()).getAsJsonObject();
|
||||
boolean success = jsonResponse.get("success").getAsBoolean();
|
||||
uuid = jsonResponse.get("uuid").getAsString();
|
||||
|
||||
if (success) {
|
||||
AuraClient.LOGGER.info("Successfully authenticated");
|
||||
}
|
||||
|
||||
// Update available cloaks list
|
||||
Cloaks.availableCloaks.clear();
|
||||
jsonResponse.get("cloaks").getAsJsonArray()
|
||||
.forEach(element -> Cloaks.availableCloaks.add(element.getAsString()));
|
||||
|
||||
String cloak = jsonResponse.get("cloak").getAsString();
|
||||
if (cloak != null) {
|
||||
AuraClient.LOGGER.info("Setting cloak to " + cloak + " for " + uuid);
|
||||
Cloaks.playerCapes.put(uuid, cloak);
|
||||
}
|
||||
|
||||
return success;
|
||||
|
||||
} catch (Exception e) {
|
||||
AuraClient.LOGGER.error("Authentication failed", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void setCloak(String cloak) {
|
||||
if (token == null) {
|
||||
AuraClient.LOGGER.error("No token found");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
String setCloakUrl = String.format("%s/cloak/%s?token=%s", URL, cloak, token);
|
||||
|
||||
URL url = URI.create(setCloakUrl).toURL();
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setRequestMethod("POST");
|
||||
|
||||
BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(conn.getInputStream()));
|
||||
StringBuilder response = new StringBuilder();
|
||||
String line;
|
||||
|
||||
while ((line = reader.readLine()) != null) {
|
||||
response.append(line);
|
||||
}
|
||||
|
||||
reader.close();
|
||||
|
||||
JsonObject jsonResponse = JsonParser.parseString(response.toString()).getAsJsonObject();
|
||||
boolean success = jsonResponse.get("success").getAsBoolean();
|
||||
|
||||
if (success) {
|
||||
AuraClient.LOGGER.info("Successfully set cloak");
|
||||
} else {
|
||||
AuraClient.LOGGER.error("Failed to set cloak");
|
||||
AuraClient.LOGGER.error(jsonResponse.get("error").getAsString());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
AuraClient.LOGGER.error("Failed to set cloak", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
package org.auraclient.auraclient.cloaks;
|
||||
|
||||
import at.dhyan.open_imaging.GifDecoder;
|
||||
import net.minecraft.util.Identifier;
|
||||
import org.auraclient.auraclient.AuraClient;
|
||||
import org.auraclient.auraclient.cloaks.utils.AnimatedCapeData;
|
||||
import org.auraclient.auraclient.auth.AuraApi;
|
||||
import org.auraclient.auraclient.cloaks.utils.IdentifierUtils;
|
||||
import org.auraclient.auraclient.cloaks.utils.RandomUtils;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
@@ -15,140 +13,59 @@ import java.util.*;
|
||||
|
||||
/**
|
||||
* Manages the cloak/cape system for Aura Client.
|
||||
* Handles loading, caching, and animating player capes.
|
||||
* Handles loading and caching of player capes.
|
||||
*/
|
||||
public class Cloaks {
|
||||
private static final String CAPES_RESOURCE_PATH = "assets/auraclient/textures/capes/";
|
||||
private static final List<AnimatedCapeData> animatedCapeFrames = new ArrayList<>();
|
||||
private static int currentFrameIndex = 0;
|
||||
private static long lastFrameTime = System.currentTimeMillis();
|
||||
private static String lastCachedCape = "NoCache";
|
||||
|
||||
public static final List<String> availableCapes = new ArrayList<>();
|
||||
public static final List<String> availableCloaks = new ArrayList<>();
|
||||
public static Identifier capeCacheIdentifier = null;
|
||||
public static final Map<String, String> playerCapes = new HashMap<>();
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the cloak system.
|
||||
* Loads cape textures from resources.
|
||||
*/
|
||||
public static void initialize() {
|
||||
availableCapes.clear();
|
||||
availableCapes.add("");
|
||||
loadCloakTextures();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads cloak textures from the resources.
|
||||
* Supports both static (.png) and animated (.gif) capes.
|
||||
*/
|
||||
private static void loadCloakTextures() {
|
||||
// In a resource-based system, we would need to manually list available capes
|
||||
// For now, we can add default capes that we know exist in resources
|
||||
// This would need to be updated when adding new capes to resources
|
||||
availableCapes.add("glitch.png");
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the cape animation state.
|
||||
* Called every tick to handle animated capes.
|
||||
*/
|
||||
public static void tick() {
|
||||
String currentCape = playerCapes.values().stream().findFirst().orElse("");
|
||||
|
||||
if (!lastCachedCape.equals(currentCape)) {
|
||||
handleCapeChange(currentCape);
|
||||
} else if (currentCape.endsWith(".gif")) {
|
||||
updateAnimatedCape();
|
||||
}
|
||||
availableCloaks.add(0, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles loading and caching of a new cape texture.
|
||||
*
|
||||
* @param capeName Name of the cape file to load
|
||||
*/
|
||||
private static void handleCapeChange(String capeName) {
|
||||
if (!capeName.isEmpty()) {
|
||||
if (capeName.endsWith(".gif")) {
|
||||
loadAnimatedCape(capeName);
|
||||
} else {
|
||||
loadStaticCape(capeName);
|
||||
}
|
||||
lastCachedCape = capeName;
|
||||
}
|
||||
}
|
||||
public static void setCape(String uuid, String capeName) {
|
||||
AuraApi.setCloak(capeName);
|
||||
Cloaks.playerCapes.put(uuid, capeName);
|
||||
|
||||
/**
|
||||
* Loads and processes an animated cape from a GIF file in resources.
|
||||
* @param fileName Name of the GIF file to load
|
||||
*/
|
||||
private static void loadAnimatedCape(String fileName) {
|
||||
try {
|
||||
animatedCapeFrames.clear();
|
||||
String resourcePath = CAPES_RESOURCE_PATH + fileName;
|
||||
InputStream inputStream = Cloaks.class.getClassLoader().getResourceAsStream(resourcePath);
|
||||
|
||||
if (inputStream != null) {
|
||||
GifDecoder.GifImage gif = GifDecoder.read(inputStream);
|
||||
int frameCount = gif.getFrameCount();
|
||||
|
||||
for (int i = 0; i < frameCount; i++) {
|
||||
BufferedImage frame = gif.getFrame(i);
|
||||
int delay = gif.getDelay(i);
|
||||
Identifier frameId = Identifier.of(AuraClient.MOD_ID,
|
||||
"capes_" + RandomUtils.randomStringLowercase(10));
|
||||
|
||||
IdentifierUtils.registerBufferedImageTexture(frameId, frame);
|
||||
animatedCapeFrames.add(new AnimatedCapeData(frameId, delay));
|
||||
}
|
||||
|
||||
currentFrameIndex = 0;
|
||||
capeCacheIdentifier = animatedCapeFrames.get(0).getTextureId();
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
AuraClient.LOGGER.error("Failed to load animated cape from resources: " + fileName, e);
|
||||
if (!capeName.isEmpty()) {
|
||||
loadStaticCape(capeName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and processes a static cape from a PNG file in resources.
|
||||
*
|
||||
* @param fileName Name of the PNG file to load
|
||||
*/
|
||||
private static void loadStaticCape(String fileName) {
|
||||
try {
|
||||
String resourcePath = CAPES_RESOURCE_PATH + fileName;
|
||||
InputStream inputStream = Cloaks.class.getClassLoader().getResourceAsStream(resourcePath);
|
||||
|
||||
|
||||
if (inputStream != null) {
|
||||
BufferedImage image = ImageIO.read(inputStream);
|
||||
|
||||
|
||||
String safeFileName = fileName.toLowerCase(Locale.ROOT)
|
||||
.replace(' ', '_')
|
||||
.replaceAll("[^a-z0-9/._-]", "");
|
||||
|
||||
.replace(' ', '_')
|
||||
.replaceAll("[^a-z0-9/._-]", "");
|
||||
|
||||
capeCacheIdentifier = Identifier.of(AuraClient.MOD_ID, "capes_" + safeFileName);
|
||||
IdentifierUtils.registerBufferedImageTexture(capeCacheIdentifier, image);
|
||||
}
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
AuraClient.LOGGER.error("Failed to load static cape from resources: " + fileName, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the current frame of an animated cape.
|
||||
*/
|
||||
private static void updateAnimatedCape() {
|
||||
if (currentFrameIndex >= animatedCapeFrames.size()) {
|
||||
currentFrameIndex = 0;
|
||||
}
|
||||
|
||||
AnimatedCapeData currentFrame = animatedCapeFrames.get(currentFrameIndex);
|
||||
if (System.currentTimeMillis() > lastFrameTime + currentFrame.getDelayMs()) {
|
||||
lastFrameTime = System.currentTimeMillis();
|
||||
capeCacheIdentifier = currentFrame.getTextureId();
|
||||
currentFrameIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +1,26 @@
|
||||
package org.auraclient.auraclient.menus;
|
||||
|
||||
import org.auraclient.auraclient.AuraClient;
|
||||
import org.auraclient.auraclient.cloaks.Cloaks;
|
||||
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.gui.widget.TextFieldWidget;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
public class CloakSelector extends Screen {
|
||||
private TextFieldWidget playerNameField;
|
||||
|
||||
public CloakSelector() {
|
||||
super(Text.literal("Cloaks"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
// Add player name text field at the top
|
||||
this.playerNameField = new TextFieldWidget(this.textRenderer,
|
||||
(this.width - 200) / 2, 20, 200, 20, Text.literal("Player Name"));
|
||||
this.playerNameField.setMaxLength(16);
|
||||
addDrawableChild(this.playerNameField);
|
||||
int y = ((this.height - (35 * (Cloaks.availableCloaks.size()))) / 2) + 30;
|
||||
|
||||
// Calculate starting Y position for cloak buttons, accounting for text field
|
||||
int y = ((this.height - (35 * (Cloaks.availableCapes.size()))) / 2) + 30;
|
||||
|
||||
for (String cloak : Cloaks.availableCapes) {
|
||||
for (String cloak : Cloaks.availableCloaks) {
|
||||
addDrawableChild(ButtonWidget.builder(Text.literal(cloak), (__) -> {
|
||||
String playerName = this.playerNameField.getText();
|
||||
if (!playerName.isEmpty() && !playerName.equals("Player Name")) {
|
||||
if (cloak.isEmpty()) {
|
||||
Cloaks.playerCapes.remove(playerName);
|
||||
AuraClient.LOGGER.info("Cape removed for player: " + playerName);
|
||||
} else {
|
||||
Cloaks.playerCapes.put(playerName, cloak);
|
||||
AuraClient.LOGGER.info("Cape set for player: " + playerName + " to " + cloak);
|
||||
}
|
||||
}
|
||||
String uuid = client.player.getUuidAsString().replace("-", "");
|
||||
Cloaks.setCape(uuid, cloak);
|
||||
// Cloaks.playerCapes.put(uuid, cloak);
|
||||
// AuraApi.setCloak(cloak);
|
||||
}).dimensions((this.width - 50) / 2, y, 50, 30).build());
|
||||
|
||||
y += 35;
|
||||
|
||||
@@ -6,7 +6,7 @@ import net.minecraft.text.Text;
|
||||
|
||||
public class MainMenu extends Screen {
|
||||
public MainMenu() {
|
||||
super(Text.literal("Custom Screen"));
|
||||
super(Text.literal("Aura Client"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+20
-19
@@ -4,6 +4,7 @@ import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.network.AbstractClientPlayerEntity;
|
||||
import net.minecraft.client.util.SkinTextures;
|
||||
import net.minecraft.util.Identifier;
|
||||
import org.auraclient.auraclient.cloaks.Cloaks;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@@ -17,31 +18,31 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
@Mixin(AbstractClientPlayerEntity.class)
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class AbstractClientPlayerEntityMixin {
|
||||
|
||||
|
||||
/**
|
||||
* Injects custom cape textures into the player's skin textures.
|
||||
*
|
||||
* @param cir Callback containing the original skin textures
|
||||
*/
|
||||
@Inject(
|
||||
method = "getSkinTextures",
|
||||
at = @At("RETURN"),
|
||||
cancellable = true
|
||||
)
|
||||
@Inject(method = "getSkinTextures", at = @At("RETURN"), cancellable = true)
|
||||
private void getSkinTextures(CallbackInfoReturnable<SkinTextures> cir) {
|
||||
AbstractClientPlayerEntity player = (AbstractClientPlayerEntity) (Object) this;
|
||||
|
||||
if (Cloaks.playerCapes.containsKey(player.getName().getString()) &&
|
||||
Cloaks.capeCacheIdentifier != null) {
|
||||
|
||||
SkinTextures textures = cir.getReturnValue();
|
||||
cir.setReturnValue(new SkinTextures(
|
||||
textures.texture(),
|
||||
textures.textureUrl(),
|
||||
Cloaks.capeCacheIdentifier,
|
||||
textures.elytraTexture(),
|
||||
textures.model(),
|
||||
textures.secure()
|
||||
));
|
||||
|
||||
String uuid = player.getUuidAsString().replace("-", "");
|
||||
|
||||
if (Cloaks.playerCapes.containsKey(uuid)) {
|
||||
String cloak = Cloaks.playerCapes.get(uuid);
|
||||
|
||||
if (!cloak.isEmpty()) {
|
||||
SkinTextures textures = cir.getReturnValue();
|
||||
cir.setReturnValue(new SkinTextures(
|
||||
textures.texture(),
|
||||
textures.textureUrl(),
|
||||
Identifier.of("auraclient", "textures/capes/" + cloak + ".png"),
|
||||
textures.elytraTexture(),
|
||||
textures.model(),
|
||||
textures.secure()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package org.auraclient.auraclient.mixin;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import org.auraclient.auraclient.cloaks.Cloaks;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
/**
|
||||
* Mixin for the MinecraftClient class.
|
||||
* Handles the periodic updating of cloaks system.
|
||||
*/
|
||||
@Mixin(MinecraftClient.class)
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class MinecraftClientMixin {
|
||||
|
||||
/**
|
||||
* Injects into the client tick to update cloaks.
|
||||
* @param ci Callback info
|
||||
*/
|
||||
@Inject(
|
||||
method = "tick",
|
||||
at = @At("HEAD")
|
||||
)
|
||||
private void tick(CallbackInfo ci) {
|
||||
Cloaks.tick();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user