From 8ff7e4e4ec35be7101ffe1cf92510ce5e6b80351 Mon Sep 17 00:00:00 2001 From: TGdoesCode Date: Mon, 23 Feb 2026 11:28:17 +0100 Subject: [PATCH] another cosmetics update --- gradle.properties | 2 +- .../szar/client/ClientCosmetics.java | 52 +++++---- .../dev/tggamesyt/szar/client/SzarClient.java | 22 ++++ .../dev/tggamesyt/szar/ServerCosmetics.java | 101 ++++++++++++++---- .../resources/data/szar/recipes/atom.json | 2 +- .../data/szar/recipes/detonator.json | 2 +- 6 files changed, 136 insertions(+), 45 deletions(-) diff --git a/gradle.properties b/gradle.properties index d8c937c..3287362 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ minecraft_version=1.20.1 yarn_mappings=1.20.1+build.10 loader_version=0.18.3 # Mod Properties -mod_version=26.2.22.2 +mod_version=26.2.23 maven_group=dev.tggamesyt archives_base_name=szar # Dependencies diff --git a/src/client/java/dev/tggamesyt/szar/client/ClientCosmetics.java b/src/client/java/dev/tggamesyt/szar/client/ClientCosmetics.java index 96e8710..c0ee969 100644 --- a/src/client/java/dev/tggamesyt/szar/client/ClientCosmetics.java +++ b/src/client/java/dev/tggamesyt/szar/client/ClientCosmetics.java @@ -1,8 +1,12 @@ package dev.tggamesyt.szar.client; import com.google.gson.*; +import com.mojang.authlib.GameProfile; +import dev.tggamesyt.szar.ServerCosmetics.NameType; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.texture.NativeImage; +import net.minecraft.client.texture.NativeImageBackedTexture; import net.minecraft.network.PacketByteBuf; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.minecraft.text.MutableText; @@ -17,12 +21,10 @@ import java.net.HttpURLConnection; import java.net.URL; import java.util.*; +import static dev.tggamesyt.szar.ServerCosmetics.MOJANG_CAPES_SYNC; + public class ClientCosmetics { - public enum NameType { - STATIC, - GRADIENT - } public static class CosmeticProfile { public NameType nameType; @@ -34,9 +36,6 @@ public class ClientCosmetics { private static final Map PROFILES = new HashMap<>(); - // Player UUID -> Mojang cape list - public static final Map> MOJANG_CAPES = new HashMap<>(); - public static class MojangCape { public String id; public String name; @@ -106,8 +105,8 @@ public class ClientCosmetics { /* ---------------- FETCH MOJANG CAPES ---------------- */ public static void fetchMojangCapes(UUID uuid) { - try { - String accessToken = getAccessTokenFromLaunchArgs(); + try {MinecraftClient client = MinecraftClient.getInstance(); + String accessToken = client.getSession().getAccessToken(); if (accessToken == null) return; URL url = new URL("https://api.minecraftservices.com/minecraft/profile"); @@ -119,8 +118,6 @@ public class ClientCosmetics { String json = new String(in.readAllBytes()); in.close(); - System.out.println("[ClientCosmetics] Mojang capes JSON: " + json); - JsonObject obj = JsonParser.parseString(json).getAsJsonObject(); JsonArray capes = obj.getAsJsonArray("capes"); if (capes == null) return; @@ -135,7 +132,17 @@ public class ClientCosmetics { list.add(cape); } - MOJANG_CAPES.put(uuid, list); + PacketByteBuf buf = PacketByteBufs.create(); + buf.writeUuid(uuid); + buf.writeInt(list.size()); + + for (MojangCape cape : list) { + buf.writeString(cape.id); + buf.writeString(cape.name); + buf.writeString(cape.url); + } + + ClientPlayNetworking.send(MOJANG_CAPES_SYNC, buf); } catch (Exception ex) { ex.printStackTrace(); @@ -143,13 +150,20 @@ public class ClientCosmetics { } private static String getAccessTokenFromLaunchArgs() { - for (String arg : ManagementFactory.getRuntimeMXBean().getInputArguments()) { - if (arg.startsWith("--accessToken")) { - String[] split = arg.split("=", 2); - if (split.length == 2) return split[1]; - else continue; - } + MinecraftClient client = MinecraftClient.getInstance(); + return client.getSession().getAccessToken(); + } + public static Identifier loadTextureFromURL(String url, String playerId) { + if (url == null || url.isEmpty() || playerId == null || playerId.isEmpty()) return null; + try (InputStream in = new URL(url).openStream()) { + NativeImage img = NativeImage.read(in); + NativeImageBackedTexture texture = new NativeImageBackedTexture(img); + Identifier id = new Identifier("szar", "cape_" + playerId); + MinecraftClient.getInstance().getTextureManager().registerTexture(id, texture); + return id; + } catch (Exception e) { + e.printStackTrace(); + return null; } - return null; } } \ No newline at end of file diff --git a/src/client/java/dev/tggamesyt/szar/client/SzarClient.java b/src/client/java/dev/tggamesyt/szar/client/SzarClient.java index e699905..853ea6d 100644 --- a/src/client/java/dev/tggamesyt/szar/client/SzarClient.java +++ b/src/client/java/dev/tggamesyt/szar/client/SzarClient.java @@ -5,6 +5,7 @@ import dev.tggamesyt.szar.NyanEntity; import dev.tggamesyt.szar.PlaneEntity; import dev.tggamesyt.szar.Szar; import dev.tggamesyt.szar.PlaneAnimation; +import dev.tggamesyt.szar.ServerCosmetics.NameType; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; @@ -43,7 +44,9 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.*; +import static dev.tggamesyt.szar.ServerCosmetics.SYNC_PACKET; import static dev.tggamesyt.szar.Szar.*; +import static dev.tggamesyt.szar.client.ClientCosmetics.loadTextureFromURL; import static dev.tggamesyt.szar.client.UraniumUtils.updateUranium; public class SzarClient implements ClientModInitializer { @@ -73,6 +76,25 @@ public class SzarClient implements ClientModInitializer { int loopStart = startOffset + startLength; @Override public void onInitializeClient() { + ClientPlayNetworking.registerGlobalReceiver(SYNC_PACKET, (client, handler, buf, responseSender) -> { + // First read the player UUID + UUID playerUuid = buf.readUuid(); + + // Read cosmetic data + NameType nameType = buf.readEnumConstant(NameType.class); + Integer staticColor = buf.readBoolean() ? buf.readInt() : null; + Integer gradientStart = buf.readBoolean() ? buf.readInt() : null; + Integer gradientEnd = gradientStart != null ? buf.readInt() : null; + + String textureUrl = buf.readString(); + Identifier capeTexture = loadTextureFromURL(textureUrl, playerUuid.toString()); + + // Apply the cosmetic profile on the main thread + client.execute(() -> { + ClientCosmetics.fetchMojangCapes(playerUuid); + ClientCosmetics.apply(playerUuid, nameType, staticColor, gradientStart, gradientEnd, capeTexture); + }); + }); ClientPlayNetworking.registerGlobalReceiver(Szar.OPEN_MERL_SCREEN, (client, handler, buf, responseSender) -> { int entityId = buf.readInt(); diff --git a/src/main/java/dev/tggamesyt/szar/ServerCosmetics.java b/src/main/java/dev/tggamesyt/szar/ServerCosmetics.java index 90e2bb6..08faab6 100644 --- a/src/main/java/dev/tggamesyt/szar/ServerCosmetics.java +++ b/src/main/java/dev/tggamesyt/szar/ServerCosmetics.java @@ -2,8 +2,8 @@ package dev.tggamesyt.szar; import com.google.gson.*; import com.mojang.brigadier.arguments.StringArgumentType; -import dev.tggamesyt.szar.client.ClientCosmetics.NameType; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.minecraft.server.command.CommandManager; import net.minecraft.server.network.ServerPlayerEntity; @@ -20,6 +20,7 @@ public class ServerCosmetics { public static final Identifier SYNC_PACKET = new Identifier(Szar.MOD_ID, "cosmetic_sync"); + public static final Identifier MOJANG_CAPES_SYNC = new Identifier(Szar.MOD_ID, "mojang_capes_sync"); private static final String CAPES_URL = "https://raw.githubusercontent.com/tggamesyt/szar/main/capes.json"; @@ -51,6 +52,40 @@ public class ServerCosmetics { public static void init() { loadJson(); registerCommand(); + ServerPlayNetworking.registerGlobalReceiver(MOJANG_CAPES_SYNC, (server, player, handler, buf, responseSender) -> { + UUID uuid = buf.readUuid(); + int size = buf.readInt(); + List list = new ArrayList<>(); + + for (int i = 0; i < size; i++) { + MojangCape c = new MojangCape(); + c.id = buf.readString(); + c.name = buf.readString(); + c.url = buf.readString(); + list.add(c); + } + + PLAYER_MOJANG_CAPES.put(uuid, list); + }); + ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { + ServerPlayerEntity player = handler.getPlayer(); + + // Send this player's own cosmetics to themselves + UserCosmetics user = USERS.get(player.getUuid()); + if (user != null) { + sync(player, user); + } + + // Optionally: send all other players' cosmetics to this new player + for (ServerPlayerEntity other : server.getPlayerManager().getPlayerList()) { + if (other.equals(player)) continue; + + UserCosmetics otherUser = USERS.get(other.getUuid()); + if (otherUser != null) { + sync(player, otherUser); // send other players’ cosmetics to the new player + } + } + }); } /* ---------------- LOAD JSON ---------------- */ @@ -117,7 +152,7 @@ public class ServerCosmetics { private static void registerCommand() { CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(CommandManager.literal("cape") - .then(CommandManager.argument("id", StringArgumentType.word()) + .then(CommandManager.argument("id", StringArgumentType.greedyString()) // <-- change here .suggests((ctx, builder) -> { ServerPlayerEntity player = ctx.getSource().getPlayer(); @@ -129,16 +164,16 @@ public class ServerCosmetics { // Mojang capes List mojang = PLAYER_MOJANG_CAPES.get(player.getUuid()); if (mojang != null) { - for (MojangCape c : mojang) builder.suggest(c.name); + for (MojangCape c : mojang) + builder.suggest(c.name); } builder.suggest("none"); return builder.buildFuture(); }) .executes(ctx -> { - ServerPlayerEntity player = ctx.getSource().getPlayer(); - String id = StringArgumentType.getString(ctx, "id"); + String id = StringArgumentType.getString(ctx, "id"); // this now includes spaces UserCosmetics user = USERS.get(player.getUuid()); if (user == null) return 0; @@ -156,7 +191,7 @@ public class ServerCosmetics { if (mojang != null) { for (MojangCape c : mojang) { if (c.name.equalsIgnoreCase(id)) { - user.selectedCape = null; // vanilla cape + user.selectedCape = c.id; // vanilla cape sync(player, user); player.sendMessage(Text.literal("Equipped Mojang cape: " + c.name), false); return 1; @@ -176,30 +211,50 @@ public class ServerCosmetics { return 1; }) ) - ) - ); + )); } /* ---------------- SYNC ---------------- */ public static void sync(ServerPlayerEntity player, UserCosmetics user) { - PacketByteBuf buf = PacketByteBufs.create(); + for (ServerPlayerEntity p : player.getServer().getPlayerManager().getPlayerList()) { + PacketByteBuf buf = PacketByteBufs.create(); - buf.writeEnumConstant(user.nameType); - buf.writeBoolean(user.staticColor != null); - if (user.staticColor != null) buf.writeInt(user.staticColor); + // Write player UUID first + buf.writeUuid(player.getUuid()); - buf.writeBoolean(user.gradientStart != null); - if (user.gradientStart != null) { - buf.writeInt(user.gradientStart); - buf.writeInt(user.gradientEnd); + // Cosmetic data + buf.writeEnumConstant(user.nameType); + buf.writeBoolean(user.staticColor != null); + if (user.staticColor != null) buf.writeInt(user.staticColor); + + buf.writeBoolean(user.gradientStart != null); + if (user.gradientStart != null) { + buf.writeInt(user.gradientStart); + buf.writeInt(user.gradientEnd); + } + + String textureUrl = null; + if (user.selectedCape != null) { + textureUrl = CAPES.get(user.selectedCape); + if (textureUrl == null) { + List mojang = PLAYER_MOJANG_CAPES.get(player.getUuid()); + if (mojang != null) { + for (MojangCape c : mojang) { + if (c.id.equalsIgnoreCase(user.selectedCape)) { + textureUrl = c.url; + break; + } + } + } + } + } + buf.writeString(textureUrl == null ? "" : textureUrl); + ServerPlayNetworking.send(p, SYNC_PACKET, buf); } - - String textureUrl = user.selectedCape != null - ? CAPES.get(user.selectedCape) - : ""; - - buf.writeString(textureUrl == null ? "" : textureUrl); - ServerPlayNetworking.send(player, SYNC_PACKET, buf); + } + public enum NameType { + STATIC, + GRADIENT } } \ No newline at end of file diff --git a/src/main/resources/data/szar/recipes/atom.json b/src/main/resources/data/szar/recipes/atom.json index f2f8e46..28b1311 100644 --- a/src/main/resources/data/szar/recipes/atom.json +++ b/src/main/resources/data/szar/recipes/atom.json @@ -14,7 +14,7 @@ } }, "result": { - "item": "szar:atom", + "item": "szar:nuke", "count": 1 } } diff --git a/src/main/resources/data/szar/recipes/detonator.json b/src/main/resources/data/szar/recipes/detonator.json index 28f712c..5d236ff 100644 --- a/src/main/resources/data/szar/recipes/detonator.json +++ b/src/main/resources/data/szar/recipes/detonator.json @@ -10,7 +10,7 @@ "item": "minecraft:redstone" }, "A": { - "item": "szar:atom" + "item": "szar:nuke" }, "I": { "item": "minecraft:iron_ingot"