diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 650aefa..ab1856a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,8 +4,6 @@ on: paths-ignore: - '.github/**' - '*.md' - tags-ignore: - - '*' pull_request: paths-ignore: - '.github/**' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 98cffc6..2a92f3a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,7 +2,7 @@ name: release on: push: tags: - - "v*" + - "v**" workflow_dispatch: jobs: diff --git a/buildSrc/src/main/groovy/multiloader-common.gradle b/buildSrc/src/main/groovy/multiloader-common.gradle index 8cf6f65..26834e4 100644 --- a/buildSrc/src/main/groovy/multiloader-common.gradle +++ b/buildSrc/src/main/groovy/multiloader-common.gradle @@ -3,8 +3,8 @@ plugins { } base { - archivesName = "${mod_id}-${project.name}" - version = "${mod_version}+${minecraft_version}" + archivesName = "${mod_id}" + version = "${mod_version}+${minecraft_version}-${project.name}" } java { diff --git a/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java b/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java index 055e997..2518497 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java +++ b/common/src/main/java/net/lionarius/skinrestorer/SkinRestorer.java @@ -1,7 +1,9 @@ package net.lionarius.skinrestorer; import com.mojang.authlib.GameProfile; +import net.lionarius.skinrestorer.config.BuiltInProviderConfig; import net.lionarius.skinrestorer.config.Config; +import net.lionarius.skinrestorer.platform.Services; import net.lionarius.skinrestorer.skin.SkinIO; import net.lionarius.skinrestorer.skin.SkinStorage; import net.lionarius.skinrestorer.skin.SkinValue; @@ -10,6 +12,7 @@ import net.lionarius.skinrestorer.translation.Translation; 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.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.level.storage.LevelResource; @@ -53,19 +56,28 @@ public final class SkinRestorer { return Optional.ofNullable(SkinRestorer.providersRegistry.get(name)); } - public static void onInitialize(Path rootConfigDir) { - SkinRestorer.configDir = rootConfigDir.resolve(SkinRestorer.MOD_ID); + 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(MojangSkinProvider.PROVIDER_NAME, SkinProvider.MOJANG); - SkinRestorer.providersRegistry.register(ElyBySkinProvider.PROVIDER_NAME, SkinProvider.ELY_BY); - SkinRestorer.providersRegistry.register(MineskinSkinProvider.PROVIDER_NAME, SkinProvider.MINESKIN); + + SkinRestorer.registerDefaultSkinProvider(MojangSkinProvider.PROVIDER_NAME, SkinProvider.MOJANG, SkinRestorer.getConfig().providersConfig().mojang()); + SkinRestorer.registerDefaultSkinProvider(ElyBySkinProvider.PROVIDER_NAME, SkinProvider.ELY_BY, SkinRestorer.getConfig().providersConfig().ely_by()); + SkinRestorer.registerDefaultSkinProvider(MineskinSkinProvider.PROVIDER_NAME, SkinProvider.MINESKIN, SkinRestorer.getConfig().providersConfig().mineskin()); + } + + private static void registerDefaultSkinProvider(String defaultName, SkinProvider provider, BuiltInProviderConfig config) { + var isDefaultName = config.name().equals(defaultName); + SkinRestorer.providersRegistry.register(defaultName, provider, config.enabled() && isDefaultName); + + if (!isDefaultName) + 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(worldSkinDirectory); + FileUtils.tryMigrateOldSkinDirectory(SkinRestorer.getConfigDir(), worldSkinDirectory); SkinRestorer.skinStorage = new SkinStorage(new SkinIO(worldSkinDirectory)); } @@ -73,9 +85,14 @@ public final class SkinRestorer { public static void reloadConfig() { SkinRestorer.config = Config.load(SkinRestorer.getConfigDir()); Translation.reloadTranslations(); + WebUtils.recreateHttpClient(); + + MojangSkinProvider.createCache(); + ElyBySkinProvider.createCache(); + MineskinSkinProvider.createCache(); } - public static String resource(String name) { + public static String assetPath(String name) { return String.format("/assets/%s/%s", SkinRestorer.MOD_ID, name); } @@ -116,7 +133,7 @@ public final class SkinRestorer { boolean save ) { return CompletableFuture.supplyAsync( - () -> SkinRestorer.getProvider(context.name()).map(provider -> provider.getSkin(context.argument(), context.variant())) + () -> SkinRestorer.getProvider(context.name()).map(provider -> provider.fetchSkin(context.argument(), context.variant())) ) .thenApplyAsync(result -> { if (result.isEmpty()) diff --git a/common/src/main/java/net/lionarius/skinrestorer/command/SkinCommand.java b/common/src/main/java/net/lionarius/skinrestorer/command/SkinCommand.java index 8521641..67a26f4 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/command/SkinCommand.java +++ b/common/src/main/java/net/lionarius/skinrestorer/command/SkinCommand.java @@ -49,9 +49,14 @@ public final class SkinCommand { var providers = SkinRestorer.getProvidersRegistry().getPublicProviders(); for (var entry : providers) set.then(buildSetSubcommand(entry.first(), entry.second())); - base.then(set); + base.then( + literal("config") + .requires(commandSourceStack -> commandSourceStack.hasPermission(4)) + .then(literal("reload").executes(SkinCommand::configReloadSubcommand)) + ); + dispatcher.register(base); } @@ -160,6 +165,16 @@ public final class SkinCommand { return setSubcommand(src, Collections.singleton(src.getPlayer().getGameProfile()), context, false); } + private static int configReloadSubcommand(CommandContext context) { + SkinRestorer.reloadConfig(); + + context.getSource().sendSuccess(() -> Translation.translatableWithFallback( + Translation.COMMAND_SKIN_CONFIG_RELOADED_KEY + ), true); + + return 0; + } + private static void sendResponse(CommandSourceStack src, Collection updatedPlayers, boolean setByOperator) { if (updatedPlayers.isEmpty()) { src.sendSuccess(() -> Translation.translatableWithFallback( diff --git a/common/src/main/java/net/lionarius/skinrestorer/config/BuiltInProviderConfig.java b/common/src/main/java/net/lionarius/skinrestorer/config/BuiltInProviderConfig.java new file mode 100644 index 0000000..a4d197e --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/config/BuiltInProviderConfig.java @@ -0,0 +1,7 @@ +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 new file mode 100644 index 0000000..90c0089 --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/config/CacheConfig.java @@ -0,0 +1,7 @@ +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 3366568..030fdde 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/config/Config.java +++ b/common/src/main/java/net/lionarius/skinrestorer/config/Config.java @@ -5,6 +5,7 @@ import net.lionarius.skinrestorer.util.FileUtils; import net.lionarius.skinrestorer.util.JsonUtils; import java.nio.file.Path; +import java.util.Optional; public final class Config { @@ -13,34 +14,47 @@ public final class Config { private String language = "en_us"; + private boolean refreshSkinOnJoin = false; + private boolean fetchSkinOnFirstJoin = true; private FirstJoinSkinProvider firstJoinSkinProvider = FirstJoinSkinProvider.MOJANG; private String proxy = ""; + private transient Proxy parsedProxy = null; private long requestTimeout = 10; - public String getLanguage() { + private ProvidersConfig providers = ProvidersConfig.DEFAULT; + + public String language() { return this.language; } + public boolean refreshSkinOnJoin() { + return this.refreshSkinOnJoin; + } + public boolean fetchSkinOnFirstJoin() { return this.fetchSkinOnFirstJoin; } - public FirstJoinSkinProvider getFirstJoinSkinProvider() { + public FirstJoinSkinProvider firstJoinSkinProvider() { return this.firstJoinSkinProvider; } - public String getProxy() { - return this.proxy; + public Optional proxy() { + return Optional.ofNullable(this.parsedProxy); } - public long getRequestTimeout() { + public long requestTimeout() { return this.requestTimeout; } + public ProvidersConfig providersConfig() { + return this.providers; + } + public static Config load(Path path) { var configFile = path.resolve(Config.CONFIG_FILENAME); @@ -62,16 +76,41 @@ public final class Config { } private void verifyAndFix() { - if (this.language == null || this.language.isEmpty()) + if (this.language == null || this.language.isEmpty()) { + SkinRestorer.LOGGER.warn("Language config is null or empty, defaulting to 'en_us'"); this.language = "en_us"; + } - if (this.firstJoinSkinProvider == null) + if (this.firstJoinSkinProvider == null) { + SkinRestorer.LOGGER.warn("FirstJoinSkinProvider config is null, defaulting to MOJANG"); this.firstJoinSkinProvider = FirstJoinSkinProvider.MOJANG; + } - if (this.proxy == null) + if (this.proxy == null) { + SkinRestorer.LOGGER.warn("Proxy config is null, defaulting to an empty string"); this.proxy = ""; + } - if (this.requestTimeout <= 0) + if (!this.proxy.isEmpty()) { + try { + this.parsedProxy = Proxy.parse(this.proxy); + } catch (Exception e) { + SkinRestorer.LOGGER.warn("Could not parse proxy config", e); + this.parsedProxy = null; + } + } + + if (this.requestTimeout <= 0) { + SkinRestorer.LOGGER.warn("Request timeout config is less than or equal to 0, defaulting to 10"); this.requestTimeout = 10; + } + + if (this.providers == null) { + 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 new file mode 100644 index 0000000..da22b99 --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/config/ProvidersConfig.java @@ -0,0 +1,65 @@ +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/Proxy.java b/common/src/main/java/net/lionarius/skinrestorer/config/Proxy.java new file mode 100644 index 0000000..f5c38ba --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/config/Proxy.java @@ -0,0 +1,21 @@ +package net.lionarius.skinrestorer.config; + +import org.jetbrains.annotations.NotNull; + +public record Proxy(@NotNull String host, int port) { + + public static Proxy parse(@NotNull String proxy) { + var colonIndex = proxy.lastIndexOf(':'); + if (colonIndex == -1) + throw new IllegalArgumentException("no port in hostname"); + + var port = Integer.parseInt(proxy.substring(colonIndex + 1)); + + if (port < 0 || port > 0xFFFF) + throw new IllegalArgumentException("port out of range: " + port); + + var host = proxy.substring(0, colonIndex); + + return new Proxy(host, port); + } +} 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 c607893..90d2210 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/mixin/ServerLoginPacketListenerImplMixin.java +++ b/common/src/main/java/net/lionarius/skinrestorer/mixin/ServerLoginPacketListenerImplMixin.java @@ -24,51 +24,65 @@ public abstract class ServerLoginPacketListenerImplMixin { private GameProfile authenticatedProfile; @Unique - private CompletableFuture skinrestorer_pendingSkin; + private CompletableFuture skinrestorer$pendingSkin; @Inject(method = "verifyLoginAndFinishConnectionSetup", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/players/PlayerList;canPlayerLogin(Ljava/net/SocketAddress;Lcom/mojang/authlib/GameProfile;)Lnet/minecraft/network/chat/Component;"), cancellable = true) public void waitForSkin(CallbackInfo ci) { - if (skinrestorer_pendingSkin == null) { - skinrestorer_pendingSkin = CompletableFuture.supplyAsync(() -> { - assert authenticatedProfile != null; - var originalSkin = PlayerUtils.getPlayerSkin(authenticatedProfile); + if (skinrestorer$pendingSkin == null) { + skinrestorer$pendingSkin = CompletableFuture.supplyAsync(() -> { + final var profile = authenticatedProfile; - if (SkinRestorer.getSkinStorage().hasSavedSkin(authenticatedProfile.getId())) { + assert profile != null; + var originalSkin = PlayerUtils.getPlayerSkin(profile); + + if (SkinRestorer.getSkinStorage().hasSavedSkin(profile.getId())) { if (originalSkin != null) { // update to the latest official skin - var value = SkinRestorer.getSkinStorage().getSkin(authenticatedProfile.getId()); - SkinRestorer.getSkinStorage().setSkin(authenticatedProfile.getId(), value.setOriginalValue(originalSkin)); + var value = SkinRestorer.getSkinStorage().getSkin(profile.getId()); + SkinRestorer.getSkinStorage().setSkin(profile.getId(), value.setOriginalValue(originalSkin)); + } + + if (SkinRestorer.getConfig().refreshSkinOnJoin()) { + var currentSkin = SkinRestorer.getSkinStorage().getSkin(profile.getId()); + var context = currentSkin.toProviderContext(); + + skinrestorer$fetchSkin(profile, context); } return null; } if (originalSkin == null && SkinRestorer.getConfig().fetchSkinOnFirstJoin()) { - SkinRestorer.LOGGER.debug("Fetching {}'s skin", authenticatedProfile.getName()); - var context = new SkinProviderContext( - SkinRestorer.getConfig().getFirstJoinSkinProvider().getName(), - authenticatedProfile.getName(), + SkinRestorer.getConfig().firstJoinSkinProvider().getName(), + profile.getName(), null ); - var result = SkinRestorer.getProvider(context.name()).map( - provider -> provider.getSkin(context.argument(), context.variant()) - ).orElse(Result.ofNullable(null)); - - if (!result.isError()) { - var value = SkinValue.fromProviderContextWithValue(context, result.getSuccessValue().orElse(null)); - SkinRestorer.getSkinStorage().setSkin(authenticatedProfile.getId(), value); - } else { - SkinRestorer.LOGGER.warn("failed to fetch skin on first join", result.getErrorValue()); - } + skinrestorer$fetchSkin(profile, context); } return null; }); } - if (!skinrestorer_pendingSkin.isDone()) + if (!skinrestorer$pendingSkin.isDone()) ci.cancel(); } + + @Unique + private static void skinrestorer$fetchSkin(GameProfile profile, SkinProviderContext context) { + 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()))); + + 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()); + } + } } diff --git a/common/src/main/java/net/lionarius/skinrestorer/mixin/TrackedEntityMixin.java b/common/src/main/java/net/lionarius/skinrestorer/mixin/TrackedEntityAccessorInvoker.java similarity index 92% rename from common/src/main/java/net/lionarius/skinrestorer/mixin/TrackedEntityMixin.java rename to common/src/main/java/net/lionarius/skinrestorer/mixin/TrackedEntityAccessorInvoker.java index c5be782..32d3852 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/mixin/TrackedEntityMixin.java +++ b/common/src/main/java/net/lionarius/skinrestorer/mixin/TrackedEntityAccessorInvoker.java @@ -9,7 +9,7 @@ import org.spongepowered.asm.mixin.gen.Invoker; import java.util.Set; @Mixin(targets = "net.minecraft.server.level.ChunkMap$TrackedEntity") -public interface TrackedEntityMixin { +public interface TrackedEntityAccessorInvoker { @Accessor Set getSeenBy(); diff --git a/common/src/main/java/net/lionarius/skinrestorer/platform/Services.java b/common/src/main/java/net/lionarius/skinrestorer/platform/Services.java new file mode 100644 index 0000000..e160259 --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/platform/Services.java @@ -0,0 +1,21 @@ +package net.lionarius.skinrestorer.platform; + +import net.lionarius.skinrestorer.SkinRestorer; +import net.lionarius.skinrestorer.platform.services.PlatformHelper; + +import java.util.ServiceLoader; + +public final class Services { + + private Services() {} + + public final static PlatformHelper PLATFORM = load(PlatformHelper.class); + + private static T load(Class clazz) { + final T loadedService = ServiceLoader.load(clazz) + .findFirst() + .orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName())); + SkinRestorer.LOGGER.debug("Loaded {} for service {}", loadedService, clazz); + return loadedService; + } +} diff --git a/common/src/main/java/net/lionarius/skinrestorer/platform/services/PlatformHelper.java b/common/src/main/java/net/lionarius/skinrestorer/platform/services/PlatformHelper.java new file mode 100644 index 0000000..ce039a8 --- /dev/null +++ b/common/src/main/java/net/lionarius/skinrestorer/platform/services/PlatformHelper.java @@ -0,0 +1,12 @@ +package net.lionarius.skinrestorer.platform.services; + +import java.nio.file.Path; + +public interface PlatformHelper { + + String getPlatformName(); + + boolean isModLoaded(String modId); + + Path getConfigDirectory(); +} 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 430b4d7..ecdfac9 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 @@ -1,32 +1,55 @@ package net.lionarius.skinrestorer.skin.provider; -import com.google.gson.JsonObject; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.util.concurrent.UncheckedExecutionException; +import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.authlib.yggdrasil.response.MinecraftProfilePropertiesResponse; +import net.lionarius.skinrestorer.SkinRestorer; 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 net.lionarius.skinrestorer.util.*; +import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.http.HttpRequest; +import java.util.Locale; import java.util.Optional; +import java.util.concurrent.TimeUnit; public final class ElyBySkinProvider implements SkinProvider { + public static final String PROVIDER_NAME = "ely.by"; private static final URI API_URI; + private static LoadingCache> SKIN_CACHE; + static { try { - API_URI = new URI("http://skinsystem.ely.by/"); + API_URI = new URI("http://skinsystem.ely.by"); } catch (URISyntaxException e) { throw new IllegalArgumentException(e); } } + public static void createCache() { + var config = SkinRestorer.getConfig().providersConfig().ely_by(); + var time = config.cache().enabled() ? config.cache().duration() : 0; + + SKIN_CACHE = CacheBuilder.newBuilder() + .expireAfterWrite(time, TimeUnit.SECONDS) + .build(new CacheLoader<>() { + @Override + public @NotNull Optional load(@NotNull String key) throws Exception { + return ElyBySkinProvider.loadSkin(key); + } + }); + } + @Override public String getArgumentName() { return "username"; @@ -38,23 +61,32 @@ public final class ElyBySkinProvider implements SkinProvider { } @Override - public Result, Exception> getSkin(String username, SkinVariant variant) { + public Result, Exception> fetchSkin(String username, SkinVariant variant) { try { - var profile = ElyBySkinProvider.getElyByProfile(username); + if (!StringUtils.isValidPlayerName(username)) + throw new IllegalArgumentException("invalid username"); - var properties = profile.getAsJsonArray("properties"); - var textures = PlayerUtils.findTexturesProperty(properties); + var usernameLowerCase = username.toLowerCase(Locale.ROOT); - return Result.ofNullable(textures); + return Result.success(SKIN_CACHE.get(usernameLowerCase)); + } catch (UncheckedExecutionException e) { + return Result.error((Exception) e.getCause()); } catch (Exception e) { return Result.error(e); } } - private static JsonObject getElyByProfile(String username) throws IOException { + private static Optional loadSkin(String username) throws Exception { + var profile = ElyBySkinProvider.getElyByProfile(username); + var textures = PlayerUtils.getPlayerSkin(profile); + + return Optional.ofNullable(textures); + } + + private static GameProfile getElyByProfile(String username) throws IOException { var request = HttpRequest.newBuilder() .uri(ElyBySkinProvider.API_URI - .resolve("textures/signed/") + .resolve("/textures/signed/") .resolve(username + "?unsigned=false") ) .GET() @@ -66,6 +98,6 @@ public final class ElyBySkinProvider implements SkinProvider { if (response.statusCode() != 200) throw new IllegalArgumentException("no profile with name " + username); - return JsonUtils.parseJson(response.body()); + return JsonUtils.fromJson(response.body(), MinecraftProfilePropertiesResponse.class).toProfile(); } } diff --git a/common/src/main/java/net/lionarius/skinrestorer/skin/provider/EmptySkinProvider.java b/common/src/main/java/net/lionarius/skinrestorer/skin/provider/EmptySkinProvider.java index fd5db1b..e0af9db 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/skin/provider/EmptySkinProvider.java +++ b/common/src/main/java/net/lionarius/skinrestorer/skin/provider/EmptySkinProvider.java @@ -21,11 +21,11 @@ public final class EmptySkinProvider implements SkinProvider { } @Override - public Result, Exception> getSkin(String argument, SkinVariant variant) { - return this.getSkin(); + public Result, Exception> fetchSkin(String argument, SkinVariant variant) { + return this.fetchSkin(); } - public Result, Exception> getSkin() { + public Result, Exception> fetchSkin() { return Result.ofNullable(null); } } 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 fa09aa7..6fd0e91 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 @@ -1,18 +1,26 @@ package net.lionarius.skinrestorer.skin.provider; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.util.concurrent.UncheckedExecutionException; import com.google.gson.JsonObject; import com.mojang.authlib.properties.Property; +import it.unimi.dsi.fastutil.Pair; +import net.lionarius.skinrestorer.SkinRestorer; 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 java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.http.HttpRequest; import java.util.Optional; +import java.util.concurrent.TimeUnit; public final class MineskinSkinProvider implements SkinProvider { @@ -20,14 +28,30 @@ public final class MineskinSkinProvider implements SkinProvider { private static final URI API_URI; + private static LoadingCache, Optional> SKIN_CACHE; + static { try { - API_URI = new URI("https://api.mineskin.org/"); + API_URI = new URI("https://api.mineskin.org"); } catch (URISyntaxException e) { throw new IllegalArgumentException(e); } } + public static void createCache() { + var config = SkinRestorer.getConfig().providersConfig().mineskin(); + var time = config.cache().enabled() ? config.cache().duration() : 0; + + SKIN_CACHE = CacheBuilder.newBuilder() + .expireAfterWrite(time, TimeUnit.SECONDS) + .build(new CacheLoader<>() { + @Override + public @NotNull Optional load(@NotNull Pair key) throws Exception { + return MineskinSkinProvider.loadSkin(key.first(), key.second()); + } + }); + } + @Override public String getArgumentName() { return "url"; @@ -39,23 +63,32 @@ public final class MineskinSkinProvider implements SkinProvider { } @Override - public Result, Exception> getSkin(String url, SkinVariant variant) { + public Result, Exception> fetchSkin(String url, SkinVariant variant) { try { - var result = MineskinSkinProvider.uploadToMineskin(url, variant); - var texture = result.getAsJsonObject("data").getAsJsonObject("texture"); + var uri = new URI(url); - return Result.ofNullable(new Property(PlayerUtils.TEXTURES_KEY, texture.get("value").getAsString(), texture.get("signature").getAsString())); + return Result.success(SKIN_CACHE.get(Pair.of(uri, variant))); + } catch (UncheckedExecutionException e) { + return Result.error((Exception) e.getCause()); } catch (Exception e) { return Result.error(e); } } - private static JsonObject uploadToMineskin(String url, SkinVariant variant) throws IOException { + 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()); + + 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 = HttpRequest.newBuilder() - .uri(MineskinSkinProvider.API_URI.resolve("generate/url")) + .uri(MineskinSkinProvider.API_URI.resolve("/generate/url")) .POST(HttpRequest.BodyPublishers.ofString(body)) .header("Content-Type", "application/json") .build(); 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 086a4c6..1523f86 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 @@ -1,19 +1,26 @@ package net.lionarius.skinrestorer.skin.provider; -import com.google.gson.JsonObject; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.util.concurrent.UncheckedExecutionException; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.authlib.yggdrasil.response.MinecraftProfilePropertiesResponse; +import com.mojang.util.UndashedUuid; +import net.lionarius.skinrestorer.SkinRestorer; 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 net.lionarius.skinrestorer.util.*; +import net.minecraft.server.players.GameProfileCache; +import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.http.HttpRequest; import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.TimeUnit; public final class MojangSkinProvider implements SkinProvider { @@ -22,13 +29,45 @@ public final class MojangSkinProvider implements SkinProvider { private static final URI API_URI; private static final URI SESSION_SERVER_URI; + public static final String PROFILE_CACHE_FILENAME = "mojang_profile_cache.json"; + private static final GameProfileCache PROFILE_CACHE; + + private static LoadingCache> SKIN_CACHE; + static { try { - API_URI = new URI("https://api.mojang.com/"); - SESSION_SERVER_URI = new URI("https://sessionserver.mojang.com/"); + API_URI = new URI("https://api.mojang.com"); + SESSION_SERVER_URI = new URI("https://sessionserver.mojang.com"); } catch (URISyntaxException e) { throw new IllegalArgumentException(e); } + + PROFILE_CACHE = new GameProfileCache((names, callback) -> { + for (var name : names) { + try { + var profile = MojangSkinProvider.getProfile(name); + callback.onProfileLookupSucceeded(profile); + } catch (IOException e) { + callback.onProfileLookupFailed(name, e); + } + } + }, SkinRestorer.getConfigDir().resolve(PROFILE_CACHE_FILENAME).toFile()); + + + } + + public static void createCache() { + var config = SkinRestorer.getConfig().providersConfig().mojang(); + var time = config.cache().enabled() ? config.cache().duration() : 0; + + SKIN_CACHE = CacheBuilder.newBuilder() + .expireAfterWrite(time, TimeUnit.SECONDS) + .build(new CacheLoader<>() { + @Override + public @NotNull Optional load(@NotNull UUID key) throws Exception { + return MojangSkinProvider.loadSkin(key); + } + }); } public static SkinProviderContext skinProviderContextFromProfile(GameProfile gameProfile) { @@ -46,24 +85,34 @@ public final class MojangSkinProvider implements SkinProvider { } @Override - public Result, Exception> getSkin(String username, SkinVariant variant) { + public Result, Exception> fetchSkin(String username, SkinVariant variant) { try { - var uuid = MojangSkinProvider.getUuid(username); - var profile = MojangSkinProvider.getMojangProfile(uuid); + if (!StringUtils.isValidPlayerName(username)) + throw new IllegalArgumentException("invalid username"); - var properties = profile.getAsJsonArray("properties"); - var textures = PlayerUtils.findTexturesProperty(properties); + var cachedProfile = MojangSkinProvider.PROFILE_CACHE.get(username); + if (cachedProfile.isEmpty()) + throw new IllegalArgumentException("no profile found for " + username); - return Result.ofNullable(textures); + return Result.success(SKIN_CACHE.get(cachedProfile.get().getId())); + } catch (UncheckedExecutionException e) { + return Result.error((Exception) e.getCause()); } catch (Exception e) { return Result.error(e); } } - private static String getUuid(final String name) throws IOException { + private static Optional loadSkin(UUID uuid) throws Exception { + var profile = MojangSkinProvider.getProfileWithProperties(uuid); + var textures = PlayerUtils.getPlayerSkin(profile); + + return Optional.ofNullable(textures); + } + + private static GameProfile getProfile(final String name) throws IOException { var request = HttpRequest.newBuilder() .uri(MojangSkinProvider.API_URI - .resolve("users/profiles/minecraft/") + .resolve("/users/profiles/minecraft/") .resolve(name) ) .GET() @@ -75,18 +124,14 @@ public final class MojangSkinProvider implements SkinProvider { if (response.statusCode() != 200) throw new IllegalArgumentException("no profile with name " + name); - var profile = JsonUtils.parseJson(response.body()); - if (profile == null) - return null; - - return profile.get("id").getAsString(); + return JsonUtils.fromJson(response.body(), GameProfile.class); } - private static JsonObject getMojangProfile(String uuid) throws IOException { + private static GameProfile getProfileWithProperties(UUID uuid) throws IOException { var request = HttpRequest.newBuilder() .uri(MojangSkinProvider.SESSION_SERVER_URI - .resolve("session/minecraft/profile/") - .resolve(uuid + "?unsigned=false") + .resolve("/session/minecraft/profile/") + .resolve(UndashedUuid.toString(uuid) + "?unsigned=false") ) .GET() .build(); @@ -97,6 +142,6 @@ public final class MojangSkinProvider implements SkinProvider { if (response.statusCode() != 200) throw new IllegalArgumentException("no profile with uuid " + uuid); - return JsonUtils.parseJson(response.body()); + return JsonUtils.fromJson(response.body(), MinecraftProfilePropertiesResponse.class).toProfile(); } } 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 70dfef3..4df3b6a 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 @@ -16,5 +16,5 @@ public interface SkinProvider { boolean hasVariantSupport(); - Result, Exception> getSkin(String argument, SkinVariant variant); + Result, Exception> fetchSkin(String argument, SkinVariant variant); } diff --git a/common/src/main/java/net/lionarius/skinrestorer/skin/provider/SkinProviderRegistry.java b/common/src/main/java/net/lionarius/skinrestorer/skin/provider/SkinProviderRegistry.java index 619121b..7292a3b 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/skin/provider/SkinProviderRegistry.java +++ b/common/src/main/java/net/lionarius/skinrestorer/skin/provider/SkinProviderRegistry.java @@ -42,7 +42,7 @@ public final class SkinProviderRegistry { public void register(@NotNull String name, @NotNull SkinProvider provider, boolean isPublic) { if (this.registry.containsKey(name)) - throw new IllegalArgumentException("Skin provider with name " + name + " is already registered"); + return; this.registry.put(name, new Entry(provider, isPublic)); } diff --git a/common/src/main/java/net/lionarius/skinrestorer/translation/Translation.java b/common/src/main/java/net/lionarius/skinrestorer/translation/Translation.java index 238e5a9..ec2b567 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/translation/Translation.java +++ b/common/src/main/java/net/lionarius/skinrestorer/translation/Translation.java @@ -19,6 +19,7 @@ public final class Translation { public static final String COMMAND_SKIN_FAILED_KEY = "skinrestorer.command.skin.failed"; public static final String COMMAND_SKIN_OK_KEY = "skinrestorer.command.skin.ok"; public static final String COMMAND_SKIN_LOADING_KEY = "skinrestorer.command.skin.loading"; + public static final String COMMAND_SKIN_CONFIG_RELOADED_KEY = "skinrestorer.command.skin.config_reloaded"; private static Map translations; private static final Map fallback; @@ -46,11 +47,11 @@ public final class Translation { } public static void reloadTranslations() { - translations = Translation.loadTranslationMap(SkinRestorer.getConfig().getLanguage()); + translations = Translation.loadTranslationMap(SkinRestorer.getConfig().language()); } private static ImmutableMap loadTranslationMap(String lang) { - var json = FileUtils.readResource(SkinRestorer.resource(String.format("lang/%s.json", lang))); + var json = FileUtils.readResource(SkinRestorer.assetPath(String.format("lang/%s.json", lang))); var type = new TypeToken>() {}.getType(); Map map = null; 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 4241c3c..d0aeb0b 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/util/FileUtils.java +++ b/common/src/main/java/net/lionarius/skinrestorer/util/FileUtils.java @@ -3,6 +3,7 @@ package net.lionarius.skinrestorer.util; import net.lionarius.skinrestorer.SkinRestorer; import net.lionarius.skinrestorer.config.Config; import net.lionarius.skinrestorer.skin.SkinIO; +import net.lionarius.skinrestorer.skin.provider.MojangSkinProvider; import net.lionarius.skinrestorer.translation.Translation; import java.io.BufferedReader; @@ -17,24 +18,28 @@ public final class FileUtils { private FileUtils() {} - public static void tryMigrateOldSkinDirectory(Path newDirectory) { + public static void tryMigrateOldSkinDirectory(Path oldDirectory, Path newDirectory) { try { - var configDirectory = SkinRestorer.getConfigDir(); - try (var stream = Files.list(configDirectory)) { + try (var stream = Files.list(oldDirectory)) { var files = stream.filter(file -> { - var name = file.getFileName(); + var name = file.getFileName().toString(); return Files.isRegularFile(file) && !name.startsWith(Translation.LEGACY_TRANSLATION_FILENAME) && !name.startsWith(Config.CONFIG_FILENAME) + && !name.startsWith(MojangSkinProvider.PROFILE_CACHE_FILENAME) && name.endsWith(SkinIO.FILE_EXTENSION); }).toList(); if (!files.isEmpty() && !Files.exists(newDirectory)) Files.createDirectories(newDirectory); - - for (var file : files) - Files.move(file, newDirectory.resolve(file.getFileName()), StandardCopyOption.REPLACE_EXISTING); + for (var file : files) { + var newFile = newDirectory.resolve(file.getFileName()); + if (!Files.exists(newFile)) + Files.move(file, newFile, StandardCopyOption.ATOMIC_MOVE); + else + Files.delete(file); + } } } catch (Exception e) { SkinRestorer.LOGGER.error("could not migrate skin directory", 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 75f396f..82e47b1 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/util/JsonUtils.java +++ b/common/src/main/java/net/lionarius/skinrestorer/util/JsonUtils.java @@ -1,16 +1,28 @@ package net.lionarius.skinrestorer.util; -import com.google.gson.*; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; +import com.mojang.util.UUIDTypeAdapter; import net.lionarius.skinrestorer.SkinRestorer; import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; import java.util.Base64; +import java.util.UUID; public final class JsonUtils { - private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + private static final Gson GSON = new GsonBuilder() + .registerTypeAdapter(UUID.class, new UUIDTypeAdapter()) + .registerTypeAdapter(PropertyMap.class, new PropertyMap.Serializer()) + .registerTypeAdapter(GameProfile.class, new GameProfile.Serializer()) + .setPrettyPrinting() + .create(); private JsonUtils() {} @@ -31,7 +43,7 @@ public final class JsonUtils { } public static JsonObject parseJson(String json) { - return JsonParser.parseString(json).getAsJsonObject(); + return GSON.fromJson(json, JsonObject.class); } public static JsonObject skinPropertyToJson(Property property) { diff --git a/common/src/main/java/net/lionarius/skinrestorer/util/PlayerUtils.java b/common/src/main/java/net/lionarius/skinrestorer/util/PlayerUtils.java index 99e406f..db74512 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/util/PlayerUtils.java +++ b/common/src/main/java/net/lionarius/skinrestorer/util/PlayerUtils.java @@ -1,11 +1,12 @@ package net.lionarius.skinrestorer.util; -import com.google.gson.JsonArray; +import com.google.common.collect.Iterables; import com.google.gson.JsonObject; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.authlib.yggdrasil.response.MinecraftProfilePropertiesResponse; import net.lionarius.skinrestorer.mixin.ChunkMapAccessor; -import net.lionarius.skinrestorer.mixin.TrackedEntityMixin; +import net.lionarius.skinrestorer.mixin.TrackedEntityAccessorInvoker; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.*; import net.minecraft.server.level.ChunkMap; @@ -49,14 +50,14 @@ public final class PlayerUtils { ) )); - var trackedEntity = (TrackedEntityMixin) ((ChunkMapAccessor) chunkMap).getEntityMap().get(player.getId()); + var trackedEntity = (TrackedEntityAccessorInvoker) ((ChunkMapAccessor) chunkMap).getEntityMap().get(player.getId()); if (trackedEntity != null) { var seenBy = Set.copyOf(trackedEntity.getSeenBy()); for (var observerConnection : seenBy) { var observer = observerConnection.getPlayer(); trackedEntity.invokeRemovePlayer(observer); - var trackedObserverEntity = (TrackedEntityMixin) ((ChunkMapAccessor) chunkMap).getEntityMap().get(observer.getId()); + var trackedObserverEntity = (TrackedEntityAccessorInvoker) ((ChunkMapAccessor) chunkMap).getEntityMap().get(observer.getId()); if (trackedObserverEntity != null) { trackedObserverEntity.invokeRemovePlayer(player); trackedObserverEntity.invokeUpdatePlayer(player); @@ -84,14 +85,14 @@ public final class PlayerUtils { } } - public static void sendActivePlayerEffects(ServerPlayer player) { + private static void sendActivePlayerEffects(ServerPlayer player) { for (var effect : player.getActiveEffects()) { player.connection.send(new ClientboundUpdateMobEffectPacket(player.getId(), effect)); } } public static Property getPlayerSkin(GameProfile profile) { - return profile.getProperties().get(TEXTURES_KEY).stream().findFirst().orElse(null); + return Iterables.getFirst(profile.getProperties().get(TEXTURES_KEY), null); } public static void applyRestoredSkin(GameProfile profile, Property skin) { @@ -101,7 +102,6 @@ public final class PlayerUtils { profile.getProperties().put(TEXTURES_KEY, skin); } - public static boolean areSkinPropertiesEquals(Property x, Property y) { if (x == y) return true; @@ -121,24 +121,9 @@ public final class PlayerUtils { return xJson.equals(yJson); } - public static Property findTexturesProperty(JsonArray properties) { - Property textures = null; - for (var property : properties) { - var propertyObject = property.getAsJsonObject(); - if (propertyObject == null) - continue; - - try { - textures = JsonUtils.fromJson(propertyObject, Property.class); - break; - } catch (Exception e) { - // ignored - } - } - - if (textures == null) - throw new IllegalStateException("no textures in profile"); - - return textures; + public static GameProfile toProfile(MinecraftProfilePropertiesResponse response) { + final GameProfile profile = new GameProfile(response.id(), response.name()); + profile.getProperties().putAll(response.properties()); + return profile; } } diff --git a/common/src/main/java/net/lionarius/skinrestorer/util/StringUtils.java b/common/src/main/java/net/lionarius/skinrestorer/util/StringUtils.java index c9c2772..a1c1f44 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/util/StringUtils.java +++ b/common/src/main/java/net/lionarius/skinrestorer/util/StringUtils.java @@ -17,4 +17,8 @@ public final class StringUtils { return response.toString(); } + + public static boolean isValidPlayerName(String playerName) { + return playerName.length() <= 16 && playerName.chars().filter(i -> i <= 32 || i >= 127).findAny().isEmpty(); + } } 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 2bce4fd..c877bf2 100644 --- a/common/src/main/java/net/lionarius/skinrestorer/util/WebUtils.java +++ b/common/src/main/java/net/lionarius/skinrestorer/util/WebUtils.java @@ -10,7 +10,6 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; import java.time.temporal.ChronoUnit; -import java.util.Date; public final class WebUtils { @@ -18,36 +17,32 @@ public final class WebUtils { public static final String USER_AGENT; + private static HttpClient HTTP_CLIENT = null; + static { USER_AGENT = String.format("SkinRestorer/%d", System.currentTimeMillis() % 65535); - + } + + public static void recreateHttpClient() { + HTTP_CLIENT = WebUtils.buildClient(); + } + + private static HttpClient buildClient() { var builder = HttpClient.newBuilder(); - var proxy = SkinRestorer.getConfig().getProxy(); + + var proxy = SkinRestorer.getConfig().proxy(); + proxy.ifPresent(value -> builder.proxy(ProxySelector.of(InetSocketAddress.createUnresolved(value.host(), value.port())))); + try { - if (proxy != null) { - var colonIndex = proxy.lastIndexOf(':'); - if (colonIndex != -1) { - var host = proxy.substring(0, colonIndex); - var port = Integer.parseInt(proxy.substring(colonIndex + 1)); - - builder.proxy(ProxySelector.of(InetSocketAddress.createUnresolved(host, port))); - } - } - } catch (Exception e) { - SkinRestorer.LOGGER.error("failed to parse proxy", e); - } - try { - builder.connectTimeout(Duration.of(SkinRestorer.getConfig().getRequestTimeout(), ChronoUnit.SECONDS)); + builder.connectTimeout(Duration.of(SkinRestorer.getConfig().requestTimeout(), ChronoUnit.SECONDS)); } catch (IllegalArgumentException e) { SkinRestorer.LOGGER.error("failed to set request timeout", e); builder.connectTimeout(Duration.of(10, ChronoUnit.SECONDS)); } - HTTP_CLIENT = builder.build(); + return builder.build(); } - private static final HttpClient HTTP_CLIENT; - public static HttpResponse executeRequest(HttpRequest request) throws IOException { try { var modifiedRequest = HttpRequest.newBuilder(request, (name, value) -> true) @@ -67,30 +62,16 @@ public final class WebUtils { } public static void throwOnClientErrors(HttpResponse response) { - String message = null; - switch (response.statusCode()) { - case 400: - message = "bad request"; - break; - case 401: - message = "unauthorized"; - break; - case 403: - message = "forbidden"; - break; - case 404: - message = "not found"; - break; - case 405: - message = "method not allowed"; - break; - case 408: - message = "request timeout"; - break; - case 429: - message = "too many requests"; - break; - } + String message = switch (response.statusCode()) { + case 400 -> "bad request"; + case 401 -> "unauthorized"; + case 403 -> "forbidden"; + case 404 -> "not found"; + case 405 -> "method not allowed"; + case 408 -> "request timeout"; + case 429 -> "too many requests"; + default -> null; + }; if (message != null) throw new IllegalStateException(message); diff --git a/common/src/main/resources/assets/skinrestorer/lang/cs_cz.json b/common/src/main/resources/assets/skinrestorer/lang/cs_cz.json index b7f12fb..78a0f76 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/cs_cz.json +++ b/common/src/main/resources/assets/skinrestorer/lang/cs_cz.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "Žádné změny skinu", "skinrestorer.command.skin.failed": "Nepodařilo se změnit skin: %s", "skinrestorer.command.skin.ok": "Skin změněn", - "skinrestorer.command.skin.loading": "Načítání skinu..." + "skinrestorer.command.skin.loading": "Načítání skinu...", + "skinrestorer.command.skin.config_reloaded": "Konfigurace byla znovu načtena" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/de_de.json b/common/src/main/resources/assets/skinrestorer/lang/de_de.json index 1874063..d66da0e 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/de_de.json +++ b/common/src/main/resources/assets/skinrestorer/lang/de_de.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "Keine Skinänderungen", "skinrestorer.command.skin.failed": "Skin konnte nicht geändert werden: %s", "skinrestorer.command.skin.ok": "Skin geändert", - "skinrestorer.command.skin.loading": "Skin wird geladen..." + "skinrestorer.command.skin.loading": "Skin wird geladen...", + "skinrestorer.command.skin.config_reloaded": "Konfiguration wurde neu geladen" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/en_us.json b/common/src/main/resources/assets/skinrestorer/lang/en_us.json index a61c7e9..61fc781 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/en_us.json +++ b/common/src/main/resources/assets/skinrestorer/lang/en_us.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "No skin changes", "skinrestorer.command.skin.failed": "Failed to change skin: %s", "skinrestorer.command.skin.ok": "Skin changed", - "skinrestorer.command.skin.loading": "Loading skin..." + "skinrestorer.command.skin.loading": "Loading skin...", + "skinrestorer.command.skin.config_reloaded": "Config has been reloaded" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/es_ar.json b/common/src/main/resources/assets/skinrestorer/lang/es_ar.json index c065bf4..42c1e30 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/es_ar.json +++ b/common/src/main/resources/assets/skinrestorer/lang/es_ar.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "No hay cambios de skin", "skinrestorer.command.skin.failed": "Error al cambiar el skin: %s", "skinrestorer.command.skin.ok": "Skin cambiado", - "skinrestorer.command.skin.loading": "Cargando skin..." + "skinrestorer.command.skin.loading": "Cargando skin...", + "skinrestorer.command.skin.config_reloaded": "La configuración se ha recargado" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/es_es.json b/common/src/main/resources/assets/skinrestorer/lang/es_es.json index c065bf4..42c1e30 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/es_es.json +++ b/common/src/main/resources/assets/skinrestorer/lang/es_es.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "No hay cambios de skin", "skinrestorer.command.skin.failed": "Error al cambiar el skin: %s", "skinrestorer.command.skin.ok": "Skin cambiado", - "skinrestorer.command.skin.loading": "Cargando skin..." + "skinrestorer.command.skin.loading": "Cargando skin...", + "skinrestorer.command.skin.config_reloaded": "La configuración se ha recargado" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/es_mx.json b/common/src/main/resources/assets/skinrestorer/lang/es_mx.json index c065bf4..42c1e30 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/es_mx.json +++ b/common/src/main/resources/assets/skinrestorer/lang/es_mx.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "No hay cambios de skin", "skinrestorer.command.skin.failed": "Error al cambiar el skin: %s", "skinrestorer.command.skin.ok": "Skin cambiado", - "skinrestorer.command.skin.loading": "Cargando skin..." + "skinrestorer.command.skin.loading": "Cargando skin...", + "skinrestorer.command.skin.config_reloaded": "La configuración se ha recargado" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/fil_ph.json b/common/src/main/resources/assets/skinrestorer/lang/fil_ph.json index ff7a286..4c48c1c 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/fil_ph.json +++ b/common/src/main/resources/assets/skinrestorer/lang/fil_ph.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "Walang pagbabago sa skin", "skinrestorer.command.skin.failed": "Nabigo sa pagbabago ng skin: %s", "skinrestorer.command.skin.ok": "Nabago ang skin", - "skinrestorer.command.skin.loading": "Naglo-load ng skin..." + "skinrestorer.command.skin.loading": "Naglo-load ng skin...", + "skinrestorer.command.skin.config_reloaded": "Na-reload ang config" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/fr_ca.json b/common/src/main/resources/assets/skinrestorer/lang/fr_ca.json index 2b51882..ce71fb9 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/fr_ca.json +++ b/common/src/main/resources/assets/skinrestorer/lang/fr_ca.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "Aucun changement de skin", "skinrestorer.command.skin.failed": "Échec du changement de skin : %s", "skinrestorer.command.skin.ok": "Skin changé", - "skinrestorer.command.skin.loading": "Chargement du skin..." + "skinrestorer.command.skin.loading": "Chargement du skin...", + "skinrestorer.command.skin.config_reloaded": "La configuration a été rechargée" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/fr_fr.json b/common/src/main/resources/assets/skinrestorer/lang/fr_fr.json index 2b51882..ce71fb9 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/fr_fr.json +++ b/common/src/main/resources/assets/skinrestorer/lang/fr_fr.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "Aucun changement de skin", "skinrestorer.command.skin.failed": "Échec du changement de skin : %s", "skinrestorer.command.skin.ok": "Skin changé", - "skinrestorer.command.skin.loading": "Chargement du skin..." + "skinrestorer.command.skin.loading": "Chargement du skin...", + "skinrestorer.command.skin.config_reloaded": "La configuration a été rechargée" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/hi_in.json b/common/src/main/resources/assets/skinrestorer/lang/hi_in.json index 13526e5..24b7662 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/hi_in.json +++ b/common/src/main/resources/assets/skinrestorer/lang/hi_in.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "कोई त्वचा परिवर्तन नहीं", "skinrestorer.command.skin.failed": "त्वचा बदलने में विफल: %s", "skinrestorer.command.skin.ok": "त्वचा बदल दी गई", - "skinrestorer.command.skin.loading": "त्वचा लोड हो रही है..." + "skinrestorer.command.skin.loading": "त्वचा लोड हो रही है...", + "skinrestorer.command.skin.config_reloaded": "कॉन्फ़िगरेशन फिर से लोड किया गया है" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/hu_hu.json b/common/src/main/resources/assets/skinrestorer/lang/hu_hu.json index dbe4395..40ce15f 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/hu_hu.json +++ b/common/src/main/resources/assets/skinrestorer/lang/hu_hu.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "Nincsenek skin változások", "skinrestorer.command.skin.failed": "Skin változtatás sikertelen: %s", "skinrestorer.command.skin.ok": "Skin megváltoztatva", - "skinrestorer.command.skin.loading": "Skin betöltése..." + "skinrestorer.command.skin.loading": "Skin betöltése...", + "skinrestorer.command.skin.config_reloaded": "A konfiguráció újratöltve" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/id_id.json b/common/src/main/resources/assets/skinrestorer/lang/id_id.json index fb40ed9..bd7dd3c 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/id_id.json +++ b/common/src/main/resources/assets/skinrestorer/lang/id_id.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "Tidak ada perubahan skin", "skinrestorer.command.skin.failed": "Gagal mengubah skin: %s", "skinrestorer.command.skin.ok": "Skin diubah", - "skinrestorer.command.skin.loading": "Memuat skin..." + "skinrestorer.command.skin.loading": "Memuat skin...", + "skinrestorer.command.skin.config_reloaded": "Konfigurasi telah dimuat ulang" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/it_it.json b/common/src/main/resources/assets/skinrestorer/lang/it_it.json index 9f646b7..ef4221a 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/it_it.json +++ b/common/src/main/resources/assets/skinrestorer/lang/it_it.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "Nessuna modifica alla skin", "skinrestorer.command.skin.failed": "Impossibile cambiare la skin: %s", "skinrestorer.command.skin.ok": "Skin cambiata", - "skinrestorer.command.skin.loading": "Caricamento della skin..." + "skinrestorer.command.skin.loading": "Caricamento della skin...", + "skinrestorer.command.skin.config_reloaded": "La configurazione è stata ricaricata" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/pl_pl.json b/common/src/main/resources/assets/skinrestorer/lang/pl_pl.json index d42cf0d..e51dfae 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/pl_pl.json +++ b/common/src/main/resources/assets/skinrestorer/lang/pl_pl.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "Brak zmian skina", "skinrestorer.command.skin.failed": "Nie udało się zmienić skina: %s", "skinrestorer.command.skin.ok": "Skin zmieniony", - "skinrestorer.command.skin.loading": "Ładowanie skina..." + "skinrestorer.command.skin.loading": "Ładowanie skina...", + "skinrestorer.command.skin.config_reloaded": "Konfiguracja została przeładowana" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/pt_br.json b/common/src/main/resources/assets/skinrestorer/lang/pt_br.json index 60d0f17..c1c98dd 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/pt_br.json +++ b/common/src/main/resources/assets/skinrestorer/lang/pt_br.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "Nenhuma alteração de skin", "skinrestorer.command.skin.failed": "Falha ao alterar a skin: %s", "skinrestorer.command.skin.ok": "Skin alterada", - "skinrestorer.command.skin.loading": "Carregando skin..." + "skinrestorer.command.skin.loading": "Carregando skin...", + "skinrestorer.command.skin.config_reloaded": "Configuração recarregada" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/pt_pt.json b/common/src/main/resources/assets/skinrestorer/lang/pt_pt.json index 60d0f17..c1c98dd 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/pt_pt.json +++ b/common/src/main/resources/assets/skinrestorer/lang/pt_pt.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "Nenhuma alteração de skin", "skinrestorer.command.skin.failed": "Falha ao alterar a skin: %s", "skinrestorer.command.skin.ok": "Skin alterada", - "skinrestorer.command.skin.loading": "Carregando skin..." + "skinrestorer.command.skin.loading": "Carregando skin...", + "skinrestorer.command.skin.config_reloaded": "Configuração recarregada" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/ru_ru.json b/common/src/main/resources/assets/skinrestorer/lang/ru_ru.json index 41b42b3..dd97624 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/ru_ru.json +++ b/common/src/main/resources/assets/skinrestorer/lang/ru_ru.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "Изменений скина нет", "skinrestorer.command.skin.failed": "Не удалось изменить скин: %s", "skinrestorer.command.skin.ok": "Скин изменён", - "skinrestorer.command.skin.loading": "Загрузка скина..." + "skinrestorer.command.skin.loading": "Загрузка скина...", + "skinrestorer.command.skin.config_reloaded": "Конфигурация была перезагружена" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/tr_tr.json b/common/src/main/resources/assets/skinrestorer/lang/tr_tr.json index e0e34c5..6e2b60d 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/tr_tr.json +++ b/common/src/main/resources/assets/skinrestorer/lang/tr_tr.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "Skin değişikliği yok", "skinrestorer.command.skin.failed": "Skin değiştirme başarısız: %s", "skinrestorer.command.skin.ok": "Skin değiştirildi", - "skinrestorer.command.skin.loading": "Skin yükleniyor..." + "skinrestorer.command.skin.loading": "Skin yükleniyor...", + "skinrestorer.command.skin.config_reloaded": "Yapılandırma yeniden yüklendi" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/uk_ua.json b/common/src/main/resources/assets/skinrestorer/lang/uk_ua.json index 48f3bfc..4085e6f 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/uk_ua.json +++ b/common/src/main/resources/assets/skinrestorer/lang/uk_ua.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "Змін скіна немає", "skinrestorer.command.skin.failed": "Не вдалося змінити скіна: %s", "skinrestorer.command.skin.ok": "Скін змінено", - "skinrestorer.command.skin.loading": "Завантаження скіна..." + "skinrestorer.command.skin.loading": "Завантаження скіна...", + "skinrestorer.command.skin.config_reloaded": "Конфігурацію перезавантажено" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/vi_vn.json b/common/src/main/resources/assets/skinrestorer/lang/vi_vn.json index 930b7ea..233d04d 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/vi_vn.json +++ b/common/src/main/resources/assets/skinrestorer/lang/vi_vn.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "Không có thay đổi skin", "skinrestorer.command.skin.failed": "Thay đổi skin thất bại: %s", "skinrestorer.command.skin.ok": "Đã thay đổi skin", - "skinrestorer.command.skin.loading": "Đang tải skin..." + "skinrestorer.command.skin.loading": "Đang tải skin...", + "skinrestorer.command.skin.config_reloaded": "Cấu hình đã được tải lại" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/zh_cn.json b/common/src/main/resources/assets/skinrestorer/lang/zh_cn.json index 2534dcb..1e01e20 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/zh_cn.json +++ b/common/src/main/resources/assets/skinrestorer/lang/zh_cn.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "没有皮肤更改", "skinrestorer.command.skin.failed": "更改皮肤失败:%s", "skinrestorer.command.skin.ok": "皮肤已更改", - "skinrestorer.command.skin.loading": "正在加载皮肤..." + "skinrestorer.command.skin.loading": "正在加载皮肤...", + "skinrestorer.command.skin.config_reloaded": "配置已重新加载" } diff --git a/common/src/main/resources/assets/skinrestorer/lang/zh_tw.json b/common/src/main/resources/assets/skinrestorer/lang/zh_tw.json index 3441d39..394080e 100644 --- a/common/src/main/resources/assets/skinrestorer/lang/zh_tw.json +++ b/common/src/main/resources/assets/skinrestorer/lang/zh_tw.json @@ -3,5 +3,6 @@ "skinrestorer.command.skin.no_changes": "沒有外觀變更", "skinrestorer.command.skin.failed": "變更外觀失敗:%s", "skinrestorer.command.skin.ok": "已變更外觀", - "skinrestorer.command.skin.loading": "正在載入外觀..." + "skinrestorer.command.skin.loading": "正在載入外觀...", + "skinrestorer.command.skin.config_reloaded": "配置已重新載入" } diff --git a/common/src/main/resources/skinrestorer.mixins.json b/common/src/main/resources/skinrestorer.mixins.json index 19ef52f..a452f3b 100644 --- a/common/src/main/resources/skinrestorer.mixins.json +++ b/common/src/main/resources/skinrestorer.mixins.json @@ -8,7 +8,7 @@ "PlayerListMixin", "ServerLoginPacketListenerImplMixin", "ChunkMapAccessor", - "TrackedEntityMixin" + "TrackedEntityAccessorInvoker" ], "injectors": { "defaultRequire": 1 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 7998314..906896e 100644 --- a/fabric/src/main/java/net/lionarius/skinrestorer/fabric/SkinRestorerFabric.java +++ b/fabric/src/main/java/net/lionarius/skinrestorer/fabric/SkinRestorerFabric.java @@ -1,12 +1,11 @@ package net.lionarius.skinrestorer.fabric; import net.fabricmc.api.ModInitializer; -import net.fabricmc.loader.api.FabricLoader; import net.lionarius.skinrestorer.SkinRestorer; public final class SkinRestorerFabric implements ModInitializer { @Override public void onInitialize() { - SkinRestorer.onInitialize(FabricLoader.getInstance().getConfigDir()); + SkinRestorer.onInitialize(); } } diff --git a/fabric/src/main/java/net/lionarius/skinrestorer/fabric/platform/FabricPlatformHelper.java b/fabric/src/main/java/net/lionarius/skinrestorer/fabric/platform/FabricPlatformHelper.java new file mode 100644 index 0000000..852603c --- /dev/null +++ b/fabric/src/main/java/net/lionarius/skinrestorer/fabric/platform/FabricPlatformHelper.java @@ -0,0 +1,23 @@ +package net.lionarius.skinrestorer.fabric.platform; + +import net.fabricmc.loader.api.FabricLoader; +import net.lionarius.skinrestorer.platform.services.PlatformHelper; + +import java.nio.file.Path; + +public final class FabricPlatformHelper implements PlatformHelper { + @Override + public String getPlatformName() { + return "fabric"; + } + + @Override + public boolean isModLoaded(String modId) { + return FabricLoader.getInstance().isModLoaded(modId); + } + + @Override + public Path getConfigDirectory() { + return FabricLoader.getInstance().getConfigDir(); + } +} diff --git a/fabric/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.PlatformHelper b/fabric/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.PlatformHelper new file mode 100644 index 0000000..f115117 --- /dev/null +++ b/fabric/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.PlatformHelper @@ -0,0 +1 @@ +net.lionarius.skinrestorer.fabric.platform.FabricPlatformHelper 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 819f339..5a0d03d 100644 --- a/forge/src/main/java/net/lionarius/skinrestorer/forge/SkinRestorerForge.java +++ b/forge/src/main/java/net/lionarius/skinrestorer/forge/SkinRestorerForge.java @@ -7,7 +7,6 @@ import net.minecraftforge.event.RegisterCommandsEvent; import net.minecraftforge.event.server.ServerStartedEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.loading.FMLPaths; @Mod(SkinRestorer.MOD_ID) @Mod.EventBusSubscriber(modid = SkinRestorer.MOD_ID) @@ -16,7 +15,7 @@ public final class SkinRestorerForge { public SkinRestorerForge() { MinecraftForge.EVENT_BUS.register(SkinRestorerForge.class); - SkinRestorer.onInitialize(FMLPaths.CONFIGDIR.get()); + SkinRestorer.onInitialize(); } @SubscribeEvent diff --git a/forge/src/main/java/net/lionarius/skinrestorer/forge/platform/ForgePlatformHelper.java b/forge/src/main/java/net/lionarius/skinrestorer/forge/platform/ForgePlatformHelper.java new file mode 100644 index 0000000..43f3c90 --- /dev/null +++ b/forge/src/main/java/net/lionarius/skinrestorer/forge/platform/ForgePlatformHelper.java @@ -0,0 +1,24 @@ +package net.lionarius.skinrestorer.forge.platform; + +import net.lionarius.skinrestorer.platform.services.PlatformHelper; +import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.loading.FMLPaths; + +import java.nio.file.Path; + +public final class ForgePlatformHelper implements PlatformHelper { + @Override + public String getPlatformName() { + return "forge"; + } + + @Override + public boolean isModLoaded(String modId) { + return ModList.get().isLoaded(modId); + } + + @Override + public Path getConfigDirectory() { + return FMLPaths.CONFIGDIR.get(); + } +} diff --git a/forge/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.PlatformHelper b/forge/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.PlatformHelper new file mode 100644 index 0000000..9f6dfae --- /dev/null +++ b/forge/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.PlatformHelper @@ -0,0 +1 @@ +net.lionarius.skinrestorer.forge.platform.ForgePlatformHelper diff --git a/gradle.properties b/gradle.properties index 84772a9..1e1cf40 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,3 @@ -# Important Notes: -# Every field you add must be added to the root build.gradle expandProps map. - # Project group=net.lionarius.skinrestorer java_version=17 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 aae33c0..54bd1ba 100644 --- a/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/SkinRestorerNeoForge.java +++ b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/SkinRestorerNeoForge.java @@ -4,7 +4,6 @@ import net.lionarius.skinrestorer.SkinRestorer; import net.lionarius.skinrestorer.command.SkinCommand; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.Mod; -import net.neoforged.fml.loading.FMLPaths; import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.event.RegisterCommandsEvent; import net.neoforged.neoforge.event.server.ServerStartedEvent; @@ -16,7 +15,7 @@ public final class SkinRestorerNeoForge { public SkinRestorerNeoForge() { NeoForge.EVENT_BUS.register(SkinRestorerNeoForge.class); - SkinRestorer.onInitialize(FMLPaths.CONFIGDIR.get()); + SkinRestorer.onInitialize(); } @SubscribeEvent diff --git a/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/platform/NeoForgePlatformHelper.java b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/platform/NeoForgePlatformHelper.java new file mode 100644 index 0000000..9164d44 --- /dev/null +++ b/neoforge/src/main/java/net/lionarius/skinrestorer/neoforge/platform/NeoForgePlatformHelper.java @@ -0,0 +1,24 @@ +package net.lionarius.skinrestorer.neoforge.platform; + +import net.lionarius.skinrestorer.platform.services.PlatformHelper; +import net.neoforged.fml.ModList; +import net.neoforged.fml.loading.FMLPaths; + +import java.nio.file.Path; + +public final class NeoForgePlatformHelper implements PlatformHelper { + @Override + public String getPlatformName() { + return "neoforge"; + } + + @Override + public boolean isModLoaded(String modId) { + return ModList.get().isLoaded(modId); + } + + @Override + public Path getConfigDirectory() { + return FMLPaths.CONFIGDIR.get(); + } +} diff --git a/neoforge/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.PlatformHelper b/neoforge/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.PlatformHelper new file mode 100644 index 0000000..c8335f2 --- /dev/null +++ b/neoforge/src/main/resources/META-INF/services/net.lionarius.skinrestorer.platform.services.PlatformHelper @@ -0,0 +1 @@ +net.lionarius.skinrestorer.neoforge.platform.NeoForgePlatformHelper