diff --git a/CHANGELOG.md b/CHANGELOG.md index 27ff975..03007f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.5.0] - 2026-01-14 +### Added +- Added collection skin provider (allows assigning random skins from a predefined set) +- Added `forceFirstJoinSkinFetch` config option to force skin fetch on first join even if player already has a skin + ## [2.4.3] - 2025-07-25 ### Fixed - Fixed crash on client when loading player head skin (fixes [#63](https://github.com/Suiranoil/SkinRestorer/issues/63) and [#64](https://github.com/Suiranoil/SkinRestorer/issues/64)) diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 21da2bd..9f04717 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -1,3 +1,3 @@ -### Fixed -- Fixed crash on client when loading player head skin (fixes [#63](https://github.com/Suiranoil/SkinRestorer/issues/63) and [#64](https://github.com/Suiranoil/SkinRestorer/issues/64)) -- Fixed server freeze when loading player head skin +### Added +- Added collection skin provider (allows assigning random skins from a predefined set) (see [wiki](https://github.com/Suiranoil/SkinRestorer/wiki/Configuration#providerscollection)) +- Added `forceFirstJoinSkinFetch` config option to force skin fetch on first join even if player already has a skin (see [wiki](https://github.com/Suiranoil/SkinRestorer/wiki/Configuration#forcefirstjoinskinfetch)) diff --git a/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java b/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java index eb69f48..b679b24 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java +++ b/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java @@ -88,6 +88,7 @@ public final class SkinRestorer { SkinRestorer.registerDefaultSkinProvider(MojangSkinProvider.PROVIDER_NAME, SkinProvider.MOJANG, SkinRestorer.getConfig().providersConfig().mojang()); SkinRestorer.registerDefaultSkinProvider(ElyBySkinProvider.PROVIDER_NAME, SkinProvider.ELY_BY, SkinRestorer.getConfig().providersConfig().ely_by()); SkinRestorer.registerDefaultSkinProvider(MineskinSkinProvider.PROVIDER_NAME, SkinProvider.MINESKIN, SkinRestorer.getConfig().providersConfig().mineskin()); + SkinRestorer.registerDefaultSkinProvider(CollectionSkinProvider.PROVIDER_NAME, SkinProvider.COLLECTION, SkinRestorer.getConfig().providersConfig().collection()); } private static void registerDefaultSkinProvider(String defaultName, SkinProvider provider, BuiltInProviderConfig config) { @@ -106,6 +107,7 @@ public final class SkinRestorer { MojangSkinProvider.reload(); ElyBySkinProvider.reload(); MineskinSkinProvider.reload(); + CollectionSkinProvider.reload(); } public static Collection applySkin(MinecraftServer server, Iterable targets, SkinValue value, boolean save) { diff --git a/common/src/main/java/net/lionarius/skinrestorer/config/Config.java b/common/src/main/java/net/lionarius/skinrestorer/config/Config.java index d8acb49..4f405a6 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/config/Config.java +++ b/common/src/main/java/net/lionarius/skinrestorer/config/Config.java @@ -22,6 +22,8 @@ public final class Config implements GsonPostProcessable { private boolean fetchSkinOnFirstJoin = true; + private boolean forceFirstJoinSkinFetch = false; + private FirstJoinSkinProvider firstJoinSkinProvider = FirstJoinSkinProvider.MOJANG; private String proxy = ""; @@ -47,6 +49,10 @@ public final class Config implements GsonPostProcessable { return this.fetchSkinOnFirstJoin; } + public boolean forceFirstJoinSkinFetch() { + return this.forceFirstJoinSkinFetch; + } + public FirstJoinSkinProvider firstJoinSkinProvider() { return this.firstJoinSkinProvider; } diff --git a/common/src/main/java/net/lionarius/skinrestorer/config/FirstJoinSkinProvider.java b/common/src/main/java/net/lionarius/skinrestorer/config/FirstJoinSkinProvider.java index 120f8de..64dc581 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/config/FirstJoinSkinProvider.java +++ b/common/src/main/java/net/lionarius/skinrestorer/config/FirstJoinSkinProvider.java @@ -1,6 +1,7 @@ package net.lionarius.skinrestorer.config; import com.google.gson.annotations.SerializedName; +import net.lionarius.skinrestorer.skin.provider.CollectionSkinProvider; import net.lionarius.skinrestorer.skin.provider.ElyBySkinProvider; import net.lionarius.skinrestorer.skin.provider.MojangSkinProvider; @@ -8,7 +9,9 @@ public enum FirstJoinSkinProvider { @SerializedName(value = "MOJANG", alternate = {"mojang"}) MOJANG(MojangSkinProvider.PROVIDER_NAME), @SerializedName(value = "ELY.BY", alternate = {"ely.by", "ELY_BY", "ely_by"}) - ELY_BY(ElyBySkinProvider.PROVIDER_NAME); + ELY_BY(ElyBySkinProvider.PROVIDER_NAME), + @SerializedName(value = "COLLECTION", alternate = {"collection"}) + COLLECTION(CollectionSkinProvider.PROVIDER_NAME); private final String name; diff --git a/common/src/main/java/net/lionarius/skinrestorer/config/provider/BuiltInProviderConfig.java b/common/src/main/java/net/lionarius/skinrestorer/config/provider/BuiltInProviderConfig.java index c27e84c..3ea7a7c 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/config/provider/BuiltInProviderConfig.java +++ b/common/src/main/java/net/lionarius/skinrestorer/config/provider/BuiltInProviderConfig.java @@ -8,8 +8,13 @@ public abstract class BuiltInProviderConfig implements GsonPostProcessable { protected String name; protected CacheConfig cache; + public BuiltInProviderConfig(String name, CacheConfig cache) { - this.enabled = true; + this(name, cache, true); + } + + public BuiltInProviderConfig(String name, CacheConfig cache, boolean enabled) { + this.enabled = enabled; this.name = name; this.cache = cache; } diff --git a/common/src/main/java/net/lionarius/skinrestorer/config/provider/ProvidersConfig.java b/common/src/main/java/net/lionarius/skinrestorer/config/provider/ProvidersConfig.java index 4e4f69b..e1de7f1 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/config/provider/ProvidersConfig.java +++ b/common/src/main/java/net/lionarius/skinrestorer/config/provider/ProvidersConfig.java @@ -1,23 +1,27 @@ package net.lionarius.skinrestorer.config.provider; import net.lionarius.skinrestorer.SkinRestorer; +import net.lionarius.skinrestorer.config.provider.collection.CollectionProviderConfig; import net.lionarius.skinrestorer.util.gson.GsonPostProcessable; public final class ProvidersConfig implements GsonPostProcessable { public static final ProvidersConfig DEFAULT = new ProvidersConfig( new MojangProviderConfig(), new ElyByProviderConfig(), - new MineskinProviderConfig() + new MineskinProviderConfig(), + new CollectionProviderConfig() ); private MojangProviderConfig mojang; private ElyByProviderConfig ely_by; private MineskinProviderConfig mineskin; + private CollectionProviderConfig collection; - public ProvidersConfig(MojangProviderConfig mojang, ElyByProviderConfig ely_by, MineskinProviderConfig mineskin) { + public ProvidersConfig(MojangProviderConfig mojang, ElyByProviderConfig ely_by, MineskinProviderConfig mineskin, CollectionProviderConfig collection) { this.mojang = mojang; this.ely_by = ely_by; this.mineskin = mineskin; + this.collection = collection; } public MojangProviderConfig mojang() { @@ -32,6 +36,10 @@ public final class ProvidersConfig implements GsonPostProcessable { return this.mineskin; } + public CollectionProviderConfig collection() { + return this.collection; + } + @Override public void gsonPostProcess() { if (this.mojang == null) { @@ -48,5 +56,10 @@ public final class ProvidersConfig implements GsonPostProcessable { SkinRestorer.LOGGER.warn("Mineskin provider config is null, using default"); this.mineskin = ProvidersConfig.DEFAULT.mineskin(); } + + if (this.collection == null) { + SkinRestorer.LOGGER.warn("Collection provider config is null, using default"); + this.collection = ProvidersConfig.DEFAULT.collection(); + } } } diff --git a/common/src/main/java/net/lionarius/skinrestorer/config/provider/collection/CollectionProviderConfig.java b/common/src/main/java/net/lionarius/skinrestorer/config/provider/collection/CollectionProviderConfig.java new file mode 100644 index 0000000..45d5c95 --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/config/provider/collection/CollectionProviderConfig.java @@ -0,0 +1,32 @@ +package net.lionarius.skinrestorer.config.provider.collection; + +import com.google.gson.annotations.JsonAdapter; +import net.lionarius.skinrestorer.config.provider.BuiltInProviderConfig; +import net.lionarius.skinrestorer.config.provider.CacheConfig; +import net.lionarius.skinrestorer.skin.provider.CollectionSkinProvider; +import net.lionarius.skinrestorer.util.gson.GsonPostProcessable; + +import java.util.ArrayList; +import java.util.List; + +public final class CollectionProviderConfig extends BuiltInProviderConfig implements GsonPostProcessable { + private static final CacheConfig DEFAULT_CACHE_VALUE = new CacheConfig(true, 604800); + + @JsonAdapter(CollectionSkinSourceListDeserializer.class) + private List sources = new ArrayList<>(); + + public CollectionProviderConfig() { + super(CollectionSkinProvider.PROVIDER_NAME, DEFAULT_CACHE_VALUE, false); + } + + public List sources() { + return this.sources; + } + + @Override + public void gsonPostProcess() { + if (this.sources == null) { + this.sources = new ArrayList<>(); + } + } +} diff --git a/common/src/main/java/net/lionarius/skinrestorer/config/provider/collection/CollectionSkinFile.java b/common/src/main/java/net/lionarius/skinrestorer/config/provider/collection/CollectionSkinFile.java new file mode 100644 index 0000000..535e3a2 --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/config/provider/collection/CollectionSkinFile.java @@ -0,0 +1,60 @@ +package net.lionarius.skinrestorer.config.provider.collection; + +import net.lionarius.skinrestorer.SkinRestorer; +import net.lionarius.skinrestorer.skin.SkinVariant; +import net.lionarius.skinrestorer.util.gson.GsonPostProcessable; +import org.jetbrains.annotations.Nullable; + +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; + +public final class CollectionSkinFile implements CollectionSkinSource, GsonPostProcessable { + private String path = ""; + private SkinVariant variant = SkinVariant.CLASSIC; + + @Override + public @Nullable URI uri() { + if (this.path.isEmpty()) + return null; + + try { + var filePath = SkinRestorer.getConfigDir().resolve(this.path); + + if (!Files.exists(filePath)) { + SkinRestorer.LOGGER.warn("Skin file does not exist: {}", this.path); + return null; + } + + if (!Files.isRegularFile(filePath)) { + SkinRestorer.LOGGER.warn("Skin path is not a file: {}", this.path); + return null; + } + + if (!this.path.toLowerCase().endsWith(".png")) { + SkinRestorer.LOGGER.warn("Skin file is not a PNG file: {}", this.path); + return null; + } + + return filePath.toUri(); + } catch (Exception e) { + SkinRestorer.LOGGER.warn("Invalid file path: {}", this.path, e); + return null; + } + } + + @Override + public SkinVariant variant() { + return this.variant; + } + + @Override + public void gsonPostProcess() { + if (this.path == null) { + this.path = ""; + } + if (this.variant == null) { + this.variant = SkinVariant.CLASSIC; + } + } +} diff --git a/common/src/main/java/net/lionarius/skinrestorer/config/provider/collection/CollectionSkinSource.java b/common/src/main/java/net/lionarius/skinrestorer/config/provider/collection/CollectionSkinSource.java new file mode 100644 index 0000000..1a8579b --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/config/provider/collection/CollectionSkinSource.java @@ -0,0 +1,12 @@ +package net.lionarius.skinrestorer.config.provider.collection; + +import net.lionarius.skinrestorer.skin.SkinVariant; +import org.jetbrains.annotations.Nullable; + +import java.net.URI; + +public interface CollectionSkinSource { + @Nullable URI uri(); + + SkinVariant variant(); +} diff --git a/common/src/main/java/net/lionarius/skinrestorer/config/provider/collection/CollectionSkinSourceListDeserializer.java b/common/src/main/java/net/lionarius/skinrestorer/config/provider/collection/CollectionSkinSourceListDeserializer.java new file mode 100644 index 0000000..7dff675 --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/config/provider/collection/CollectionSkinSourceListDeserializer.java @@ -0,0 +1,35 @@ +package net.lionarius.skinrestorer.config.provider.collection; + +import com.google.gson.*; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +public class CollectionSkinSourceListDeserializer implements JsonSerializer>, JsonDeserializer> { + @Override + public JsonElement serialize(List src, Type typeOfT, JsonSerializationContext context) { + return context.serialize(src, List.class); + } + + @Override + public List deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + List sources = new ArrayList<>(); + + if (json.isJsonArray()) { + for (JsonElement element : json.getAsJsonArray()) { + if (element.isJsonObject()) { + JsonObject obj = element.getAsJsonObject(); + if (obj.has("url")) { + sources.add(context.deserialize(obj, CollectionSkinUrl.class)); + } else if (obj.has("path")) { + sources.add(context.deserialize(obj, CollectionSkinFile.class)); + } + } + } + } + + return sources; + } +} diff --git a/common/src/main/java/net/lionarius/skinrestorer/config/provider/collection/CollectionSkinUrl.java b/common/src/main/java/net/lionarius/skinrestorer/config/provider/collection/CollectionSkinUrl.java new file mode 100644 index 0000000..6607219 --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/config/provider/collection/CollectionSkinUrl.java @@ -0,0 +1,41 @@ +package net.lionarius.skinrestorer.config.provider.collection; + +import net.lionarius.skinrestorer.SkinRestorer; +import net.lionarius.skinrestorer.skin.SkinVariant; +import net.lionarius.skinrestorer.util.gson.GsonPostProcessable; +import org.jetbrains.annotations.Nullable; + +import java.net.URI; + +public final class CollectionSkinUrl implements CollectionSkinSource, GsonPostProcessable { + private String url = ""; + private SkinVariant variant = SkinVariant.CLASSIC; + + @Override + public @Nullable URI uri() { + try { + if (this.url.isEmpty()) + return null; + + return new URI(this.url); + } catch (Exception e) { + SkinRestorer.LOGGER.warn("Invalid URI: {}", this.url, e); + return null; + } + } + + @Override + public SkinVariant variant() { + return this.variant; + } + + @Override + public void gsonPostProcess() { + if (this.url == null) { + this.url = ""; + } + if (this.variant == null) { + this.variant = SkinVariant.CLASSIC; + } + } +} 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 39d88da..ccfe57b 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/mixin/ServerLoginPacketListenerImplMixin.java +++ b/common/src/main/java/net/lionarius/skinrestorer/mixin/ServerLoginPacketListenerImplMixin.java @@ -2,6 +2,7 @@ package net.lionarius.skinrestorer.mixin; import com.mojang.authlib.GameProfile; import net.lionarius.skinrestorer.SkinRestorer; +import net.lionarius.skinrestorer.config.FirstJoinSkinProvider; import net.lionarius.skinrestorer.skin.SkinValue; import net.lionarius.skinrestorer.skin.provider.SkinProviderContext; import net.lionarius.skinrestorer.util.PlayerUtils; @@ -57,9 +58,15 @@ public abstract class ServerLoginPacketListenerImplMixin { return null; } - if (originalSkin == null && SkinRestorer.getConfig().fetchSkinOnFirstJoin()) { + var config = SkinRestorer.getConfig(); + var provider = config.firstJoinSkinProvider(); + + var shouldFetch = (originalSkin == null && config.fetchSkinOnFirstJoin()) || + (originalSkin != null && config.forceFirstJoinSkinFetch() && provider != FirstJoinSkinProvider.MOJANG); + + if (shouldFetch) { var context = new SkinProviderContext( - SkinRestorer.getConfig().firstJoinSkinProvider().getName(), + provider.getName(), profile.getName(), null ); diff --git a/common/src/main/java/net/lionarius/skinrestorer/skin/SkinVariant.java b/common/src/main/java/net/lionarius/skinrestorer/skin/SkinVariant.java index d30d5a6..e0494ce 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/skin/SkinVariant.java +++ b/common/src/main/java/net/lionarius/skinrestorer/skin/SkinVariant.java @@ -1,8 +1,11 @@ package net.lionarius.skinrestorer.skin; +import com.google.gson.annotations.SerializedName; + public enum SkinVariant { - + @SerializedName(value = "classic", alternate = {"CLASSIC"}) CLASSIC("classic"), + @SerializedName(value = "slim", alternate = {"SLIM"}) SLIM("slim"); private final String name; diff --git a/common/src/main/java/net/lionarius/skinrestorer/skin/provider/CollectionSkinProvider.java b/common/src/main/java/net/lionarius/skinrestorer/skin/provider/CollectionSkinProvider.java new file mode 100644 index 0000000..89970c2 --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/skin/provider/CollectionSkinProvider.java @@ -0,0 +1,91 @@ +package net.lionarius.skinrestorer.skin.provider; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.util.concurrent.UncheckedExecutionException; +import com.mojang.authlib.properties.Property; +import it.unimi.dsi.fastutil.Pair; +import net.lionarius.skinrestorer.SkinRestorer; +import net.lionarius.skinrestorer.config.provider.collection.CollectionSkinSource; +import net.lionarius.skinrestorer.skin.SkinVariant; +import net.lionarius.skinrestorer.util.Result; +import org.jetbrains.annotations.NotNull; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +public final class CollectionSkinProvider implements SkinProvider { + + public static final String PROVIDER_NAME = "collection"; + + private static LoadingCache> SKIN_CACHE; + + private static List> COLLECTION_SKINS; + + public static void reload() { + COLLECTION_SKINS = loadCollectionSkins(); + + createCache(); + } + + private static List> loadCollectionSkins() { + List> skins = new ArrayList<>(); + + var config = SkinRestorer.getConfig().providersConfig().collection(); + + for (CollectionSkinSource source : config.sources()) { + var uri = source.uri(); + if (uri != null) { + skins.add(Pair.of(uri, source.variant())); + } + } + + return skins; + } + + private static void createCache() { + var config = SkinRestorer.getConfig().providersConfig().collection(); + var time = config.cache().enabled() ? config.cache().duration() : 0; + + SKIN_CACHE = CacheBuilder.newBuilder() + .expireAfterWrite(time, TimeUnit.SECONDS) + .build(new CacheLoader<>() { + @Override + public @NotNull Optional load(@NotNull Integer key) throws Exception { + var skinEntry = COLLECTION_SKINS.get(key); + return MineskinSkinProvider.loadSkin(skinEntry.first(), skinEntry.second()); + } + }); + } + + @Override + public String getArgumentName() { + return "seed"; + } + + @Override + public boolean hasVariantSupport() { + return false; + } + + @Override + public Result, Exception> fetchSkin(String argument, SkinVariant variant) { + if (COLLECTION_SKINS.isEmpty()) { + return Result.error(new IllegalStateException("No collection skins configured")); + } + + var skinIndex = Math.abs(argument.hashCode()) % COLLECTION_SKINS.size(); + + try { + return Result.success(SKIN_CACHE.get(skinIndex)); + } catch (UncheckedExecutionException e) { + return Result.error((Exception) e.getCause()); + } catch (Exception e) { + return Result.error(e); + } + } +} diff --git a/common/src/main/java/net/lionarius/skinrestorer/skin/provider/MineskinSkinProvider.java b/common/src/main/java/net/lionarius/skinrestorer/skin/provider/MineskinSkinProvider.java index 0386927..e254a95 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/skin/provider/MineskinSkinProvider.java +++ b/common/src/main/java/net/lionarius/skinrestorer/skin/provider/MineskinSkinProvider.java @@ -22,6 +22,8 @@ import org.mineskin.response.QueueResponse; import java.net.InetSocketAddress; import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; import java.time.Duration; import java.util.Optional; import java.util.concurrent.TimeUnit; @@ -94,13 +96,18 @@ public final class MineskinSkinProvider implements SkinProvider { } } - private static Optional loadSkin(URI uri, SkinVariant variant) throws Exception { + static Optional loadSkin(URI uri, SkinVariant variant) throws Exception { var mineskinVariant = switch (variant) { case CLASSIC -> Variant.CLASSIC; case SLIM -> Variant.SLIM; }; - var request = GenerateRequest.url(uri) + var request = "file".equals(uri.getScheme()) + ? GenerateRequest.upload(Files.newInputStream(Path.of(uri))) + .variant(mineskinVariant) + .name("skinrestorer-skin") + .visibility(Visibility.UNLISTED) + : GenerateRequest.url(uri) .variant(mineskinVariant) .name("skinrestorer-skin") .visibility(Visibility.UNLISTED); diff --git a/common/src/main/java/net/lionarius/skinrestorer/skin/provider/SkinProvider.java b/common/src/main/java/net/lionarius/skinrestorer/skin/provider/SkinProvider.java index 8b5aad5..c588882 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/skin/provider/SkinProvider.java +++ b/common/src/main/java/net/lionarius/skinrestorer/skin/provider/SkinProvider.java @@ -13,6 +13,7 @@ public interface SkinProvider { MojangSkinProvider MOJANG = new MojangSkinProvider(); ElyBySkinProvider ELY_BY = new ElyBySkinProvider(); MineskinSkinProvider MINESKIN = new MineskinSkinProvider(); + CollectionSkinProvider COLLECTION = new CollectionSkinProvider(); SkinShuffleSkinProvider SKIN_SHUFFLE = new SkinShuffleSkinProvider(); Set BUILTIN_PROVIDER_NAMES = ImmutableSet.of( @@ -20,6 +21,7 @@ public interface SkinProvider { MojangSkinProvider.PROVIDER_NAME, ElyBySkinProvider.PROVIDER_NAME, MineskinSkinProvider.PROVIDER_NAME, + CollectionSkinProvider.PROVIDER_NAME, SkinShuffleSkinProvider.PROVIDER_NAME ); 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 be63a97..67b067d 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/util/PlayerUtils.java +++ b/common/src/main/java/net/lionarius/skinrestorer/util/PlayerUtils.java @@ -6,7 +6,6 @@ import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import com.mojang.authlib.yggdrasil.response.MinecraftProfilePropertiesResponse; import net.lionarius.skinrestorer.mixin.ChunkMapAccessor; -import net.lionarius.skinrestorer.mixin.TrackedEntityAccessorInvoker; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.*; import net.minecraft.server.level.ChunkMap; diff --git a/gradle.properties b/gradle.properties index d5765eb..55ce5ca 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ minecraft_version_list=1.19.4 minecraft_version_range=[1.19.4,1.20) mod_id=skinrestorer mod_name=SkinRestorer -mod_version=2.4.3 +mod_version=2.5.0 mod_author=Lionarius mod_homepage=https://modrinth.com/mod/skinrestorer mod_sources=https://github.com/Suiranoil/SkinRestorer @@ -18,7 +18,7 @@ credits= description=A server-side mod for managing skins. # Dependencies -mineskin_client_version=3.0.6-SNAPSHOT +mineskin_client_version=3.2.1-SNAPSHOT # ParchmentMC mappings, see https://parchmentmc.org/docs/getting-started#choose-a-version for new versions parchment_minecraft=1.19.4