From 30f027d37f032f1613fd6a17ddbd5830f9150c65 Mon Sep 17 00:00:00 2001 From: lionarius Date: Thu, 26 Sep 2024 10:32:05 +0300 Subject: [PATCH 01/29] do not trigger release workflow on tag push --- .github/workflows/release.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2a92f3a..5737561 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,8 +1,5 @@ name: release on: - push: - tags: - - "v**" workflow_dispatch: jobs: From 5f6236cdf53e00c5ef5e30a89e2d4ce9aaccf29b Mon Sep 17 00:00:00 2001 From: lionarius Date: Fri, 27 Sep 2024 10:58:22 +0300 Subject: [PATCH 02/29] update README.md --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e1e902e..f91f7fa 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,12 @@ For a detailed list of available commands and their usage, please visit the [com ## 🪙 Donation -If you enjoy using **SkinRestorer** and would like to support its development, you can contribute through cryptocurrency donations. +If you enjoy using **SkinRestorer** and would like to support its development, you can contribute through the following platforms: -Bitcoin (BTC): `1Ndbwny8pxdnWXFgadp95fp97y5JqMJKTX`\ -USDT (TRC20): `TGXn8wrqku5KLzwPWQAeH7wgnV4UzwHEae`\ +[![Ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/lionarius) + +Bitcoin (BTC): `1Ndbwny8pxdnWXFgadp95fp97y5JqMJKTX` +USDT (TRC20): `TGXn8wrqku5KLzwPWQAeH7wgnV4UzwHEae` USDT (TON): `UQAQF18Xlmx-V1oZ90C2YOju5qI7q1LgrCP5QaIUhqIELmDS` Thank you for your generosity! From 62256c77a9e7629cdb950d98fdaaad43c7844fbb Mon Sep 17 00:00:00 2001 From: lionarius Date: Tue, 26 Nov 2024 04:04:46 +0300 Subject: [PATCH 03/29] add 1.21.2 and 1.21.3 to version list --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 631c9cb..8aa426d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ java_version=21 # Common minecraft_version=1.21 -minecraft_version_list=1.21,1.21.1 +minecraft_version_list=1.21,1.21.1,1.21.2,1.21.3 minecraft_version_range=[1.21, 1.22) mod_id=skinrestorer mod_name=SkinRestorer From 7292a25d7f600b83462c9424efe8d81c507f99cc Mon Sep 17 00:00:00 2001 From: lionarius Date: Tue, 26 Nov 2024 12:23:23 +0300 Subject: [PATCH 04/29] update Parchment mappings --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 8aa426d..593fe18 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,7 +19,7 @@ description=A server-side mod for managing skins. # ParchmentMC mappings, see https://parchmentmc.org/docs/getting-started#choose-a-version for new versions parchment_minecraft=1.21 -parchment_version=2024.07.28 +parchment_version=2024.11.10 # Fabric, see https://fabricmc.net/develop/ for new versions fabric_loader_version=0.15.0 From 557ff88299be242d72ddef67fbc7751199ff6a1c Mon Sep 17 00:00:00 2001 From: lionarius Date: Wed, 27 Nov 2024 12:48:50 +0300 Subject: [PATCH 05/29] implement skinshuffle support (closes #34) --- .../main/groovy/multiloader-publish.gradle | 6 +++ .../lionarius/skinrestorer/SkinRestorer.java | 9 +++- .../skinshuffle/SkinShuffleCompatibility.java | 41 +++++++++++++++++ .../SkinShuffleHandshakePayload.java | 19 ++++++++ .../SkinShuffleSkinRefreshPayload.java | 7 +++ .../SkinShuffleSkinRefreshV1Payload.java | 33 ++++++++++++++ .../SkinShuffleSkinRefreshV2Payload.java | 41 +++++++++++++++++ .../skinrestorer/platform/Services.java | 4 +- .../services/CompatibilityHelper.java | 8 ++++ .../skin/provider/SkinProvider.java | 10 ++++- .../provider/SkinShuffleSkinProvider.java | 27 +++++++++++ fabric/build.gradle | 2 + .../fabric/SkinRestorerFabric.java | 8 ++++ .../skinshuffle/SkinShuffleCompatibility.java | 37 +++++++++++++++ .../platform/FabricCompatibilityHelper.java | 13 ++++++ ...orer.platform.services.CompatibilityHelper | 1 + fabric/src/main/resources/fabric.mod.json | 3 ++ .../skinrestorer/forge/SkinRestorerForge.java | 7 +-- .../skinshuffle/SkinShuffleCompatibility.java | 14 ++++++ .../SkinShuffleGameEventHandler.java | 16 +++++++ .../skinshuffle/SkinShufflePacketHandler.java | 45 +++++++++++++++++++ .../platform/ForgeCompatibilityHelper.java | 13 ++++++ ...orer.platform.services.CompatibilityHelper | 1 + gradle.properties | 2 + .../neoforge/SkinRestorerNeoForge.java | 7 +-- .../skinshuffle/SkinShuffleCompatibility.java | 17 +++++++ .../SkinShuffleGameEventHandler.java | 16 +++++++ .../SkinShuffleModEventHandler.java | 31 +++++++++++++ .../platform/NeoForgeCompatibilityHelper.java | 15 +++++++ ...orer.platform.services.CompatibilityHelper | 1 + 30 files changed, 444 insertions(+), 10 deletions(-) create mode 100644 common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleCompatibility.java create mode 100644 common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleHandshakePayload.java create mode 100644 common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshPayload.java create mode 100644 common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV1Payload.java create mode 100644 common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV2Payload.java create mode 100644 common/src/main/java/net/lionarius/skinrestorer/platform/services/CompatibilityHelper.java create mode 100644 common/src/main/java/net/lionarius/skinrestorer/skin/provider/SkinShuffleSkinProvider.java create mode 100644 fabric/src/main/java/net/lionarius/skinrestorer/fabric/compat/skinshuffle/SkinShuffleCompatibility.java create mode 100644 fabric/src/main/java/net/lionarius/skinrestorer/fabric/platform/FabricCompatibilityHelper.java create mode 100644 fabric/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.CompatibilityHelper create mode 100644 forge/src/main/java/net/lionarius/skinrestorer/forge/compat/skinshuffle/SkinShuffleCompatibility.java create mode 100644 forge/src/main/java/net/lionarius/skinrestorer/forge/compat/skinshuffle/SkinShuffleGameEventHandler.java create mode 100644 forge/src/main/java/net/lionarius/skinrestorer/forge/compat/skinshuffle/SkinShufflePacketHandler.java create mode 100644 forge/src/main/java/net/lionarius/skinrestorer/forge/platform/ForgeCompatibilityHelper.java create mode 100644 forge/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.CompatibilityHelper create mode 100644 neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShuffleCompatibility.java create mode 100644 neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShuffleGameEventHandler.java create mode 100644 neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShuffleModEventHandler.java create mode 100644 neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/platform/NeoForgeCompatibilityHelper.java create mode 100644 neoforge/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.CompatibilityHelper diff --git a/buildSrc/src/main/groovy/multiloader-publish.gradle b/buildSrc/src/main/groovy/multiloader-publish.gradle index abbf530..8648805 100644 --- a/buildSrc/src/main/groovy/multiloader-publish.gradle +++ b/buildSrc/src/main/groovy/multiloader-publish.gradle @@ -22,6 +22,9 @@ publishMods { minecraftVersions.addAll(minecraft_version_list.split(',')) serverRequired = true + + if (project.name == 'fabric') + optional(fabric_optional_dependencies.split(',')) } modrinth { @@ -31,5 +34,8 @@ publishMods { accessToken = providers.environmentVariable("MODRINTH_TOKEN") minecraftVersions.addAll(minecraft_version_list.split(',')) + + if (project.name == 'fabric') + optional(fabric_optional_dependencies.split(',')) } } diff --git a/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java b/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java index a324c84..8c95b44 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java +++ b/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java @@ -13,6 +13,7 @@ import net.lionarius.skinrestorer.util.FileUtils; import net.lionarius.skinrestorer.util.PlayerUtils; import net.lionarius.skinrestorer.util.Result; import net.lionarius.skinrestorer.util.WebUtils; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.level.storage.LevelResource; @@ -20,7 +21,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.file.Path; -import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Optional; @@ -57,11 +57,16 @@ public final class SkinRestorer { return Optional.ofNullable(SkinRestorer.providersRegistry.get(name)); } + public static ResourceLocation resourceLocation(String name) { + return ResourceLocation.fromNamespaceAndPath(SkinRestorer.MOD_ID, name); + } + public static void onInitialize() { SkinRestorer.configDir = Services.PLATFORM.getConfigDirectory().resolve(SkinRestorer.MOD_ID); SkinRestorer.reloadConfig(); SkinRestorer.providersRegistry.register(EmptySkinProvider.PROVIDER_NAME, SkinProvider.EMPTY, false); + SkinRestorer.providersRegistry.register(SkinShuffleSkinProvider.PROVIDER_NAME, SkinProvider.SKIN_SHUFFLE, false); SkinRestorer.registerDefaultSkinProvider(MojangSkinProvider.PROVIDER_NAME, SkinProvider.MOJANG, SkinRestorer.getConfig().providersConfig().mojang()); SkinRestorer.registerDefaultSkinProvider(ElyBySkinProvider.PROVIDER_NAME, SkinProvider.ELY_BY, SkinRestorer.getConfig().providersConfig().ely_by()); @@ -72,7 +77,7 @@ public final class SkinRestorer { var isDefaultName = config.name().equals(defaultName); SkinRestorer.providersRegistry.register(defaultName, provider, config.enabled() && isDefaultName); - if (!isDefaultName && Arrays.stream(SkinProvider.BUILTIN_PROVIDER_NAMES).noneMatch(name -> name.equals(config.name()))) + if (!isDefaultName && !SkinProvider.BUILTIN_PROVIDER_NAMES.contains(config.name())) SkinRestorer.providersRegistry.register(config.name(), provider, config.enabled()); } 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 new file mode 100644 index 0000000..488e3b5 --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleCompatibility.java @@ -0,0 +1,41 @@ +package net.lionarius.skinrestorer.compat.skinshuffle; + +import net.lionarius.skinrestorer.SkinRestorer; +import net.lionarius.skinrestorer.platform.Services; +import net.lionarius.skinrestorer.skin.SkinValue; +import net.lionarius.skinrestorer.skin.provider.SkinShuffleSkinProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; + +import java.util.Collections; + +public class SkinShuffleCompatibility { + + public static final String MOD_ID = "skinshuffle"; + + private static final boolean SHOULD_APPLY = !Services.PLATFORM.isModLoaded(SkinShuffleCompatibility.MOD_ID); + + private SkinShuffleCompatibility() {} + + public static boolean shouldApply() { + return SkinShuffleCompatibility.SHOULD_APPLY; + } + + public static ResourceLocation resourceLocation(String name) { + return ResourceLocation.fromNamespaceAndPath(SkinShuffleCompatibility.MOD_ID, name); + } + + public static void onPlayerJoin(ServerPlayer player) { + Services.COMPATIBILITY.skinShuffle_sendHandshake(player); + } + + public static void handleSkinRefresh(MinecraftServer server, ServerPlayer player, SkinShuffleSkinRefreshPayload payload) { + var property = payload.textureProperty(); + + if (!property.hasSignature()) + return; + + server.execute(() -> SkinRestorer.applySkin(server, Collections.singleton(player.getGameProfile()), new SkinValue(SkinShuffleSkinProvider.PROVIDER_NAME, null, null, property))); + } +} diff --git a/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleHandshakePayload.java b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleHandshakePayload.java new file mode 100644 index 0000000..798ed92 --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleHandshakePayload.java @@ -0,0 +1,19 @@ +package net.lionarius.skinrestorer.compat.skinshuffle; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import org.jetbrains.annotations.NotNull; + +public record SkinShuffleHandshakePayload() implements CustomPacketPayload { + + public static final SkinShuffleHandshakePayload INSTANCE = new SkinShuffleHandshakePayload(); + + public static final CustomPacketPayload.Type PACKET_ID = new CustomPacketPayload.Type<>(SkinShuffleCompatibility.resourceLocation("handshake")); + public static final StreamCodec PACKET_CODEC = StreamCodec.unit(INSTANCE); + + @Override + public CustomPacketPayload.@NotNull Type type() { + return PACKET_ID; + } +} diff --git a/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshPayload.java b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshPayload.java new file mode 100644 index 0000000..f8c6030 --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshPayload.java @@ -0,0 +1,7 @@ +package net.lionarius.skinrestorer.compat.skinshuffle; + +import com.mojang.authlib.properties.Property; + +public interface SkinShuffleSkinRefreshPayload { + Property textureProperty(); +} diff --git a/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV1Payload.java b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV1Payload.java new file mode 100644 index 0000000..d879bfc --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV1Payload.java @@ -0,0 +1,33 @@ +package net.lionarius.skinrestorer.compat.skinshuffle; + +import com.mojang.authlib.properties.Property; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import org.jetbrains.annotations.NotNull; + +public record SkinShuffleSkinRefreshV1Payload(Property textureProperty) implements CustomPacketPayload, SkinShuffleSkinRefreshPayload { + + public static final CustomPacketPayload.Type PACKET_ID = new CustomPacketPayload.Type<>(SkinShuffleCompatibility.resourceLocation("refresh")); + public static final StreamCodec PACKET_CODEC = StreamCodec.of( + SkinShuffleSkinRefreshV1Payload::encode, + SkinShuffleSkinRefreshV1Payload::decode + ); + + private static void encode(FriendlyByteBuf buf, SkinShuffleSkinRefreshV1Payload value) { + var textureProperty = value.textureProperty(); + + buf.writeUtf(textureProperty.name()); + buf.writeUtf(textureProperty.value()); + buf.writeNullable(textureProperty.signature(), FriendlyByteBuf::writeUtf); + } + + private static SkinShuffleSkinRefreshV1Payload decode(FriendlyByteBuf buf) { + return new SkinShuffleSkinRefreshV1Payload(new Property(buf.readUtf(), buf.readUtf(), buf.readNullable(FriendlyByteBuf::readUtf))); + } + + @Override + public @NotNull CustomPacketPayload.Type type() { + return PACKET_ID; + } +} diff --git a/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV2Payload.java b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV2Payload.java new file mode 100644 index 0000000..aabcbdb --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV2Payload.java @@ -0,0 +1,41 @@ +package net.lionarius.skinrestorer.compat.skinshuffle; + +import com.mojang.authlib.properties.Property; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import org.jetbrains.annotations.NotNull; + +public record SkinShuffleSkinRefreshV2Payload(Property textureProperty) implements CustomPacketPayload, SkinShuffleSkinRefreshPayload { + + public static final CustomPacketPayload.Type PACKET_ID = new CustomPacketPayload.Type<>(SkinShuffleCompatibility.resourceLocation("skin_refresh")); + public static final StreamCodec PACKET_CODEC = StreamCodec.of( + SkinShuffleSkinRefreshV2Payload::encode, + SkinShuffleSkinRefreshV2Payload::decode + ); + + private static void encode(FriendlyByteBuf buf, SkinShuffleSkinRefreshV2Payload value) { + var textureProperty = value.textureProperty(); + + buf.writeBoolean(textureProperty.hasSignature()); + buf.writeUtf(textureProperty.name()); + buf.writeUtf(textureProperty.value()); + if (textureProperty.hasSignature()) { + assert textureProperty.signature() != null; + + buf.writeUtf(textureProperty.signature()); + } + } + + private static SkinShuffleSkinRefreshV2Payload decode(FriendlyByteBuf buf) { + if (buf.readBoolean()) { + return new SkinShuffleSkinRefreshV2Payload(new Property(buf.readUtf(), buf.readUtf(), buf.readUtf())); + } + return new SkinShuffleSkinRefreshV2Payload(new Property(buf.readUtf(), buf.readUtf(), null)); + } + + @Override + public @NotNull CustomPacketPayload.Type type() { + return PACKET_ID; + } +} diff --git a/common/src/main/java/net/lionarius/skinrestorer/platform/Services.java b/common/src/main/java/net/lionarius/skinrestorer/platform/Services.java index e160259..7b3c00f 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/platform/Services.java +++ b/common/src/main/java/net/lionarius/skinrestorer/platform/Services.java @@ -1,6 +1,7 @@ package net.lionarius.skinrestorer.platform; import net.lionarius.skinrestorer.SkinRestorer; +import net.lionarius.skinrestorer.platform.services.CompatibilityHelper; import net.lionarius.skinrestorer.platform.services.PlatformHelper; import java.util.ServiceLoader; @@ -8,8 +9,9 @@ import java.util.ServiceLoader; public final class Services { private Services() {} - + public final static PlatformHelper PLATFORM = load(PlatformHelper.class); + public final static CompatibilityHelper COMPATIBILITY = load(CompatibilityHelper.class); private static T load(Class clazz) { final T loadedService = ServiceLoader.load(clazz) diff --git a/common/src/main/java/net/lionarius/skinrestorer/platform/services/CompatibilityHelper.java b/common/src/main/java/net/lionarius/skinrestorer/platform/services/CompatibilityHelper.java new file mode 100644 index 0000000..a372f49 --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/platform/services/CompatibilityHelper.java @@ -0,0 +1,8 @@ +package net.lionarius.skinrestorer.platform.services; + +import net.minecraft.server.level.ServerPlayer; + +public interface CompatibilityHelper { + + void skinShuffle_sendHandshake(ServerPlayer player); +} 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 86a5815..f191be0 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 @@ -5,14 +5,22 @@ import net.lionarius.skinrestorer.skin.SkinVariant; import net.lionarius.skinrestorer.util.Result; import java.util.Optional; +import java.util.Set; public interface SkinProvider { EmptySkinProvider EMPTY = new EmptySkinProvider(); MojangSkinProvider MOJANG = new MojangSkinProvider(); ElyBySkinProvider ELY_BY = new ElyBySkinProvider(); MineskinSkinProvider MINESKIN = new MineskinSkinProvider(); + SkinShuffleSkinProvider SKIN_SHUFFLE = new SkinShuffleSkinProvider(); - String[] BUILTIN_PROVIDER_NAMES = new String[]{EmptySkinProvider.PROVIDER_NAME, MojangSkinProvider.PROVIDER_NAME, ElyBySkinProvider.PROVIDER_NAME, MineskinSkinProvider.PROVIDER_NAME}; + Set BUILTIN_PROVIDER_NAMES = Set.of( + EmptySkinProvider.PROVIDER_NAME, + MojangSkinProvider.PROVIDER_NAME, + ElyBySkinProvider.PROVIDER_NAME, + MineskinSkinProvider.PROVIDER_NAME, + SkinShuffleSkinProvider.PROVIDER_NAME + ); String getArgumentName(); diff --git a/common/src/main/java/net/lionarius/skinrestorer/skin/provider/SkinShuffleSkinProvider.java b/common/src/main/java/net/lionarius/skinrestorer/skin/provider/SkinShuffleSkinProvider.java new file mode 100644 index 0000000..e8642ce --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/skin/provider/SkinShuffleSkinProvider.java @@ -0,0 +1,27 @@ +package net.lionarius.skinrestorer.skin.provider; + +import com.mojang.authlib.properties.Property; +import net.lionarius.skinrestorer.skin.SkinVariant; +import net.lionarius.skinrestorer.util.Result; + +import java.util.Optional; + +public final class SkinShuffleSkinProvider implements SkinProvider { + + public static final String PROVIDER_NAME = "skinshuffle"; + + @Override + public String getArgumentName() { + return "unsupported"; + } + + @Override + public boolean hasVariantSupport() { + return false; + } + + @Override + public Result, Exception> fetchSkin(String argument, SkinVariant variant) { + return Result.error(new UnsupportedOperationException("SkinShuffle Provider does not support fetching skins")); + } +} diff --git a/fabric/build.gradle b/fabric/build.gradle index ffdbf57..21414f2 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -12,6 +12,8 @@ dependencies { parchment("org.parchmentmc.data:parchment-${parchment_minecraft}:${parchment_version}@zip") } modImplementation "net.fabricmc:fabric-loader:${fabric_loader_version}" + + modCompileOnly "net.fabricmc.fabric-api:fabric-api:${fabric_api_version}" } loom { diff --git a/fabric/src/main/java/net/lionarius/skinrestorer/fabric/SkinRestorerFabric.java b/fabric/src/main/java/net/lionarius/skinrestorer/fabric/SkinRestorerFabric.java index 906896e..ae7a70b 100644 --- a/fabric/src/main/java/net/lionarius/skinrestorer/fabric/SkinRestorerFabric.java +++ b/fabric/src/main/java/net/lionarius/skinrestorer/fabric/SkinRestorerFabric.java @@ -2,10 +2,18 @@ package net.lionarius.skinrestorer.fabric; import net.fabricmc.api.ModInitializer; import net.lionarius.skinrestorer.SkinRestorer; +import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility; +import net.lionarius.skinrestorer.platform.Services; public final class SkinRestorerFabric implements ModInitializer { + + public static final boolean FABRIC_API_LOADED = Services.PLATFORM.isModLoaded("fabric-api"); + @Override public void onInitialize() { SkinRestorer.onInitialize(); + + if (SkinShuffleCompatibility.shouldApply()) + net.lionarius.skinrestorer.fabric.compat.skinshuffle.SkinShuffleCompatibility.initialize(); } } 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 new file mode 100644 index 0000000..662ae14 --- /dev/null +++ b/fabric/src/main/java/net/lionarius/skinrestorer/fabric/compat/skinshuffle/SkinShuffleCompatibility.java @@ -0,0 +1,37 @@ +package net.lionarius.skinrestorer.fabric.compat.skinshuffle; + +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.lionarius.skinrestorer.SkinRestorer; +import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleHandshakePayload; +import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleSkinRefreshPayload; +import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleSkinRefreshV1Payload; +import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleSkinRefreshV2Payload; +import net.lionarius.skinrestorer.fabric.SkinRestorerFabric; + +public final class SkinShuffleCompatibility { + + private SkinShuffleCompatibility() {} + + public static void initialize() { + if (!SkinRestorerFabric.FABRIC_API_LOADED) { + SkinRestorer.LOGGER.warn("fabric-api is not loaded, SkinShuffle compatibility will not be available"); + return; + } + + PayloadTypeRegistry.playS2C().register(SkinShuffleHandshakePayload.PACKET_ID, SkinShuffleHandshakePayload.PACKET_CODEC); + PayloadTypeRegistry.playC2S().register(SkinShuffleSkinRefreshV1Payload.PACKET_ID, SkinShuffleSkinRefreshV1Payload.PACKET_CODEC); + PayloadTypeRegistry.playC2S().register(SkinShuffleSkinRefreshV2Payload.PACKET_ID, SkinShuffleSkinRefreshV2Payload.PACKET_CODEC); + + ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility.onPlayerJoin(handler.getPlayer())); + + ServerPlayNetworking.registerGlobalReceiver(SkinShuffleSkinRefreshV1Payload.PACKET_ID, SkinShuffleCompatibility::handleSkinRefreshPacket); + + ServerPlayNetworking.registerGlobalReceiver(SkinShuffleSkinRefreshV2Payload.PACKET_ID, SkinShuffleCompatibility::handleSkinRefreshPacket); + } + + private static void handleSkinRefreshPacket(SkinShuffleSkinRefreshPayload payload, ServerPlayNetworking.Context context) { + net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility.handleSkinRefresh(context.player().getServer(), context.player(), payload); + } +} diff --git a/fabric/src/main/java/net/lionarius/skinrestorer/fabric/platform/FabricCompatibilityHelper.java b/fabric/src/main/java/net/lionarius/skinrestorer/fabric/platform/FabricCompatibilityHelper.java new file mode 100644 index 0000000..c8d7588 --- /dev/null +++ b/fabric/src/main/java/net/lionarius/skinrestorer/fabric/platform/FabricCompatibilityHelper.java @@ -0,0 +1,13 @@ +package net.lionarius.skinrestorer.fabric.platform; + +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleHandshakePayload; +import net.lionarius.skinrestorer.platform.services.CompatibilityHelper; +import net.minecraft.server.level.ServerPlayer; + +public final class FabricCompatibilityHelper implements CompatibilityHelper { + @Override + public void skinShuffle_sendHandshake(ServerPlayer player) { + ServerPlayNetworking.send(player, SkinShuffleHandshakePayload.INSTANCE); + } +} diff --git a/fabric/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.CompatibilityHelper b/fabric/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.CompatibilityHelper new file mode 100644 index 0000000..a325afc --- /dev/null +++ b/fabric/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.CompatibilityHelper @@ -0,0 +1 @@ +net.lionarius.skinrestorer.fabric.platform.FabricCompatibilityHelper diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 89d74b6..85c219d 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -28,5 +28,8 @@ "fabricloader": ">=${fabric_loader_version}", "minecraft": ">=${minecraft_version}", "java": ">=${java_version}" + }, + "suggests": { + "fabric-api": "*" } } diff --git a/forge/src/main/java/net/lionarius/skinrestorer/forge/SkinRestorerForge.java b/forge/src/main/java/net/lionarius/skinrestorer/forge/SkinRestorerForge.java index 5a0d03d..8417a8b 100644 --- a/forge/src/main/java/net/lionarius/skinrestorer/forge/SkinRestorerForge.java +++ b/forge/src/main/java/net/lionarius/skinrestorer/forge/SkinRestorerForge.java @@ -2,7 +2,7 @@ package net.lionarius.skinrestorer.forge; import net.lionarius.skinrestorer.SkinRestorer; import net.lionarius.skinrestorer.command.SkinCommand; -import net.minecraftforge.common.MinecraftForge; +import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility; import net.minecraftforge.event.RegisterCommandsEvent; import net.minecraftforge.event.server.ServerStartedEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -13,9 +13,10 @@ import net.minecraftforge.fml.common.Mod; public final class SkinRestorerForge { public SkinRestorerForge() { - MinecraftForge.EVENT_BUS.register(SkinRestorerForge.class); - SkinRestorer.onInitialize(); + + if (SkinShuffleCompatibility.shouldApply()) + net.lionarius.skinrestorer.forge.compat.skinshuffle.SkinShuffleCompatibility.initialize(); } @SubscribeEvent diff --git a/forge/src/main/java/net/lionarius/skinrestorer/forge/compat/skinshuffle/SkinShuffleCompatibility.java b/forge/src/main/java/net/lionarius/skinrestorer/forge/compat/skinshuffle/SkinShuffleCompatibility.java new file mode 100644 index 0000000..a433843 --- /dev/null +++ b/forge/src/main/java/net/lionarius/skinrestorer/forge/compat/skinshuffle/SkinShuffleCompatibility.java @@ -0,0 +1,14 @@ +package net.lionarius.skinrestorer.forge.compat.skinshuffle; + +import net.minecraftforge.common.MinecraftForge; + +public final class SkinShuffleCompatibility { + + private SkinShuffleCompatibility() {} + + public static void initialize() { + MinecraftForge.EVENT_BUS.register(SkinShuffleGameEventHandler.class); + + SkinShufflePacketHandler.initialize(); + } +} diff --git a/forge/src/main/java/net/lionarius/skinrestorer/forge/compat/skinshuffle/SkinShuffleGameEventHandler.java b/forge/src/main/java/net/lionarius/skinrestorer/forge/compat/skinshuffle/SkinShuffleGameEventHandler.java new file mode 100644 index 0000000..70daee9 --- /dev/null +++ b/forge/src/main/java/net/lionarius/skinrestorer/forge/compat/skinshuffle/SkinShuffleGameEventHandler.java @@ -0,0 +1,16 @@ +package net.lionarius.skinrestorer.forge.compat.skinshuffle; + +import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility; +import net.minecraft.server.level.ServerPlayer; +import net.minecraftforge.event.entity.player.PlayerEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +public final class SkinShuffleGameEventHandler { + + private SkinShuffleGameEventHandler() {} + + @SubscribeEvent + public static void onPlayerLoggedIn(PlayerEvent.PlayerLoggedInEvent event) { + SkinShuffleCompatibility.onPlayerJoin((ServerPlayer) event.getEntity()); + } +} 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 new file mode 100644 index 0000000..538ddd4 --- /dev/null +++ b/forge/src/main/java/net/lionarius/skinrestorer/forge/compat/skinshuffle/SkinShufflePacketHandler.java @@ -0,0 +1,45 @@ +package net.lionarius.skinrestorer.forge.compat.skinshuffle; + +import net.lionarius.skinrestorer.SkinRestorer; +import net.lionarius.skinrestorer.compat.skinshuffle.*; +import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility; +import net.minecraft.network.Connection; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraftforge.event.network.CustomPayloadEvent; +import net.minecraftforge.network.Channel; +import net.minecraftforge.network.ChannelBuilder; + +public class SkinShufflePacketHandler { + private SkinShufflePacketHandler() { + } + + private static final Channel INSTANCE = ChannelBuilder + .named(SkinRestorer.resourceLocation("skin_shuffle_compat")) + .optional() + .payloadChannel() + .any() + .clientbound() + .add(SkinShuffleHandshakePayload.PACKET_ID, SkinShuffleHandshakePayload.PACKET_CODEC, (payload, context) -> { + }) + .serverbound() + .add(SkinShuffleSkinRefreshV1Payload.PACKET_ID, SkinShuffleSkinRefreshV1Payload.PACKET_CODEC, SkinShufflePacketHandler::handleSkinRefreshPacket) + .add(SkinShuffleSkinRefreshV2Payload.PACKET_ID, SkinShuffleSkinRefreshV2Payload.PACKET_CODEC, SkinShufflePacketHandler::handleSkinRefreshPacket) + .build(); + + protected static void initialize() { + // NO-OP + } + + public static void sendHandshake(Connection connection) { + INSTANCE.send(SkinShuffleHandshakePayload.INSTANCE, connection); + } + + private static void handleSkinRefreshPacket(SkinShuffleSkinRefreshPayload payload, CustomPayloadEvent.Context context) { + var sender = context.getSender(); + + if (!context.isServerSide() || sender == null) + return; + + SkinShuffleCompatibility.handleSkinRefresh(sender.getServer(), sender, payload); + } +} diff --git a/forge/src/main/java/net/lionarius/skinrestorer/forge/platform/ForgeCompatibilityHelper.java b/forge/src/main/java/net/lionarius/skinrestorer/forge/platform/ForgeCompatibilityHelper.java new file mode 100644 index 0000000..f613a00 --- /dev/null +++ b/forge/src/main/java/net/lionarius/skinrestorer/forge/platform/ForgeCompatibilityHelper.java @@ -0,0 +1,13 @@ +package net.lionarius.skinrestorer.forge.platform; + +import net.lionarius.skinrestorer.forge.compat.skinshuffle.SkinShufflePacketHandler; +import net.lionarius.skinrestorer.platform.services.CompatibilityHelper; +import net.minecraft.server.level.ServerPlayer; + +public final class ForgeCompatibilityHelper implements CompatibilityHelper { + + @Override + public void skinShuffle_sendHandshake(ServerPlayer player) { + SkinShufflePacketHandler.sendHandshake(player.connection.getConnection()); + } +} diff --git a/forge/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.CompatibilityHelper b/forge/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.CompatibilityHelper new file mode 100644 index 0000000..73cddf5 --- /dev/null +++ b/forge/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.CompatibilityHelper @@ -0,0 +1 @@ +net.lionarius.skinrestorer.forge.platform.ForgeCompatibilityHelper diff --git a/gradle.properties b/gradle.properties index 593fe18..d9eeef2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -23,6 +23,8 @@ parchment_version=2024.11.10 # Fabric, see https://fabricmc.net/develop/ for new versions fabric_loader_version=0.15.0 +fabric_api_version=0.100.1+1.21 +fabric_optional_dependencies=fabric-api # Forge, see https://files.minecraftforge.net/net/minecraftforge/forge/ for new versions forge_version=51.0.0 diff --git a/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/SkinRestorerNeoForge.java b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/SkinRestorerNeoForge.java index c15cc42..f1078a3 100644 --- a/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/SkinRestorerNeoForge.java +++ b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/SkinRestorerNeoForge.java @@ -2,10 +2,10 @@ package net.lionarius.skinrestorer.neoforge; import net.lionarius.skinrestorer.SkinRestorer; import net.lionarius.skinrestorer.command.SkinCommand; +import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.fml.common.Mod; -import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.event.RegisterCommandsEvent; import net.neoforged.neoforge.event.server.ServerStartedEvent; @@ -14,9 +14,10 @@ import net.neoforged.neoforge.event.server.ServerStartedEvent; public final class SkinRestorerNeoForge { public SkinRestorerNeoForge() { - NeoForge.EVENT_BUS.register(SkinRestorerNeoForge.class); - SkinRestorer.onInitialize(); + + if (SkinShuffleCompatibility.shouldApply()) + net.lionarius.skinrestorer.neoforge.compat.skinshuffle.SkinShuffleCompatibility.initialize(); } @SubscribeEvent diff --git a/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShuffleCompatibility.java b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShuffleCompatibility.java new file mode 100644 index 0000000..702ea67 --- /dev/null +++ b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShuffleCompatibility.java @@ -0,0 +1,17 @@ +package net.lionarius.skinrestorer.neoforge.compat.skinshuffle; + +import net.lionarius.skinrestorer.SkinRestorer; +import net.neoforged.fml.ModList; +import net.neoforged.neoforge.common.NeoForge; + +public final class SkinShuffleCompatibility { + + private SkinShuffleCompatibility() {} + + public static void initialize() { + NeoForge.EVENT_BUS.register(SkinShuffleGameEventHandler.class); + + final var mod = ModList.get().getModContainerById(SkinRestorer.MOD_ID).get(); + mod.getEventBus().register(SkinShuffleModEventHandler.class); + } +} diff --git a/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShuffleGameEventHandler.java b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShuffleGameEventHandler.java new file mode 100644 index 0000000..9f4b260 --- /dev/null +++ b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShuffleGameEventHandler.java @@ -0,0 +1,16 @@ +package net.lionarius.skinrestorer.neoforge.compat.skinshuffle; + +import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility; +import net.minecraft.server.level.ServerPlayer; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; + +public final class SkinShuffleGameEventHandler { + + private SkinShuffleGameEventHandler() {} + + @SubscribeEvent + public static void onPlayerLoggedIn(PlayerEvent.PlayerLoggedInEvent event) { + SkinShuffleCompatibility.onPlayerJoin((ServerPlayer) event.getEntity()); + } +} 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 new file mode 100644 index 0000000..6036393 --- /dev/null +++ b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShuffleModEventHandler.java @@ -0,0 +1,31 @@ +package net.lionarius.skinrestorer.neoforge.compat.skinshuffle; + +import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility; +import net.lionarius.skinrestorer.compat.skinshuffle.*; +import net.minecraft.server.level.ServerPlayer; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; +import net.neoforged.neoforge.network.registration.HandlerThread; + +public final class SkinShuffleModEventHandler { + private SkinShuffleModEventHandler() {} + + @SubscribeEvent + public static void onRegisterPayloadHandlers(RegisterPayloadHandlersEvent event) { + final var registrar = event.registrar("1").optional().executesOn(HandlerThread.NETWORK); + + registrar + .playToClient(SkinShuffleHandshakePayload.PACKET_ID, SkinShuffleHandshakePayload.PACKET_CODEC, + (payload, context) -> {}) + .playToServer(SkinShuffleSkinRefreshV1Payload.PACKET_ID, SkinShuffleSkinRefreshV1Payload.PACKET_CODEC, + SkinShuffleModEventHandler::handleSkinRefreshPacket) + .playToServer(SkinShuffleSkinRefreshV2Payload.PACKET_ID, SkinShuffleSkinRefreshV2Payload.PACKET_CODEC, + SkinShuffleModEventHandler::handleSkinRefreshPacket); + } + + private static void handleSkinRefreshPacket(SkinShuffleSkinRefreshPayload payload, IPayloadContext context) { + var player = (ServerPlayer) context.player(); + SkinShuffleCompatibility.handleSkinRefresh(player.getServer(), player, payload); + } +} diff --git a/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/platform/NeoForgeCompatibilityHelper.java b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/platform/NeoForgeCompatibilityHelper.java new file mode 100644 index 0000000..4cd9a0c --- /dev/null +++ b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/platform/NeoForgeCompatibilityHelper.java @@ -0,0 +1,15 @@ +package net.lionarius.skinrestorer.neoforge.platform; + +import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleHandshakePayload; +import net.lionarius.skinrestorer.platform.services.CompatibilityHelper; +import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; +import net.minecraft.server.level.ServerPlayer; + +public final class NeoForgeCompatibilityHelper implements CompatibilityHelper { + + @Override + public void skinShuffle_sendHandshake(ServerPlayer player) { + // we can't use the packet distributor here because neoforge doesn't support sending packets to non-neoforge players + player.connection.getConnection().send(new ClientboundCustomPayloadPacket(SkinShuffleHandshakePayload.INSTANCE)); + } +} diff --git a/neoforge/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.CompatibilityHelper b/neoforge/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.CompatibilityHelper new file mode 100644 index 0000000..5138d46 --- /dev/null +++ b/neoforge/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.CompatibilityHelper @@ -0,0 +1 @@ +net.lionarius.skinrestorer.neoforge.platform.NeoForgeCompatibilityHelper From 5e0f67a1e606086e7084e949fb8777cd875550d8 Mon Sep 17 00:00:00 2001 From: lionarius Date: Wed, 27 Nov 2024 12:49:54 +0300 Subject: [PATCH 06/29] save only if applying skin --- .../main/java/net/lionarius/skinrestorer/SkinRestorer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java b/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java index 8c95b44..e9fee55 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java +++ b/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java @@ -109,12 +109,12 @@ public final class SkinRestorer { if (!SkinRestorer.getSkinStorage().hasSavedSkin(profile.getId())) value = value.setOriginalValue(PlayerUtils.getPlayerSkin(profile)); - if (save) - SkinRestorer.getSkinStorage().setSkin(profile.getId(), value); - if (PlayerUtils.areSkinPropertiesEquals(value.value(), PlayerUtils.getPlayerSkin(profile))) continue; + if (save) + SkinRestorer.getSkinStorage().setSkin(profile.getId(), value); + PlayerUtils.applyRestoredSkin(profile, value.value()); var player = server.getPlayerList().getPlayer(profile.getId()); From eeda2f585737fa5b08aa9036f656d4fc75d0ae76 Mon Sep 17 00:00:00 2001 From: lionarius Date: Wed, 27 Nov 2024 12:50:20 +0300 Subject: [PATCH 07/29] change project group from net.lionarius.skinrestorer to net.lionarius --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index d9eeef2..2eb6290 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Project -group=net.lionarius.skinrestorer +group=net.lionarius java_version=21 # Common From 4a43a0de41046ab74f83b02add3304bec85b125e Mon Sep 17 00:00:00 2001 From: lionarius Date: Wed, 27 Nov 2024 13:02:18 +0300 Subject: [PATCH 08/29] capitalize logger messages --- .../mixin/ServerLoginPacketListenerImplMixin.java | 6 +++--- .../net/lionarius/skinrestorer/util/FileUtils.java | 10 +++++----- .../net/lionarius/skinrestorer/util/JsonUtils.java | 2 +- .../java/net/lionarius/skinrestorer/util/WebUtils.java | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) 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 90d2210..28e588e 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/mixin/ServerLoginPacketListenerImplMixin.java +++ b/common/src/main/java/net/lionarius/skinrestorer/mixin/ServerLoginPacketListenerImplMixin.java @@ -72,17 +72,17 @@ public abstract class ServerLoginPacketListenerImplMixin { @Unique private static void skinrestorer$fetchSkin(GameProfile profile, SkinProviderContext context) { - SkinRestorer.LOGGER.debug("fetching {}'s skin", profile.getName()); + SkinRestorer.LOGGER.debug("Fetching {}'s skin", profile.getName()); var result = SkinRestorer.getProvider(context.name()).map( provider -> provider.fetchSkin(context.argument(), context.variant()) - ).orElseGet(() -> Result.error(new IllegalArgumentException("skin provider is not registered: " + context.name()))); + ).orElseGet(() -> Result.error(new IllegalArgumentException("Skin provider is not registered: " + context.name()))); if (!result.isError()) { var value = SkinValue.fromProviderContextWithValue(context, result.getSuccessValue().orElse(null)); SkinRestorer.getSkinStorage().setSkin(profile.getId(), value); } else { - SkinRestorer.LOGGER.warn("failed to fetch skin", result.getErrorValue()); + SkinRestorer.LOGGER.warn("Failed to fetch skin: {}", result.getErrorValue().getMessage()); } } } diff --git a/common/src/main/java/net/lionarius/skinrestorer/util/FileUtils.java b/common/src/main/java/net/lionarius/skinrestorer/util/FileUtils.java index d0aeb0b..f1b7de9 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/util/FileUtils.java +++ b/common/src/main/java/net/lionarius/skinrestorer/util/FileUtils.java @@ -42,7 +42,7 @@ public final class FileUtils { } } } catch (Exception e) { - SkinRestorer.LOGGER.error("could not migrate skin directory", e); + SkinRestorer.LOGGER.error("Could not migrate skin directory", e); } } @@ -55,7 +55,7 @@ public final class FileUtils { return StringUtils.readString(reader); } } catch (IOException e) { - SkinRestorer.LOGGER.error("failed to read resource", e); + SkinRestorer.LOGGER.error("Failed to read resource", e); return null; } } @@ -67,7 +67,7 @@ public final class FileUtils { return Files.readString(file); } catch (Exception e) { - SkinRestorer.LOGGER.error("failed to read file", e); + SkinRestorer.LOGGER.error("Failed to read file", e); return null; } } @@ -83,7 +83,7 @@ public final class FileUtils { Files.writeString(file, content); } catch (IOException e) { - SkinRestorer.LOGGER.error("failed to write file", e); + SkinRestorer.LOGGER.error("Failed to write file", e); } } @@ -92,7 +92,7 @@ public final class FileUtils { if (Files.exists(file)) Files.delete(file); } catch (IOException e) { - SkinRestorer.LOGGER.error("failed to delete file", e); + SkinRestorer.LOGGER.error("Failed to delete file", e); } } } 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 82e47b1..d648601 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/util/JsonUtils.java +++ b/common/src/main/java/net/lionarius/skinrestorer/util/JsonUtils.java @@ -54,7 +54,7 @@ public final class JsonUtils { return json; } catch (Exception e) { - SkinRestorer.LOGGER.error(e.toString()); + SkinRestorer.LOGGER.error("Could not parse skin property", e); return null; } } diff --git a/common/src/main/java/net/lionarius/skinrestorer/util/WebUtils.java b/common/src/main/java/net/lionarius/skinrestorer/util/WebUtils.java index c877bf2..1f6946a 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/util/WebUtils.java +++ b/common/src/main/java/net/lionarius/skinrestorer/util/WebUtils.java @@ -36,7 +36,7 @@ public final class WebUtils { try { builder.connectTimeout(Duration.of(SkinRestorer.getConfig().requestTimeout(), ChronoUnit.SECONDS)); } catch (IllegalArgumentException e) { - SkinRestorer.LOGGER.error("failed to set request timeout", e); + SkinRestorer.LOGGER.error("Failed to set request timeout", e); builder.connectTimeout(Duration.of(10, ChronoUnit.SECONDS)); } From aa027597803e87c1644d0a34bc34eb884acd183c Mon Sep 17 00:00:00 2001 From: lionarius Date: Wed, 27 Nov 2024 13:08:16 +0300 Subject: [PATCH 09/29] use immutable set for BUILTIN_PROVIDER_NAMES --- .../net/lionarius/skinrestorer/skin/provider/SkinProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 f191be0..8b5aad5 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 @@ -1,5 +1,6 @@ package net.lionarius.skinrestorer.skin.provider; +import com.google.common.collect.ImmutableSet; import com.mojang.authlib.properties.Property; import net.lionarius.skinrestorer.skin.SkinVariant; import net.lionarius.skinrestorer.util.Result; @@ -14,7 +15,7 @@ public interface SkinProvider { MineskinSkinProvider MINESKIN = new MineskinSkinProvider(); SkinShuffleSkinProvider SKIN_SHUFFLE = new SkinShuffleSkinProvider(); - Set BUILTIN_PROVIDER_NAMES = Set.of( + Set BUILTIN_PROVIDER_NAMES = ImmutableSet.of( EmptySkinProvider.PROVIDER_NAME, MojangSkinProvider.PROVIDER_NAME, ElyBySkinProvider.PROVIDER_NAME, From ba47986e944ee8ed686aba694cc21db3d137dfb1 Mon Sep 17 00:00:00 2001 From: lionarius Date: Wed, 27 Nov 2024 13:26:20 +0300 Subject: [PATCH 10/29] formatting --- buildSrc/src/main/groovy/multiloader-loader.gradle | 4 ++-- common/build.gradle | 4 ++-- common/gradle.properties | 2 +- .../compat/skinshuffle/SkinShuffleCompatibility.java | 6 +++++- .../skinshuffle/SkinShuffleSkinRefreshV1Payload.java | 3 ++- .../skinshuffle/SkinShuffleSkinRefreshV2Payload.java | 3 ++- common/src/main/resources/skinrestorer.mixins.json | 2 +- fabric/build.gradle | 8 ++++---- forge/build.gradle | 2 +- .../compat/skinshuffle/SkinShufflePacketHandler.java | 2 +- 10 files changed, 21 insertions(+), 15 deletions(-) diff --git a/buildSrc/src/main/groovy/multiloader-loader.gradle b/buildSrc/src/main/groovy/multiloader-loader.gradle index ca19b7f..b9dfd60 100644 --- a/buildSrc/src/main/groovy/multiloader-loader.gradle +++ b/buildSrc/src/main/groovy/multiloader-loader.gradle @@ -3,10 +3,10 @@ plugins { } configurations { - commonJava{ + commonJava { canBeResolved = true } - commonResources{ + commonResources { canBeResolved = true } } diff --git a/common/build.gradle b/common/build.gradle index 63e1da1..0a4bef1 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,6 +1,6 @@ plugins { id 'multiloader-common' - + id 'fabric-loom' } @@ -18,7 +18,7 @@ loom { if (aw.exists()) { accessWidenerPath.set(aw) } - + mixin { useLegacyMixinAp = false } diff --git a/common/gradle.properties b/common/gradle.properties index 76b0f70..95dca56 100644 --- a/common/gradle.properties +++ b/common/gradle.properties @@ -1 +1 @@ -fabric.loom.dontRemap = true +fabric.loom.dontRemap=true 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 488e3b5..97d19d7 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 @@ -36,6 +36,10 @@ public class SkinShuffleCompatibility { if (!property.hasSignature()) return; - server.execute(() -> SkinRestorer.applySkin(server, Collections.singleton(player.getGameProfile()), new SkinValue(SkinShuffleSkinProvider.PROVIDER_NAME, null, null, property))); + server.execute(() -> SkinRestorer.applySkin( + server, + Collections.singleton(player.getGameProfile()), + new SkinValue(SkinShuffleSkinProvider.PROVIDER_NAME, null, null, property) + )); } } diff --git a/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV1Payload.java b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV1Payload.java index d879bfc..900439d 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV1Payload.java +++ b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV1Payload.java @@ -6,7 +6,8 @@ import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import org.jetbrains.annotations.NotNull; -public record SkinShuffleSkinRefreshV1Payload(Property textureProperty) implements CustomPacketPayload, SkinShuffleSkinRefreshPayload { +public record SkinShuffleSkinRefreshV1Payload( + Property textureProperty) implements CustomPacketPayload, SkinShuffleSkinRefreshPayload { public static final CustomPacketPayload.Type PACKET_ID = new CustomPacketPayload.Type<>(SkinShuffleCompatibility.resourceLocation("refresh")); public static final StreamCodec PACKET_CODEC = StreamCodec.of( diff --git a/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV2Payload.java b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV2Payload.java index aabcbdb..0c283a3 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV2Payload.java +++ b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV2Payload.java @@ -6,7 +6,8 @@ import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import org.jetbrains.annotations.NotNull; -public record SkinShuffleSkinRefreshV2Payload(Property textureProperty) implements CustomPacketPayload, SkinShuffleSkinRefreshPayload { +public record SkinShuffleSkinRefreshV2Payload( + Property textureProperty) implements CustomPacketPayload, SkinShuffleSkinRefreshPayload { public static final CustomPacketPayload.Type PACKET_ID = new CustomPacketPayload.Type<>(SkinShuffleCompatibility.resourceLocation("skin_refresh")); public static final StreamCodec PACKET_CODEC = StreamCodec.of( diff --git a/common/src/main/resources/skinrestorer.mixins.json b/common/src/main/resources/skinrestorer.mixins.json index a452f3b..084b56c 100644 --- a/common/src/main/resources/skinrestorer.mixins.json +++ b/common/src/main/resources/skinrestorer.mixins.json @@ -5,9 +5,9 @@ "compatibilityLevel": "JAVA_8", "refmap": "${mod_id}.refmap.json", "mixins": [ + "ChunkMapAccessor", "PlayerListMixin", "ServerLoginPacketListenerImplMixin", - "ChunkMapAccessor", "TrackedEntityAccessorInvoker" ], "injectors": { diff --git a/fabric/build.gradle b/fabric/build.gradle index 21414f2..2136a8d 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -1,6 +1,6 @@ plugins { id 'multiloader-loader' - + id 'fabric-loom' id 'multiloader-publish' @@ -12,7 +12,7 @@ dependencies { parchment("org.parchmentmc.data:parchment-${parchment_minecraft}:${parchment_version}@zip") } modImplementation "net.fabricmc:fabric-loader:${fabric_loader_version}" - + modCompileOnly "net.fabricmc.fabric-api:fabric-api:${fabric_api_version}" } @@ -21,11 +21,11 @@ loom { if (aw.exists()) { accessWidenerPath.set(aw) } - + mixin { defaultRefmapName.set("${mod_id}.refmap.json") } - + runs { client { client() diff --git a/forge/build.gradle b/forge/build.gradle index 7fb5ceb..1624867 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -2,7 +2,7 @@ plugins { id 'multiloader-loader' id 'idea' id 'eclipse' - + id 'net.minecraftforge.gradle' id 'org.parchmentmc.librarian.forgegradle' id 'org.spongepowered.mixin' 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 538ddd4..16084a7 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 @@ -1,8 +1,8 @@ package net.lionarius.skinrestorer.forge.compat.skinshuffle; import net.lionarius.skinrestorer.SkinRestorer; -import net.lionarius.skinrestorer.compat.skinshuffle.*; import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility; +import net.lionarius.skinrestorer.compat.skinshuffle.*; import net.minecraft.network.Connection; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraftforge.event.network.CustomPayloadEvent; From 60c890d2b0962318fdc2292ce55ca8d07e07408b Mon Sep 17 00:00:00 2001 From: lionarius Date: Wed, 27 Nov 2024 13:55:14 +0300 Subject: [PATCH 11/29] treat skinshuffle skins as official mojang skins if using online mode --- .../skinshuffle/SkinShuffleCompatibility.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) 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 97d19d7..a60b125 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 @@ -4,6 +4,7 @@ import net.lionarius.skinrestorer.SkinRestorer; import net.lionarius.skinrestorer.platform.Services; import net.lionarius.skinrestorer.skin.SkinValue; import net.lionarius.skinrestorer.skin.provider.SkinShuffleSkinProvider; +import net.lionarius.skinrestorer.util.PlayerUtils; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; @@ -36,10 +37,16 @@ public class SkinShuffleCompatibility { if (!property.hasSignature()) return; - server.execute(() -> SkinRestorer.applySkin( - server, - Collections.singleton(player.getGameProfile()), - new SkinValue(SkinShuffleSkinProvider.PROVIDER_NAME, null, null, property) - )); + server.execute(() -> { + SkinRestorer.applySkin( + server, + Collections.singleton(player.getGameProfile()), + new SkinValue(SkinShuffleSkinProvider.PROVIDER_NAME, null, null, property), + !server.usesAuthentication() + ); + + if (server.usesAuthentication() && SkinRestorer.getSkinStorage().hasSavedSkin(player.getUUID())) + SkinRestorer.getSkinStorage().deleteSkin(player.getUUID()); + }); } } From 188425605180ee4c056d8d09004dda77a85b6cb2 Mon Sep 17 00:00:00 2001 From: lionarius Date: Wed, 27 Nov 2024 13:56:15 +0300 Subject: [PATCH 12/29] verify property name for skinshuffle --- .../compat/skinshuffle/SkinShuffleCompatibility.java | 3 +++ 1 file changed, 3 insertions(+) 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 a60b125..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 @@ -34,6 +34,9 @@ public class SkinShuffleCompatibility { public static void handleSkinRefresh(MinecraftServer server, ServerPlayer player, SkinShuffleSkinRefreshPayload payload) { var property = payload.textureProperty(); + if (!property.name().equals(PlayerUtils.TEXTURES_KEY)) + return; + if (!property.hasSignature()) return; From 43df28381ddebc1d62da94275227e42db34c3332 Mon Sep 17 00:00:00 2001 From: lionarius Date: Wed, 27 Nov 2024 19:08:55 +0300 Subject: [PATCH 13/29] replace createCache with reload --- .../java/net/lionarius/skinrestorer/SkinRestorer.java | 6 +++--- .../skinrestorer/skin/provider/ElyBySkinProvider.java | 6 +++++- .../skinrestorer/skin/provider/MineskinSkinProvider.java | 6 +++++- .../skinrestorer/skin/provider/MojangSkinProvider.java | 8 +++++--- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java b/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java index e9fee55..9bb53a8 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java +++ b/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java @@ -93,9 +93,9 @@ public final class SkinRestorer { Translation.reloadTranslations(); WebUtils.recreateHttpClient(); - MojangSkinProvider.createCache(); - ElyBySkinProvider.createCache(); - MineskinSkinProvider.createCache(); + MojangSkinProvider.reload(); + ElyBySkinProvider.reload(); + MineskinSkinProvider.reload(); } public static String assetPath(String name) { 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 b10e2f9..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 @@ -40,7 +40,11 @@ public final class ElyBySkinProvider implements SkinProvider { } } - public static void createCache() { + public static void reload() { + createCache(); + } + + private static void createCache() { var config = SkinRestorer.getConfig().providersConfig().ely_by(); var time = config.cache().enabled() ? config.cache().duration() : 0; 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 6fd0e91..f869678 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 @@ -38,7 +38,11 @@ public final class MineskinSkinProvider implements SkinProvider { } } - public static void createCache() { + public static void reload() { + createCache(); + } + + private static void createCache() { var config = SkinRestorer.getConfig().providersConfig().mineskin(); var time = config.cache().enabled() ? config.cache().duration() : 0; 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 200420b..5d902a9 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 @@ -56,11 +56,13 @@ public final class MojangSkinProvider implements SkinProvider { } } }, SkinRestorer.getConfigDir().resolve(PROFILE_CACHE_FILENAME).toFile()); - - } - public static void createCache() { + public static void reload() { + createCache(); + } + + private static void createCache() { var config = SkinRestorer.getConfig().providersConfig().mojang(); var time = config.cache().enabled() ? config.cache().duration() : 0; From da9afc4befeda881bda08508593a0437f63eed91 Mon Sep 17 00:00:00 2001 From: lionarius Date: Wed, 27 Nov 2024 20:28:53 +0300 Subject: [PATCH 14/29] update gradle --- gradle/wrapper/gradle-wrapper.jar | Bin 43453 -> 43583 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 5 ++++- gradlew.bat | 2 ++ 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136f3d4ba8a0da8d277868979cfbc8ad796..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch delta 12612 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 HJ4oML2Lo<@i8BwbL^1~GkG`E7C$SEa_ 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a441313..9355b41 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index b740cf1..f5feea6 100644 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 25da30d..9d21a21 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## From fb7020354acdfc28b432d91103f77fa31e27d22b Mon Sep 17 00:00:00 2001 From: lionarius Date: Wed, 27 Nov 2024 20:29:29 +0300 Subject: [PATCH 15/29] update fabric-loom and net.minecraftforge.gradle plugins --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index e040975..8e1540b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,10 +1,10 @@ plugins { // see https://fabricmc.net/develop/ for new versions - id 'fabric-loom' version '1.7-SNAPSHOT' apply false + id 'fabric-loom' version '1.8-SNAPSHOT' apply false // see https://projects.neoforged.net/neoforged/neogradle for new versions id 'net.neoforged.gradle.userdev' version '7.0.153' apply false // see https://files.minecraftforge.net/net/minecraftforge/gradle/ForgeGradle/ for new versions - id 'net.minecraftforge.gradle' version '6.0.26' apply false + id 'net.minecraftforge.gradle' version '6.0.29' apply false id 'org.parchmentmc.librarian.forgegradle' version '1.+' apply false id 'org.spongepowered.mixin' version '0.7-SNAPSHOT' apply false From 0d56c339d1f7631509d8d681c89813f6592154e9 Mon Sep 17 00:00:00 2001 From: lionarius Date: Wed, 27 Nov 2024 21:37:21 +0300 Subject: [PATCH 16/29] use mineskin client to support mineskin api v2 --- build.gradle | 18 +- .../main/groovy/multiloader-publish.gradle | 2 +- common/build.gradle | 2 + .../mineskin/Java11RequestHandler.java | 187 ++++++++++++++++++ .../skin/provider/MineskinSkinProvider.java | 65 +++--- .../skinrestorer/util/JsonUtils.java | 2 +- fabric/build.gradle | 3 + forge/build.gradle | 13 ++ gradle.properties | 2 + neoforge/build.gradle | 24 ++- 10 files changed, 287 insertions(+), 31 deletions(-) create mode 100644 common/src/main/java/net/lionarius/skinrestorer/mineskin/Java11RequestHandler.java diff --git a/build.gradle b/build.gradle index 8e1540b..d986858 100644 --- a/build.gradle +++ b/build.gradle @@ -9,5 +9,21 @@ plugins { id 'org.spongepowered.mixin' version '0.7-SNAPSHOT' apply false - id 'me.modmuss50.mod-publish-plugin' version '0.6.3' apply false + id 'me.modmuss50.mod-publish-plugin' version '0.8.1' apply false +} + +allprojects { + repositories { + exclusiveContent { + forRepository { + maven { + name = 'MineSkin' + url = 'https://repo.inventivetalent.org/repository/public' + } + } + filter { + includeGroupAndSubgroups('org.mineskin') + } + } + } } diff --git a/buildSrc/src/main/groovy/multiloader-publish.gradle b/buildSrc/src/main/groovy/multiloader-publish.gradle index 8648805..f759713 100644 --- a/buildSrc/src/main/groovy/multiloader-publish.gradle +++ b/buildSrc/src/main/groovy/multiloader-publish.gradle @@ -6,7 +6,7 @@ publishMods { if (project.name == 'fabric') file = remapJar.archiveFile else - file = jar.archiveFile + file = tasks.named('jarJar').get().archiveFile modLoaders.add(project.name) type = STABLE diff --git a/common/build.gradle b/common/build.gradle index 0a4bef1..c168537 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -11,6 +11,8 @@ dependencies { parchment("org.parchmentmc.data:parchment-${parchment_minecraft}:${parchment_version}@zip") } compileOnly group: 'org.spongepowered', name: 'mixin', version: '0.8.5' + + implementation("org.mineskin:java-client:${mineskin_client_version}") } loom { diff --git a/common/src/main/java/net/lionarius/skinrestorer/mineskin/Java11RequestHandler.java b/common/src/main/java/net/lionarius/skinrestorer/mineskin/Java11RequestHandler.java new file mode 100644 index 0000000..b69832a --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/mineskin/Java11RequestHandler.java @@ -0,0 +1,187 @@ +package net.lionarius.skinrestorer.mineskin; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import org.mineskin.MineSkinClientImpl; +import org.mineskin.data.CodeAndMessage; +import org.mineskin.exception.MineSkinRequestException; +import org.mineskin.exception.MineskinException; +import org.mineskin.request.RequestHandler; +import org.mineskin.response.MineSkinResponse; +import org.mineskin.response.ResponseConstructor; + +import java.io.IOException; +import java.io.InputStream; +import java.net.InetSocketAddress; +import java.net.ProxySelector; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpRequest.BodyPublishers; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandlers; +import java.util.Map; +import java.util.logging.Level; +import java.util.stream.Collectors; + +// copy-pasted from https://github.com/InventivetalentDev/MineskinClient/blob/master/java11/src/main/java/org/mineskin/Java11RequestHandler.java +// with some modifications to support proxy +public class Java11RequestHandler extends RequestHandler { + + private final Gson gson; + private final HttpClient httpClient; + + public Java11RequestHandler(String userAgent, String apiKey, int timeout, Gson gson, InetSocketAddress proxy) { + super(userAgent, apiKey, timeout, gson); + this.gson = gson; + + HttpClient.Builder clientBuilder = HttpClient.newBuilder() + .connectTimeout(java.time.Duration.ofMillis(timeout)); + + if (userAgent != null) { + clientBuilder.followRedirects(HttpClient.Redirect.NORMAL); + } + + if (proxy != null) { + clientBuilder.proxy(ProxySelector.of(proxy)); + } + + this.httpClient = clientBuilder.build(); + } + + private > R wrapResponse(HttpResponse response, Class clazz, ResponseConstructor constructor) + throws IOException { + String rawBody = response.body(); + try { + JsonObject jsonBody = gson.fromJson(rawBody, JsonObject.class); + R wrapped = constructor.construct( + response.statusCode(), + lowercaseHeaders(response.headers().map()), + jsonBody, + gson, clazz + ); + if (!wrapped.isSuccess()) { + throw new MineSkinRequestException( + wrapped.getFirstError().map(CodeAndMessage::code).orElse("request_failed"), + wrapped.getFirstError().map(CodeAndMessage::message).orElse("Request Failed"), + wrapped + ); + } + return wrapped; + } catch (JsonParseException e) { + MineSkinClientImpl.LOGGER.log(Level.WARNING, "Failed to parse response body: " + rawBody, e); + throw new MineskinException("Failed to parse response", e); + } + } + + private Map lowercaseHeaders(Map> headers) { + return headers.entrySet().stream() + .collect(Collectors.toMap( + entry -> entry.getKey().toLowerCase(), + entry -> String.join(", ", entry.getValue()) + )); + } + + public > R getJson(String url, Class clazz, ResponseConstructor constructor) + throws IOException { + MineSkinClientImpl.LOGGER.fine("GET " + url); + + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder() + .uri(URI.create(url)) + .GET() + .header("User-Agent", this.userAgent); + HttpRequest request; + if (apiKey != null) { + request = requestBuilder + .header("Authorization", "Bearer " + apiKey) + .header("Accept", "application/json").build(); + } else { + request = requestBuilder.build(); + } + HttpResponse response; + try { + response = this.httpClient.send(request, BodyHandlers.ofString()); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return wrapResponse(response, clazz, constructor); + } + + public > R postJson(String url, JsonObject data, Class clazz, ResponseConstructor constructor) + throws IOException { + MineSkinClientImpl.LOGGER.fine("POST " + url); + + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder() + .uri(URI.create(url)) + .POST(BodyPublishers.ofString(gson.toJson(data))) + .header("Content-Type", "application/json") + .header("User-Agent", this.userAgent); + HttpRequest request; + if (apiKey != null) { + request = requestBuilder + .header("Authorization", "Bearer " + apiKey) + .header("Accept", "application/json").build(); + } else { + request = requestBuilder.build(); + } + + HttpResponse response; + try { + response = this.httpClient.send(request, BodyHandlers.ofString()); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return wrapResponse(response, clazz, constructor); + } + + public > R postFormDataFile(String url, String key, String filename, InputStream in, Map data, Class clazz, ResponseConstructor constructor) + throws IOException { + MineSkinClientImpl.LOGGER.fine("POST " + url); + + String boundary = "mineskin-" + System.currentTimeMillis(); + StringBuilder bodyBuilder = new StringBuilder(); + + // add form fields + for (Map.Entry entry : data.entrySet()) { + bodyBuilder.append("--").append(boundary).append("\r\n") + .append("Content-Disposition: form-data; name=\"").append(entry.getKey()).append("\"\r\n\r\n") + .append(entry.getValue()).append("\r\n"); + } + + // add file + byte[] fileContent = in.readAllBytes(); + bodyBuilder.append("--").append(boundary).append("\r\n") + .append("Content-Disposition: form-data; name=\"").append(key) + .append("\"; filename=\"").append(filename).append("\"\r\n") + .append("Content-Type: image/png\r\n\r\n"); + byte[] bodyStart = bodyBuilder.toString().getBytes(); + byte[] boundaryEnd = ("\r\n--" + boundary + "--\r\n").getBytes(); + byte[] bodyString = new byte[bodyStart.length + fileContent.length + boundaryEnd.length]; + System.arraycopy(bodyStart, 0, bodyString, 0, bodyStart.length); + System.arraycopy(fileContent, 0, bodyString, bodyStart.length, fileContent.length); + System.arraycopy(boundaryEnd, 0, bodyString, bodyStart.length + fileContent.length, boundaryEnd.length); + + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder() + .uri(URI.create(url)) + .POST(HttpRequest.BodyPublishers.ofByteArray(bodyString)) + .header("Content-Type", "multipart/form-data; boundary=" + boundary) + .header("User-Agent", this.userAgent); + HttpRequest request; + if (apiKey != null) { + request = requestBuilder + .header("Authorization", "Bearer " + apiKey) + .header("Accept", "application/json").build(); + } else { + request = requestBuilder.build(); + } + + HttpResponse response; + try { + response = this.httpClient.send(request, BodyHandlers.ofString()); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return wrapResponse(response, clazz, constructor); + } +} 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 f869678..bdb53d0 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 @@ -4,21 +4,26 @@ 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.google.gson.JsonObject; import com.mojang.authlib.properties.Property; import it.unimi.dsi.fastutil.Pair; import net.lionarius.skinrestorer.SkinRestorer; +import net.lionarius.skinrestorer.mineskin.Java11RequestHandler; import net.lionarius.skinrestorer.skin.SkinVariant; 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 org.jetbrains.annotations.NotNull; +import org.mineskin.MineSkinClient; +import org.mineskin.data.Variant; +import org.mineskin.data.Visibility; +import org.mineskin.request.GenerateRequest; +import org.mineskin.response.QueueResponse; -import java.io.IOException; +import java.net.InetSocketAddress; import java.net.URI; import java.net.URISyntaxException; -import java.net.http.HttpRequest; +import java.time.Duration; import java.util.Optional; import java.util.concurrent.TimeUnit; @@ -27,6 +32,7 @@ public final class MineskinSkinProvider implements SkinProvider { public static final String PROVIDER_NAME = "web"; private static final URI API_URI; + private static MineSkinClient MINESKIN_CLIENT; private static LoadingCache, Optional> SKIN_CACHE; @@ -39,6 +45,20 @@ public final class MineskinSkinProvider implements SkinProvider { } public static void reload() { + MINESKIN_CLIENT = MineSkinClient + .builder() + .userAgent(WebUtils.USER_AGENT) + .gson(JsonUtils.GSON) + .timeout((int) Duration.ofSeconds(SkinRestorer.getConfig().requestTimeout()).toMillis()) + .requestHandler((userAgent, apiKey, timeout, gson) -> new Java11RequestHandler( + userAgent, + apiKey, + timeout, + gson, + SkinRestorer.getConfig().proxy().map(proxy -> new InetSocketAddress(proxy.host(), proxy.port())).orElse(null) + )) + .build(); + createCache(); } @@ -80,29 +100,26 @@ public final class MineskinSkinProvider implements SkinProvider { } private static Optional loadSkin(URI uri, SkinVariant variant) throws Exception { - var result = MineskinSkinProvider.uploadToMineskin(uri, variant); - var texture = result.getAsJsonObject("data").getAsJsonObject("texture"); - var textures = new Property(PlayerUtils.TEXTURES_KEY, texture.get("value").getAsString(), texture.get("signature").getAsString()); + var mineskinVariant = switch (variant) { + case CLASSIC -> Variant.CLASSIC; + case SLIM -> Variant.SLIM; + }; - return Optional.of(textures); - } - - private static JsonObject uploadToMineskin(URI url, SkinVariant variant) throws IOException { - var body = ("{\"variant\":\"%s\",\"name\":\"%s\",\"visibility\":%d,\"url\":\"%s\"}") - .formatted(variant.toString(), "none", 0, url); + var request = GenerateRequest.url(uri) + .variant(mineskinVariant) + .name("skinrestorer-skin") + .visibility(Visibility.UNLISTED); - var request = HttpRequest.newBuilder() - .uri(MineskinSkinProvider.API_URI.resolve("/generate/url")) - .POST(HttpRequest.BodyPublishers.ofString(body)) - .header("Content-Type", "application/json") - .build(); + var skin = MINESKIN_CLIENT.queue().submit(request) + .thenApply(QueueResponse::getJob) + .thenCompose(jobInfo -> jobInfo.waitForCompletion(MINESKIN_CLIENT)) + .thenCompose(jobReference -> jobReference.getOrLoadSkin(MINESKIN_CLIENT)) + .join(); - var response = WebUtils.executeRequest(request); - WebUtils.throwOnClientErrors(response); - - if (response.statusCode() != 200) - throw new IllegalArgumentException("could not get mineskin skin"); - - return JsonUtils.parseJson(response.body()); + return Optional.of(new Property( + PlayerUtils.TEXTURES_KEY, + skin.texture().data().value(), + skin.texture().data().signature() + )); } } 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 d648601..14aec21 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/util/JsonUtils.java +++ b/common/src/main/java/net/lionarius/skinrestorer/util/JsonUtils.java @@ -17,7 +17,7 @@ import java.util.UUID; public final class JsonUtils { - private static final Gson GSON = new GsonBuilder() + public static final Gson GSON = new GsonBuilder() .registerTypeAdapter(UUID.class, new UUIDTypeAdapter()) .registerTypeAdapter(PropertyMap.class, new PropertyMap.Serializer()) .registerTypeAdapter(GameProfile.class, new GameProfile.Serializer()) diff --git a/fabric/build.gradle b/fabric/build.gradle index 2136a8d..62adc91 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -5,6 +5,7 @@ plugins { id 'multiloader-publish' } + dependencies { minecraft "com.mojang:minecraft:${minecraft_version}" mappings loom.layered { @@ -14,6 +15,8 @@ dependencies { modImplementation "net.fabricmc:fabric-loader:${fabric_loader_version}" modCompileOnly "net.fabricmc.fabric-api:fabric-api:${fabric_api_version}" + + include implementation("org.mineskin:java-client:${mineskin_client_version}") } loom { diff --git a/forge/build.gradle b/forge/build.gradle index 1624867..9211492 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -15,6 +15,14 @@ mixin { config "${mod_id}.mixins.json" } +jarJar.enable() + +tasks.named('jarJar') { + archiveClassifier = '' +} + +jar.finalizedBy('jarJar') + minecraft { mappings channel: 'parchment', version: "${parchment_version}-${parchment_minecraft}" @@ -60,6 +68,11 @@ dependencies { annotationProcessor('org.spongepowered:mixin:0.8.5-SNAPSHOT:processor') implementation('net.sf.jopt-simple:jopt-simple:5.0.4') { version { strictly '5.0.4' } } + + // TODO: somehow fix forge gradle including dependencies of java-client + minecraftLibrary(jarJar(group: 'org.mineskin', name: 'java-client', version: mineskin_client_version)) { + jarJar.ranged(it, "[${mineskin_client_version},)") + } } // for some reason mixin plugin does not add 'MixinConfigs' to MANIFEST.MF so we do it manually diff --git a/gradle.properties b/gradle.properties index 2eb6290..44eec92 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,6 +17,8 @@ license=MIT credits= description=A server-side mod for managing skins. +mineskin_client_version=3.0.1-SNAPSHOT + # ParchmentMC mappings, see https://parchmentmc.org/docs/getting-started#choose-a-version for new versions parchment_minecraft=1.21 parchment_version=2024.11.10 diff --git a/neoforge/build.gradle b/neoforge/build.gradle index 7082cf5..872c927 100644 --- a/neoforge/build.gradle +++ b/neoforge/build.gradle @@ -14,6 +14,26 @@ if (at.exists()) { minecraft.accessTransformers.file(at) } +jarJar.enable() + +tasks.named('jar') { + archiveClassifier = 'thin' +} + +tasks.named('jarJar') { + archiveClassifier = '' +} + +jar.finalizedBy('jarJar') + +dependencies { + implementation "net.neoforged:neoforge:${neoforge_version}" + + implementation(jarJar(group: 'org.mineskin', name: 'java-client', version: mineskin_client_version)) { + jarJar.ranged(it, "[${mineskin_client_version},)") + } +} + subsystems { parchment { minecraftVersion = parchment_minecraft @@ -36,7 +56,3 @@ runs { workingDirectory = file('../run/server') } } - -dependencies { - implementation "net.neoforged:neoforge:${neoforge_version}" -} From 7e063977c5cfdbb80a7ad0fe3ecaf33251d17b3d Mon Sep 17 00:00:00 2001 From: lionarius Date: Thu, 28 Nov 2024 07:11:50 +0300 Subject: [PATCH 17/29] refactor common events --- .../lionarius/skinrestorer/SkinRestorer.java | 37 +++++++++++++------ .../skinrestorer/mixin/PlayerListMixin.java | 6 +-- .../fabric/mixin/CommandsMixin.java | 4 +- .../fabric/mixin/MinecraftServerMixin.java | 2 +- .../skinrestorer/forge/SkinRestorerForge.java | 5 +-- .../neoforge/SkinRestorerNeoForge.java | 5 +-- 6 files changed, 36 insertions(+), 23 deletions(-) diff --git a/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java b/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java index 9bb53a8..11f45d8 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java +++ b/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java @@ -1,6 +1,8 @@ package net.lionarius.skinrestorer; import com.mojang.authlib.GameProfile; +import com.mojang.brigadier.CommandDispatcher; +import net.lionarius.skinrestorer.command.SkinCommand; import net.lionarius.skinrestorer.config.BuiltInProviderConfig; import net.lionarius.skinrestorer.config.Config; import net.lionarius.skinrestorer.platform.Services; @@ -13,6 +15,7 @@ import net.lionarius.skinrestorer.util.FileUtils; import net.lionarius.skinrestorer.util.PlayerUtils; import net.lionarius.skinrestorer.util.Result; import net.lionarius.skinrestorer.util.WebUtils; +import net.minecraft.commands.CommandSourceStack; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; @@ -61,6 +64,10 @@ public final class SkinRestorer { return ResourceLocation.fromNamespaceAndPath(SkinRestorer.MOD_ID, name); } + public static String assetPath(String name) { + return String.format("/assets/%s/%s", SkinRestorer.MOD_ID, name); + } + public static void onInitialize() { SkinRestorer.configDir = Services.PLATFORM.getConfigDirectory().resolve(SkinRestorer.MOD_ID); SkinRestorer.reloadConfig(); @@ -81,13 +88,6 @@ public final class SkinRestorer { SkinRestorer.providersRegistry.register(config.name(), provider, config.enabled()); } - public static void onServerStarted(MinecraftServer server) { - Path worldSkinDirectory = server.getWorldPath(LevelResource.ROOT).resolve(SkinRestorer.MOD_ID); - FileUtils.tryMigrateOldSkinDirectory(SkinRestorer.getConfigDir(), worldSkinDirectory); - - SkinRestorer.skinStorage = new SkinStorage(new SkinIO(worldSkinDirectory)); - } - public static void reloadConfig() { SkinRestorer.config = Config.load(SkinRestorer.getConfigDir()); Translation.reloadTranslations(); @@ -98,10 +98,6 @@ public final class SkinRestorer { MineskinSkinProvider.reload(); } - public static String assetPath(String name) { - return String.format("/assets/%s/%s", SkinRestorer.MOD_ID, name); - } - public static Collection applySkin(MinecraftServer server, Iterable targets, SkinValue value, boolean save) { var acceptedPlayers = new HashSet(); @@ -160,4 +156,23 @@ public final class SkinRestorer { return Result.error(e.getMessage()); }); } + + public static class Events { + private Events() {} + + public static void onServerStarted(MinecraftServer server) { + Path worldSkinDirectory = server.getWorldPath(LevelResource.ROOT).resolve(SkinRestorer.MOD_ID); + FileUtils.tryMigrateOldSkinDirectory(SkinRestorer.getConfigDir(), worldSkinDirectory); + + SkinRestorer.skinStorage = new SkinStorage(new SkinIO(worldSkinDirectory)); + } + + public static void onCommandRegister(CommandDispatcher dispatcher) { + SkinCommand.register(dispatcher); + } + + public static void onPlayerDisconnect(ServerPlayer player) { + SkinRestorer.getSkinStorage().removeSkin(player.getUUID()); + } + } } 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 b73691c..ec1f02e 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/mixin/PlayerListMixin.java +++ b/common/src/main/java/net/lionarius/skinrestorer/mixin/PlayerListMixin.java @@ -27,13 +27,13 @@ public abstract class PlayerListMixin { @Inject(method = "remove", at = @At("TAIL")) private void remove(ServerPlayer player, CallbackInfo ci) { - SkinRestorer.getSkinStorage().removeSkin(player.getUUID()); + SkinRestorer.Events.onPlayerDisconnect(player); } @Inject(method = "removeAll", at = @At("HEAD")) private void removeAll(CallbackInfo ci) { - for (ServerPlayer player : getPlayers()) { - SkinRestorer.getSkinStorage().removeSkin(player.getUUID()); + for (var player : getPlayers()) { + SkinRestorer.Events.onPlayerDisconnect(player); } } diff --git a/fabric/src/main/java/net/lionarius/skinrestorer/fabric/mixin/CommandsMixin.java b/fabric/src/main/java/net/lionarius/skinrestorer/fabric/mixin/CommandsMixin.java index b071501..cd10fcd 100644 --- a/fabric/src/main/java/net/lionarius/skinrestorer/fabric/mixin/CommandsMixin.java +++ b/fabric/src/main/java/net/lionarius/skinrestorer/fabric/mixin/CommandsMixin.java @@ -1,7 +1,7 @@ package net.lionarius.skinrestorer.fabric.mixin; import com.mojang.brigadier.CommandDispatcher; -import net.lionarius.skinrestorer.command.SkinCommand; +import net.lionarius.skinrestorer.SkinRestorer; import net.minecraft.commands.CommandBuildContext; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; @@ -21,6 +21,6 @@ public abstract class CommandsMixin { @Inject(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/commands/AdvancementCommands;register(Lcom/mojang/brigadier/CommandDispatcher;)V")) private void init(Commands.CommandSelection environment, CommandBuildContext commandRegistryAccess, CallbackInfo ci) { - SkinCommand.register(dispatcher); + SkinRestorer.Events.onCommandRegister(dispatcher); } } diff --git a/fabric/src/main/java/net/lionarius/skinrestorer/fabric/mixin/MinecraftServerMixin.java b/fabric/src/main/java/net/lionarius/skinrestorer/fabric/mixin/MinecraftServerMixin.java index ac6cdc2..f14d1ce 100644 --- a/fabric/src/main/java/net/lionarius/skinrestorer/fabric/mixin/MinecraftServerMixin.java +++ b/fabric/src/main/java/net/lionarius/skinrestorer/fabric/mixin/MinecraftServerMixin.java @@ -13,6 +13,6 @@ public abstract class MinecraftServerMixin { @Inject(method = "runServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/Util;getNanos()J", ordinal = 0)) private void onServerStarted(CallbackInfo ci) { - SkinRestorer.onServerStarted((MinecraftServer) (Object) this); + SkinRestorer.Events.onServerStarted((MinecraftServer) (Object) this); } } diff --git a/forge/src/main/java/net/lionarius/skinrestorer/forge/SkinRestorerForge.java b/forge/src/main/java/net/lionarius/skinrestorer/forge/SkinRestorerForge.java index 8417a8b..ef34aa0 100644 --- a/forge/src/main/java/net/lionarius/skinrestorer/forge/SkinRestorerForge.java +++ b/forge/src/main/java/net/lionarius/skinrestorer/forge/SkinRestorerForge.java @@ -1,7 +1,6 @@ package net.lionarius.skinrestorer.forge; import net.lionarius.skinrestorer.SkinRestorer; -import net.lionarius.skinrestorer.command.SkinCommand; import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility; import net.minecraftforge.event.RegisterCommandsEvent; import net.minecraftforge.event.server.ServerStartedEvent; @@ -21,11 +20,11 @@ public final class SkinRestorerForge { @SubscribeEvent public static void onCommandRegister(RegisterCommandsEvent event) { - SkinCommand.register(event.getDispatcher()); + SkinRestorer.Events.onCommandRegister(event.getDispatcher()); } @SubscribeEvent public static void onServerStarted(ServerStartedEvent event) { - SkinRestorer.onServerStarted(event.getServer()); + SkinRestorer.Events.onServerStarted(event.getServer()); } } diff --git a/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/SkinRestorerNeoForge.java b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/SkinRestorerNeoForge.java index f1078a3..b18b23c 100644 --- a/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/SkinRestorerNeoForge.java +++ b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/SkinRestorerNeoForge.java @@ -1,7 +1,6 @@ package net.lionarius.skinrestorer.neoforge; import net.lionarius.skinrestorer.SkinRestorer; -import net.lionarius.skinrestorer.command.SkinCommand; import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; @@ -22,11 +21,11 @@ public final class SkinRestorerNeoForge { @SubscribeEvent public static void onCommandRegister(RegisterCommandsEvent event) { - SkinCommand.register(event.getDispatcher()); + SkinRestorer.Events.onCommandRegister(event.getDispatcher()); } @SubscribeEvent public static void onServerStarted(ServerStartedEvent event) { - SkinRestorer.onServerStarted(event.getServer()); + SkinRestorer.Events.onServerStarted(event.getServer()); } } From 71c826e8b70a653dc0407d8c581f0862356270b5 Mon Sep 17 00:00:00 2001 From: lionarius Date: Thu, 28 Nov 2024 07:24:56 +0300 Subject: [PATCH 18/29] fix invalid isValid logic for ProvidersConfig --- .../net/lionarius/skinrestorer/config/ProvidersConfig.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/net/lionarius/skinrestorer/config/ProvidersConfig.java b/common/src/main/java/net/lionarius/skinrestorer/config/ProvidersConfig.java index da22b99..0a8a157 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/config/ProvidersConfig.java +++ b/common/src/main/java/net/lionarius/skinrestorer/config/ProvidersConfig.java @@ -26,9 +26,9 @@ public final class ProvidersConfig { if (this == ProvidersConfig.DEFAULT) return true; - return this.mojang == null || !this.mojang.isValid() - || this.ely_by == null || !this.ely_by.isValid() - || this.mineskin == null || !this.mineskin.isValid(); + return (this.mojang != null && this.mojang.isValid()) + && (this.ely_by != null && this.ely_by.isValid()) + && (this.mineskin != null && this.mineskin.isValid()); } public void fix() { From 8329adc476f05d2e37b99447a5058127b21bedf5 Mon Sep 17 00:00:00 2001 From: lionarius Date: Thu, 28 Nov 2024 08:27:13 +0300 Subject: [PATCH 19/29] convert config to more modular system --- .../lionarius/skinrestorer/SkinRestorer.java | 2 +- .../config/BuiltInProviderConfig.java | 7 -- .../skinrestorer/config/CacheConfig.java | 7 -- .../lionarius/skinrestorer/config/Config.java | 14 ++-- .../skinrestorer/config/ProvidersConfig.java | 65 ------------------- .../provider/BuiltInProviderConfig.java | 10 +++ .../config/provider/CacheConfig.java | 28 ++++++++ .../config/provider/ElyByProviderConfig.java | 46 +++++++++++++ .../provider/MineskinProviderConfig.java | 46 +++++++++++++ .../config/provider/MojangProviderConfig.java | 46 +++++++++++++ .../config/provider/ProvidersConfig.java | 52 +++++++++++++++ .../skinrestorer/util/JsonUtils.java | 2 + .../util/gson/GsonPostProcessable.java | 5 ++ .../util/gson/PostProcessingEnabler.java | 34 ++++++++++ 14 files changed, 276 insertions(+), 88 deletions(-) delete mode 100644 common/src/main/java/net/lionarius/skinrestorer/config/BuiltInProviderConfig.java delete mode 100644 common/src/main/java/net/lionarius/skinrestorer/config/CacheConfig.java delete mode 100644 common/src/main/java/net/lionarius/skinrestorer/config/ProvidersConfig.java create mode 100644 common/src/main/java/net/lionarius/skinrestorer/config/provider/BuiltInProviderConfig.java create mode 100644 common/src/main/java/net/lionarius/skinrestorer/config/provider/CacheConfig.java create mode 100644 common/src/main/java/net/lionarius/skinrestorer/config/provider/ElyByProviderConfig.java create mode 100644 common/src/main/java/net/lionarius/skinrestorer/config/provider/MineskinProviderConfig.java create mode 100644 common/src/main/java/net/lionarius/skinrestorer/config/provider/MojangProviderConfig.java create mode 100644 common/src/main/java/net/lionarius/skinrestorer/config/provider/ProvidersConfig.java create mode 100644 common/src/main/java/net/lionarius/skinrestorer/util/gson/GsonPostProcessable.java create mode 100644 common/src/main/java/net/lionarius/skinrestorer/util/gson/PostProcessingEnabler.java diff --git a/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java b/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java index 11f45d8..46bedfc 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java +++ b/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java @@ -3,8 +3,8 @@ package net.lionarius.skinrestorer; import com.mojang.authlib.GameProfile; import com.mojang.brigadier.CommandDispatcher; import net.lionarius.skinrestorer.command.SkinCommand; -import net.lionarius.skinrestorer.config.BuiltInProviderConfig; import net.lionarius.skinrestorer.config.Config; +import net.lionarius.skinrestorer.config.provider.BuiltInProviderConfig; import net.lionarius.skinrestorer.platform.Services; import net.lionarius.skinrestorer.skin.SkinIO; import net.lionarius.skinrestorer.skin.SkinStorage; diff --git a/common/src/main/java/net/lionarius/skinrestorer/config/BuiltInProviderConfig.java b/common/src/main/java/net/lionarius/skinrestorer/config/BuiltInProviderConfig.java deleted file mode 100644 index a4d197e..0000000 --- a/common/src/main/java/net/lionarius/skinrestorer/config/BuiltInProviderConfig.java +++ /dev/null @@ -1,7 +0,0 @@ -package net.lionarius.skinrestorer.config; - -public record BuiltInProviderConfig(boolean enabled, String name, CacheConfig cache) { - public boolean isValid() { - return this.name != null && this.cache != null && !this.name.isEmpty() && this.cache.isValid(); - } -} diff --git a/common/src/main/java/net/lionarius/skinrestorer/config/CacheConfig.java b/common/src/main/java/net/lionarius/skinrestorer/config/CacheConfig.java deleted file mode 100644 index 90c0089..0000000 --- a/common/src/main/java/net/lionarius/skinrestorer/config/CacheConfig.java +++ /dev/null @@ -1,7 +0,0 @@ -package net.lionarius.skinrestorer.config; - -public record CacheConfig(boolean enabled, long duration) { - public boolean isValid() { - return this.duration > 0; - } -} 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 59e1017..c22f6bc 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/config/Config.java +++ b/common/src/main/java/net/lionarius/skinrestorer/config/Config.java @@ -1,13 +1,15 @@ package net.lionarius.skinrestorer.config; import net.lionarius.skinrestorer.SkinRestorer; +import net.lionarius.skinrestorer.config.provider.ProvidersConfig; import net.lionarius.skinrestorer.util.FileUtils; import net.lionarius.skinrestorer.util.JsonUtils; +import net.lionarius.skinrestorer.util.gson.GsonPostProcessable; import java.nio.file.Path; import java.util.Optional; -public final class Config { +public final class Config implements GsonPostProcessable { public static final String CONFIG_FILENAME = "config.json"; @@ -68,14 +70,13 @@ public final class Config { if (config == null) config = new Config(); - config.verifyAndFix(); - FileUtils.writeFile(path.resolve(Config.CONFIG_FILENAME), JsonUtils.toJson(config)); return config; } - private void verifyAndFix() { + @Override + public void gsonPostProcess() { if (this.language == null || this.language.isEmpty()) { SkinRestorer.LOGGER.warn("Language config is null or empty, defaulting to 'en_us'"); this.language = "en_us"; @@ -95,7 +96,7 @@ public final class Config { try { this.parsedProxy = Proxy.parse(this.proxy); } catch (Exception e) { - SkinRestorer.LOGGER.warn("Could not parse proxy config", e); + SkinRestorer.LOGGER.warn("Could not parse proxy config: {}", e.getMessage()); this.parsedProxy = null; } } @@ -109,8 +110,5 @@ public final class Config { SkinRestorer.LOGGER.warn("Providers config is null, using default"); this.providers = ProvidersConfig.DEFAULT; } - - if (!this.providers.isValid()) - this.providers.fix(); } } diff --git a/common/src/main/java/net/lionarius/skinrestorer/config/ProvidersConfig.java b/common/src/main/java/net/lionarius/skinrestorer/config/ProvidersConfig.java deleted file mode 100644 index 0a8a157..0000000 --- a/common/src/main/java/net/lionarius/skinrestorer/config/ProvidersConfig.java +++ /dev/null @@ -1,65 +0,0 @@ -package net.lionarius.skinrestorer.config; - -import net.lionarius.skinrestorer.SkinRestorer; -import net.lionarius.skinrestorer.skin.provider.ElyBySkinProvider; -import net.lionarius.skinrestorer.skin.provider.MineskinSkinProvider; -import net.lionarius.skinrestorer.skin.provider.MojangSkinProvider; - -public final class ProvidersConfig { - public static final ProvidersConfig DEFAULT = new ProvidersConfig( - new BuiltInProviderConfig(true, MojangSkinProvider.PROVIDER_NAME, new CacheConfig(true, 60)), - new BuiltInProviderConfig(true, ElyBySkinProvider.PROVIDER_NAME, new CacheConfig(true, 60)), - new BuiltInProviderConfig(true, MineskinSkinProvider.PROVIDER_NAME, new CacheConfig(true, 300)) - ); - - private BuiltInProviderConfig mojang; - private BuiltInProviderConfig ely_by; - private BuiltInProviderConfig mineskin; - - public ProvidersConfig(BuiltInProviderConfig mojang, BuiltInProviderConfig ely_by, BuiltInProviderConfig mineskin) { - this.mojang = mojang; - this.ely_by = ely_by; - this.mineskin = mineskin; - } - - public boolean isValid() { - if (this == ProvidersConfig.DEFAULT) - return true; - - return (this.mojang != null && this.mojang.isValid()) - && (this.ely_by != null && this.ely_by.isValid()) - && (this.mineskin != null && this.mineskin.isValid()); - } - - public void fix() { - if (this == ProvidersConfig.DEFAULT) - return; - - if (this.mojang == null || !this.mojang.isValid()) { - SkinRestorer.LOGGER.warn("Mojang provider config is invalid, using default"); - this.mojang = ProvidersConfig.DEFAULT.mojang(); - } - - if (this.ely_by == null || !this.ely_by.isValid()) { - SkinRestorer.LOGGER.warn("Ely.By provider config is invalid, using default"); - this.ely_by = ProvidersConfig.DEFAULT.ely_by(); - } - - if (this.mineskin == null || !this.mineskin.isValid()) { - SkinRestorer.LOGGER.warn("Mineskin provider config is invalid, using default"); - this.mineskin = ProvidersConfig.DEFAULT.mineskin(); - } - } - - public BuiltInProviderConfig mojang() { - return this.mojang; - } - - public BuiltInProviderConfig ely_by() { - return this.ely_by; - } - - public BuiltInProviderConfig mineskin() { - return this.mineskin; - } -} 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 new file mode 100644 index 0000000..198e9f1 --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/config/provider/BuiltInProviderConfig.java @@ -0,0 +1,10 @@ +package net.lionarius.skinrestorer.config.provider; + +public interface BuiltInProviderConfig { + + boolean enabled(); + + String name(); + + CacheConfig cache(); +} diff --git a/common/src/main/java/net/lionarius/skinrestorer/config/provider/CacheConfig.java b/common/src/main/java/net/lionarius/skinrestorer/config/provider/CacheConfig.java new file mode 100644 index 0000000..6daf190 --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/config/provider/CacheConfig.java @@ -0,0 +1,28 @@ +package net.lionarius.skinrestorer.config.provider; + +import net.lionarius.skinrestorer.SkinRestorer; + +public final class CacheConfig { + private boolean enabled; + private long duration; + + public CacheConfig(boolean enabled, long duration) { + this.enabled = enabled; + this.duration = duration; + } + + public boolean enabled() { + return enabled; + } + + public long duration() { + return duration; + } + + void validate(CacheConfig defaultValue) { + if (this.duration <= 0) { + SkinRestorer.LOGGER.warn("Cache duration is less than or equal to zero, defaulting to {}", defaultValue.duration()); + this.duration = defaultValue.duration(); + } + } +} diff --git a/common/src/main/java/net/lionarius/skinrestorer/config/provider/ElyByProviderConfig.java b/common/src/main/java/net/lionarius/skinrestorer/config/provider/ElyByProviderConfig.java new file mode 100644 index 0000000..c36caf8 --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/config/provider/ElyByProviderConfig.java @@ -0,0 +1,46 @@ +package net.lionarius.skinrestorer.config.provider; + +import net.lionarius.skinrestorer.SkinRestorer; +import net.lionarius.skinrestorer.skin.provider.ElyBySkinProvider; +import net.lionarius.skinrestorer.util.gson.GsonPostProcessable; + +public class ElyByProviderConfig implements BuiltInProviderConfig, GsonPostProcessable { + private static final CacheConfig DEFAULT_CACHE_VALUE = new CacheConfig(true, 60); + + private boolean enabled; + private String name; + private CacheConfig cache; + + public ElyByProviderConfig() { + this.enabled = true; + this.name = ElyBySkinProvider.PROVIDER_NAME; + this.cache = DEFAULT_CACHE_VALUE; + } + + public boolean enabled() { + return enabled; + } + + public String name() { + return name; + } + + public CacheConfig cache() { + return cache; + } + + @Override + public void gsonPostProcess() { + if (this.name == null || this.name.isEmpty()) { + SkinRestorer.LOGGER.warn("Ely.By provider name is null or empty, defaulting to '{}'", ElyBySkinProvider.PROVIDER_NAME); + this.name = ElyBySkinProvider.PROVIDER_NAME; + } + + if (this.cache == null) { + SkinRestorer.LOGGER.warn("Ely.By provider cache is null, using default"); + this.cache = DEFAULT_CACHE_VALUE; + } else { + this.cache.validate(DEFAULT_CACHE_VALUE); + } + } +} diff --git a/common/src/main/java/net/lionarius/skinrestorer/config/provider/MineskinProviderConfig.java b/common/src/main/java/net/lionarius/skinrestorer/config/provider/MineskinProviderConfig.java new file mode 100644 index 0000000..e3b796d --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/config/provider/MineskinProviderConfig.java @@ -0,0 +1,46 @@ +package net.lionarius.skinrestorer.config.provider; + +import net.lionarius.skinrestorer.SkinRestorer; +import net.lionarius.skinrestorer.skin.provider.MineskinSkinProvider; +import net.lionarius.skinrestorer.util.gson.GsonPostProcessable; + +public class MineskinProviderConfig implements BuiltInProviderConfig, GsonPostProcessable { + private static final CacheConfig DEFAULT_CACHE_VALUE = new CacheConfig(true, 300); + + private boolean enabled; + private String name; + private CacheConfig cache; + + public MineskinProviderConfig() { + this.enabled = true; + this.name = MineskinSkinProvider.PROVIDER_NAME; + this.cache = DEFAULT_CACHE_VALUE; + } + + public boolean enabled() { + return enabled; + } + + public String name() { + return name; + } + + public CacheConfig cache() { + return cache; + } + + @Override + public void gsonPostProcess() { + if (this.name == null || this.name.isEmpty()) { + SkinRestorer.LOGGER.warn("Mineskin provider name is null or empty, defaulting to '{}'", MineskinSkinProvider.PROVIDER_NAME); + this.name = MineskinSkinProvider.PROVIDER_NAME; + } + + if (this.cache == null) { + SkinRestorer.LOGGER.warn("Mineskin cache is null, using default"); + this.cache = DEFAULT_CACHE_VALUE; + } else { + this.cache.validate(DEFAULT_CACHE_VALUE); + } + } +} diff --git a/common/src/main/java/net/lionarius/skinrestorer/config/provider/MojangProviderConfig.java b/common/src/main/java/net/lionarius/skinrestorer/config/provider/MojangProviderConfig.java new file mode 100644 index 0000000..625a55e --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/config/provider/MojangProviderConfig.java @@ -0,0 +1,46 @@ +package net.lionarius.skinrestorer.config.provider; + +import net.lionarius.skinrestorer.SkinRestorer; +import net.lionarius.skinrestorer.skin.provider.MojangSkinProvider; +import net.lionarius.skinrestorer.util.gson.GsonPostProcessable; + +public class MojangProviderConfig implements BuiltInProviderConfig, GsonPostProcessable { + private static final CacheConfig DEFAULT_CACHE_VALUE = new CacheConfig(true, 60); + + private boolean enabled; + private String name; + private CacheConfig cache; + + public MojangProviderConfig() { + this.enabled = true; + this.name = MojangSkinProvider.PROVIDER_NAME; + this.cache = DEFAULT_CACHE_VALUE; + } + + public boolean enabled() { + return enabled; + } + + public String name() { + return name; + } + + public CacheConfig cache() { + return cache; + } + + @Override + public void gsonPostProcess() { + if (this.name == null || this.name.isEmpty()) { + SkinRestorer.LOGGER.warn("Mojang provider name is null or empty, defaulting to '{}'", MojangSkinProvider.PROVIDER_NAME); + this.name = MojangSkinProvider.PROVIDER_NAME; + } + + if (this.cache == null) { + SkinRestorer.LOGGER.warn("Mojang provider cache is null, using default"); + this.cache = DEFAULT_CACHE_VALUE; + } else { + this.cache.validate(DEFAULT_CACHE_VALUE); + } + } +} 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 new file mode 100644 index 0000000..c8a793e --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/config/provider/ProvidersConfig.java @@ -0,0 +1,52 @@ +package net.lionarius.skinrestorer.config.provider; + +import net.lionarius.skinrestorer.SkinRestorer; +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() + ); + + private MojangProviderConfig mojang; + private ElyByProviderConfig ely_by; + private MineskinProviderConfig mineskin; + + public ProvidersConfig(MojangProviderConfig mojang, ElyByProviderConfig ely_by, MineskinProviderConfig mineskin) { + this.mojang = mojang; + this.ely_by = ely_by; + this.mineskin = mineskin; + } + + public MojangProviderConfig mojang() { + return this.mojang; + } + + public ElyByProviderConfig ely_by() { + return this.ely_by; + } + + public MineskinProviderConfig mineskin() { + return this.mineskin; + } + + @Override + public void gsonPostProcess() { + if (this.mojang == null) { + SkinRestorer.LOGGER.warn("Mojang provider config is null, using default"); + this.mojang = ProvidersConfig.DEFAULT.mojang(); + } + + if (this.ely_by == null) { + SkinRestorer.LOGGER.warn("Ely.By provider config is null, using default"); + this.ely_by = ProvidersConfig.DEFAULT.ely_by(); + } + + if (this.mineskin == null) { + SkinRestorer.LOGGER.warn("Mineskin provider config is null, using default"); + this.mineskin = ProvidersConfig.DEFAULT.mineskin(); + } + } +} 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 14aec21..7eef4e1 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/util/JsonUtils.java +++ b/common/src/main/java/net/lionarius/skinrestorer/util/JsonUtils.java @@ -9,6 +9,7 @@ import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import com.mojang.util.UUIDTypeAdapter; import net.lionarius.skinrestorer.SkinRestorer; +import net.lionarius.skinrestorer.util.gson.PostProcessingEnabler; import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; @@ -18,6 +19,7 @@ import java.util.UUID; public final class JsonUtils { public static final Gson GSON = new GsonBuilder() + .registerTypeAdapterFactory(new PostProcessingEnabler()) .registerTypeAdapter(UUID.class, new UUIDTypeAdapter()) .registerTypeAdapter(PropertyMap.class, new PropertyMap.Serializer()) .registerTypeAdapter(GameProfile.class, new GameProfile.Serializer()) diff --git a/common/src/main/java/net/lionarius/skinrestorer/util/gson/GsonPostProcessable.java b/common/src/main/java/net/lionarius/skinrestorer/util/gson/GsonPostProcessable.java new file mode 100644 index 0000000..b02128a --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/util/gson/GsonPostProcessable.java @@ -0,0 +1,5 @@ +package net.lionarius.skinrestorer.util.gson; + +public interface GsonPostProcessable { + void gsonPostProcess(); +} diff --git a/common/src/main/java/net/lionarius/skinrestorer/util/gson/PostProcessingEnabler.java b/common/src/main/java/net/lionarius/skinrestorer/util/gson/PostProcessingEnabler.java new file mode 100644 index 0000000..b6a2181 --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/util/gson/PostProcessingEnabler.java @@ -0,0 +1,34 @@ +package net.lionarius.skinrestorer.util.gson; + +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; + +public class PostProcessingEnabler implements TypeAdapterFactory { + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + var adapter = gson.getDelegateAdapter(this, type); + + return new TypeAdapter<>() { + @Override + public void write(JsonWriter out, T value) throws IOException { + adapter.write(out, value); + } + + @Override + public T read(JsonReader in) throws IOException { + var value = adapter.read(in); + + if (value instanceof GsonPostProcessable postProcessable) + postProcessable.gsonPostProcess(); + + return value; + } + }; + } +} From 8820e3ba3f62ddba406500591e71875b091f5f07 Mon Sep 17 00:00:00 2001 From: lionarius Date: Thu, 28 Nov 2024 08:31:18 +0300 Subject: [PATCH 20/29] add mineskin api key to config --- .../config/provider/MineskinProviderConfig.java | 10 ++++++++++ .../skin/provider/MineskinSkinProvider.java | 6 +++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/net/lionarius/skinrestorer/config/provider/MineskinProviderConfig.java b/common/src/main/java/net/lionarius/skinrestorer/config/provider/MineskinProviderConfig.java index e3b796d..3dff272 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/config/provider/MineskinProviderConfig.java +++ b/common/src/main/java/net/lionarius/skinrestorer/config/provider/MineskinProviderConfig.java @@ -10,6 +10,7 @@ public class MineskinProviderConfig implements BuiltInProviderConfig, GsonPostPr private boolean enabled; private String name; private CacheConfig cache; + private String apiKey; public MineskinProviderConfig() { this.enabled = true; @@ -29,6 +30,10 @@ public class MineskinProviderConfig implements BuiltInProviderConfig, GsonPostPr return cache; } + public String apiKey() { + return apiKey; + } + @Override public void gsonPostProcess() { if (this.name == null || this.name.isEmpty()) { @@ -42,5 +47,10 @@ public class MineskinProviderConfig implements BuiltInProviderConfig, GsonPostPr } else { this.cache.validate(DEFAULT_CACHE_VALUE); } + + if (this.apiKey == null) { + SkinRestorer.LOGGER.warn("Mineskin API key is null, defaulting to an empty string"); + this.apiKey = ""; + } } } 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 bdb53d0..5e79fc5 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 @@ -45,11 +45,14 @@ public final class MineskinSkinProvider implements SkinProvider { } public static void reload() { + var config = SkinRestorer.getConfig(); + var configApiKey = config.providersConfig().mineskin().apiKey(); + MINESKIN_CLIENT = MineSkinClient .builder() .userAgent(WebUtils.USER_AGENT) .gson(JsonUtils.GSON) - .timeout((int) Duration.ofSeconds(SkinRestorer.getConfig().requestTimeout()).toMillis()) + .timeout((int) Duration.ofSeconds(config.requestTimeout()).toMillis()) .requestHandler((userAgent, apiKey, timeout, gson) -> new Java11RequestHandler( userAgent, apiKey, @@ -57,6 +60,7 @@ public final class MineskinSkinProvider implements SkinProvider { gson, SkinRestorer.getConfig().proxy().map(proxy -> new InetSocketAddress(proxy.host(), proxy.port())).orElse(null) )) + .apiKey(configApiKey.isEmpty() ? null : configApiKey) .build(); createCache(); From f2b53f4f3f5ddbd7b3bde5f93a186ef6904699ae Mon Sep 17 00:00:00 2001 From: lionarius Date: Thu, 28 Nov 2024 14:48:12 +0300 Subject: [PATCH 21/29] update README.md --- README.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f91f7fa..50063e2 100644 --- a/README.md +++ b/README.md @@ -9,23 +9,29 @@ A server-side mod for managing and restoring player skins. - **Set skins from Mojang Account**: Fetch and apply skins using a valid Minecraft username. - **Set skins from Ely.by**: Fetch and apply skins using a valid [Ely.by](https://ely.by/) username. -- **Set skins from URL**: Fetch and apply skins from any image URL, supporting both classic (Steve) and slim (Alex) skin models. -- **Automatic skin fetching**: Automatically fetch skin from Mojang/Ely.by when a player joins the server running in offline/insecure mode ([configurable](https://github.com/Suiranoil/SkinRestorer/wiki/Configuration)). +- **Set skins from URL**: Fetch and apply skins from any image URL, supporting both classic (Steve) and slim (Alex) skin + models. +- **Automatic skin fetching**: Automatically fetch skin from Mojang/Ely.by when a player joins the server running in + offline/insecure mode ([configurable](https://github.com/Suiranoil/SkinRestorer/wiki/Configuration)). - **Singleplayer support**: Apply skins individually for each world. - **Permissions API support** +- **SkinShuffle support**: Allow players with [SkinShuffle](https://modrinth.com/mod/skinshuffle) installed to apply skins using GUI. ## 📜 Command Usage Guide -For a detailed list of available commands and their usage, please visit the [commands wiki page](https://github.com/Suiranoil/SkinRestorer/wiki/Commands). +For a detailed list of available commands and their usage, please visit +the [commands wiki page](https://github.com/Suiranoil/SkinRestorer/wiki/Commands). ## ❌ Known Incompatibilities -- **[Arclight](https://github.com/IzzelAliz/Arclight) (<=1.20.1)**: Trials or older versions are not compatible due to mixin conflicts. +- **[Arclight](https://github.com/IzzelAliz/Arclight) (<=1.20.1)**: Trials or older versions are not compatible due to + mixin conflicts. As an alternative, consider using the [SkinsRestorer](https://www.spigotmc.org/resources/skinsrestorer.2124/) plugin. ## 🪙 Donation -If you enjoy using **SkinRestorer** and would like to support its development, you can contribute through the following platforms: +If you enjoy using **SkinRestorer** and would like to support its development, you can contribute through the following +platforms: [![Ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/lionarius) From b5ad427ff3f1b60b37504828b8e1dc05dfcdfc12 Mon Sep 17 00:00:00 2001 From: lionarius Date: Thu, 28 Nov 2024 14:55:14 +0300 Subject: [PATCH 22/29] bump version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 44eec92..be7ef45 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ minecraft_version_list=1.21,1.21.1,1.21.2,1.21.3 minecraft_version_range=[1.21, 1.22) mod_id=skinrestorer mod_name=SkinRestorer -mod_version=2.1.0 +mod_version=2.2.0 mod_author=Lionarius mod_homepage=https://modrinth.com/mod/skinrestorer mod_sources=https://github.com/Suiranoil/SkinRestorer From b475168fb16278cb14dab4037915c35993c2ee97 Mon Sep 17 00:00:00 2001 From: lionarius Date: Thu, 28 Nov 2024 14:55:39 +0300 Subject: [PATCH 23/29] update CHANGELOG.md --- CHANGELOG.md | 10 ++++++++++ CHANGELOG_LATEST.md | 13 ++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41c55ab..0ad418f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ 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.2.0] - 2024-11-28 +### Added +- Added support for [SkinShuffle](https://modrinth.com/mod/skinshuffle) clients (requires FabricAPI on Fabric) + (closes [#34](https://github.com/Suiranoil/SkinRestorer/issues/34)) +- Added `providers.mineskin.apiKey` config option (see [wiki](https://github.com/Suiranoil/SkinRestorer/wiki/Configuration#providersmineskin)) +### Changed +- Migrated to MineSkin's new API V2 +### Fixed +- Fixed `providers` config validation + ## [2.1.0] - 2024-09-26 ### Added - Added `config reload` command for dynamic configuration updates diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 9143cea..ce46783 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -1,9 +1,8 @@ ### Added -- Added `config reload` command for dynamic configuration updates -- Added `refreshSkinOnJoin` config option (see [wiki](https://github.com/Suiranoil/SkinRestorer/wiki/Configuration#refreshskinonjoin)) -- Implemented caching for skin providers -- Added provider configurations (see [wiki](https://github.com/Suiranoil/SkinRestorer/wiki/Configuration#providers)) -- Added username and url validation for requests +- Added support for [SkinShuffle](https://modrinth.com/mod/skinshuffle) clients (requires FabricAPI on Fabric) + (closes [#34](https://github.com/Suiranoil/SkinRestorer/issues/34)) +- Added `providers.mineskin.apiKey` config option (see [wiki](https://github.com/Suiranoil/SkinRestorer/wiki/Configuration##providersmineskin)) +### Changed +- Migrated to MineSkin's new API V2 ### Fixed -- Fixed old skin directory migration not working -- Prevented overwriting existing skin files during migration +- Fixed `providers` config validation From 8338f5dac99f5c19933398c720addcc5115cf82e Mon Sep 17 00:00:00 2001 From: lionarius Date: Thu, 28 Nov 2024 16:02:50 +0300 Subject: [PATCH 24/29] make decode and encode public --- .../skinshuffle/SkinShuffleSkinRefreshV1Payload.java | 6 +++--- .../skinshuffle/SkinShuffleSkinRefreshV2Payload.java | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV1Payload.java b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV1Payload.java index 900439d..8892357 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV1Payload.java +++ b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV1Payload.java @@ -15,15 +15,15 @@ public record SkinShuffleSkinRefreshV1Payload( SkinShuffleSkinRefreshV1Payload::decode ); - private static void encode(FriendlyByteBuf buf, SkinShuffleSkinRefreshV1Payload value) { + public static void encode(FriendlyByteBuf buf, SkinShuffleSkinRefreshV1Payload value) { var textureProperty = value.textureProperty(); buf.writeUtf(textureProperty.name()); buf.writeUtf(textureProperty.value()); buf.writeNullable(textureProperty.signature(), FriendlyByteBuf::writeUtf); } - - private static SkinShuffleSkinRefreshV1Payload decode(FriendlyByteBuf buf) { + + public static SkinShuffleSkinRefreshV1Payload decode(FriendlyByteBuf buf) { return new SkinShuffleSkinRefreshV1Payload(new Property(buf.readUtf(), buf.readUtf(), buf.readNullable(FriendlyByteBuf::readUtf))); } diff --git a/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV2Payload.java b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV2Payload.java index 0c283a3..177fef9 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV2Payload.java +++ b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV2Payload.java @@ -14,8 +14,8 @@ public record SkinShuffleSkinRefreshV2Payload( SkinShuffleSkinRefreshV2Payload::encode, SkinShuffleSkinRefreshV2Payload::decode ); - - private static void encode(FriendlyByteBuf buf, SkinShuffleSkinRefreshV2Payload value) { + + public static void encode(FriendlyByteBuf buf, SkinShuffleSkinRefreshV2Payload value) { var textureProperty = value.textureProperty(); buf.writeBoolean(textureProperty.hasSignature()); @@ -27,8 +27,8 @@ public record SkinShuffleSkinRefreshV2Payload( buf.writeUtf(textureProperty.signature()); } } - - private static SkinShuffleSkinRefreshV2Payload decode(FriendlyByteBuf buf) { + + public static SkinShuffleSkinRefreshV2Payload decode(FriendlyByteBuf buf) { if (buf.readBoolean()) { return new SkinShuffleSkinRefreshV2Payload(new Property(buf.readUtf(), buf.readUtf(), buf.readUtf())); } From dda9a9632a25c1ced5f7709b9060af499f1704ee Mon Sep 17 00:00:00 2001 From: lionarius Date: Fri, 29 Nov 2024 11:53:03 +0300 Subject: [PATCH 25/29] backport to 1.20.5 --- .../lionarius/skinrestorer/SkinRestorer.java | 2 +- .../skinshuffle/SkinShuffleCompatibility.java | 2 +- .../skinshuffle/SkinShufflePacketHandler.java | 50 ++++++++++++------- 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java b/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java index 46bedfc..553ee5d 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java +++ b/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java @@ -61,7 +61,7 @@ public final class SkinRestorer { } public static ResourceLocation resourceLocation(String name) { - return ResourceLocation.fromNamespaceAndPath(SkinRestorer.MOD_ID, name); + return new ResourceLocation(SkinRestorer.MOD_ID, name); } public static String assetPath(String name) { 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 3b60331..b535f0f 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 @@ -24,7 +24,7 @@ public class SkinShuffleCompatibility { } public static ResourceLocation resourceLocation(String name) { - return ResourceLocation.fromNamespaceAndPath(SkinShuffleCompatibility.MOD_ID, name); + return new ResourceLocation(SkinShuffleCompatibility.MOD_ID, name); } public static void onPlayerJoin(ServerPlayer player) { 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 16084a7..9f6ba68 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 @@ -1,39 +1,53 @@ package net.lionarius.skinrestorer.forge.compat.skinshuffle; -import net.lionarius.skinrestorer.SkinRestorer; -import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility; +import io.netty.buffer.Unpooled; import net.lionarius.skinrestorer.compat.skinshuffle.*; +import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility; import net.minecraft.network.Connection; -import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.network.FriendlyByteBuf; import net.minecraftforge.event.network.CustomPayloadEvent; -import net.minecraftforge.network.Channel; import net.minecraftforge.network.ChannelBuilder; +import net.minecraftforge.network.EventNetworkChannel; public class SkinShufflePacketHandler { private SkinShufflePacketHandler() { } - - private static final Channel INSTANCE = ChannelBuilder - .named(SkinRestorer.resourceLocation("skin_shuffle_compat")) + + private static final EventNetworkChannel HANDSHAKE_INSTANCE = ChannelBuilder + .named(SkinShuffleHandshakePayload.PACKET_ID.id()) .optional() - .payloadChannel() - .any() - .clientbound() - .add(SkinShuffleHandshakePayload.PACKET_ID, SkinShuffleHandshakePayload.PACKET_CODEC, (payload, context) -> { - }) - .serverbound() - .add(SkinShuffleSkinRefreshV1Payload.PACKET_ID, SkinShuffleSkinRefreshV1Payload.PACKET_CODEC, SkinShufflePacketHandler::handleSkinRefreshPacket) - .add(SkinShuffleSkinRefreshV2Payload.PACKET_ID, SkinShuffleSkinRefreshV2Payload.PACKET_CODEC, SkinShufflePacketHandler::handleSkinRefreshPacket) - .build(); + .eventNetworkChannel(); + private static final EventNetworkChannel SKIN_REFRESH_V1_INSTANCE = ChannelBuilder + .named(SkinShuffleSkinRefreshV1Payload.PACKET_ID.id()) + .optional() + .eventNetworkChannel() + .addListener(SkinShufflePacketHandler::skinRefreshV1Listener); + + private static final EventNetworkChannel SKIN_REFRESH_V2_INSTANCE = ChannelBuilder + .named(SkinShuffleSkinRefreshV2Payload.PACKET_ID.id()) + .optional() + .eventNetworkChannel() + .addListener(SkinShufflePacketHandler::skinRefreshV2Listener); + protected static void initialize() { // NO-OP } - + public static void sendHandshake(Connection connection) { - INSTANCE.send(SkinShuffleHandshakePayload.INSTANCE, connection); + HANDSHAKE_INSTANCE.send(new FriendlyByteBuf(Unpooled.buffer(0, 0)), connection); } + private static void skinRefreshV1Listener(CustomPayloadEvent event) { + var payload = SkinShuffleSkinRefreshV1Payload.PACKET_CODEC.decode(event.getPayload()); + handleSkinRefreshPacket(payload, event.getSource()); + } + + private static void skinRefreshV2Listener(CustomPayloadEvent event) { + var payload = SkinShuffleSkinRefreshV2Payload.PACKET_CODEC.decode(event.getPayload()); + handleSkinRefreshPacket(payload, event.getSource()); + } + private static void handleSkinRefreshPacket(SkinShuffleSkinRefreshPayload payload, CustomPayloadEvent.Context context) { var sender = context.getSender(); From 3b71911ba0bf9478b4ef43c3c5ff66d4d07784a6 Mon Sep 17 00:00:00 2001 From: lionarius Date: Sat, 30 Nov 2024 00:37:27 +0300 Subject: [PATCH 26/29] backport to 1.20.3 --- .../SkinShuffleHandshakePayload.java | 16 +++--- .../SkinShuffleSkinRefreshV1Payload.java | 17 ++++--- .../SkinShuffleSkinRefreshV2Payload.java | 15 +++--- .../skinshuffle/SkinShuffleCompatibility.java | 29 +++++++---- .../platform/FabricCompatibilityHelper.java | 4 +- forge/build.gradle | 6 ++- .../skinshuffle/SkinShufflePacketHandler.java | 10 ++-- .../skinshuffle/SkinShuffleCompatibility.java | 5 +- .../SkinShuffleModEventHandler.java | 31 ----------- .../skinshuffle/SkinShufflePacketHandler.java | 51 +++++++++++++++++++ .../platform/NeoForgeCompatibilityHelper.java | 2 +- 11 files changed, 110 insertions(+), 76 deletions(-) delete mode 100644 neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShuffleModEventHandler.java create mode 100644 neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShufflePacketHandler.java diff --git a/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleHandshakePayload.java b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleHandshakePayload.java index 798ed92..b4afa59 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleHandshakePayload.java +++ b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleHandshakePayload.java @@ -1,19 +1,23 @@ package net.lionarius.skinrestorer.compat.skinshuffle; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; public record SkinShuffleHandshakePayload() implements CustomPacketPayload { - + public static final SkinShuffleHandshakePayload INSTANCE = new SkinShuffleHandshakePayload(); - - public static final CustomPacketPayload.Type PACKET_ID = new CustomPacketPayload.Type<>(SkinShuffleCompatibility.resourceLocation("handshake")); - public static final StreamCodec PACKET_CODEC = StreamCodec.unit(INSTANCE); + + public static final ResourceLocation PACKET_ID = SkinShuffleCompatibility.resourceLocation("handshake"); + + @Override + public void write(@NotNull FriendlyByteBuf buf) { + // NO-OP + } @Override - public CustomPacketPayload.@NotNull Type type() { + public @NotNull ResourceLocation id() { return PACKET_ID; } } diff --git a/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV1Payload.java b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV1Payload.java index 8892357..6a3132b 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV1Payload.java +++ b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV1Payload.java @@ -2,18 +2,14 @@ package net.lionarius.skinrestorer.compat.skinshuffle; import com.mojang.authlib.properties.Property; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; public record SkinShuffleSkinRefreshV1Payload( Property textureProperty) implements CustomPacketPayload, SkinShuffleSkinRefreshPayload { - public static final CustomPacketPayload.Type PACKET_ID = new CustomPacketPayload.Type<>(SkinShuffleCompatibility.resourceLocation("refresh")); - public static final StreamCodec PACKET_CODEC = StreamCodec.of( - SkinShuffleSkinRefreshV1Payload::encode, - SkinShuffleSkinRefreshV1Payload::decode - ); + public static final ResourceLocation PACKET_ID = SkinShuffleCompatibility.resourceLocation("refresh"); public static void encode(FriendlyByteBuf buf, SkinShuffleSkinRefreshV1Payload value) { var textureProperty = value.textureProperty(); @@ -22,13 +18,18 @@ public record SkinShuffleSkinRefreshV1Payload( buf.writeUtf(textureProperty.value()); buf.writeNullable(textureProperty.signature(), FriendlyByteBuf::writeUtf); } - + public static SkinShuffleSkinRefreshV1Payload decode(FriendlyByteBuf buf) { return new SkinShuffleSkinRefreshV1Payload(new Property(buf.readUtf(), buf.readUtf(), buf.readNullable(FriendlyByteBuf::readUtf))); } @Override - public @NotNull CustomPacketPayload.Type type() { + public void write(@NotNull FriendlyByteBuf buf) { + encode(buf, this); + } + + @Override + public @NotNull ResourceLocation id() { return PACKET_ID; } } diff --git a/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV2Payload.java b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV2Payload.java index 177fef9..82cab98 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV2Payload.java +++ b/common/src/main/java/net/lionarius/skinrestorer/compat/skinshuffle/SkinShuffleSkinRefreshV2Payload.java @@ -2,18 +2,14 @@ package net.lionarius.skinrestorer.compat.skinshuffle; import com.mojang.authlib.properties.Property; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.NotNull; public record SkinShuffleSkinRefreshV2Payload( Property textureProperty) implements CustomPacketPayload, SkinShuffleSkinRefreshPayload { - public static final CustomPacketPayload.Type PACKET_ID = new CustomPacketPayload.Type<>(SkinShuffleCompatibility.resourceLocation("skin_refresh")); - public static final StreamCodec PACKET_CODEC = StreamCodec.of( - SkinShuffleSkinRefreshV2Payload::encode, - SkinShuffleSkinRefreshV2Payload::decode - ); + public static final ResourceLocation PACKET_ID = SkinShuffleCompatibility.resourceLocation("skin_refresh"); public static void encode(FriendlyByteBuf buf, SkinShuffleSkinRefreshV2Payload value) { var textureProperty = value.textureProperty(); @@ -36,7 +32,12 @@ public record SkinShuffleSkinRefreshV2Payload( } @Override - public @NotNull CustomPacketPayload.Type type() { + public void write(@NotNull FriendlyByteBuf buf) { + encode(buf, this); + } + + @Override + public @NotNull ResourceLocation id() { return PACKET_ID; } } 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 662ae14..5b77b27 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 @@ -1,14 +1,17 @@ package net.lionarius.skinrestorer.fabric.compat.skinshuffle; -import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; +import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.lionarius.skinrestorer.SkinRestorer; -import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleHandshakePayload; import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleSkinRefreshPayload; import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleSkinRefreshV1Payload; import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleSkinRefreshV2Payload; import net.lionarius.skinrestorer.fabric.SkinRestorerFabric; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerGamePacketListenerImpl; public final class SkinShuffleCompatibility { @@ -20,18 +23,24 @@ public final class SkinShuffleCompatibility { return; } - PayloadTypeRegistry.playS2C().register(SkinShuffleHandshakePayload.PACKET_ID, SkinShuffleHandshakePayload.PACKET_CODEC); - PayloadTypeRegistry.playC2S().register(SkinShuffleSkinRefreshV1Payload.PACKET_ID, SkinShuffleSkinRefreshV1Payload.PACKET_CODEC); - PayloadTypeRegistry.playC2S().register(SkinShuffleSkinRefreshV2Payload.PACKET_ID, SkinShuffleSkinRefreshV2Payload.PACKET_CODEC); - ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility.onPlayerJoin(handler.getPlayer())); - ServerPlayNetworking.registerGlobalReceiver(SkinShuffleSkinRefreshV1Payload.PACKET_ID, SkinShuffleCompatibility::handleSkinRefreshPacket); + ServerPlayNetworking.registerGlobalReceiver(SkinShuffleSkinRefreshV1Payload.PACKET_ID, SkinShuffleCompatibility::handleSkinRefreshV1Packet); - ServerPlayNetworking.registerGlobalReceiver(SkinShuffleSkinRefreshV2Payload.PACKET_ID, SkinShuffleCompatibility::handleSkinRefreshPacket); + ServerPlayNetworking.registerGlobalReceiver(SkinShuffleSkinRefreshV2Payload.PACKET_ID, SkinShuffleCompatibility::handleSkinRefreshV2Packet); } - private static void handleSkinRefreshPacket(SkinShuffleSkinRefreshPayload payload, ServerPlayNetworking.Context context) { - net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility.handleSkinRefresh(context.player().getServer(), context.player(), payload); + private static void handleSkinRefreshV1Packet(MinecraftServer server, ServerPlayer player, ServerGamePacketListenerImpl listener, FriendlyByteBuf buf, PacketSender sender) { + var payload = SkinShuffleSkinRefreshV1Payload.decode(buf); + SkinShuffleCompatibility.handleSkinRefreshPacket(payload, server, player); + } + + private static void handleSkinRefreshV2Packet(MinecraftServer server, ServerPlayer player, ServerGamePacketListenerImpl listener, FriendlyByteBuf buf, PacketSender sender) { + var payload = SkinShuffleSkinRefreshV2Payload.decode(buf); + SkinShuffleCompatibility.handleSkinRefreshPacket(payload, server, player); + } + + private static void handleSkinRefreshPacket(SkinShuffleSkinRefreshPayload payload, MinecraftServer server, ServerPlayer player) { + net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility.handleSkinRefresh(server, player, payload); } } diff --git a/fabric/src/main/java/net/lionarius/skinrestorer/fabric/platform/FabricCompatibilityHelper.java b/fabric/src/main/java/net/lionarius/skinrestorer/fabric/platform/FabricCompatibilityHelper.java index c8d7588..706ac01 100644 --- a/fabric/src/main/java/net/lionarius/skinrestorer/fabric/platform/FabricCompatibilityHelper.java +++ b/fabric/src/main/java/net/lionarius/skinrestorer/fabric/platform/FabricCompatibilityHelper.java @@ -1,13 +1,13 @@ package net.lionarius.skinrestorer.fabric.platform; -import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleHandshakePayload; import net.lionarius.skinrestorer.platform.services.CompatibilityHelper; +import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket; import net.minecraft.server.level.ServerPlayer; public final class FabricCompatibilityHelper implements CompatibilityHelper { @Override public void skinShuffle_sendHandshake(ServerPlayer player) { - ServerPlayNetworking.send(player, SkinShuffleHandshakePayload.INSTANCE); + player.connection.send(new ServerboundCustomPayloadPacket(SkinShuffleHandshakePayload.INSTANCE)); } } diff --git a/forge/build.gradle b/forge/build.gradle index e3b12c2..173721d 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -17,12 +17,14 @@ mixin { jarJar.enable() +tasks.named('jar') { + archiveClassifier = 'thin' +} + tasks.named('jarJar') { archiveClassifier = '' } -jar.finalizedBy('jarJar') - minecraft { mappings channel: 'parchment', version: "${parchment_version}-${parchment_minecraft}" 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 9f6ba68..2b02632 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 @@ -14,18 +14,18 @@ public class SkinShufflePacketHandler { } private static final EventNetworkChannel HANDSHAKE_INSTANCE = ChannelBuilder - .named(SkinShuffleHandshakePayload.PACKET_ID.id()) + .named(SkinShuffleHandshakePayload.PACKET_ID) .optional() .eventNetworkChannel(); private static final EventNetworkChannel SKIN_REFRESH_V1_INSTANCE = ChannelBuilder - .named(SkinShuffleSkinRefreshV1Payload.PACKET_ID.id()) + .named(SkinShuffleSkinRefreshV1Payload.PACKET_ID) .optional() .eventNetworkChannel() .addListener(SkinShufflePacketHandler::skinRefreshV1Listener); private static final EventNetworkChannel SKIN_REFRESH_V2_INSTANCE = ChannelBuilder - .named(SkinShuffleSkinRefreshV2Payload.PACKET_ID.id()) + .named(SkinShuffleSkinRefreshV2Payload.PACKET_ID) .optional() .eventNetworkChannel() .addListener(SkinShufflePacketHandler::skinRefreshV2Listener); @@ -39,12 +39,12 @@ public class SkinShufflePacketHandler { } private static void skinRefreshV1Listener(CustomPayloadEvent event) { - var payload = SkinShuffleSkinRefreshV1Payload.PACKET_CODEC.decode(event.getPayload()); + var payload = SkinShuffleSkinRefreshV1Payload.decode(event.getPayload()); handleSkinRefreshPacket(payload, event.getSource()); } private static void skinRefreshV2Listener(CustomPayloadEvent event) { - var payload = SkinShuffleSkinRefreshV2Payload.PACKET_CODEC.decode(event.getPayload()); + var payload = SkinShuffleSkinRefreshV2Payload.decode(event.getPayload()); handleSkinRefreshPacket(payload, event.getSource()); } diff --git a/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShuffleCompatibility.java b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShuffleCompatibility.java index 702ea67..404cabd 100644 --- a/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShuffleCompatibility.java +++ b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShuffleCompatibility.java @@ -1,7 +1,5 @@ package net.lionarius.skinrestorer.neoforge.compat.skinshuffle; -import net.lionarius.skinrestorer.SkinRestorer; -import net.neoforged.fml.ModList; import net.neoforged.neoforge.common.NeoForge; public final class SkinShuffleCompatibility { @@ -11,7 +9,6 @@ public final class SkinShuffleCompatibility { public static void initialize() { NeoForge.EVENT_BUS.register(SkinShuffleGameEventHandler.class); - final var mod = ModList.get().getModContainerById(SkinRestorer.MOD_ID).get(); - mod.getEventBus().register(SkinShuffleModEventHandler.class); + SkinShufflePacketHandler.initialize(); } } 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 deleted file mode 100644 index 6036393..0000000 --- a/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShuffleModEventHandler.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.lionarius.skinrestorer.neoforge.compat.skinshuffle; - -import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility; -import net.lionarius.skinrestorer.compat.skinshuffle.*; -import net.minecraft.server.level.ServerPlayer; -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; -import net.neoforged.neoforge.network.handling.IPayloadContext; -import net.neoforged.neoforge.network.registration.HandlerThread; - -public final class SkinShuffleModEventHandler { - private SkinShuffleModEventHandler() {} - - @SubscribeEvent - public static void onRegisterPayloadHandlers(RegisterPayloadHandlersEvent event) { - final var registrar = event.registrar("1").optional().executesOn(HandlerThread.NETWORK); - - registrar - .playToClient(SkinShuffleHandshakePayload.PACKET_ID, SkinShuffleHandshakePayload.PACKET_CODEC, - (payload, context) -> {}) - .playToServer(SkinShuffleSkinRefreshV1Payload.PACKET_ID, SkinShuffleSkinRefreshV1Payload.PACKET_CODEC, - SkinShuffleModEventHandler::handleSkinRefreshPacket) - .playToServer(SkinShuffleSkinRefreshV2Payload.PACKET_ID, SkinShuffleSkinRefreshV2Payload.PACKET_CODEC, - SkinShuffleModEventHandler::handleSkinRefreshPacket); - } - - private static void handleSkinRefreshPacket(SkinShuffleSkinRefreshPayload payload, IPayloadContext context) { - var player = (ServerPlayer) context.player(); - SkinShuffleCompatibility.handleSkinRefresh(player.getServer(), player, payload); - } -} diff --git a/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShufflePacketHandler.java b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShufflePacketHandler.java new file mode 100644 index 0000000..9280c14 --- /dev/null +++ b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShufflePacketHandler.java @@ -0,0 +1,51 @@ +package net.lionarius.skinrestorer.neoforge.compat.skinshuffle; + +import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility; +import net.lionarius.skinrestorer.compat.skinshuffle.*; +import net.neoforged.neoforge.network.NetworkEvent; +import net.neoforged.neoforge.network.NetworkRegistry; +import net.neoforged.neoforge.network.event.EventNetworkChannel; + +public final class SkinShufflePacketHandler { + private SkinShufflePacketHandler() { + } + + // there is no need for handshake channel but register it to not allow other mods to use it + private static final EventNetworkChannel HANDSHAKE_INSTANCE = NetworkRegistry.ChannelBuilder + .named(SkinShuffleHandshakePayload.PACKET_ID) + .serverAcceptedVersions(NetworkRegistry.acceptMissingOr("1")) + .clientAcceptedVersions(NetworkRegistry.acceptMissingOr("1")) + .eventNetworkChannel(); + + private static final EventNetworkChannel SKIN_REFRESH_V1_INSTANCE = NetworkRegistry.ChannelBuilder + .named(SkinShuffleSkinRefreshV1Payload.PACKET_ID) + .serverAcceptedVersions(NetworkRegistry.acceptMissingOr("1")) + .clientAcceptedVersions(NetworkRegistry.acceptMissingOr("1")) + .eventNetworkChannel(); + + private static final EventNetworkChannel SKIN_REFRESH_V2_INSTANCE = NetworkRegistry.ChannelBuilder + .named(SkinShuffleSkinRefreshV2Payload.PACKET_ID) + .serverAcceptedVersions(NetworkRegistry.acceptMissingOr("1")) + .clientAcceptedVersions(NetworkRegistry.acceptMissingOr("1")) + .eventNetworkChannel(); + + static void initialize() { + SKIN_REFRESH_V1_INSTANCE.addListener(SkinShufflePacketHandler::skinRefreshV1Listener); + SKIN_REFRESH_V2_INSTANCE.addListener(SkinShufflePacketHandler::skinRefreshV2Listener); + } + + private static void skinRefreshV1Listener(NetworkEvent.ServerCustomPayloadEvent event) { + var payload = SkinShuffleSkinRefreshV1Payload.decode(event.getPayload()); + handleSkinRefreshPacket(payload, event.getSource()); + } + + private static void skinRefreshV2Listener(NetworkEvent.ServerCustomPayloadEvent event) { + var payload = SkinShuffleSkinRefreshV2Payload.decode(event.getPayload()); + handleSkinRefreshPacket(payload, event.getSource()); + } + + private static void handleSkinRefreshPacket(SkinShuffleSkinRefreshPayload payload, NetworkEvent.Context context) { + var player = context.getSender(); + SkinShuffleCompatibility.handleSkinRefresh(player.getServer(), player, payload); + } +} diff --git a/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/platform/NeoForgeCompatibilityHelper.java b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/platform/NeoForgeCompatibilityHelper.java index 4cd9a0c..b488b12 100644 --- a/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/platform/NeoForgeCompatibilityHelper.java +++ b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/platform/NeoForgeCompatibilityHelper.java @@ -10,6 +10,6 @@ public final class NeoForgeCompatibilityHelper implements CompatibilityHelper { @Override public void skinShuffle_sendHandshake(ServerPlayer player) { // we can't use the packet distributor here because neoforge doesn't support sending packets to non-neoforge players - player.connection.getConnection().send(new ClientboundCustomPayloadPacket(SkinShuffleHandshakePayload.INSTANCE)); + player.connection.connection.send(new ClientboundCustomPayloadPacket(SkinShuffleHandshakePayload.INSTANCE)); } } From 95cc551df7255b0e79625566aac935fefab3abb2 Mon Sep 17 00:00:00 2001 From: lionarius Date: Sat, 30 Nov 2024 03:48:01 +0300 Subject: [PATCH 27/29] drop neoforge support --- .../neoforge/compat/skinshuffle/SkinShufflePacketHandler.java | 4 ++++ settings.gradle | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShufflePacketHandler.java b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShufflePacketHandler.java index 9280c14..76f4d87 100644 --- a/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShufflePacketHandler.java +++ b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/compat/skinshuffle/SkinShufflePacketHandler.java @@ -2,6 +2,7 @@ package net.lionarius.skinrestorer.neoforge.compat.skinshuffle; import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleCompatibility; import net.lionarius.skinrestorer.compat.skinshuffle.*; +import net.neoforged.neoforge.network.NetworkConstants; import net.neoforged.neoforge.network.NetworkEvent; import net.neoforged.neoforge.network.NetworkRegistry; import net.neoforged.neoforge.network.event.EventNetworkChannel; @@ -15,18 +16,21 @@ public final class SkinShufflePacketHandler { .named(SkinShuffleHandshakePayload.PACKET_ID) .serverAcceptedVersions(NetworkRegistry.acceptMissingOr("1")) .clientAcceptedVersions(NetworkRegistry.acceptMissingOr("1")) + .networkProtocolVersion(() -> NetworkConstants.NETVERSION) .eventNetworkChannel(); private static final EventNetworkChannel SKIN_REFRESH_V1_INSTANCE = NetworkRegistry.ChannelBuilder .named(SkinShuffleSkinRefreshV1Payload.PACKET_ID) .serverAcceptedVersions(NetworkRegistry.acceptMissingOr("1")) .clientAcceptedVersions(NetworkRegistry.acceptMissingOr("1")) + .networkProtocolVersion(() -> NetworkConstants.NETVERSION) .eventNetworkChannel(); private static final EventNetworkChannel SKIN_REFRESH_V2_INSTANCE = NetworkRegistry.ChannelBuilder .named(SkinShuffleSkinRefreshV2Payload.PACKET_ID) .serverAcceptedVersions(NetworkRegistry.acceptMissingOr("1")) .clientAcceptedVersions(NetworkRegistry.acceptMissingOr("1")) + .networkProtocolVersion(() -> NetworkConstants.NETVERSION) .eventNetworkChannel(); static void initialize() { diff --git a/settings.gradle b/settings.gradle index a5ff64a..bf949e5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -71,4 +71,4 @@ rootProject.name = 'skin-restorer' include('common') include('fabric') include('forge') -include('neoforge') +//include('neoforge') From cab2ab323964176ecdc5f9ba58ae854b72e63249 Mon Sep 17 00:00:00 2001 From: lionarius Date: Sat, 30 Nov 2024 03:48:43 +0300 Subject: [PATCH 28/29] fix fabric handshake send --- .../fabric/platform/FabricCompatibilityHelper.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fabric/src/main/java/net/lionarius/skinrestorer/fabric/platform/FabricCompatibilityHelper.java b/fabric/src/main/java/net/lionarius/skinrestorer/fabric/platform/FabricCompatibilityHelper.java index 706ac01..38cedc7 100644 --- a/fabric/src/main/java/net/lionarius/skinrestorer/fabric/platform/FabricCompatibilityHelper.java +++ b/fabric/src/main/java/net/lionarius/skinrestorer/fabric/platform/FabricCompatibilityHelper.java @@ -1,13 +1,14 @@ package net.lionarius.skinrestorer.fabric.platform; +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.lionarius.skinrestorer.compat.skinshuffle.SkinShuffleHandshakePayload; import net.lionarius.skinrestorer.platform.services.CompatibilityHelper; -import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket; import net.minecraft.server.level.ServerPlayer; public final class FabricCompatibilityHelper implements CompatibilityHelper { @Override public void skinShuffle_sendHandshake(ServerPlayer player) { - player.connection.send(new ServerboundCustomPayloadPacket(SkinShuffleHandshakePayload.INSTANCE)); + ServerPlayNetworking.send(player, SkinShuffleHandshakePayload.PACKET_ID, PacketByteBufs.empty()); } } From 120a8b7e3d91626aef344b2df795169f05427513 Mon Sep 17 00:00:00 2001 From: lionarius Date: Sat, 30 Nov 2024 03:49:04 +0300 Subject: [PATCH 29/29] fix reobf on forge --- forge/build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/forge/build.gradle b/forge/build.gradle index 173721d..df8a548 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -25,6 +25,10 @@ tasks.named('jarJar') { archiveClassifier = '' } +tasks.named('jar') { + dependsOn('jarJar') +} + minecraft { mappings channel: 'parchment', version: "${parchment_version}-${parchment_minecraft}"