diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml
new file mode 100644
index 0000000..0bbbc3b
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yaml
@@ -0,0 +1,88 @@
+name: Bug Report
+description: Report a bug encountered with SkinRestorer
+title: "[Bug]: "
+labels: ["bug"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ 🐛 **Before submitting:**
+ - Ensure you're using the latest mod version
+ - Ensure this bug is reproducible consistently
+ - Check existing issues for duplicates
+
+ - type: input
+ id: mod-version
+ attributes:
+ label: SkinRestorer Version
+ description: Exact version of the mod
+ placeholder: e.g., 2.2.1
+ validations:
+ required: true
+
+ - type: input
+ id: minecraft-version
+ attributes:
+ label: Minecraft Version
+ description: Full Minecraft version
+ placeholder: e.g., 1.21.4
+ validations:
+ required: true
+
+ - type: input
+ id: loader-version
+ attributes:
+ label: Mod Loader & Version
+ description: Fabric/Quilt/Forge/NeoForge version
+ placeholder: e.g., Fabric 0.15.7
+ validations:
+ required: true
+
+ - type: input
+ id: java-version
+ attributes:
+ label: Java Version
+ placeholder: e.g. 17, 21
+ validations:
+ required: true
+
+ - type: textarea
+ id: description
+ attributes:
+ label: Bug Description
+ description: What happened vs what you expected to happen
+ validations:
+ required: true
+
+ - type: textarea
+ id: steps
+ attributes:
+ label: Reproduction Steps
+ placeholder: |
+ 1.
+ 2.
+ 3.
+ validations:
+ required: true
+
+ - type: textarea
+ id: logs
+ attributes:
+ label: Relevant Logs
+ description: |
+ Please provide any relevant logs, especially error logs from your server console or `latest.log` file.
+ **Important**: Paste the FULL log content. Use a service like [mclo.gs](https://mclo.gs/).
+ render: shell
+ validations:
+ required: true
+
+ - type: checkboxes
+ id: confirmations
+ attributes:
+ label: Confirmations
+ options:
+ - label: I've checked for existing issues
+ required: true
+ - label: This bug is reproducible consistently
+ required: true
+ - label: I've tested without other mods
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..0086358
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1 @@
+blank_issues_enabled: true
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml
new file mode 100644
index 0000000..0e9351e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yaml
@@ -0,0 +1,52 @@
+name: Feature Request
+description: Suggest a new feature for SkinRestorer
+title: "[Feature Request]: "
+labels: ["enhancement"]
+body:
+ - type: markdown
+ attributes:
+ value: |
+ 💡 **Before submitting:**
+ - Check existing feature requests for duplicates
+ - Be clear and concise
+ - Explain the *why* and the *how*
+
+ - type: textarea
+ id: description
+ attributes:
+ label: Feature Description
+ description: Detailed description of the feature
+ validations:
+ required: true
+
+ - type: textarea
+ id: motivation
+ attributes:
+ label: Motivation
+ description: Why is this feature needed? What problem does it solve?
+ validations:
+ required: true
+
+ - type: textarea
+ id: use-cases
+ attributes:
+ label: Use Cases
+ description: How would this feature be used and who would benefit?
+ validations:
+ required: true
+
+ - type: textarea
+ id: implementation-ideas
+ attributes:
+ label: Implementation Ideas (Optional)
+ description: Any thoughts on how it could be implemented?
+ validations:
+ required: false
+
+ - type: checkboxes
+ id: confirmations
+ attributes:
+ label: Confirmations
+ options:
+ - label: I've checked for existing feature requests
+ required: true
diff --git a/README.md b/README.md
index 50063e2..a7b6af3 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# SkinRestorer
-
-
+
+
A server-side mod for managing and restoring player skins.
@@ -33,7 +33,9 @@ the [commands wiki page](https://github.com/Suiranoil/SkinRestorer/wiki/Commands
If you enjoy using **SkinRestorer** and would like to support its development, you can contribute through the following
platforms:
-[](https://ko-fi.com/lionarius)
+
+
+
Bitcoin (BTC): `1Ndbwny8pxdnWXFgadp95fp97y5JqMJKTX`
USDT (TRC20): `TGXn8wrqku5KLzwPWQAeH7wgnV4UzwHEae`
diff --git a/build.gradle b/build.gradle
index c3dc515..36f20ad 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,15 +1,15 @@
plugins {
// see https://fabricmc.net/develop/ for new versions
- 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
+ id 'fabric-loom' version '1.10-SNAPSHOT' apply false
+ // see https://projects.neoforged.net/neoforged/moddevgradle for new versions
+ id 'net.neoforged.moddev' version '2.0.80' apply false
// see https://files.minecraftforge.net/net/minecraftforge/gradle/ForgeGradle/ for new versions
- id 'net.minecraftforge.gradle' version '6.0.29' apply false
+ id 'net.minecraftforge.gradle' version '6.0.35' apply false
id 'org.parchmentmc.librarian.forgegradle' version '1.+' apply false
id 'org.spongepowered.mixin' version '0.7-SNAPSHOT' apply false
- id 'me.modmuss50.mod-publish-plugin' version '0.8.1' apply false
+ id 'me.modmuss50.mod-publish-plugin' version '0.8.4' apply false
}
allprojects {
diff --git a/buildSrc/src/main/groovy/multiloader-publish.gradle b/buildSrc/src/main/groovy/multiloader-publish.gradle
index f759713..8058a7a 100644
--- a/buildSrc/src/main/groovy/multiloader-publish.gradle
+++ b/buildSrc/src/main/groovy/multiloader-publish.gradle
@@ -5,6 +5,8 @@ plugins {
publishMods {
if (project.name == 'fabric')
file = remapJar.archiveFile
+ else if (project.name == 'neoforge')
+ file = jar.archiveFile
else
file = tasks.named('jarJar').get().archiveFile
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 abd80df..8dd93ea 100644
--- a/common/src/main/java/net/lionarius/skinrestorer/command/SkinCommand.java
+++ b/common/src/main/java/net/lionarius/skinrestorer/command/SkinCommand.java
@@ -34,7 +34,7 @@ public final class SkinCommand {
private SkinCommand() {}
public static void register(CommandDispatcher dispatcher) {
- LiteralArgumentBuilder base =
+ var base =
literal("skin")
.then(buildSetSubcommand("clear", SkinValue.EMPTY::toProviderContext))
.then(literal("reset")
@@ -44,7 +44,7 @@ public final class SkinCommand {
)))
.then(literal("refresh").executes(context -> refreshSubcommand(context.getSource())));
- LiteralArgumentBuilder set = literal("set");
+ var set = literal("set");
var providers = SkinRestorer.getProvidersRegistry().getPublicProviders();
for (var entry : providers)
@@ -92,7 +92,7 @@ public final class SkinCommand {
Collection targets,
boolean setByOperator
) {
- Collection updatedPlayers = new HashSet<>();
+ var updatedPlayers = new HashSet();
for (var profile : targets) {
SkinValue skin = null;
if (SkinRestorer.getSkinStorage().hasSavedSkin(profile.getId()))
@@ -199,7 +199,7 @@ public final class SkinCommand {
}
private static LiteralArgumentBuilder buildSetSubcommand(String name, SkinProvider provider) {
- LiteralArgumentBuilder action = literal(name);
+ var action = literal(name);
if (provider.hasVariantSupport()) {
for (SkinVariant variant : SkinVariant.values()) {
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 b535f0f..5c07460 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
@@ -5,6 +5,7 @@ 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.lionarius.skinrestorer.util.ServerUtils;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
@@ -40,7 +41,7 @@ public class SkinShuffleCompatibility {
if (!property.hasSignature())
return;
- server.execute(() -> {
+ ServerUtils.scheduleServerTask(server, () -> {
SkinRestorer.applySkin(
server,
Collections.singleton(player.getGameProfile()),
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 c22f6bc..d8acb49 100644
--- a/common/src/main/java/net/lionarius/skinrestorer/config/Config.java
+++ b/common/src/main/java/net/lionarius/skinrestorer/config/Config.java
@@ -18,6 +18,8 @@ public final class Config implements GsonPostProcessable {
private boolean refreshSkinOnJoin = true;
+ private int skinApplyDelayOnJoin = 0;
+
private boolean fetchSkinOnFirstJoin = true;
private FirstJoinSkinProvider firstJoinSkinProvider = FirstJoinSkinProvider.MOJANG;
@@ -37,6 +39,10 @@ public final class Config implements GsonPostProcessable {
return this.refreshSkinOnJoin;
}
+ public int skinApplyDelayOnJoin() {
+ return this.skinApplyDelayOnJoin;
+ }
+
public boolean fetchSkinOnFirstJoin() {
return this.fetchSkinOnFirstJoin;
}
@@ -82,6 +88,11 @@ public final class Config implements GsonPostProcessable {
this.language = "en_us";
}
+ if (this.skinApplyDelayOnJoin < 0) {
+ SkinRestorer.LOGGER.warn("SkinApplyDelayOnJoin config is less than 0, defaulting to 0");
+ this.skinApplyDelayOnJoin = 0;
+ }
+
if (this.firstJoinSkinProvider == null) {
SkinRestorer.LOGGER.warn("FirstJoinSkinProvider config is null, defaulting to MOJANG");
this.firstJoinSkinProvider = FirstJoinSkinProvider.MOJANG;
diff --git a/common/src/main/java/net/lionarius/skinrestorer/config/provider/BuiltInProviderConfig.java b/common/src/main/java/net/lionarius/skinrestorer/config/provider/BuiltInProviderConfig.java
index 198e9f1..c27e84c 100644
--- a/common/src/main/java/net/lionarius/skinrestorer/config/provider/BuiltInProviderConfig.java
+++ b/common/src/main/java/net/lionarius/skinrestorer/config/provider/BuiltInProviderConfig.java
@@ -1,10 +1,42 @@
package net.lionarius.skinrestorer.config.provider;
-public interface BuiltInProviderConfig {
+import net.lionarius.skinrestorer.SkinRestorer;
+import net.lionarius.skinrestorer.util.gson.GsonPostProcessable;
- boolean enabled();
-
- String name();
-
- CacheConfig cache();
+public abstract class BuiltInProviderConfig implements GsonPostProcessable {
+ protected boolean enabled;
+ protected String name;
+ protected CacheConfig cache;
+
+ public BuiltInProviderConfig(String name, CacheConfig cache) {
+ this.enabled = true;
+ this.name = name;
+ this.cache = cache;
+ }
+
+ public boolean enabled() {
+ return enabled;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public CacheConfig cache() {
+ return cache;
+ }
+
+ protected void validate(String defaultName, CacheConfig defaultCache) {
+ if (this.name == null || this.name.isEmpty()) {
+ SkinRestorer.LOGGER.warn("Provider name is null or empty, defaulting to '{}'", defaultName);
+ this.name = defaultName;
+ }
+
+ if (this.cache == null) {
+ SkinRestorer.LOGGER.warn("Provider cache is null, using default");
+ this.cache = defaultCache;
+ } else {
+ this.cache.validate(defaultCache);
+ }
+ }
}
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
index c36caf8..e4a5dfa 100644
--- a/common/src/main/java/net/lionarius/skinrestorer/config/provider/ElyByProviderConfig.java
+++ b/common/src/main/java/net/lionarius/skinrestorer/config/provider/ElyByProviderConfig.java
@@ -1,46 +1,16 @@
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 {
+public final class ElyByProviderConfig extends BuiltInProviderConfig {
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;
+ super(ElyBySkinProvider.PROVIDER_NAME, DEFAULT_CACHE_VALUE);
}
@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);
- }
+ super.validate(ElyBySkinProvider.PROVIDER_NAME, 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
index b12ed30..ee7c05b 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
@@ -2,52 +2,25 @@ 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 {
+public final class MineskinProviderConfig extends BuiltInProviderConfig {
private static final CacheConfig DEFAULT_CACHE_VALUE = new CacheConfig(true, 300);
- private boolean enabled;
- private String name;
- private CacheConfig cache;
private String apiKey;
public MineskinProviderConfig() {
- this.enabled = true;
- this.name = MineskinSkinProvider.PROVIDER_NAME;
- this.cache = DEFAULT_CACHE_VALUE;
+ super(MineskinSkinProvider.PROVIDER_NAME, DEFAULT_CACHE_VALUE);
+
this.apiKey = "";
}
- public boolean enabled() {
- return enabled;
- }
-
- public String name() {
- return name;
- }
-
- public CacheConfig cache() {
- return cache;
- }
-
public String apiKey() {
return apiKey;
}
@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);
- }
+ super.validate(MineskinSkinProvider.PROVIDER_NAME, DEFAULT_CACHE_VALUE);
if (this.apiKey == null) {
SkinRestorer.LOGGER.warn("Mineskin API key is null, defaulting to an empty string");
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
index 625a55e..20da780 100644
--- a/common/src/main/java/net/lionarius/skinrestorer/config/provider/MojangProviderConfig.java
+++ b/common/src/main/java/net/lionarius/skinrestorer/config/provider/MojangProviderConfig.java
@@ -1,46 +1,16 @@
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 {
+public final class MojangProviderConfig extends BuiltInProviderConfig {
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;
+ super(MojangSkinProvider.PROVIDER_NAME, DEFAULT_CACHE_VALUE);
}
@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);
- }
+ super.validate(MojangSkinProvider.PROVIDER_NAME, DEFAULT_CACHE_VALUE);
}
}
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 ec1f02e..4b02ac5 100644
--- a/common/src/main/java/net/lionarius/skinrestorer/mixin/PlayerListMixin.java
+++ b/common/src/main/java/net/lionarius/skinrestorer/mixin/PlayerListMixin.java
@@ -1,6 +1,7 @@
package net.lionarius.skinrestorer.mixin;
import net.lionarius.skinrestorer.SkinRestorer;
+import net.lionarius.skinrestorer.util.ServerUtils;
import net.minecraft.network.Connection;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
@@ -9,6 +10,7 @@ import net.minecraft.server.players.PlayerList;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@@ -39,6 +41,22 @@ public abstract class PlayerListMixin {
@Inject(method = "placeNewPlayer", at = @At("HEAD"))
private void placeNewPlayer(Connection connection, ServerPlayer player, CommonListenerCookie cookie, CallbackInfo ci) {
+ var delay = SkinRestorer.getConfig().skinApplyDelayOnJoin();
+ var uuid = player.getUUID();
+
+ if (delay <= 0) {
+ skinrestorer$tryApplySkin(server, player);
+ } else {
+ ServerUtils.scheduleServerTask(server, () -> {
+ var actualPlayer = server.getPlayerList().getPlayer(uuid);
+ if (actualPlayer != null)
+ skinrestorer$tryApplySkin(server, actualPlayer);
+ }, delay);
+ }
+ }
+
+ @Unique
+ private static void skinrestorer$tryApplySkin(MinecraftServer server, ServerPlayer player) {
if (SkinRestorer.getSkinStorage().hasSavedSkin(player.getUUID()))
SkinRestorer.applySkin(server, Collections.singleton(player.getGameProfile()), SkinRestorer.getSkinStorage().getSkin(player.getUUID()));
}
diff --git a/common/src/main/java/net/lionarius/skinrestorer/util/ServerUtils.java b/common/src/main/java/net/lionarius/skinrestorer/util/ServerUtils.java
new file mode 100644
index 0000000..a93de78
--- /dev/null
+++ b/common/src/main/java/net/lionarius/skinrestorer/util/ServerUtils.java
@@ -0,0 +1,37 @@
+package net.lionarius.skinrestorer.util;
+
+import net.minecraft.server.MinecraftServer;
+
+import java.util.function.Consumer;
+
+public class ServerUtils {
+
+ private ServerUtils() {}
+
+ public static void scheduleServerTask(MinecraftServer server, Consumer task) {
+ ServerUtils.scheduleServerTask(server, task, 0);
+ }
+
+ public static void scheduleServerTask(MinecraftServer server, Runnable task) {
+ ServerUtils.scheduleServerTask(server, task, 0);
+ }
+
+ public static void scheduleServerTask(MinecraftServer server, Consumer task, int tickDelay) {
+ server.execute(new ScheduledTickTask(server, task, server.getTickCount() + tickDelay));
+ }
+
+ public static void scheduleServerTask(MinecraftServer server, Runnable task, int tickDelay) {
+ server.execute(new ScheduledTickTask(server, _server -> task.run(), server.getTickCount() + tickDelay));
+ }
+
+ public record ScheduledTickTask(MinecraftServer server, Consumer task,
+ int tickTarget) implements Runnable {
+ @Override
+ public void run() {
+ if (this.server.getTickCount() >= this.tickTarget)
+ this.task.accept(this.server);
+ else
+ this.server.execute(this);
+ }
+ }
+}
diff --git a/forge/build.gradle b/forge/build.gradle
index 094cc7f..3d033c9 100644
--- a/forge/build.gradle
+++ b/forge/build.gradle
@@ -40,7 +40,7 @@ minecraft {
runs {
client {
- workingDirectory file('../run/client')
+ workingDirectory rootProject.file('run/client')
ideaModule "${rootProject.name}.${project.name}.main"
taskName 'Client'
mods {
@@ -51,7 +51,7 @@ minecraft {
}
server {
- workingDirectory file('../run/server')
+ workingDirectory rootProject.file('run/server')
ideaModule "${rootProject.name}.${project.name}.main"
taskName 'Server'
mods {
diff --git a/gradle.properties b/gradle.properties
index 2bb9776..3371ce2 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -17,6 +17,7 @@ license=MIT
credits=
description=A server-side mod for managing skins.
+# Dependencies
mineskin_client_version=3.0.1-SNAPSHOT
# ParchmentMC mappings, see https://parchmentmc.org/docs/getting-started#choose-a-version for new versions
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 9355b41..e18bc25 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.10-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
diff --git a/gradlew b/gradlew
index f5feea6..f3b75f3 100644
--- a/gradlew
+++ b/gradlew
@@ -86,8 +86,7 @@ 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 -P "${APP_HOME:-./}" > /dev/null && printf '%s
-' "$PWD" ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
diff --git a/neoforge/build.gradle b/neoforge/build.gradle
index 872c927..72eb58a 100644
--- a/neoforge/build.gradle
+++ b/neoforge/build.gradle
@@ -3,56 +3,58 @@ plugins {
id 'idea'
id 'eclipse'
- id 'net.neoforged.gradle.userdev'
+ id 'net.neoforged.moddev'
id 'multiloader-publish'
}
-// Automatically enable neoforge AccessTransformers if the file exists
-def at = project(':common').file('src/main/resources/META-INF/accesstransformer.cfg')
-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},)")
+neoForge {
+ version = neoforge_version
+
+ // Automatically enable neoforge AccessTransformers if the file exists
+ def at = project(':common').file('src/main/resources/META-INF/accesstransformer.cfg')
+ if (at.exists()) {
+ minecraft.accessTransformers.file(at)
}
-}
-subsystems {
parchment {
minecraftVersion = parchment_minecraft
mappingsVersion = parchment_version
}
-}
-runs {
- configureEach {
- modSource project.sourceSets.main
- systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id
+ runs {
+ configureEach {
+ ideName = "NeoForge ${it.name.capitalize()} (${project.path})" // Unify the run config names with fabric
+ }
+
+ client {
+ client()
+ gameDirectory = rootProject.file('run/client')
+ }
+
+ server {
+ server()
+ programArgument '--nogui'
+ gameDirectory = rootProject.file('run/server')
+ }
}
- client {
- workingDirectory = file('../run/client')
- }
-
- server {
- programArgument '--nogui'
- workingDirectory = file('../run/server')
+ mods {
+ "${mod_id}" {
+ sourceSet sourceSets.main
+ }
}
}
+
+dependencies {
+ implementation "net.neoforged:neoforge:${neoforge_version}"
+
+ jarJar(implementation('org.mineskin:java-client')) {
+ version {
+ strictly "[${mineskin_client_version},)"
+ prefer mineskin_client_version
+ }
+ }
+
+ additionalRuntimeClasspath "org.mineskin:java-client:${mineskin_client_version}"
+}