From b5bed1c4412e59ef5fc04e5d8f21315450236c3b Mon Sep 17 00:00:00 2001 From: Lionarius Date: Sat, 4 Oct 2025 22:56:48 +0300 Subject: [PATCH] backport to 1.21.6 --- build.gradle | 2 +- .../lionarius/skinrestorer/SkinRestorer.java | 27 ++++---- .../skinrestorer/command/SkinCommand.java | 44 +++++------- .../skinshuffle/SkinShuffleCompatibility.java | 2 +- .../mixin/GameProfileCacheAccessor.java | 14 ++++ .../skinrestorer/mixin/PlayerAccessor.java | 15 ---- .../skinrestorer/mixin/PlayerListMixin.java | 2 +- .../ServerLoginPacketListenerImplMixin.java | 16 ++--- .../mixin/SkullBlockEntityMixin.java | 69 +++++++++++++++++++ .../skin/provider/ElyBySkinProvider.java | 2 +- .../skin/provider/MojangSkinProvider.java | 27 ++++---- .../skinrestorer/util/JsonUtils.java | 2 + .../skinrestorer/util/PlayerUtils.java | 23 +++---- .../resources/META-INF/accesstransformer.cfg | 1 + .../main/resources/skinrestorer.accesswidener | 2 + .../main/resources/skinrestorer.mixins.json | 3 +- fabric/gradle.properties | 2 +- .../skinshuffle/SkinShuffleCompatibility.java | 2 +- forge/gradle.properties | 6 +- .../skinshuffle/SkinShufflePacketHandler.java | 2 +- gradle.properties | 10 +-- neoforge/build.gradle | 2 + neoforge/gradle.properties | 2 +- .../SkinShuffleModEventHandler.java | 3 +- 24 files changed, 168 insertions(+), 112 deletions(-) create mode 100644 common/src/main/java/net/lionarius/skinrestorer/mixin/GameProfileCacheAccessor.java delete mode 100644 common/src/main/java/net/lionarius/skinrestorer/mixin/PlayerAccessor.java create mode 100644 common/src/main/java/net/lionarius/skinrestorer/mixin/SkullBlockEntityMixin.java diff --git a/build.gradle b/build.gradle index 5be6436..b092859 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { // see https://fabricmc.net/develop/ for new versions - id 'fabric-loom' version '1.11-SNAPSHOT' apply false + id 'fabric-loom' version '1.10-SNAPSHOT' apply false // see https://projects.neoforged.net/neoforged/moddevgradle for new versions id 'net.neoforged.moddev' version '2.0.+' apply false // see https://files.minecraftforge.net/net/minecraftforge/gradle/ForgeGradle/ for new versions diff --git a/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java b/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java index 2296958..f2270f1 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java +++ b/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java @@ -1,12 +1,12 @@ package net.lionarius.skinrestorer; import com.google.common.base.Throwables; +import com.mojang.authlib.GameProfile; import com.mojang.brigadier.CommandDispatcher; import net.lionarius.skinrestorer.command.SkinCommand; import net.lionarius.skinrestorer.config.Config; import net.lionarius.skinrestorer.config.provider.BuiltInProviderConfig; import net.lionarius.skinrestorer.exception.TransparentException; -import net.lionarius.skinrestorer.mixin.PlayerAccessor; import net.lionarius.skinrestorer.platform.Services; import net.lionarius.skinrestorer.skin.SkinIO; import net.lionarius.skinrestorer.skin.SkinStorage; @@ -108,26 +108,23 @@ public final class SkinRestorer { MineskinSkinProvider.reload(); } - public static Collection applySkin(MinecraftServer server, Iterable targets, SkinValue value, boolean save) { + public static Collection applySkin(MinecraftServer server, Iterable targets, SkinValue value, boolean save) { var acceptedPlayers = new HashSet(); - for (var player : targets) { - var profile = player.getGameProfile(); - var skin = PlayerUtils.getPlayerSkin(profile); + for (var profile : targets) { + if (!SkinRestorer.getSkinStorage().hasSavedSkin(profile.getId())) + value = value.setOriginalValue(PlayerUtils.getPlayerSkin(profile)); - if (!SkinRestorer.getSkinStorage().hasSavedSkin(profile.id())) - value = value.setOriginalValue(skin); - - if (PlayerUtils.areSkinPropertiesEquals(value.value(), skin)) + if (PlayerUtils.areSkinPropertiesEquals(value.value(), PlayerUtils.getPlayerSkin(profile))) continue; if (save) - SkinRestorer.getSkinStorage().setSkin(profile.id(), value); + SkinRestorer.getSkinStorage().setSkin(profile.getId(), value); - var newProfile = PlayerUtils.applyRestoredSkin(profile, value.value()); - ((PlayerAccessor) player).setGameProfile(newProfile); + PlayerUtils.applyRestoredSkin(profile, value.value()); - if (player.connection == null) + var player = server.getPlayerList().getPlayer(profile.getId()); + if (player == null) continue; PlayerUtils.refreshPlayer(player); @@ -139,13 +136,13 @@ public final class SkinRestorer { return acceptedPlayers; } - public static Collection applySkin(MinecraftServer server, Iterable targets, SkinValue value) { + public static Collection applySkin(MinecraftServer server, Iterable targets, SkinValue value) { return SkinRestorer.applySkin(server, targets, value, true); } public static CompletableFuture, String>> setSkinAsync( MinecraftServer server, - Collection targets, + Collection targets, SkinProviderContext context, boolean save ) { diff --git a/common/src/main/java/net/lionarius/skinrestorer/command/SkinCommand.java b/common/src/main/java/net/lionarius/skinrestorer/command/SkinCommand.java index c2ab49d..8dd93ea 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/command/SkinCommand.java +++ b/common/src/main/java/net/lionarius/skinrestorer/command/SkinCommand.java @@ -1,5 +1,6 @@ package net.lionarius.skinrestorer.command; +import com.mojang.authlib.GameProfile; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.ArgumentBuilder; @@ -17,12 +18,10 @@ import net.lionarius.skinrestorer.util.PlayerUtils; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.arguments.GameProfileArgument; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.players.NameAndId; import java.util.Collection; import java.util.Collections; import java.util.HashSet; -import java.util.Objects; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; @@ -73,41 +72,37 @@ public final class SkinCommand { SkinProviderContext context = null; var save = true; - if (!SkinRestorer.getSkinStorage().hasSavedSkin(profile.id())) { - if (profile.properties().containsKey(PlayerUtils.TEXTURES_KEY)) { + if (!SkinRestorer.getSkinStorage().hasSavedSkin(profile.getId())) { + if (profile.getProperties().containsKey(PlayerUtils.TEXTURES_KEY)) { save = false; context = MojangSkinProvider.skinProviderContextFromProfile(profile); } } else { - context = SkinRestorer.getSkinStorage().getSkin(profile.id()).toProviderContext(); + context = SkinRestorer.getSkinStorage().getSkin(profile.getId()).toProviderContext(); } if (context == null) return 0; - return SkinCommand.setSubcommand(src, Collections.singleton(new NameAndId(profile)), context, save, false); + return SkinCommand.setSubcommand(src, Collections.singleton(profile), context, save, false); } private static int resetSubcommand( CommandSourceStack src, - Collection targets, + Collection targets, boolean setByOperator ) { var updatedPlayers = new HashSet(); - for (var nameAndId : targets) { + for (var profile : targets) { SkinValue skin = null; - if (SkinRestorer.getSkinStorage().hasSavedSkin(nameAndId.id())) - skin = SkinRestorer.getSkinStorage().getSkin(nameAndId.id()).replaceValueWithOriginal(); + if (SkinRestorer.getSkinStorage().hasSavedSkin(profile.getId())) + skin = SkinRestorer.getSkinStorage().getSkin(profile.getId()).replaceValueWithOriginal(); if (skin == null) continue; - var player = src.getServer().getPlayerList().getPlayer(nameAndId.id()); - if (player == null) - continue; - - var updatedPlayer = SkinRestorer.applySkin(src.getServer(), Collections.singleton(player), skin, false); - SkinRestorer.getSkinStorage().deleteSkin(nameAndId.id()); + var updatedPlayer = SkinRestorer.applySkin(src.getServer(), Collections.singleton(profile), skin, false); + SkinRestorer.getSkinStorage().deleteSkin(profile.getId()); updatedPlayers.addAll(updatedPlayer); } @@ -123,24 +118,19 @@ public final class SkinCommand { if (src.getPlayer() == null) return 0; - return resetSubcommand(src, Collections.singleton(src.getPlayer().nameAndId()), false); + return resetSubcommand(src, Collections.singleton(src.getPlayer().getGameProfile()), false); } private static int setSubcommand( CommandSourceStack src, - Collection targets, + Collection targets, SkinProviderContext context, boolean save, boolean setByOperator ) { src.sendSystemMessage(Translation.translatableWithFallback(Translation.COMMAND_SKIN_LOADING_KEY)); - var profileTargets = targets.stream() - .map(nameAndId -> src.getServer().getPlayerList().getPlayer(nameAndId.id())) - .filter(Objects::nonNull) - .toList(); - - SkinRestorer.setSkinAsync(src.getServer(), profileTargets, context, save).thenAccept(result -> { + SkinRestorer.setSkinAsync(src.getServer(), targets, context, save).thenAccept(result -> { if (result.isError()) { src.sendFailure(Translation.translatableWithFallback( Translation.COMMAND_SKIN_FAILED_KEY, @@ -159,7 +149,7 @@ public final class SkinCommand { private static int setSubcommand( CommandSourceStack src, - Collection targets, + Collection targets, SkinProviderContext context, boolean setByOperator ) { @@ -173,7 +163,7 @@ public final class SkinCommand { if (src.getPlayer() == null) return 0; - return setSubcommand(src, Collections.singleton(src.getPlayer().nameAndId()), context, false); + return setSubcommand(src, Collections.singleton(src.getPlayer().getGameProfile()), context, false); } private static int configReloadSubcommand(CommandContext context) { @@ -266,7 +256,7 @@ public final class SkinCommand { } private static RequiredArgumentBuilder makeTargetsArgument( - BiFunction, Collection, Integer> consumer + BiFunction, Collection, Integer> consumer ) { return argument("targets", GameProfileArgument.gameProfile()) .requires(source -> source.hasPermission(2)) diff --git a/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleCompatibility.java b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleCompatibility.java index 431fe20..3b60331 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleCompatibility.java +++ b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleCompatibility.java @@ -43,7 +43,7 @@ public class SkinShuffleCompatibility { server.execute(() -> { SkinRestorer.applySkin( server, - Collections.singleton(player), + Collections.singleton(player.getGameProfile()), new SkinValue(SkinShuffleSkinProvider.PROVIDER_NAME, null, null, property), !server.usesAuthentication() ); diff --git a/common/src/main/java/net/lionarius/skinrestorer/mixin/GameProfileCacheAccessor.java b/common/src/main/java/net/lionarius/skinrestorer/mixin/GameProfileCacheAccessor.java new file mode 100644 index 0000000..f129fc3 --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/mixin/GameProfileCacheAccessor.java @@ -0,0 +1,14 @@ +package net.lionarius.skinrestorer.mixin; + +import net.minecraft.server.players.GameProfileCache; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(GameProfileCache.class) +public interface GameProfileCacheAccessor { + + @Accessor + Map getProfilesByName(); +} diff --git a/common/src/main/java/net/lionarius/skinrestorer/mixin/PlayerAccessor.java b/common/src/main/java/net/lionarius/skinrestorer/mixin/PlayerAccessor.java deleted file mode 100644 index 61a4d04..0000000 --- a/common/src/main/java/net/lionarius/skinrestorer/mixin/PlayerAccessor.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.lionarius.skinrestorer.mixin; - -import com.mojang.authlib.GameProfile; -import net.minecraft.world.entity.player.Player; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Mutable; -import org.spongepowered.asm.mixin.gen.Accessor; - - -@Mixin(Player.class) -public interface PlayerAccessor { - @Accessor("gameProfile") - @Mutable - void setGameProfile(GameProfile properties); -} diff --git a/common/src/main/java/net/lionarius/skinrestorer/mixin/PlayerListMixin.java b/common/src/main/java/net/lionarius/skinrestorer/mixin/PlayerListMixin.java index 4752301..ccaed02 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/mixin/PlayerListMixin.java +++ b/common/src/main/java/net/lionarius/skinrestorer/mixin/PlayerListMixin.java @@ -57,6 +57,6 @@ public abstract class PlayerListMixin { @Unique private static void skinrestorer$tryApplySkin(MinecraftServer server, ServerPlayer player) { if (SkinRestorer.getSkinStorage().hasSavedSkin(player.getUUID())) - SkinRestorer.applySkin(server, Collections.singleton(player), SkinRestorer.getSkinStorage().getSkin(player.getUUID())); + SkinRestorer.applySkin(server, Collections.singleton(player.getGameProfile()), SkinRestorer.getSkinStorage().getSkin(player.getUUID())); } } diff --git a/common/src/main/java/net/lionarius/skinrestorer/mixin/ServerLoginPacketListenerImplMixin.java b/common/src/main/java/net/lionarius/skinrestorer/mixin/ServerLoginPacketListenerImplMixin.java index 09a97dc..ca9780c 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/mixin/ServerLoginPacketListenerImplMixin.java +++ b/common/src/main/java/net/lionarius/skinrestorer/mixin/ServerLoginPacketListenerImplMixin.java @@ -27,7 +27,7 @@ public abstract class ServerLoginPacketListenerImplMixin { private CompletableFuture skinrestorer$pendingSkin; @Inject(method = "verifyLoginAndFinishConnectionSetup", at = @At(value = "INVOKE", - target = "Lnet/minecraft/server/players/PlayerList;canPlayerLogin(Ljava/net/SocketAddress;Lnet/minecraft/server/players/NameAndId;)Lnet/minecraft/network/chat/Component;"), + target = "Lnet/minecraft/server/players/PlayerList;canPlayerLogin(Ljava/net/SocketAddress;Lcom/mojang/authlib/GameProfile;)Lnet/minecraft/network/chat/Component;"), cancellable = true) public void waitForSkin(CallbackInfo ci) { if (skinrestorer$pendingSkin == null) { @@ -37,14 +37,14 @@ public abstract class ServerLoginPacketListenerImplMixin { assert profile != null; var originalSkin = PlayerUtils.getPlayerSkin(profile); - if (SkinRestorer.getSkinStorage().hasSavedSkin(profile.id())) { + if (SkinRestorer.getSkinStorage().hasSavedSkin(profile.getId())) { if (originalSkin != null) { // update to the latest official skin - var value = SkinRestorer.getSkinStorage().getSkin(profile.id()); - SkinRestorer.getSkinStorage().setSkin(profile.id(), value.setOriginalValue(originalSkin)); + var value = SkinRestorer.getSkinStorage().getSkin(profile.getId()); + SkinRestorer.getSkinStorage().setSkin(profile.getId(), value.setOriginalValue(originalSkin)); } if (SkinRestorer.getConfig().refreshSkinOnJoin()) { - var currentSkin = SkinRestorer.getSkinStorage().getSkin(profile.id()); + var currentSkin = SkinRestorer.getSkinStorage().getSkin(profile.getId()); var context = currentSkin.toProviderContext(); skinrestorer$fetchSkin(profile, context); @@ -56,7 +56,7 @@ public abstract class ServerLoginPacketListenerImplMixin { if (originalSkin == null && SkinRestorer.getConfig().fetchSkinOnFirstJoin()) { var context = new SkinProviderContext( SkinRestorer.getConfig().firstJoinSkinProvider().getName(), - profile.name(), + profile.getName(), null ); skinrestorer$fetchSkin(profile, context); @@ -72,7 +72,7 @@ public abstract class ServerLoginPacketListenerImplMixin { @Unique private static void skinrestorer$fetchSkin(GameProfile profile, SkinProviderContext context) { - SkinRestorer.LOGGER.debug("Fetching {}'s skin", profile.name()); + SkinRestorer.LOGGER.debug("Fetching {}'s skin", profile.getName()); var result = SkinRestorer.getProvider(context.name()).map( provider -> provider.fetchSkin(context.argument(), context.variant()) @@ -80,7 +80,7 @@ public abstract class ServerLoginPacketListenerImplMixin { if (!result.isError()) { var value = SkinValue.fromProviderContextWithValue(context, result.getSuccessValue().orElse(null)); - SkinRestorer.getSkinStorage().setSkin(profile.id(), value); + SkinRestorer.getSkinStorage().setSkin(profile.getId(), value); } else { SkinRestorer.LOGGER.warn("Failed to fetch skin '{}:{}'", context.name(), context.argument(), result.getErrorValue()); } diff --git a/common/src/main/java/net/lionarius/skinrestorer/mixin/SkullBlockEntityMixin.java b/common/src/main/java/net/lionarius/skinrestorer/mixin/SkullBlockEntityMixin.java new file mode 100644 index 0000000..21d4d38 --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/mixin/SkullBlockEntityMixin.java @@ -0,0 +1,69 @@ +package net.lionarius.skinrestorer.mixin; + +import com.mojang.authlib.GameProfile; +import net.lionarius.skinrestorer.SkinRestorer; +import net.lionarius.skinrestorer.util.PlayerUtils; +import net.minecraft.Util; +import net.minecraft.server.Services; +import net.minecraft.world.level.block.entity.SkullBlockEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.Locale; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.function.BooleanSupplier; + +@Mixin(SkullBlockEntity.class) +public abstract class SkullBlockEntityMixin { + + @Inject(method = "fetchProfileByName", at = @At("HEAD"), + cancellable = true) + private static void fetchProfileByName(String name, Services services, CallbackInfoReturnable>> cir) { + if (name == null) + return; + + var profileOpt = Optional.empty(); + var gameProfileInfo = ((GameProfileCacheAccessor) services.profileCache()).getProfilesByName().get(name.toLowerCase(Locale.ROOT)); + + if (gameProfileInfo != null) + profileOpt = Optional.of(gameProfileInfo.getProfile()); + + skinrestorer$replaceSkin(profileOpt, cir); + } + + @Inject(method = "fetchProfileById", at = @At("HEAD"), + cancellable = true) + private static void fetchProfileById(UUID id, Services services, BooleanSupplier cacheUninitialized, CallbackInfoReturnable>> cir) { + if (id == null) + return; + + var profileOpt = services.profileCache().get(id); + + skinrestorer$replaceSkin(profileOpt, cir); + } + + @Unique + private static void skinrestorer$replaceSkin(Optional profileOpt, CallbackInfoReturnable>> cir) { + if (SkinRestorer.getMinecraftServer() == null) + return; + + if (profileOpt.isEmpty()) + return; + + var profile = PlayerUtils.cloneGameProfile(profileOpt.get()); + + if (SkinRestorer.getSkinStorage().hasSavedSkin(profile.getId())) { + cir.setReturnValue(CompletableFuture.supplyAsync(() -> { + var skin = SkinRestorer.getSkinStorage().getSkin(profile.getId(), false); + PlayerUtils.applyRestoredSkin(profile, skin.value()); + + return Optional.of(profile); + }, Util.backgroundExecutor().forName("getProfile"))); + } + } +} diff --git a/common/src/main/java/net/lionarius/skinrestorer/skin/provider/ElyBySkinProvider.java b/common/src/main/java/net/lionarius/skinrestorer/skin/provider/ElyBySkinProvider.java index a8bdfc7..b8496f1 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/skin/provider/ElyBySkinProvider.java +++ b/common/src/main/java/net/lionarius/skinrestorer/skin/provider/ElyBySkinProvider.java @@ -106,6 +106,6 @@ public final class ElyBySkinProvider implements SkinProvider { if (response.statusCode() != 200) throw new IllegalArgumentException("no profile with name " + username); - return JsonUtils.fromJson(response.body(), MinecraftProfilePropertiesResponse.class).profile(); + return JsonUtils.fromJson(response.body(), MinecraftProfilePropertiesResponse.class).toProfile(); } } diff --git a/common/src/main/java/net/lionarius/skinrestorer/skin/provider/MojangSkinProvider.java b/common/src/main/java/net/lionarius/skinrestorer/skin/provider/MojangSkinProvider.java index b41e10f..56f6bff 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/skin/provider/MojangSkinProvider.java +++ b/common/src/main/java/net/lionarius/skinrestorer/skin/provider/MojangSkinProvider.java @@ -8,7 +8,6 @@ import com.mojang.authlib.*; import com.mojang.authlib.properties.Property; import com.mojang.authlib.yggdrasil.YggdrasilEnvironment; import com.mojang.authlib.yggdrasil.response.MinecraftProfilePropertiesResponse; -import com.mojang.authlib.yggdrasil.response.NameAndId; import com.mojang.util.UndashedUuid; import net.lionarius.skinrestorer.SkinRestorer; import net.lionarius.skinrestorer.exception.TransparentException; @@ -17,7 +16,7 @@ import net.lionarius.skinrestorer.util.JsonUtils; import net.lionarius.skinrestorer.util.PlayerUtils; import net.lionarius.skinrestorer.util.Result; import net.lionarius.skinrestorer.util.WebUtils; -import net.minecraft.server.players.CachedUserNameToIdResolver; +import net.minecraft.server.players.GameProfileCache; import net.minecraft.util.StringUtil; import org.jetbrains.annotations.NotNull; @@ -32,11 +31,13 @@ import java.util.concurrent.TimeUnit; public final class MojangSkinProvider implements SkinProvider { public static final String PROVIDER_NAME = "mojang"; - public static final String PROFILE_CACHE_FILENAME = "mojang_profile_cache.json"; + private static final Environment ENVIRONMENT; private static final URI SERVICES_SERVER_URI; private static final URI SESSION_SERVER_URI; - private static final CachedUserNameToIdResolver PROFILE_CACHE; + + public static final String PROFILE_CACHE_FILENAME = "mojang_profile_cache.json"; + private static final GameProfileCache PROFILE_CACHE; private static LoadingCache> SKIN_CACHE; @@ -50,13 +51,13 @@ public final class MojangSkinProvider implements SkinProvider { throw new IllegalArgumentException(e); } - PROFILE_CACHE = new CachedUserNameToIdResolver(new GameProfileRepository() { + PROFILE_CACHE = new GameProfileCache(new GameProfileRepository() { @Override public void findProfilesByNames(String[] names, ProfileLookupCallback callback) { for (var name : names) { try { var profile = MojangSkinProvider.getProfile(name); - callback.onProfileLookupSucceeded(profile.name(), profile.id()); + callback.onProfileLookupSucceeded(profile); } catch (IOException e) { throw new TransparentException(e); } @@ -64,10 +65,10 @@ public final class MojangSkinProvider implements SkinProvider { } @Override - public Optional findProfileByName(String name) { + public Optional findProfileByName(String name) { try { var profile = MojangSkinProvider.getProfile(name); - return Optional.of(new NameAndId(profile.id(), profile.name())); + return Optional.of(profile); } catch (IOException e) { throw new TransparentException(e); } @@ -94,7 +95,7 @@ public final class MojangSkinProvider implements SkinProvider { } public static SkinProviderContext skinProviderContextFromProfile(GameProfile gameProfile) { - return new SkinProviderContext(MojangSkinProvider.PROVIDER_NAME, gameProfile.name(), null); + return new SkinProviderContext(MojangSkinProvider.PROVIDER_NAME, gameProfile.getName(), null); } @Override @@ -117,7 +118,7 @@ public final class MojangSkinProvider implements SkinProvider { if (cachedProfile.isEmpty()) throw new IllegalArgumentException("no profile found for " + username); - return Result.success(SKIN_CACHE.get(cachedProfile.get().id())); + return Result.success(SKIN_CACHE.get(cachedProfile.get().getId())); } catch (UncheckedExecutionException e) { return Result.error((Exception) e.getCause()); } catch (Exception e) { @@ -132,7 +133,7 @@ public final class MojangSkinProvider implements SkinProvider { return Optional.ofNullable(textures); } - private static NameAndId getProfile(final String name) throws IOException { + private static GameProfile getProfile(final String name) throws IOException { var request = HttpRequest.newBuilder() .uri(MojangSkinProvider.SERVICES_SERVER_URI .resolve("/minecraft/profile/lookup/name/") @@ -147,7 +148,7 @@ public final class MojangSkinProvider implements SkinProvider { if (response.statusCode() != 200) throw new IllegalArgumentException("no profile with name " + name); - return JsonUtils.fromJson(response.body(), NameAndId.class); + return JsonUtils.fromJson(response.body(), GameProfile.class); } private static GameProfile getProfileWithProperties(UUID uuid) throws IOException { @@ -165,6 +166,6 @@ public final class MojangSkinProvider implements SkinProvider { if (response.statusCode() != 200) throw new IllegalArgumentException("no profile with uuid " + uuid); - return JsonUtils.fromJson(response.body(), MinecraftProfilePropertiesResponse.class).profile(); + return JsonUtils.fromJson(response.body(), MinecraftProfilePropertiesResponse.class).toProfile(); } } diff --git a/common/src/main/java/net/lionarius/skinrestorer/util/JsonUtils.java b/common/src/main/java/net/lionarius/skinrestorer/util/JsonUtils.java index a3726b3..7eef4e1 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/util/JsonUtils.java +++ b/common/src/main/java/net/lionarius/skinrestorer/util/JsonUtils.java @@ -4,6 +4,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import com.mojang.util.UUIDTypeAdapter; @@ -21,6 +22,7 @@ public final class JsonUtils { .registerTypeAdapterFactory(new PostProcessingEnabler()) .registerTypeAdapter(UUID.class, new UUIDTypeAdapter()) .registerTypeAdapter(PropertyMap.class, new PropertyMap.Serializer()) + .registerTypeAdapter(GameProfile.class, new GameProfile.Serializer()) .setPrettyPrinting() .create(); diff --git a/common/src/main/java/net/lionarius/skinrestorer/util/PlayerUtils.java b/common/src/main/java/net/lionarius/skinrestorer/util/PlayerUtils.java index 031a510..fbb1476 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/util/PlayerUtils.java +++ b/common/src/main/java/net/lionarius/skinrestorer/util/PlayerUtils.java @@ -1,11 +1,9 @@ package net.lionarius.skinrestorer.util; import com.google.common.collect.Iterables; -import com.google.common.collect.LinkedHashMultimap; import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; -import com.mojang.authlib.properties.PropertyMap; import com.mojang.authlib.yggdrasil.response.MinecraftProfilePropertiesResponse; import net.lionarius.skinrestorer.mixin.ChunkMapAccessor; import net.minecraft.network.chat.Component; @@ -98,26 +96,21 @@ public final class PlayerUtils { } public static GameProfile cloneGameProfile(GameProfile profile) { - var newProfile = new GameProfile(profile.id(), profile.name()); - newProfile.properties().putAll(profile.properties()); + var newProfile = new GameProfile(profile.getId(), profile.getName()); + newProfile.getProperties().putAll(profile.getProperties()); return newProfile; } public static Property getPlayerSkin(GameProfile profile) { - return Iterables.getFirst(profile.properties().get(TEXTURES_KEY), null); + return Iterables.getFirst(profile.getProperties().get(TEXTURES_KEY), null); } - public static GameProfile applyRestoredSkin(GameProfile profile, Property skin) { - var propertiesMap = profile.properties(); + public static void applyRestoredSkin(GameProfile profile, Property skin) { + profile.getProperties().removeAll(TEXTURES_KEY); - var newProperties = LinkedHashMultimap.create(propertiesMap); - newProperties.removeAll(TEXTURES_KEY); - if (skin != null) { - newProperties.put(TEXTURES_KEY, skin); - } - - return new GameProfile(profile.id(), profile.name(), new PropertyMap(newProperties)); + if (skin != null) + profile.getProperties().put(TEXTURES_KEY, skin); } public static boolean areSkinPropertiesEquals(Property x, Property y) { @@ -141,7 +134,7 @@ public final class PlayerUtils { public static GameProfile toProfile(MinecraftProfilePropertiesResponse response) { final GameProfile profile = new GameProfile(response.id(), response.name()); - profile.properties().putAll(response.properties()); + profile.getProperties().putAll(response.properties()); return profile; } } diff --git a/common/src/main/resources/META-INF/accesstransformer.cfg b/common/src/main/resources/META-INF/accesstransformer.cfg index e69de29..8c8e31a 100644 --- a/common/src/main/resources/META-INF/accesstransformer.cfg +++ b/common/src/main/resources/META-INF/accesstransformer.cfg @@ -0,0 +1 @@ +public net.minecraft.server.players.GameProfileCache$GameProfileInfo diff --git a/common/src/main/resources/skinrestorer.accesswidener b/common/src/main/resources/skinrestorer.accesswidener index 9ab2173..28ef0d1 100644 --- a/common/src/main/resources/skinrestorer.accesswidener +++ b/common/src/main/resources/skinrestorer.accesswidener @@ -1 +1,3 @@ accessWidener v2 named + +accessible class net/minecraft/server/players/GameProfileCache$GameProfileInfo diff --git a/common/src/main/resources/skinrestorer.mixins.json b/common/src/main/resources/skinrestorer.mixins.json index 741efe1..1956e5a 100644 --- a/common/src/main/resources/skinrestorer.mixins.json +++ b/common/src/main/resources/skinrestorer.mixins.json @@ -10,7 +10,8 @@ "PlayerListMixin", "ServerLoginPacketListenerImplMixin", "TrackedEntityAccessorInvoker", - "PlayerAccessor" + "SkullBlockEntityMixin", + "GameProfileCacheAccessor" ], "injectors": { "defaultRequire": 1 diff --git a/fabric/gradle.properties b/fabric/gradle.properties index 7dc2ea4..d4f3a28 100644 --- a/fabric/gradle.properties +++ b/fabric/gradle.properties @@ -1,6 +1,6 @@ # Fabric, see https://fabricmc.net/develop/ for new versions fabric_loader_version=0.15.0 -fabric_api_version=0.133.14+1.21.9 +fabric_api_version=0.127.0+1.21.6 optional_dependencies=fabric-api additional_modloaders=quilt diff --git a/fabric/src/main/java/net/lionarius/skinrestorer/fabric/compat/skinshuffle/SkinShuffleCompatibility.java b/fabric/src/main/java/net/lionarius/skinrestorer/fabric/compat/skinshuffle/SkinShuffleCompatibility.java index b8073a4..662ae14 100644 --- a/fabric/src/main/java/net/lionarius/skinrestorer/fabric/compat/skinshuffle/SkinShuffleCompatibility.java +++ b/fabric/src/main/java/net/lionarius/skinrestorer/fabric/compat/skinshuffle/SkinShuffleCompatibility.java @@ -32,6 +32,6 @@ public final class SkinShuffleCompatibility { } private static void handleSkinRefreshPacket(SkinShuffleSkinRefreshPayload payload, ServerPlayNetworking.Context context) { - net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility.handleSkinRefresh(SkinRestorer.getMinecraftServer(), context.player(), payload); + net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility.handleSkinRefresh(context.player().getServer(), context.player(), payload); } } diff --git a/forge/gradle.properties b/forge/gradle.properties index d1e8843..1d49e44 100644 --- a/forge/gradle.properties +++ b/forge/gradle.properties @@ -1,5 +1,5 @@ # Forge, see https://files.minecraftforge.net/net/minecraftforge/forge/ for new versions -forge_version=59.0.0 -forge_loader_version_range=[59,) +forge_version=56.0.0 +forge_loader_version_range=[56,) # Forge sometimes skips minor minecraft versions (like 1.20.5) -forge_minecraft_version=1.21.9 +forge_minecraft_version=1.21.6 diff --git a/forge/src/main/java/net/lionarius/skinrestorer/forge/compat/skinshuffle/SkinShufflePacketHandler.java b/forge/src/main/java/net/lionarius/skinrestorer/forge/compat/skinshuffle/SkinShufflePacketHandler.java index efd5049..badc589 100644 --- a/forge/src/main/java/net/lionarius/skinrestorer/forge/compat/skinshuffle/SkinShufflePacketHandler.java +++ b/forge/src/main/java/net/lionarius/skinrestorer/forge/compat/skinshuffle/SkinShufflePacketHandler.java @@ -40,6 +40,6 @@ public class SkinShufflePacketHandler { if (!context.isServerSide() || sender == null) return; - SkinShuffleCompatibility.handleSkinRefresh(SkinRestorer.getMinecraftServer(), sender, payload); + SkinShuffleCompatibility.handleSkinRefresh(sender.getServer(), sender, payload); } } diff --git a/gradle.properties b/gradle.properties index 2ee5965..cbfc991 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,9 +3,9 @@ group=net.lionarius java_version=21 # Common -minecraft_version=1.21.9 -minecraft_version_list=1.21.9 -minecraft_version_range=[1.21.9, 1.22) +minecraft_version=1.21.6 +minecraft_version_list=1.21.6,1.21.7,1.21.8 +minecraft_version_range=[1.21.6, 1.21.8] mod_id=skinrestorer mod_name=SkinRestorer mod_version=2.4.3 @@ -21,8 +21,8 @@ description=A server-side mod for managing skins. mineskin_client_version=3.0.6-SNAPSHOT # ParchmentMC mappings, see https://parchmentmc.org/docs/getting-started#choose-a-version for new versions -parchment_minecraft=1.21.8 -parchment_version=2025.09.14 +parchment_minecraft=1.21.6 +parchment_version=2025.06.29 # Publishing curseforge_id=443823 diff --git a/neoforge/build.gradle b/neoforge/build.gradle index 0c9aca9..0385d9e 100644 --- a/neoforge/build.gradle +++ b/neoforge/build.gradle @@ -55,4 +55,6 @@ dependencies { prefer mineskin_client_version } } + + additionalRuntimeClasspath "org.mineskin:java-client:${mineskin_client_version}" } diff --git a/neoforge/gradle.properties b/neoforge/gradle.properties index 4ecb081..4fe7510 100644 --- a/neoforge/gradle.properties +++ b/neoforge/gradle.properties @@ -1,3 +1,3 @@ # NeoForge, see https://projects.neoforged.net/neoforged/neoforge for new versions -neoforge_version=21.9.0-beta +neoforge_version=21.6.0-beta neoforge_loader_version_range=[4,) diff --git a/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShuffleModEventHandler.java b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShuffleModEventHandler.java index 99c41f4..fdd2fdc 100644 --- a/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShuffleModEventHandler.java +++ b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShuffleModEventHandler.java @@ -1,6 +1,5 @@ package net.lionarius.skinrestorer.neoforge.compat.skinshuffle; -import net.lionarius.skinrestorer.SkinRestorer; import net.lionarius.skinrestorer.compat.skinshuffle.*; import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility; import net.minecraft.server.level.ServerPlayer; @@ -27,6 +26,6 @@ public final class SkinShuffleModEventHandler { private static void handleSkinRefreshPacket(SkinShuffleSkinRefreshPayload payload, IPayloadContext context) { var player = (ServerPlayer) context.player(); - SkinShuffleCompatibility.handleSkinRefresh(SkinRestorer.getMinecraftServer(), player, payload); + SkinShuffleCompatibility.handleSkinRefresh(player.getServer(), player, payload); } }