From 6c2e9d027da24a2ff59ae2ee82eb8763546f1740 Mon Sep 17 00:00:00 2001 From: PT400C Jomcraft Date: Sun, 5 Oct 2025 14:10:24 +0200 Subject: [PATCH 1/6] Initial update of NeoForge to `1.21.9` --- .github/workflows/build.yml | 14 +- .github/workflows/publish.yml | 14 +- .gitignore | 31 +- build.gradle | 6 +- changelog.html | 7 +- gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle | 8 +- sources/Core | 2 +- .../defaultsettings/FabricCoreHook.java | 5 + sources/Forge-1.20.6/build.gradle | 2 +- .../defaultsettings/ForgeCoreHook.java | 5 + sources/Forge-1.20/build.gradle | 2 +- .../defaultsettings/ForgeCoreHook.java | 5 + sources/NeoForge-1.20.2/build.gradle | 2 +- .../defaultsettings/NeoForgeCoreHook.java | 5 + .../defaultsettings/mixin/MinecraftMixin.java | 15 + .../resources/META-INF/accesstransformer.cfg | 1 + .../src/main/resources/META-INF/mods.toml | 29 ++ .../main/resources/defaultsettings.mixin.json | 15 + .../defaultsettings/DefaultSettings.java | 287 ++++++++++++++++++ .../defaultsettings/EventHandlers.java | 13 + .../jomcraft/defaultsettings/FileUtil.java | 182 +++++++++++ .../defaultsettings/KeyContainer.java | 16 + .../defaultsettings/NeoForgeCoreHook.java | 190 ++++++++++++ .../commands/CommandDefaultSettings.java | 51 ++++ .../commands/ConfigArguments.java | 118 +++++++ .../commands/OperationArguments.java | 92 ++++++ .../commands/TypeArguments.java | 83 +++++ .../defaultsettings/mixin/MinecraftMixin.java | 15 + .../resources/META-INF/accesstransformer.cfg | 1 + .../src/main/resources/META-INF/mods.toml | 29 ++ .../resources/META-INF/neoforge.mods.toml | 29 ++ .../main/resources/defaultsettings.mixin.json | 15 + .../src/main/resources/logo.png | Bin 0 -> 51342 bytes .../src/main/resources/pack.mcmeta | 8 + 35 files changed, 1276 insertions(+), 23 deletions(-) create mode 100644 sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/mixin/MinecraftMixin.java create mode 100644 sources/NeoForge-1.21.5/src/main/resources/META-INF/accesstransformer.cfg create mode 100644 sources/NeoForge-1.21.5/src/main/resources/META-INF/mods.toml create mode 100644 sources/NeoForge-1.21.5/src/main/resources/defaultsettings.mixin.json create mode 100644 sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java create mode 100644 sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/EventHandlers.java create mode 100644 sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/FileUtil.java create mode 100644 sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/KeyContainer.java create mode 100644 sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/NeoForgeCoreHook.java create mode 100644 sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/commands/CommandDefaultSettings.java create mode 100644 sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/commands/ConfigArguments.java create mode 100644 sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/commands/OperationArguments.java create mode 100644 sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/commands/TypeArguments.java create mode 100644 sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/mixin/MinecraftMixin.java create mode 100644 sources/NeoForge-1.21.9/src/main/resources/META-INF/accesstransformer.cfg create mode 100644 sources/NeoForge-1.21.9/src/main/resources/META-INF/mods.toml create mode 100644 sources/NeoForge-1.21.9/src/main/resources/META-INF/neoforge.mods.toml create mode 100644 sources/NeoForge-1.21.9/src/main/resources/defaultsettings.mixin.json create mode 100644 sources/NeoForge-1.21.9/src/main/resources/logo.png create mode 100644 sources/NeoForge-1.21.9/src/main/resources/pack.mcmeta diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9456f86e..c0cebb94 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,23 +7,25 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 with: submodules: recursive token: ${{ secrets.PAT_TOKEN }} - - name: Set up JDK 17 - uses: actions/setup-java@v2 + - name: Set up JDK 21 + uses: actions/setup-java@v5 with: - java-version: '17' + java-version: | + 16 + 21 distribution: 'adopt' cache: gradle - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Validate Gradle wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/actions/wrapper-validation@v3 - name: Build with Gradle run: ./gradlew build copyRelease - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: 'Prebuilt Artifacts' path: build/libs diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 56b1978d..ce5ff3b6 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -18,20 +18,22 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 with: submodules: recursive token: ${{ secrets.PAT_TOKEN }} - - name: Set up JDK 17 - uses: actions/setup-java@v2 + - name: Set up JDK 21 + uses: actions/setup-java@v5 with: - java-version: '17' + java-version: | + 16 + 21 distribution: 'adopt' cache: gradle - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Validate Gradle wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/actions/wrapper-validation@v3 - name: Build with Gradle and publish all editions if: ${{ github.event.inputs.publish-all == 'true' }} run: ./gradlew build publishCurseForge copyRelease @@ -42,7 +44,7 @@ jobs: run: ./gradlew :${{ github.event.inputs.publish-edition }}:build :${{ github.event.inputs.publish-edition }}:publishCurseForge :${{ github.event.inputs.publish-edition }}:copyRelease env: CURSE_API: ${{ secrets.CURSE_API }} - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: 'Prebuilt Artifacts' path: build/libs \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1ff38fb8..aa11f7bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,35 @@ /* /*/ -!/sources/ +!/sources/Core/src/ +!/sources/Core/.gitignore +!/sources/Core/build.gradle +!/sources/Core/gradle.properties +!/sources/Core/LICENSE +!/sources/Core/README.md + +!/sources/Fabric-1.20/src/ +!/sources/Fabric-1.20/build.gradle +!/sources/Fabric-1.20/gradle.properties + +!/sources/Forge-1.20/src/ +!/sources/Forge-1.20/build.gradle +!/sources/Forge-1.20/gradle.properties + +!/sources/Forge-1.20.6/src/ +!/sources/Forge-1.20.6/build.gradle +!/sources/Forge-1.20.6/gradle.properties + +!/sources/NeoForge-1.20.2/src/ +!/sources/NeoForge-1.20.2/build.gradle +!/sources/NeoForge-1.20.2/gradle.properties + +!/sources/NeoForge-1.21.5/src/ +!/sources/NeoForge-1.21.5/build.gradle +!/sources/NeoForge-1.21.5/gradle.properties + +!/sources/NeoForge-1.21.9/src/ +!/sources/NeoForge-1.21.9/build.gradle +!/sources/NeoForge-1.21.9/gradle.properties !/gradlew.bat !/gradlew !/build.gradle diff --git a/build.gradle b/build.gradle index ed25ffb2..d4c04d52 100644 --- a/build.gradle +++ b/build.gradle @@ -6,11 +6,11 @@ subprojects { apply plugin: "java" apply plugin: "idea" - project.version = "4.0.8" + project.version = "4.0.9" project.ext.relType = "release" - //Descending version order, Forge first; Fabric last - project.ext.jcplugin_versions = ["4430994", "4430992", "4430990", "4430988"] as String[] + //Descending version order, Forge first; Fabric second-last and NeoForge last + project.ext.jcplugin_versions = ["4573148", "4431129", "4431127", "4573146", "7068700"] as String[] project.ext.jcplugin_id = "659192" rootProject.ext.setProperty("JCPluginVersion", jcpluginVersion); diff --git a/changelog.html b/changelog.html index e3733ad9..a4c0fb6f 100644 --- a/changelog.html +++ b/changelog.html @@ -1,4 +1,9 @@ -

Latest release v4.0.8

+

Latest release v4.0.9

+ + +

v4.0.8

diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c898b7af..43d6de63 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.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index a9897487..382d38a2 100644 --- a/settings.gradle +++ b/settings.gradle @@ -27,4 +27,10 @@ include("Forge-1.20.6") project(":Forge-1.20.6").projectDir = file("./sources/Forge-1.20.6") include("NeoForge-1.20.2") -project(":NeoForge-1.20.2").projectDir = file("./sources/NeoForge-1.20.2") \ No newline at end of file +project(":NeoForge-1.20.2").projectDir = file("./sources/NeoForge-1.20.2") + +include("NeoForge-1.21.5") +project(":NeoForge-1.21.5").projectDir = file("./sources/NeoForge-1.21.5") + +include("NeoForge-1.21.9") +project(":NeoForge-1.21.9").projectDir = file("./sources/NeoForge-1.21.9") \ No newline at end of file diff --git a/sources/Core b/sources/Core index 69926930..0580e7a0 160000 --- a/sources/Core +++ b/sources/Core @@ -1 +1 @@ -Subproject commit 6992693069668e52d7fcd4e041c536949abcf371 +Subproject commit 0580e7a036a644f156ef465c5fc45aea1b775053 diff --git a/sources/Fabric-1.20/src/main/java/net/jomcraft/defaultsettings/FabricCoreHook.java b/sources/Fabric-1.20/src/main/java/net/jomcraft/defaultsettings/FabricCoreHook.java index d2186c2c..4deb2fc7 100644 --- a/sources/Fabric-1.20/src/main/java/net/jomcraft/defaultsettings/FabricCoreHook.java +++ b/sources/Fabric-1.20/src/main/java/net/jomcraft/defaultsettings/FabricCoreHook.java @@ -180,4 +180,9 @@ public void saveServers() throws IOException { public void restoreKeys(boolean update, boolean initial) throws IOException { FileUtil.restoreKeys(update, initial); } + + @Override + public void saveOptionsFile() { + Minecraft.getInstance().options.save(); + } } diff --git a/sources/Forge-1.20.6/build.gradle b/sources/Forge-1.20.6/build.gradle index a3134a41..12edc859 100644 --- a/sources/Forge-1.20.6/build.gradle +++ b/sources/Forge-1.20.6/build.gradle @@ -4,7 +4,7 @@ buildscript { mavenCentral() } //dependencies { - // classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+', changing: true + // classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '6.0.+', changing: true //} } diff --git a/sources/Forge-1.20.6/src/main/java/net/jomcraft/defaultsettings/ForgeCoreHook.java b/sources/Forge-1.20.6/src/main/java/net/jomcraft/defaultsettings/ForgeCoreHook.java index 0c6933f3..3690f55d 100644 --- a/sources/Forge-1.20.6/src/main/java/net/jomcraft/defaultsettings/ForgeCoreHook.java +++ b/sources/Forge-1.20.6/src/main/java/net/jomcraft/defaultsettings/ForgeCoreHook.java @@ -186,4 +186,9 @@ public void saveServers() throws IOException { public void restoreKeys(boolean update, boolean initial) throws IOException { FileUtil.restoreKeys(update, initial); } + + @Override + public void saveOptionsFile() { + Minecraft.getInstance().options.save(); + } } diff --git a/sources/Forge-1.20/build.gradle b/sources/Forge-1.20/build.gradle index a9469e32..db63f4e6 100644 --- a/sources/Forge-1.20/build.gradle +++ b/sources/Forge-1.20/build.gradle @@ -4,7 +4,7 @@ buildscript { mavenCentral() } //dependencies { - // classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+', changing: true + // classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '6.0.+', changing: true //} } diff --git a/sources/Forge-1.20/src/main/java/net/jomcraft/defaultsettings/ForgeCoreHook.java b/sources/Forge-1.20/src/main/java/net/jomcraft/defaultsettings/ForgeCoreHook.java index 0ad95c0c..24dc9391 100644 --- a/sources/Forge-1.20/src/main/java/net/jomcraft/defaultsettings/ForgeCoreHook.java +++ b/sources/Forge-1.20/src/main/java/net/jomcraft/defaultsettings/ForgeCoreHook.java @@ -182,4 +182,9 @@ public void saveServers() throws IOException { public void restoreKeys(boolean update, boolean initial) throws IOException { FileUtil.restoreKeys(update, initial); } + + @Override + public void saveOptionsFile() { + Minecraft.getInstance().options.save(); + } } diff --git a/sources/NeoForge-1.20.2/build.gradle b/sources/NeoForge-1.20.2/build.gradle index eeaf8bb6..f962b1ed 100644 --- a/sources/NeoForge-1.20.2/build.gradle +++ b/sources/NeoForge-1.20.2/build.gradle @@ -1,6 +1,6 @@ plugins { id 'net.darkhax.curseforgegradle' version '1.1.18' - id 'net.neoforged.gradle.userdev' version '7.0.55' + id 'net.neoforged.gradle.userdev' version '7.0.192' id 'idea' id 'java-library' } diff --git a/sources/NeoForge-1.20.2/src/main/java/net/jomcraft/defaultsettings/NeoForgeCoreHook.java b/sources/NeoForge-1.20.2/src/main/java/net/jomcraft/defaultsettings/NeoForgeCoreHook.java index 575f33d7..4d5338e0 100644 --- a/sources/NeoForge-1.20.2/src/main/java/net/jomcraft/defaultsettings/NeoForgeCoreHook.java +++ b/sources/NeoForge-1.20.2/src/main/java/net/jomcraft/defaultsettings/NeoForgeCoreHook.java @@ -183,4 +183,9 @@ public void saveServers() throws IOException { public void restoreKeys(boolean update, boolean initial) throws IOException { FileUtil.restoreKeys(update, initial); } + + @Override + public void saveOptionsFile() { + Minecraft.getInstance().options.save(); + } } \ No newline at end of file diff --git a/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/mixin/MinecraftMixin.java b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/mixin/MinecraftMixin.java new file mode 100644 index 00000000..67d391cf --- /dev/null +++ b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/mixin/MinecraftMixin.java @@ -0,0 +1,15 @@ +package net.jomcraft.defaultsettings.mixin; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.Options; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(Minecraft.class) +public class MinecraftMixin { + @Redirect(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Options;save()V")) + private void redirected(Options instance) { + + } +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.5/src/main/resources/META-INF/accesstransformer.cfg b/sources/NeoForge-1.21.5/src/main/resources/META-INF/accesstransformer.cfg new file mode 100644 index 00000000..ae38a58e --- /dev/null +++ b/sources/NeoForge-1.21.5/src/main/resources/META-INF/accesstransformer.cfg @@ -0,0 +1 @@ +public-f net.minecraft.client.KeyMapping defaultKey \ No newline at end of file diff --git a/sources/NeoForge-1.21.5/src/main/resources/META-INF/mods.toml b/sources/NeoForge-1.21.5/src/main/resources/META-INF/mods.toml new file mode 100644 index 00000000..e8ff9040 --- /dev/null +++ b/sources/NeoForge-1.21.5/src/main/resources/META-INF/mods.toml @@ -0,0 +1,29 @@ +modLoader="javafml" +loaderVersion="[1,)" +logoFile="logo.png" +license="Apache License 2.0" +displayTest="IGNORE_ALL_VERSION" + +[[mods]] + modId="defaultsettings" + version="${version}" + displayName="DefaultSettings" + description='''Keep your game's local settings in case of an update to your modpack''' + side="CLIENT" + authors="PT400C - Jomcraft Network" + credits="Developed by Jomcraft Network" + displayURL="https://www.curseforge.com/minecraft/mc-mods/defaultsettings" + +[[dependencies.defaultsettings]] + modId="neoforge" + type="required" + versionRange="[21.5,)" + ordering="NONE" + side="CLIENT" + +[[dependencies.defaultsettings]] + modId="minecraft" + type="required" + versionRange="[1.21.5,)" + ordering="NONE" + side="CLIENT" \ No newline at end of file diff --git a/sources/NeoForge-1.21.5/src/main/resources/defaultsettings.mixin.json b/sources/NeoForge-1.21.5/src/main/resources/defaultsettings.mixin.json new file mode 100644 index 00000000..d6272800 --- /dev/null +++ b/sources/NeoForge-1.21.5/src/main/resources/defaultsettings.mixin.json @@ -0,0 +1,15 @@ +{ + "required": true, + "package": "net.jomcraft.defaultsettings.mixin", + "compatibilityLevel": "JAVA_21", + "refmap": "defaultsettings.refmap.json", + "mixins": [ + ], + "client": [ + "MinecraftMixin" + ], + "injectors": { + "defaultRequire": 1 + }, + "minVersion": "0.8" +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java new file mode 100644 index 00000000..2fbc843d --- /dev/null +++ b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java @@ -0,0 +1,287 @@ +package net.jomcraft.defaultsettings; + +import java.io.*; +import java.lang.reflect.Field; +import java.net.*; +import java.nio.file.*; +import java.security.CodeSource; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.zip.ZipEntry; +import java.util.zip.ZipError; + +import net.jomcraft.defaultsettings.commands.ConfigArguments; +import net.jomcraft.defaultsettings.commands.OperationArguments; +import net.jomcraft.defaultsettings.commands.TypeArguments; +import net.jomcraft.jcplugin.JCLogger; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.commands.synchronization.ArgumentTypeInfos; +import net.minecraft.core.registries.Registries; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.fml.event.lifecycle.FMLLoadCompleteEvent; +import net.neoforged.fml.loading.FMLLoader; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.fml.common.Mod; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import net.jomcraft.jcplugin.FileUtilNoMC; + +@Mod(DefaultSettings.MODID) +public class DefaultSettings { + + public static final String MODID = "defaultsettings"; + public static final Logger log = LogManager.getLogger(DefaultSettings.MODID); + public static String VERSION = "none"; + public static Map keyRebinds = new HashMap(); + public static boolean setUp = false; + public static DefaultSettings instance; + public static boolean shutDown = false; + public static String shutdownReason = null; + + public String getVersion() throws IOException, URISyntaxException { + Manifest manifest = readManifest(this.getClass()); + Attributes attr = manifest.getMainAttributes(); + return attr.getValue("Implementation-Version"); + } + + private static final DeferredRegister> COMMAND_ARGUMENT_TYPES = DeferredRegister.create(Registries.COMMAND_ARGUMENT_TYPE, DefaultSettings.MODID); + + @SuppressWarnings({"deprecation"}) + public DefaultSettings(IEventBus modEventBus) { + instance = this; + NeoForgeCoreHook core = new NeoForgeCoreHook(); + Core.setInstance(core); + + try { + VERSION = getVersion(); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + + if (FMLLoader.getCurrent().getDist().isClient()) { + if (setUp) return; + + try { + Field pluginClass = Class.forName("net.jomcraft.jcplugin.JCPlugin").getDeclaredField("checksSuccessful"); + + if (!pluginClass.getBoolean(null)) { + shutDown = true; + shutdownReason = "The JCPlugin mod couldn't be found! Please make sure that the correct version (probably " + VERSION + ") is installed!"; + DefaultSettings.log.log(Level.ERROR, "DefaultSettings can't start up! Something is hella broken! Shutting down..."); + } else { + + final Path location = FMLLoader.getCurrent().getGameDir(); + + File mods = new File(location.toFile(), "mods"); + + boolean foundDefaultSettings = false; + String wantedVersion = null; + + for (File mod : mods.listFiles()) { + if (mod.getName().toLowerCase().contains("defaultsettings")) { + + JarFile jar = new JarFile(mod); + + ZipEntry toml = jar.getEntry("META-INF/MANIFEST.MF"); + if (toml != null) { + + BufferedReader result = new BufferedReader(new InputStreamReader(jar.getInputStream(toml))); + + String readerLine; + + while ((readerLine = result.readLine()) != null) { + if (readerLine.contains("Implementation-Title: DefaultSettings")) { + foundDefaultSettings = true; + } else if (readerLine.startsWith("JCPluginVersion")) { + wantedVersion = readerLine.split(": ")[1]; + } + } + + result.close(); + } + + jar.close(); + + if (foundDefaultSettings && wantedVersion != null) { + + if (wantedVersion.equals(JCLogger.class.getPackage().getImplementationVersion())) { + DefaultSettings.log.log(Level.INFO, "DefaultSettings found correct version of JCPlugin, starting up..."); + break; + } else { + shutDown = true; + shutdownReason = "The correct JCPlugin mod version couldn't be found! Please install version " + wantedVersion; + DefaultSettings.log.log(Level.ERROR, "DefaultSettings can't start up! JCPlugin version must be " + wantedVersion + "!"); + } + + } + } + } + + if (FMLLoader.getCurrent().isProduction() && (!foundDefaultSettings || wantedVersion == null)) { + shutDown = true; + shutdownReason = "Strange! We can't find the DefaultSettings mod, eventhough you're currently using it!"; + DefaultSettings.log.log(Level.ERROR, "DefaultSettings can't start up! Couldn't get requested version of JCPlugin!"); + } + } + } catch (ClassNotFoundException | NoSuchFieldException | SecurityException | IllegalArgumentException | + IllegalAccessException | IOException e) { + shutDown = true; + shutdownReason = "The JCPlugin mod couldn't be found! Please make sure that the correct version (probably " + VERSION + ") is installed!"; + DefaultSettings.log.log(Level.ERROR, "DefaultSettings is missing the JCPlugin mod! Shutting down..."); + } + + modEventBus.addListener(this::postInit); + + COMMAND_ARGUMENT_TYPES.register("ds_config", () -> ArgumentTypeInfos.registerByClass(ConfigArguments.class, new ConfigArguments.Info())); + COMMAND_ARGUMENT_TYPES.register("ds_operation", () -> ArgumentTypeInfos.registerByClass(OperationArguments.class, new OperationArguments.Info())); + COMMAND_ARGUMENT_TYPES.register("ds_type", () -> ArgumentTypeInfos.registerByClass(TypeArguments.class, new TypeArguments.Info())); + + COMMAND_ARGUMENT_TYPES.register(modEventBus); + + //ModLoadingContext.get().registerExtensionPoint(IExtensionPoint.DisplayTest.class, () -> new IExtensionPoint.DisplayTest(() -> "ANY", (remote, isServer) -> true)); + + NeoForge.EVENT_BUS.register(new EventHandlers()); + + if (shutDown) return; + + try { + FileUtil.restoreContents(); + + } catch (Exception e) { + DefaultSettings.log.log(Level.ERROR, "An exception occurred while starting up the game:", e); + } + setUp = true; + + } + + if (FMLLoader.getCurrent().getDist().isDedicatedServer()) { + DefaultSettings.log.log(Level.WARN, "DefaultSettings is a client-side mod only! It won't do anything on servers!"); + } + } + + @SuppressWarnings("deprecation") + public void postInit(FMLLoadCompleteEvent event) { + if (FMLLoader.getCurrent().getDist().isClient()) { + try { + if (!shutDown) FileUtil.restoreKeys(true, FileUtilNoMC.privateJson.firstBootUp); + } catch (IOException e) { + DefaultSettings.log.log(Level.ERROR, "An exception occurred while starting up the game (Post):", e); + } catch (NullPointerException e) { + DefaultSettings.log.log(Level.ERROR, "An exception occurred while starting up the game (Post):", e); + } + } + + if (FMLLoader.getCurrent().getDist().isDedicatedServer()) { + DefaultSettings.log.log(Level.WARN, "DefaultSettings is a client-side mod only! It won't do anything on servers!"); + } + } + + public static DefaultSettings getInstance() { + return instance; + } + + public static Manifest readManifest(Class cls) throws IOException, URISyntaxException { + CodeSource cs = cls.getProtectionDomain().getCodeSource(); + if (cs == null) return null; + + URL url = cs.getLocation(); + if (url == null) return null; + + return readManifest(url); + } + + public static Path asPath(URL url) { + try { + return Paths.get(url.toURI()); + } catch (URISyntaxException e) { + return null; + } + } + + public static Manifest readManifest(URL codeSourceUrl) throws IOException, URISyntaxException { + Path path = asPath(codeSourceUrl); + + if (Files.isDirectory(path)) { + return readManifest(path); + } else { + URLConnection connection = new URL("jar:" + codeSourceUrl.toString() + "!/").openConnection(); + + if (connection instanceof JarURLConnection) { + return ((JarURLConnection) connection).getManifest(); + } + + try (FileSystemDelegate jarFs = getJarFileSystem(path.toUri(), false)) { + return readManifest(jarFs.get().getRootDirectories().iterator().next()); + } + } + } + + private static final Map jfsArgsCreate = Collections.singletonMap("create", "true"); + private static final Map jfsArgsEmpty = Collections.emptyMap(); + + public static FileSystemDelegate getJarFileSystem(URI uri, boolean create) throws IOException { + URI jarUri; + + try { + jarUri = new URI("jar:" + uri.getScheme(), uri.getHost(), uri.getPath(), uri.getFragment()); + } catch (URISyntaxException e) { + throw new IOException(e); + } + + boolean opened = false; + FileSystem ret = null; + + try { + ret = FileSystems.getFileSystem(jarUri); + } catch (FileSystemNotFoundException ignore) { + try { + ret = FileSystems.newFileSystem(jarUri, create ? jfsArgsCreate : jfsArgsEmpty); + opened = true; + } catch (FileSystemAlreadyExistsException ignore2) { + ret = FileSystems.getFileSystem(jarUri); + } catch (IOException | ZipError e) { + throw new IOException("Error accessing "+uri+": "+e, e); + } + } + + return new FileSystemDelegate(ret, opened); + } + + public static Manifest readManifest(Path basePath) throws IOException { + Path path = basePath.resolve("META-INF").resolve("MANIFEST.MF"); + if (!Files.exists(path)) return null; + + try (InputStream stream = Files.newInputStream(path)) { + return new Manifest(stream); + } + } + + public static class FileSystemDelegate implements AutoCloseable { + private final FileSystem fileSystem; + private final boolean owner; + + public FileSystemDelegate(FileSystem fileSystem, boolean owner) { + this.fileSystem = fileSystem; + this.owner = owner; + } + + public FileSystem get() { + return fileSystem; + } + + @Override + public void close() throws IOException { + if (owner) { + fileSystem.close(); + } + } + } +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/EventHandlers.java b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/EventHandlers.java new file mode 100644 index 00000000..e3672cb6 --- /dev/null +++ b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/EventHandlers.java @@ -0,0 +1,13 @@ +package net.jomcraft.defaultsettings; + +import net.jomcraft.defaultsettings.commands.CommandDefaultSettings; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.neoforge.event.server.ServerStartingEvent; + +public class EventHandlers { + + @SubscribeEvent + public void serverStarting(ServerStartingEvent event) { + CommandDefaultSettings.register(event); + } +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/FileUtil.java b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/FileUtil.java new file mode 100644 index 00000000..faa253b3 --- /dev/null +++ b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/FileUtil.java @@ -0,0 +1,182 @@ +package net.jomcraft.defaultsettings; + +import static net.jomcraft.jcplugin.FileUtilNoMC.*; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.util.ArrayList; + +import com.mojang.blaze3d.platform.InputConstants; +import net.minecraft.client.KeyMapping; +import net.neoforged.fml.util.ObfuscationReflectionHelper; +import net.neoforged.neoforge.client.settings.KeyModifier; +import org.apache.logging.log4j.Level; +import net.minecraft.client.Minecraft; + +public class FileUtil { + + public static void restoreContents() throws NullPointerException, IOException { + + final String version = getMainJSON().getVersion(); + + if (!DefaultSettings.VERSION.equals(version)) + mainJson.setVersion(DefaultSettings.VERSION).setPrevVersion(version); + + if (mainJson.generatedBy.equals("")) + mainJson.generatedBy = privateJson.privateIdentifier; + + activeProfile = privateJson.currentProfile; + + if (!privateJson.firstBootUp) { + copyAndHashPrivate(true, true); + } + + final File optionsOF = new File(mcDataDir, "optionsof.txt"); + if (!optionsOF.exists()) + restoreOptionsOF(); + + final File optionsShaders = new File(mcDataDir, "optionsshaders.txt"); + if (!optionsShaders.exists()) + restoreOptionsShaders(); + + final File optionsJEK = new File(mcDataDir, "options.justenoughkeys.txt"); + if (!optionsJEK.exists()) + restoreOptionsJEK(); + + final File optionsAmecs = new File(mcDataDir, "options.amecsapi.txt"); + if (!optionsAmecs.exists()) + restoreOptionsAmecs(); + + final File serversFile = new File(mcDataDir, "servers.dat"); + if (!serversFile.exists()) + restoreServers(); + + mainJson.save(); + } + + @SuppressWarnings("resource") + public static void restoreKeys(boolean update, boolean initial) throws NullPointerException, IOException, NumberFormatException { + CoreUtil.restoreKeys(update, initial); + } + + @SuppressWarnings("resource") + public static void saveKeys() throws IOException, NullPointerException { + CoreUtil.saveKeys(); + } + + @SuppressWarnings("resource") + public static boolean saveOptions() throws NullPointerException, IOException { + Minecraft.getInstance().options.save(); + return CoreUtil.saveOptions(); + } + + public static boolean checkChanged() { + boolean ret = false; + try { + + InputStream keys = CoreUtil.getKeysStream(false); + InputStream options = getOptionsStream(); + InputStream optionsOF = getOptionsOFStream(); + InputStream optionsShaders = getOptionsShadersStream(); + InputStream optionsJEK = getOptionsJEKStream(); + InputStream optionsAmecs = getOptionsAmecsStream(); + InputStream servers = getServersStream(); + + String hashO = ""; + String writtenHashO = ""; + + if (options != null) { + hashO = fileToHash(options); + writtenHashO = mainJson.hashes.get(activeProfile + "/options.txt"); + } + + String hashK = ""; + String writtenHashK = ""; + + if (keys != null) { + hashK = fileToHash(keys); + writtenHashK = mainJson.hashes.get(activeProfile + "/keys.txt"); + } + + String hashOF = ""; + String writtenHashOF = ""; + + if (optionsOF != null) { + hashOF = fileToHash(optionsOF); + writtenHashOF = mainJson.hashes.get(activeProfile + "/optionsof.txt"); + } + + String hashShaders = ""; + String writtenHashShaders = ""; + + if (optionsShaders != null) { + hashShaders = fileToHash(optionsShaders); + writtenHashShaders = mainJson.hashes.get(activeProfile + "/optionsshaders.txt"); + } + + String hashJEK = ""; + String writtenHashJEK = ""; + + if (optionsJEK != null) { + hashJEK = fileToHash(optionsJEK); + writtenHashJEK = mainJson.hashes.get(activeProfile + "/options.justenoughkeys.txt"); + } + + String hashAmecs = ""; + String writtenHashAmecs = ""; + + if (optionsAmecs != null) { + hashAmecs = fileToHash(optionsAmecs); + writtenHashAmecs = mainJson.hashes.get(activeProfile + "/options.amecsapi.txt"); + } + + String hashS = ""; + String writtenHashS = ""; + + if (servers != null) { + hashS = fileToHash(servers); + writtenHashS = mainJson.hashes.get(activeProfile + "/servers.dat"); + } + + if (mainJson.hashes.containsKey(activeProfile + "/options.txt") && !hashO.equals(writtenHashO)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/keys.txt") && !hashK.equals(writtenHashK)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/optionsof.txt") && !hashOF.equals(writtenHashOF)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/optionsshaders.txt") && !hashShaders.equals(writtenHashShaders)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/options.justenoughkeys.txt") && !hashJEK.equals(writtenHashJEK)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/options.amecsapi.txt") && !hashAmecs.equals(writtenHashAmecs)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/servers.dat") && !hashS.equals(writtenHashS)) { + ret = true; + } + + if (options != null) { + options.close(); + File fileO = new File(getMainFolder(), activeProfile + "/options.txt_temp"); + Files.delete(fileO.toPath()); + } + + if (keys != null) { + keys.close(); + File fileK = new File(getMainFolder(), activeProfile + "/keys.txt_temp"); + Files.delete(fileK.toPath()); + } + + } catch (Exception e) { + DefaultSettings.log.log(Level.ERROR, "Error while saving configs: ", e); + } + + return ret; + } +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/KeyContainer.java b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/KeyContainer.java new file mode 100644 index 00000000..b80e99b0 --- /dev/null +++ b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/KeyContainer.java @@ -0,0 +1,16 @@ +package net.jomcraft.defaultsettings; + +import com.mojang.blaze3d.platform.InputConstants; +import net.neoforged.neoforge.client.settings.KeyModifier; + +public class KeyContainer { + + public final InputConstants.Key input; + public final KeyModifier modifier; + + public KeyContainer(final InputConstants.Key input, final KeyModifier modifier) { + this.input = input; + this.modifier = modifier; + } + +} diff --git a/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/NeoForgeCoreHook.java b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/NeoForgeCoreHook.java new file mode 100644 index 00000000..079fcd8a --- /dev/null +++ b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/NeoForgeCoreHook.java @@ -0,0 +1,190 @@ +package net.jomcraft.defaultsettings; + +import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import net.jomcraft.jcplugin.FileUtilNoMC; +import net.minecraft.ChatFormatting; +import net.minecraft.client.KeyMapping; +import net.minecraft.client.Minecraft; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.network.chat.Component; +import net.neoforged.fml.util.ObfuscationReflectionHelper; +import net.neoforged.neoforge.client.settings.KeyModifier; +import org.apache.logging.log4j.Logger; +import java.io.File; +import java.io.IOException; + +public class NeoForgeCoreHook implements ICoreHook { + + private static final SimpleCommandExceptionType FAILED_EXCEPTION = new SimpleCommandExceptionType(Component.literal(ChatFormatting.RED + "Please wait until the last request has finished")); + + @Override + public File getMCDataDir() { + return FileUtilNoMC.mcDataDir; + } + + @Override + public File getMainFolder() { + return FileUtilNoMC.getMainFolder(); + } + + @Override + public String getActiveProfile() { + return FileUtilNoMC.activeProfile; + } + + @Override + public KeyPlaceholder[] getKeyMappings() { + KeyMapping[] mappings = Minecraft.getInstance().options.keyMappings; + if(mappings == null || mappings.length == 0) + return new KeyPlaceholder[0]; + + KeyPlaceholder[] keys = new KeyPlaceholder[mappings.length]; + + for(int i = 0; i < mappings.length; i++) { + keys[i] = new KeyPlaceholder(mappings[i].getName(), mappings[i].getKey().toString(), mappings[i].getKeyModifier().name()); + } + return keys; + } + + @Override + public void resetMappings() { + KeyMapping.resetMapping(); + } + + @Override + public void clearKeyBinds() { + DefaultSettings.keyRebinds.clear(); + } + + @Override + public void putKeybind(String first, String second, String third) { + DefaultSettings.keyRebinds.put(first, new KeyContainer(InputConstants.getKey(second), third != null ? KeyModifier.valueFromString(third) : KeyModifier.NONE)); + } + + @Override + public boolean keybindExists(String key) { + return DefaultSettings.keyRebinds.containsKey(key); + } + + @Override + public void setKeybind(KeyPlaceholder key, boolean init) { + KeyMapping[] mappings = Minecraft.getInstance().options.keyMappings; + for(int i = 0; i < mappings.length; i++){ + if(mappings[i].getName().equals(key.name)){ + KeyContainer container = DefaultSettings.keyRebinds.get(key.name); + + if(init) + mappings[i].setKey(container.input); + + mappings[i].defaultKey = container.input; + + ObfuscationReflectionHelper.setPrivateValue(KeyMapping.class, mappings[i], container.modifier, "keyModifierDefault"); + mappings[i].setKeyModifierAndCode(mappings[i].getDefaultKeyModifier(), container.input); + break; + } + } + } + + @Override + public void sendSuccess(Object source, String text, int color) { + if (source instanceof CommandSourceStack) { + ((CommandSourceStack) source).sendSuccess(() -> Component.literal(text).withStyle(ChatFormatting.getById(color)), true); + } + } + + @Override + public Exception throwFailedException() { + return FAILED_EXCEPTION.create(); + } + + @Override + public boolean hasDSShutDown() { + return DefaultSettings.shutDown; + } + + @Override + public Logger getDSLog() { + return DefaultSettings.log; + } + + @Override + public String shutdownReason() { + return DefaultSettings.shutdownReason; + } + + @Override + public boolean isOtherCreator() { + return FileUtilNoMC.otherCreator; + } + + @Override + public boolean disableCreatorCheck() { + return FileUtilNoMC.privateJson.disableCreatorCheck; + } + + @Override + public boolean checkChangedConfig() { + return FileUtilNoMC.checkChangedConfig(); + } + + @Override + public boolean checkForConfigFiles() { + return FileUtilNoMC.checkForConfigFiles(); + } + + @Override + public void checkMD5(boolean updateExisting, boolean configs, String file) throws IOException { + FileUtilNoMC.checkMD5(updateExisting, configs, file); + } + + @Override + public void copyAndHashPrivate(boolean options, boolean configs) throws NullPointerException, IOException { + FileUtilNoMC.copyAndHashPrivate(options, configs); + } + + @Override + public boolean keysFileExist() { + return FileUtilNoMC.keysFileExist(); + } + + @Override + public boolean optionsFilesExist() { + return FileUtilNoMC.optionsFilesExist(); + } + + @Override + public boolean serversFileExists() { + return FileUtilNoMC.serversFileExists(); + } + + @Override + public boolean checkChanged() { + return FileUtil.checkChanged(); + } + + @Override + public void saveKeys() throws IOException { + FileUtil.saveKeys(); + } + + @Override + public boolean saveOptions() throws IOException { + return FileUtil.saveOptions(); + } + + @Override + public void saveServers() throws IOException { + FileUtilNoMC.saveServers(); + } + + @Override + public void restoreKeys(boolean update, boolean initial) throws IOException { + FileUtil.restoreKeys(update, initial); + } + + @Override + public void saveOptionsFile() { + Minecraft.getInstance().options.save(); + } +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/commands/CommandDefaultSettings.java b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/commands/CommandDefaultSettings.java new file mode 100644 index 00000000..8fc09c66 --- /dev/null +++ b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/commands/CommandDefaultSettings.java @@ -0,0 +1,51 @@ +package net.jomcraft.defaultsettings.commands; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.tree.LiteralCommandNode; +import net.jomcraft.defaultsettings.CoreUtil; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.neoforged.neoforge.event.server.ServerStartingEvent; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +public class CommandDefaultSettings { + + public static void register(ServerStartingEvent event) { + LiteralArgumentBuilder literalargumentbuilder = Commands.literal("defaultsettings"); + + literalargumentbuilder.then(Commands.literal("save").executes((command) -> { + return saveProcess(command.getSource(), null, null); + }).then(Commands.argument("operation", OperationArguments.operationArguments(false)).executes((command) -> { + return saveProcess(command.getSource(), OperationArguments.getString(command, "operation"), null); + }).then(Commands.argument("type", TypeArguments.typeArguments()).executes((command) -> { + return saveProcess(command.getSource(), OperationArguments.getString(command, "operation"), TypeArguments.getString(command, "type")); + })))).then(Commands.literal("saveconfigs").executes((command) -> { + return saveProcessConfigs(command.getSource(), null, null); + }).then(Commands.argument("operation", OperationArguments.operationArguments(true)).executes((command) -> { + return saveProcessConfigs(command.getSource(), OperationArguments.getString(command, "operation"), null); + }).then(Commands.argument("config", ConfigArguments.configArguments()).executes((command) -> { + return saveProcessConfigs(command.getSource(), OperationArguments.getString(command, "operation"), ConfigArguments.getString(command, "config")); + })))); + + LiteralCommandNode node = event.getServer().getCommands().getDispatcher().register(literalargumentbuilder); + event.getServer().getCommands().getDispatcher().register(Commands.literal("ds").redirect(node)); + } + + private static int saveProcessConfigs(CommandSourceStack source, String argument, String argument2) throws CommandSyntaxException { + try { + return CoreUtil.saveProcessConfigs(source, argument, argument2); + } catch (Exception e) { + if (e instanceof CommandSyntaxException) throw (CommandSyntaxException) e; + return 0; + } + } + + private static int saveProcess(CommandSourceStack source, String argument, String argument2) throws CommandSyntaxException { + try { + return CoreUtil.saveProcess(source, argument, argument2); + } catch (Exception e) { + if (e instanceof CommandSyntaxException) throw (CommandSyntaxException) e; + return 0; + } + } +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/commands/ConfigArguments.java b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/commands/ConfigArguments.java new file mode 100644 index 00000000..a52b8d5f --- /dev/null +++ b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/commands/ConfigArguments.java @@ -0,0 +1,118 @@ +package net.jomcraft.defaultsettings.commands; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import com.google.gson.JsonObject; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.jomcraft.defaultsettings.DefaultSettings; +import net.jomcraft.jcplugin.FileUtilNoMC; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.network.FriendlyByteBuf; + +public class ConfigArguments implements ArgumentType { + + private static List ARGUMENTS = Arrays.asList("fml.toml", "forge-client.toml"); + + public static ConfigArguments configArguments() { + return new ConfigArguments(); + } + + @Override + public String parse(final StringReader reader) throws CommandSyntaxException { + return readQuotedString(reader); + } + + public String readQuotedString(final StringReader reader) throws CommandSyntaxException { + if (!reader.canRead()) { + return ""; + } + final char next = reader.getString().charAt(reader.getCursor()); + if (!reader.isQuotedStringStart(next)) { + + final int start = reader.getCursor(); + while (reader.canRead()) { + reader.skip(); + } + return reader.getString().substring(start, reader.getCursor()); + } + reader.skip(); + return reader.readStringUntil(next); + } + + public static String getString(final CommandContext context, final String name) { + return context.getArgument(name, String.class); + } + + @Override + public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) { + try { + ArrayList filtered = new ArrayList(); + ArrayList prevList = FileUtilNoMC.listConfigFiles(); + for(int i = 0; i < prevList.size(); i++){ + String name = prevList.get(i); + if(name.contains(" ")) + name = "\"" + name + "\""; + filtered.add(name); + } + ARGUMENTS = filtered; + } catch (IOException e) { + DefaultSettings.log.error(e); + } + return SharedSuggestionProvider.suggest(ARGUMENTS, builder); + } + + @Override + public Collection getExamples() { + return ARGUMENTS; + } + + public static class Info implements ArgumentTypeInfo { + @Override + public void serializeToNetwork(Template template, FriendlyByteBuf buffer) { + + } + + @Override + public Template deserializeFromNetwork(FriendlyByteBuf buffer) { + return new Template(); + } + + @Override + public void serializeToJson(Template template, JsonObject json) { + + } + + @Override + public Template unpack(ConfigArguments argument) { + return new Template(); + } + + public class Template implements ArgumentTypeInfo.Template { + + Template() { + + } + + @Override + public ConfigArguments instantiate(CommandBuildContext p_223435_) { + return new ConfigArguments(); + } + + @Override + public ArgumentTypeInfo type() { + return Info.this; + } + } + } +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/commands/OperationArguments.java b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/commands/OperationArguments.java new file mode 100644 index 00000000..bb9f85b1 --- /dev/null +++ b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/commands/OperationArguments.java @@ -0,0 +1,92 @@ +package net.jomcraft.defaultsettings.commands; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import com.google.gson.JsonObject; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.network.FriendlyByteBuf; + +public class OperationArguments implements ArgumentType { + + private static final List ARGUMENTS = Arrays.asList("override", "forceOverride"); + private static final List ARGUMENTS_LIMITED = Arrays.asList("forceOverride"); + private final boolean limited; + + public OperationArguments(boolean limited) { + this.limited = limited; + } + + public static OperationArguments operationArguments(boolean limited) { + return new OperationArguments(limited); + } + + @Override + public String parse(final StringReader reader) throws CommandSyntaxException { + return reader.readUnquotedString(); + } + + public static String getString(final CommandContext context, final String name) { + return context.getArgument(name, String.class); + } + + @Override + public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) { + return SharedSuggestionProvider.suggest(this.limited ? ARGUMENTS_LIMITED : ARGUMENTS, builder); + } + + @Override + public Collection getExamples() { + return ARGUMENTS; + } + + public static class Info implements ArgumentTypeInfo { + @Override + public void serializeToNetwork(Template template, FriendlyByteBuf buffer) { + buffer.writeBoolean(template.limited); + } + + @Override + public Template deserializeFromNetwork(FriendlyByteBuf buffer) { + boolean limited = buffer.readBoolean(); + return new Template(limited); + } + + @Override + public void serializeToJson(Template template, JsonObject json) { + json.addProperty("limited", template.limited); + } + + @Override + public Template unpack(OperationArguments argument) { + return new Template(argument.limited); + } + + public class Template implements ArgumentTypeInfo.Template { + final boolean limited; + + Template(boolean limited) { + this.limited = limited; + } + + @Override + public OperationArguments instantiate(CommandBuildContext p_223435_) { + return new OperationArguments(this.limited); + } + + @Override + public ArgumentTypeInfo type() { + return Info.this; + } + } + } +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/commands/TypeArguments.java b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/commands/TypeArguments.java new file mode 100644 index 00000000..8fa88263 --- /dev/null +++ b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/commands/TypeArguments.java @@ -0,0 +1,83 @@ +package net.jomcraft.defaultsettings.commands; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import com.google.gson.JsonObject; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.network.FriendlyByteBuf; + +public class TypeArguments implements ArgumentType { + + private static final List ARGUMENTS = Arrays.asList("options", "keybinds", "servers"); + + public static TypeArguments typeArguments() { + return new TypeArguments(); + } + + @Override + public String parse(final StringReader reader) throws CommandSyntaxException { + return reader.readUnquotedString(); + } + + public static String getString(final CommandContext context, final String name) { + return context.getArgument(name, String.class); + } + + @Override + public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) { + return SharedSuggestionProvider.suggest(ARGUMENTS, builder); + } + + @Override + public Collection getExamples() { + return ARGUMENTS; + } + + public static class Info implements ArgumentTypeInfo { + @Override + public void serializeToNetwork(Template template, FriendlyByteBuf buffer) { + + } + + @Override + public Template deserializeFromNetwork(FriendlyByteBuf buffer) { + return new Template(); + } + + @Override + public void serializeToJson(Template template, JsonObject json) { + } + + @Override + public Template unpack(TypeArguments argument) { + return new Template(); + } + + public class Template implements ArgumentTypeInfo.Template { + + Template() { + + } + + @Override + public TypeArguments instantiate(CommandBuildContext p_223435_) { + return new TypeArguments(); + } + + @Override + public ArgumentTypeInfo type() { + return Info.this; + } + } + } +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/mixin/MinecraftMixin.java b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/mixin/MinecraftMixin.java new file mode 100644 index 00000000..67d391cf --- /dev/null +++ b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/mixin/MinecraftMixin.java @@ -0,0 +1,15 @@ +package net.jomcraft.defaultsettings.mixin; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.Options; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(Minecraft.class) +public class MinecraftMixin { + @Redirect(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Options;save()V")) + private void redirected(Options instance) { + + } +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.9/src/main/resources/META-INF/accesstransformer.cfg b/sources/NeoForge-1.21.9/src/main/resources/META-INF/accesstransformer.cfg new file mode 100644 index 00000000..ae38a58e --- /dev/null +++ b/sources/NeoForge-1.21.9/src/main/resources/META-INF/accesstransformer.cfg @@ -0,0 +1 @@ +public-f net.minecraft.client.KeyMapping defaultKey \ No newline at end of file diff --git a/sources/NeoForge-1.21.9/src/main/resources/META-INF/mods.toml b/sources/NeoForge-1.21.9/src/main/resources/META-INF/mods.toml new file mode 100644 index 00000000..e8ff9040 --- /dev/null +++ b/sources/NeoForge-1.21.9/src/main/resources/META-INF/mods.toml @@ -0,0 +1,29 @@ +modLoader="javafml" +loaderVersion="[1,)" +logoFile="logo.png" +license="Apache License 2.0" +displayTest="IGNORE_ALL_VERSION" + +[[mods]] + modId="defaultsettings" + version="${version}" + displayName="DefaultSettings" + description='''Keep your game's local settings in case of an update to your modpack''' + side="CLIENT" + authors="PT400C - Jomcraft Network" + credits="Developed by Jomcraft Network" + displayURL="https://www.curseforge.com/minecraft/mc-mods/defaultsettings" + +[[dependencies.defaultsettings]] + modId="neoforge" + type="required" + versionRange="[21.5,)" + ordering="NONE" + side="CLIENT" + +[[dependencies.defaultsettings]] + modId="minecraft" + type="required" + versionRange="[1.21.5,)" + ordering="NONE" + side="CLIENT" \ No newline at end of file diff --git a/sources/NeoForge-1.21.9/src/main/resources/META-INF/neoforge.mods.toml b/sources/NeoForge-1.21.9/src/main/resources/META-INF/neoforge.mods.toml new file mode 100644 index 00000000..3ee42210 --- /dev/null +++ b/sources/NeoForge-1.21.9/src/main/resources/META-INF/neoforge.mods.toml @@ -0,0 +1,29 @@ +modLoader="javafml" +loaderVersion="[1,)" +logoFile="logo.png" +license="Apache License 2.0" +displayTest="IGNORE_ALL_VERSION" + +[[mods]] + modId="defaultsettings" + version="${version}" + displayName="DefaultSettings" + description='''Keep your game's local settings in case of an update to your modpack''' + side="CLIENT" + authors="PT400C - Jomcraft Network" + credits="Developed by Jomcraft Network" + displayURL="https://www.curseforge.com/minecraft/mc-mods/defaultsettings" + +[[dependencies.defaultsettings]] + modId="neoforge" + type="required" + versionRange="[21.9,)" + ordering="NONE" + side="CLIENT" + +[[dependencies.defaultsettings]] + modId="minecraft" + type="required" + versionRange="[1.21.9,)" + ordering="NONE" + side="CLIENT" \ No newline at end of file diff --git a/sources/NeoForge-1.21.9/src/main/resources/defaultsettings.mixin.json b/sources/NeoForge-1.21.9/src/main/resources/defaultsettings.mixin.json new file mode 100644 index 00000000..d6272800 --- /dev/null +++ b/sources/NeoForge-1.21.9/src/main/resources/defaultsettings.mixin.json @@ -0,0 +1,15 @@ +{ + "required": true, + "package": "net.jomcraft.defaultsettings.mixin", + "compatibilityLevel": "JAVA_21", + "refmap": "defaultsettings.refmap.json", + "mixins": [ + ], + "client": [ + "MinecraftMixin" + ], + "injectors": { + "defaultRequire": 1 + }, + "minVersion": "0.8" +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.9/src/main/resources/logo.png b/sources/NeoForge-1.21.9/src/main/resources/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6f345514da0f0b162d7759a1c9d62d85b82a638e GIT binary patch literal 51342 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 n!ZX~V14{r4{eOLYa%>)6=DYpuB{JC%{UXv& Date: Sun, 5 Oct 2025 14:36:13 +0200 Subject: [PATCH 2/6] Add missing files to repository --- .github/workflows/build.yml | 1 + .github/workflows/publish.yml | 1 + .gitignore | 80 ++++---- sources/NeoForge-1.21.5/build.gradle | 146 ++++++++++++++ sources/NeoForge-1.21.5/gradle.properties | 1 + .../defaultsettings/DefaultSettings.java | 185 +++++++++++++++++ .../defaultsettings/EventHandlers.java | 13 ++ .../jomcraft/defaultsettings/FileUtil.java | 182 +++++++++++++++++ .../defaultsettings/KeyContainer.java | 16 ++ .../defaultsettings/ManifestUtility.java | 113 +++++++++++ .../defaultsettings/NeoForgeCoreHook.java | 190 ++++++++++++++++++ .../commands/CommandDefaultSettings.java | 51 +++++ .../commands/ConfigArguments.java | 118 +++++++++++ .../commands/OperationArguments.java | 92 +++++++++ .../commands/TypeArguments.java | 83 ++++++++ .../resources/META-INF/neoforge.mods.toml | 29 +++ .../src/main/resources/logo.png | Bin 0 -> 51342 bytes .../src/main/resources/pack.mcmeta | 8 + sources/NeoForge-1.21.9/build.gradle | 146 ++++++++++++++ sources/NeoForge-1.21.9/gradle.properties | 1 + .../defaultsettings/DefaultSettings.java | 98 +-------- .../defaultsettings/ManifestUtility.java | 113 +++++++++++ 22 files changed, 1532 insertions(+), 135 deletions(-) create mode 100644 sources/NeoForge-1.21.5/build.gradle create mode 100644 sources/NeoForge-1.21.5/gradle.properties create mode 100644 sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java create mode 100644 sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/EventHandlers.java create mode 100644 sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/FileUtil.java create mode 100644 sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/KeyContainer.java create mode 100644 sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/ManifestUtility.java create mode 100644 sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/NeoForgeCoreHook.java create mode 100644 sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/CommandDefaultSettings.java create mode 100644 sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/ConfigArguments.java create mode 100644 sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/OperationArguments.java create mode 100644 sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/TypeArguments.java create mode 100644 sources/NeoForge-1.21.5/src/main/resources/META-INF/neoforge.mods.toml create mode 100644 sources/NeoForge-1.21.5/src/main/resources/logo.png create mode 100644 sources/NeoForge-1.21.5/src/main/resources/pack.mcmeta create mode 100644 sources/NeoForge-1.21.9/build.gradle create mode 100644 sources/NeoForge-1.21.9/gradle.properties create mode 100644 sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/ManifestUtility.java diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c0cebb94..9c69a740 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,6 +15,7 @@ jobs: uses: actions/setup-java@v5 with: java-version: | + 8 16 21 distribution: 'adopt' diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index ce5ff3b6..d63d8f0f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -26,6 +26,7 @@ jobs: uses: actions/setup-java@v5 with: java-version: | + 8 16 21 distribution: 'adopt' diff --git a/.gitignore b/.gitignore index aa11f7bf..2da58bc6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,44 +1,48 @@ -/* -/*/ -!/sources/Core/src/ -!/sources/Core/.gitignore -!/sources/Core/build.gradle -!/sources/Core/gradle.properties -!/sources/Core/LICENSE -!/sources/Core/README.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ +!**/src/main/**/runs/ +!**/src/test/**/runs/ +sources/**/runs/ -!/sources/Fabric-1.20/src/ -!/sources/Fabric-1.20/build.gradle -!/sources/Fabric-1.20/gradle.properties +### Minecraft ### +run -!/sources/Forge-1.20/src/ -!/sources/Forge-1.20/build.gradle -!/sources/Forge-1.20/gradle.properties +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ -!/sources/Forge-1.20.6/src/ -!/sources/Forge-1.20.6/build.gradle -!/sources/Forge-1.20.6/gradle.properties +### Kotlin ### +.kotlin -!/sources/NeoForge-1.20.2/src/ -!/sources/NeoForge-1.20.2/build.gradle -!/sources/NeoForge-1.20.2/gradle.properties +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ -!/sources/NeoForge-1.21.5/src/ -!/sources/NeoForge-1.21.5/build.gradle -!/sources/NeoForge-1.21.5/gradle.properties +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ -!/sources/NeoForge-1.21.9/src/ -!/sources/NeoForge-1.21.9/build.gradle -!/sources/NeoForge-1.21.9/gradle.properties -!/gradlew.bat -!/gradlew -!/build.gradle -!/.gitignore -!/.gitmodules -!/changelog.html -!/gradle/ -!/README.md -!/LICENSE -!/.github/ -!/settings.gradle -!/gradle.properties \ No newline at end of file +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/sources/NeoForge-1.21.5/build.gradle b/sources/NeoForge-1.21.5/build.gradle new file mode 100644 index 00000000..a593c1bf --- /dev/null +++ b/sources/NeoForge-1.21.5/build.gradle @@ -0,0 +1,146 @@ +plugins { + id 'net.darkhax.curseforgegradle' version '1.1.18' + id 'net.neoforged.gradle.userdev' version '7.0.192' + id 'idea' + id 'java-library' +} + +archivesBaseName = "${rootProject.name}" + +java.toolchain.languageVersion = JavaLanguageVersion.of(21) +def file_version = version; + +version = "1.21.5-${version}-NeoForge" + +minecraft.accessTransformers.file file('src/main/resources/META-INF/accesstransformer.cfg') + +repositories { + maven { + url "https://cursemaven.com" + content { + includeGroup "curse.maven" + } + } +} + +runs { + configureEach { + systemProperty 'neoforge.logging.markers', 'REGISTRIES' + systemProperty 'neoforge.logging.console.level', 'debug' + modSource project.sourceSets.main + } + + client { + systemProperty 'neoforge.enabledGameTestNamespaces', "defaultsettings" + programArgument "-mixin.config="+"defaultsettings.mixin.json" + systemProperty 'mixin.env.disableRefMap', 'true' + } + + server { + systemProperty 'neoforge.enabledGameTestNamespaces', "defaultsettings" + systemProperty 'mixin.env.disableRefMap', 'true' + + programArgument "-mixin.config="+"defaultsettings.mixin.json" + + programArgument '--nogui' + } + + gameTestServer { + systemProperty 'neoforge.enabledGameTestNamespaces', "defaultsettings" + } + + clientData { + arguments.addAll '--mod', "defaultsettings", '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath() + } +} + +sourceSets.main.resources { srcDir 'src/generated/resources' } + +configurations { + runtimeClasspath.extendsFrom localRuntime +} + +dependencies { + implementation "net.neoforged:neoforge:21.5.95" + implementation("curse.maven:jcp-${project.ext.jcplugin_id}:${project.ext.jcplugin_versions[0]}") + implementation project(":Core") +} + +processResources { + inputs.property "version", file_version + + filesMatching(["**/fabric.mod.json", "**/mods.toml", "**/neoforge.mods.toml"]) { + expand "version": file_version + } +} + +Spec notNeoTask = { Task it -> !it.name.startsWith("neo") } as Spec + +tasks.withType(JavaCompile).matching(notNeoTask).configureEach { + source(project(":Core").sourceSets.main.allSource) +} + +task sourcesJar(type: Jar) { + from sourceSets.main.allSource + from(project(":Core").sourceSets.main.allSource) + archiveClassifier = 'sources' +} + +jar { + manifest { + attributes([ + 'FMLAT': 'accesstransformer.cfg', + "MixinConfigs" : "defaultsettings.mixin.json" + ]) + } +} + +artifacts { + archives jar + archives sourcesJar +} + +task publishCurseForge(type: net.darkhax.curseforgegradle.TaskPublishCurseForge) { + if (System.getenv("CURSE_API") != null && !System.getenv("CURSE_API").equals("")) { + disableVersionDetection() + apiToken = System.getenv("CURSE_API") + + def mainFile = upload(318012, jar) + mainFile.releaseType = project.ext.relType + mainFile.displayName = "$archivesBaseName-$version" + mainFile.changelogType = 'html' + mainFile.changelog = file('../../changelog.html') + mainFile.addRequirement('jcplugin') + mainFile.addModLoader('NeoForge') + mainFile.addJavaVersion('Java 21') + mainFile.addJavaVersion('Java 17') + mainFile.addGameVersion('1.20.6') + mainFile.addGameVersion('1.20.5') + mainFile.addGameVersion('1.20.4') + mainFile.addGameVersion('1.20.3') + mainFile.addGameVersion('1.20.2') + mainFile.addGameVersion('Client') + + def sourcesFile = mainFile.withAdditionalFile(sourcesJar) + sourcesFile.changelog = file('../../changelog.html') + sourcesFile.addRequirement('jcplugin') + sourcesFile.displayName = "$archivesBaseName-$version-sources" + } +} + +task("copyRelease") { + dependsOn "build" + + doFirst { + println "Gathering builds" + copy { + def libDir = project.projectDir.toPath().resolve("build/libs") + from(libDir) { + include "*.jar" + exclude "*-dev.jar", "*-sources.jar" + } + into "../../build/libs/" + duplicatesStrategy DuplicatesStrategy.INCLUDE + } + } +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.5/gradle.properties b/sources/NeoForge-1.21.5/gradle.properties new file mode 100644 index 00000000..2c1dbc7e --- /dev/null +++ b/sources/NeoForge-1.21.5/gradle.properties @@ -0,0 +1 @@ +javaVersion = 21 \ No newline at end of file diff --git a/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java new file mode 100644 index 00000000..8122ba77 --- /dev/null +++ b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java @@ -0,0 +1,185 @@ +package net.jomcraft.defaultsettings; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.Field; +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.zip.ZipEntry; +import cpw.mods.modlauncher.Launcher; +import cpw.mods.modlauncher.api.IEnvironment; +import net.jomcraft.defaultsettings.commands.ConfigArguments; +import net.jomcraft.defaultsettings.commands.OperationArguments; +import net.jomcraft.defaultsettings.commands.TypeArguments; +import net.jomcraft.jcplugin.JCLogger; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.commands.synchronization.ArgumentTypeInfos; +import net.minecraft.core.registries.Registries; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.fml.event.lifecycle.FMLLoadCompleteEvent; +import net.neoforged.fml.loading.FMLLoader; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.fml.common.Mod; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import net.jomcraft.jcplugin.FileUtilNoMC; + +@Mod(DefaultSettings.MODID) +public class DefaultSettings { + + public static final String MODID = "defaultsettings"; + public static final Logger log = LogManager.getLogger(DefaultSettings.MODID); + public static final String VERSION = DefaultSettings.class.getPackage().getImplementationVersion(); + public static Map keyRebinds = new HashMap(); + public static boolean setUp = false; + public static DefaultSettings instance; + public static boolean shutDown = false; + public static String shutdownReason = null; + + public String getVersion() throws IOException, URISyntaxException { + Manifest manifest = ManifestUtility.readManifest(this.getClass()); + Attributes attr = manifest.getMainAttributes(); + return attr.getValue("Implementation-Version"); + } + + private static final DeferredRegister> COMMAND_ARGUMENT_TYPES = DeferredRegister.create(Registries.COMMAND_ARGUMENT_TYPE, DefaultSettings.MODID); + + @SuppressWarnings({"deprecation"}) + public DefaultSettings(IEventBus modEventBus) { + instance = this; + NeoForgeCoreHook core = new NeoForgeCoreHook(); + Core.setInstance(core); + + if (FMLLoader.getDist().isClient()) { + if (setUp) return; + + try { + Field pluginClass = Class.forName("net.jomcraft.jcplugin.JCPlugin").getDeclaredField("checksSuccessful"); + + if (!pluginClass.getBoolean(null)) { + shutDown = true; + shutdownReason = "The JCPlugin mod couldn't be found! Please make sure that the correct version (probably " + VERSION + ") is installed!"; + DefaultSettings.log.log(Level.ERROR, "DefaultSettings can't start up! Something is hella broken! Shutting down..."); + } else { + + final Path location = Launcher.INSTANCE.environment().getProperty(IEnvironment.Keys.GAMEDIR.get()).get(); + + File mods = new File(location.toFile(), "mods"); + + boolean foundDefaultSettings = false; + String wantedVersion = null; + + for (File mod : mods.listFiles()) { + if (mod.getName().toLowerCase().contains("defaultsettings")) { + + JarFile jar = new JarFile(mod); + + ZipEntry toml = jar.getEntry("META-INF/MANIFEST.MF"); + if (toml != null) { + + BufferedReader result = new BufferedReader(new InputStreamReader(jar.getInputStream(toml))); + + String readerLine; + + while ((readerLine = result.readLine()) != null) { + if (readerLine.contains("Implementation-Title: DefaultSettings")) { + foundDefaultSettings = true; + } else if (readerLine.startsWith("JCPluginVersion")) { + wantedVersion = readerLine.split(": ")[1]; + } + } + + result.close(); + } + + jar.close(); + + if (foundDefaultSettings && wantedVersion != null) { + + if (wantedVersion.equals(JCLogger.class.getPackage().getImplementationVersion())) { + DefaultSettings.log.log(Level.INFO, "DefaultSettings found correct version of JCPlugin, starting up..."); + break; + } else { + shutDown = true; + shutdownReason = "The correct JCPlugin mod version couldn't be found! Please install version " + wantedVersion; + DefaultSettings.log.log(Level.ERROR, "DefaultSettings can't start up! JCPlugin version must be " + wantedVersion + "!"); + } + + } + } + } + + String launchTarget = Launcher.INSTANCE.environment().getProperty(IEnvironment.Keys.LAUNCHTARGET.get()).get(); + + if (!launchTarget.contains("dev") && (!foundDefaultSettings || wantedVersion == null)) { + shutDown = true; + shutdownReason = "Strange! We can't find the DefaultSettings mod, eventhough you're currently using it!"; + DefaultSettings.log.log(Level.ERROR, "DefaultSettings can't start up! Couldn't get requested version of JCPlugin!"); + } + } + } catch (ClassNotFoundException | NoSuchFieldException | SecurityException | IllegalArgumentException | + IllegalAccessException | IOException e) { + shutDown = true; + shutdownReason = "The JCPlugin mod couldn't be found! Please make sure that the correct version (probably " + VERSION + ") is installed!"; + DefaultSettings.log.log(Level.ERROR, "DefaultSettings is missing the JCPlugin mod! Shutting down..."); + } + + modEventBus.addListener(this::postInit); + + COMMAND_ARGUMENT_TYPES.register("ds_config", () -> ArgumentTypeInfos.registerByClass(ConfigArguments.class, new ConfigArguments.Info())); + COMMAND_ARGUMENT_TYPES.register("ds_operation", () -> ArgumentTypeInfos.registerByClass(OperationArguments.class, new OperationArguments.Info())); + COMMAND_ARGUMENT_TYPES.register("ds_type", () -> ArgumentTypeInfos.registerByClass(TypeArguments.class, new TypeArguments.Info())); + + COMMAND_ARGUMENT_TYPES.register(modEventBus); + + //ModLoadingContext.get().registerExtensionPoint(IExtensionPoint.DisplayTest.class, () -> new IExtensionPoint.DisplayTest(() -> "ANY", (remote, isServer) -> true)); + + NeoForge.EVENT_BUS.register(new EventHandlers()); + + if (shutDown) return; + + try { + FileUtil.restoreContents(); + + } catch (Exception e) { + DefaultSettings.log.log(Level.ERROR, "An exception occurred while starting up the game:", e); + } + setUp = true; + + } + + if (FMLLoader.getDist().isDedicatedServer()) { + DefaultSettings.log.log(Level.WARN, "DefaultSettings is a client-side mod only! It won't do anything on servers!"); + } + } + + @SuppressWarnings("deprecation") + public void postInit(FMLLoadCompleteEvent event) { + if (FMLLoader.getDist().isClient()) { + try { + if (!shutDown) FileUtil.restoreKeys(true, FileUtilNoMC.privateJson.firstBootUp); + } catch (IOException e) { + DefaultSettings.log.log(Level.ERROR, "An exception occurred while starting up the game (Post):", e); + } catch (NullPointerException e) { + DefaultSettings.log.log(Level.ERROR, "An exception occurred while starting up the game (Post):", e); + } + } + + if (FMLLoader.getDist().isDedicatedServer()) { + DefaultSettings.log.log(Level.WARN, "DefaultSettings is a client-side mod only! It won't do anything on servers!"); + } + } + + public static DefaultSettings getInstance() { + return instance; + } +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/EventHandlers.java b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/EventHandlers.java new file mode 100644 index 00000000..e3672cb6 --- /dev/null +++ b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/EventHandlers.java @@ -0,0 +1,13 @@ +package net.jomcraft.defaultsettings; + +import net.jomcraft.defaultsettings.commands.CommandDefaultSettings; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.neoforge.event.server.ServerStartingEvent; + +public class EventHandlers { + + @SubscribeEvent + public void serverStarting(ServerStartingEvent event) { + CommandDefaultSettings.register(event); + } +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/FileUtil.java b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/FileUtil.java new file mode 100644 index 00000000..faa253b3 --- /dev/null +++ b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/FileUtil.java @@ -0,0 +1,182 @@ +package net.jomcraft.defaultsettings; + +import static net.jomcraft.jcplugin.FileUtilNoMC.*; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.util.ArrayList; + +import com.mojang.blaze3d.platform.InputConstants; +import net.minecraft.client.KeyMapping; +import net.neoforged.fml.util.ObfuscationReflectionHelper; +import net.neoforged.neoforge.client.settings.KeyModifier; +import org.apache.logging.log4j.Level; +import net.minecraft.client.Minecraft; + +public class FileUtil { + + public static void restoreContents() throws NullPointerException, IOException { + + final String version = getMainJSON().getVersion(); + + if (!DefaultSettings.VERSION.equals(version)) + mainJson.setVersion(DefaultSettings.VERSION).setPrevVersion(version); + + if (mainJson.generatedBy.equals("")) + mainJson.generatedBy = privateJson.privateIdentifier; + + activeProfile = privateJson.currentProfile; + + if (!privateJson.firstBootUp) { + copyAndHashPrivate(true, true); + } + + final File optionsOF = new File(mcDataDir, "optionsof.txt"); + if (!optionsOF.exists()) + restoreOptionsOF(); + + final File optionsShaders = new File(mcDataDir, "optionsshaders.txt"); + if (!optionsShaders.exists()) + restoreOptionsShaders(); + + final File optionsJEK = new File(mcDataDir, "options.justenoughkeys.txt"); + if (!optionsJEK.exists()) + restoreOptionsJEK(); + + final File optionsAmecs = new File(mcDataDir, "options.amecsapi.txt"); + if (!optionsAmecs.exists()) + restoreOptionsAmecs(); + + final File serversFile = new File(mcDataDir, "servers.dat"); + if (!serversFile.exists()) + restoreServers(); + + mainJson.save(); + } + + @SuppressWarnings("resource") + public static void restoreKeys(boolean update, boolean initial) throws NullPointerException, IOException, NumberFormatException { + CoreUtil.restoreKeys(update, initial); + } + + @SuppressWarnings("resource") + public static void saveKeys() throws IOException, NullPointerException { + CoreUtil.saveKeys(); + } + + @SuppressWarnings("resource") + public static boolean saveOptions() throws NullPointerException, IOException { + Minecraft.getInstance().options.save(); + return CoreUtil.saveOptions(); + } + + public static boolean checkChanged() { + boolean ret = false; + try { + + InputStream keys = CoreUtil.getKeysStream(false); + InputStream options = getOptionsStream(); + InputStream optionsOF = getOptionsOFStream(); + InputStream optionsShaders = getOptionsShadersStream(); + InputStream optionsJEK = getOptionsJEKStream(); + InputStream optionsAmecs = getOptionsAmecsStream(); + InputStream servers = getServersStream(); + + String hashO = ""; + String writtenHashO = ""; + + if (options != null) { + hashO = fileToHash(options); + writtenHashO = mainJson.hashes.get(activeProfile + "/options.txt"); + } + + String hashK = ""; + String writtenHashK = ""; + + if (keys != null) { + hashK = fileToHash(keys); + writtenHashK = mainJson.hashes.get(activeProfile + "/keys.txt"); + } + + String hashOF = ""; + String writtenHashOF = ""; + + if (optionsOF != null) { + hashOF = fileToHash(optionsOF); + writtenHashOF = mainJson.hashes.get(activeProfile + "/optionsof.txt"); + } + + String hashShaders = ""; + String writtenHashShaders = ""; + + if (optionsShaders != null) { + hashShaders = fileToHash(optionsShaders); + writtenHashShaders = mainJson.hashes.get(activeProfile + "/optionsshaders.txt"); + } + + String hashJEK = ""; + String writtenHashJEK = ""; + + if (optionsJEK != null) { + hashJEK = fileToHash(optionsJEK); + writtenHashJEK = mainJson.hashes.get(activeProfile + "/options.justenoughkeys.txt"); + } + + String hashAmecs = ""; + String writtenHashAmecs = ""; + + if (optionsAmecs != null) { + hashAmecs = fileToHash(optionsAmecs); + writtenHashAmecs = mainJson.hashes.get(activeProfile + "/options.amecsapi.txt"); + } + + String hashS = ""; + String writtenHashS = ""; + + if (servers != null) { + hashS = fileToHash(servers); + writtenHashS = mainJson.hashes.get(activeProfile + "/servers.dat"); + } + + if (mainJson.hashes.containsKey(activeProfile + "/options.txt") && !hashO.equals(writtenHashO)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/keys.txt") && !hashK.equals(writtenHashK)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/optionsof.txt") && !hashOF.equals(writtenHashOF)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/optionsshaders.txt") && !hashShaders.equals(writtenHashShaders)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/options.justenoughkeys.txt") && !hashJEK.equals(writtenHashJEK)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/options.amecsapi.txt") && !hashAmecs.equals(writtenHashAmecs)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/servers.dat") && !hashS.equals(writtenHashS)) { + ret = true; + } + + if (options != null) { + options.close(); + File fileO = new File(getMainFolder(), activeProfile + "/options.txt_temp"); + Files.delete(fileO.toPath()); + } + + if (keys != null) { + keys.close(); + File fileK = new File(getMainFolder(), activeProfile + "/keys.txt_temp"); + Files.delete(fileK.toPath()); + } + + } catch (Exception e) { + DefaultSettings.log.log(Level.ERROR, "Error while saving configs: ", e); + } + + return ret; + } +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/KeyContainer.java b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/KeyContainer.java new file mode 100644 index 00000000..b80e99b0 --- /dev/null +++ b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/KeyContainer.java @@ -0,0 +1,16 @@ +package net.jomcraft.defaultsettings; + +import com.mojang.blaze3d.platform.InputConstants; +import net.neoforged.neoforge.client.settings.KeyModifier; + +public class KeyContainer { + + public final InputConstants.Key input; + public final KeyModifier modifier; + + public KeyContainer(final InputConstants.Key input, final KeyModifier modifier) { + this.input = input; + this.modifier = modifier; + } + +} diff --git a/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/ManifestUtility.java b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/ManifestUtility.java new file mode 100644 index 00000000..c9897a28 --- /dev/null +++ b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/ManifestUtility.java @@ -0,0 +1,113 @@ +//Part of fabric-loader (net.fabricmc.loader.impl.util.ManifestUtil) +package net.jomcraft.defaultsettings; + +import java.io.IOException; +import java.io.InputStream; +import java.net.*; +import java.nio.file.*; +import java.security.CodeSource; +import java.util.Collections; +import java.util.Map; +import java.util.jar.Manifest; +import java.util.zip.ZipError; + +public class ManifestUtility { + + private static final Map jfsArgsCreate = Collections.singletonMap("create", "true"); + private static final Map jfsArgsEmpty = Collections.emptyMap(); + + public static Manifest readManifest(Class cls) throws IOException, URISyntaxException { + CodeSource cs = cls.getProtectionDomain().getCodeSource(); + if (cs == null) return null; + + URL url = cs.getLocation(); + if (url == null) return null; + + return readManifest(url); + } + + public static Path asPath(URL url) { + try { + return Paths.get(url.toURI()); + } catch (URISyntaxException e) { + return null; + } + } + + public static Manifest readManifest(URL codeSourceUrl) throws IOException, URISyntaxException { + Path path = asPath(codeSourceUrl); + + if (Files.isDirectory(path)) { + return readManifest(path); + } else { + URLConnection connection = new URL("jar:" + codeSourceUrl.toString() + "!/").openConnection(); + + if (connection instanceof JarURLConnection) { + return ((JarURLConnection) connection).getManifest(); + } + + try (FileSystemDelegate jarFs = getJarFileSystem(path.toUri(), false)) { + return readManifest(jarFs.get().getRootDirectories().iterator().next()); + } + } + } + + public static FileSystemDelegate getJarFileSystem(URI uri, boolean create) throws IOException { + URI jarUri; + + try { + jarUri = new URI("jar:" + uri.getScheme(), uri.getHost(), uri.getPath(), uri.getFragment()); + } catch (URISyntaxException e) { + throw new IOException(e); + } + + boolean opened = false; + FileSystem ret = null; + + try { + ret = FileSystems.getFileSystem(jarUri); + } catch (FileSystemNotFoundException ignore) { + try { + ret = FileSystems.newFileSystem(jarUri, create ? jfsArgsCreate : jfsArgsEmpty); + opened = true; + } catch (FileSystemAlreadyExistsException ignore2) { + ret = FileSystems.getFileSystem(jarUri); + } catch (IOException | ZipError e) { + throw new IOException("Error accessing "+uri+": "+e, e); + } + } + + return new FileSystemDelegate(ret, opened); + } + + public static Manifest readManifest(Path basePath) throws IOException { + Path path = basePath.resolve("META-INF").resolve("MANIFEST.MF"); + if (!Files.exists(path)) return null; + + try (InputStream stream = Files.newInputStream(path)) { + return new Manifest(stream); + } + } + + public static class FileSystemDelegate implements AutoCloseable { + private final FileSystem fileSystem; + private final boolean owner; + + public FileSystemDelegate(FileSystem fileSystem, boolean owner) { + this.fileSystem = fileSystem; + this.owner = owner; + } + + public FileSystem get() { + return fileSystem; + } + + @Override + public void close() throws IOException { + if (owner) { + fileSystem.close(); + } + } + } + +} diff --git a/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/NeoForgeCoreHook.java b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/NeoForgeCoreHook.java new file mode 100644 index 00000000..079fcd8a --- /dev/null +++ b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/NeoForgeCoreHook.java @@ -0,0 +1,190 @@ +package net.jomcraft.defaultsettings; + +import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import net.jomcraft.jcplugin.FileUtilNoMC; +import net.minecraft.ChatFormatting; +import net.minecraft.client.KeyMapping; +import net.minecraft.client.Minecraft; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.network.chat.Component; +import net.neoforged.fml.util.ObfuscationReflectionHelper; +import net.neoforged.neoforge.client.settings.KeyModifier; +import org.apache.logging.log4j.Logger; +import java.io.File; +import java.io.IOException; + +public class NeoForgeCoreHook implements ICoreHook { + + private static final SimpleCommandExceptionType FAILED_EXCEPTION = new SimpleCommandExceptionType(Component.literal(ChatFormatting.RED + "Please wait until the last request has finished")); + + @Override + public File getMCDataDir() { + return FileUtilNoMC.mcDataDir; + } + + @Override + public File getMainFolder() { + return FileUtilNoMC.getMainFolder(); + } + + @Override + public String getActiveProfile() { + return FileUtilNoMC.activeProfile; + } + + @Override + public KeyPlaceholder[] getKeyMappings() { + KeyMapping[] mappings = Minecraft.getInstance().options.keyMappings; + if(mappings == null || mappings.length == 0) + return new KeyPlaceholder[0]; + + KeyPlaceholder[] keys = new KeyPlaceholder[mappings.length]; + + for(int i = 0; i < mappings.length; i++) { + keys[i] = new KeyPlaceholder(mappings[i].getName(), mappings[i].getKey().toString(), mappings[i].getKeyModifier().name()); + } + return keys; + } + + @Override + public void resetMappings() { + KeyMapping.resetMapping(); + } + + @Override + public void clearKeyBinds() { + DefaultSettings.keyRebinds.clear(); + } + + @Override + public void putKeybind(String first, String second, String third) { + DefaultSettings.keyRebinds.put(first, new KeyContainer(InputConstants.getKey(second), third != null ? KeyModifier.valueFromString(third) : KeyModifier.NONE)); + } + + @Override + public boolean keybindExists(String key) { + return DefaultSettings.keyRebinds.containsKey(key); + } + + @Override + public void setKeybind(KeyPlaceholder key, boolean init) { + KeyMapping[] mappings = Minecraft.getInstance().options.keyMappings; + for(int i = 0; i < mappings.length; i++){ + if(mappings[i].getName().equals(key.name)){ + KeyContainer container = DefaultSettings.keyRebinds.get(key.name); + + if(init) + mappings[i].setKey(container.input); + + mappings[i].defaultKey = container.input; + + ObfuscationReflectionHelper.setPrivateValue(KeyMapping.class, mappings[i], container.modifier, "keyModifierDefault"); + mappings[i].setKeyModifierAndCode(mappings[i].getDefaultKeyModifier(), container.input); + break; + } + } + } + + @Override + public void sendSuccess(Object source, String text, int color) { + if (source instanceof CommandSourceStack) { + ((CommandSourceStack) source).sendSuccess(() -> Component.literal(text).withStyle(ChatFormatting.getById(color)), true); + } + } + + @Override + public Exception throwFailedException() { + return FAILED_EXCEPTION.create(); + } + + @Override + public boolean hasDSShutDown() { + return DefaultSettings.shutDown; + } + + @Override + public Logger getDSLog() { + return DefaultSettings.log; + } + + @Override + public String shutdownReason() { + return DefaultSettings.shutdownReason; + } + + @Override + public boolean isOtherCreator() { + return FileUtilNoMC.otherCreator; + } + + @Override + public boolean disableCreatorCheck() { + return FileUtilNoMC.privateJson.disableCreatorCheck; + } + + @Override + public boolean checkChangedConfig() { + return FileUtilNoMC.checkChangedConfig(); + } + + @Override + public boolean checkForConfigFiles() { + return FileUtilNoMC.checkForConfigFiles(); + } + + @Override + public void checkMD5(boolean updateExisting, boolean configs, String file) throws IOException { + FileUtilNoMC.checkMD5(updateExisting, configs, file); + } + + @Override + public void copyAndHashPrivate(boolean options, boolean configs) throws NullPointerException, IOException { + FileUtilNoMC.copyAndHashPrivate(options, configs); + } + + @Override + public boolean keysFileExist() { + return FileUtilNoMC.keysFileExist(); + } + + @Override + public boolean optionsFilesExist() { + return FileUtilNoMC.optionsFilesExist(); + } + + @Override + public boolean serversFileExists() { + return FileUtilNoMC.serversFileExists(); + } + + @Override + public boolean checkChanged() { + return FileUtil.checkChanged(); + } + + @Override + public void saveKeys() throws IOException { + FileUtil.saveKeys(); + } + + @Override + public boolean saveOptions() throws IOException { + return FileUtil.saveOptions(); + } + + @Override + public void saveServers() throws IOException { + FileUtilNoMC.saveServers(); + } + + @Override + public void restoreKeys(boolean update, boolean initial) throws IOException { + FileUtil.restoreKeys(update, initial); + } + + @Override + public void saveOptionsFile() { + Minecraft.getInstance().options.save(); + } +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/CommandDefaultSettings.java b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/CommandDefaultSettings.java new file mode 100644 index 00000000..8fc09c66 --- /dev/null +++ b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/CommandDefaultSettings.java @@ -0,0 +1,51 @@ +package net.jomcraft.defaultsettings.commands; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.tree.LiteralCommandNode; +import net.jomcraft.defaultsettings.CoreUtil; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.neoforged.neoforge.event.server.ServerStartingEvent; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +public class CommandDefaultSettings { + + public static void register(ServerStartingEvent event) { + LiteralArgumentBuilder literalargumentbuilder = Commands.literal("defaultsettings"); + + literalargumentbuilder.then(Commands.literal("save").executes((command) -> { + return saveProcess(command.getSource(), null, null); + }).then(Commands.argument("operation", OperationArguments.operationArguments(false)).executes((command) -> { + return saveProcess(command.getSource(), OperationArguments.getString(command, "operation"), null); + }).then(Commands.argument("type", TypeArguments.typeArguments()).executes((command) -> { + return saveProcess(command.getSource(), OperationArguments.getString(command, "operation"), TypeArguments.getString(command, "type")); + })))).then(Commands.literal("saveconfigs").executes((command) -> { + return saveProcessConfigs(command.getSource(), null, null); + }).then(Commands.argument("operation", OperationArguments.operationArguments(true)).executes((command) -> { + return saveProcessConfigs(command.getSource(), OperationArguments.getString(command, "operation"), null); + }).then(Commands.argument("config", ConfigArguments.configArguments()).executes((command) -> { + return saveProcessConfigs(command.getSource(), OperationArguments.getString(command, "operation"), ConfigArguments.getString(command, "config")); + })))); + + LiteralCommandNode node = event.getServer().getCommands().getDispatcher().register(literalargumentbuilder); + event.getServer().getCommands().getDispatcher().register(Commands.literal("ds").redirect(node)); + } + + private static int saveProcessConfigs(CommandSourceStack source, String argument, String argument2) throws CommandSyntaxException { + try { + return CoreUtil.saveProcessConfigs(source, argument, argument2); + } catch (Exception e) { + if (e instanceof CommandSyntaxException) throw (CommandSyntaxException) e; + return 0; + } + } + + private static int saveProcess(CommandSourceStack source, String argument, String argument2) throws CommandSyntaxException { + try { + return CoreUtil.saveProcess(source, argument, argument2); + } catch (Exception e) { + if (e instanceof CommandSyntaxException) throw (CommandSyntaxException) e; + return 0; + } + } +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/ConfigArguments.java b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/ConfigArguments.java new file mode 100644 index 00000000..a52b8d5f --- /dev/null +++ b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/ConfigArguments.java @@ -0,0 +1,118 @@ +package net.jomcraft.defaultsettings.commands; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import com.google.gson.JsonObject; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.jomcraft.defaultsettings.DefaultSettings; +import net.jomcraft.jcplugin.FileUtilNoMC; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.network.FriendlyByteBuf; + +public class ConfigArguments implements ArgumentType { + + private static List ARGUMENTS = Arrays.asList("fml.toml", "forge-client.toml"); + + public static ConfigArguments configArguments() { + return new ConfigArguments(); + } + + @Override + public String parse(final StringReader reader) throws CommandSyntaxException { + return readQuotedString(reader); + } + + public String readQuotedString(final StringReader reader) throws CommandSyntaxException { + if (!reader.canRead()) { + return ""; + } + final char next = reader.getString().charAt(reader.getCursor()); + if (!reader.isQuotedStringStart(next)) { + + final int start = reader.getCursor(); + while (reader.canRead()) { + reader.skip(); + } + return reader.getString().substring(start, reader.getCursor()); + } + reader.skip(); + return reader.readStringUntil(next); + } + + public static String getString(final CommandContext context, final String name) { + return context.getArgument(name, String.class); + } + + @Override + public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) { + try { + ArrayList filtered = new ArrayList(); + ArrayList prevList = FileUtilNoMC.listConfigFiles(); + for(int i = 0; i < prevList.size(); i++){ + String name = prevList.get(i); + if(name.contains(" ")) + name = "\"" + name + "\""; + filtered.add(name); + } + ARGUMENTS = filtered; + } catch (IOException e) { + DefaultSettings.log.error(e); + } + return SharedSuggestionProvider.suggest(ARGUMENTS, builder); + } + + @Override + public Collection getExamples() { + return ARGUMENTS; + } + + public static class Info implements ArgumentTypeInfo { + @Override + public void serializeToNetwork(Template template, FriendlyByteBuf buffer) { + + } + + @Override + public Template deserializeFromNetwork(FriendlyByteBuf buffer) { + return new Template(); + } + + @Override + public void serializeToJson(Template template, JsonObject json) { + + } + + @Override + public Template unpack(ConfigArguments argument) { + return new Template(); + } + + public class Template implements ArgumentTypeInfo.Template { + + Template() { + + } + + @Override + public ConfigArguments instantiate(CommandBuildContext p_223435_) { + return new ConfigArguments(); + } + + @Override + public ArgumentTypeInfo type() { + return Info.this; + } + } + } +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/OperationArguments.java b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/OperationArguments.java new file mode 100644 index 00000000..bb9f85b1 --- /dev/null +++ b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/OperationArguments.java @@ -0,0 +1,92 @@ +package net.jomcraft.defaultsettings.commands; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import com.google.gson.JsonObject; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.network.FriendlyByteBuf; + +public class OperationArguments implements ArgumentType { + + private static final List ARGUMENTS = Arrays.asList("override", "forceOverride"); + private static final List ARGUMENTS_LIMITED = Arrays.asList("forceOverride"); + private final boolean limited; + + public OperationArguments(boolean limited) { + this.limited = limited; + } + + public static OperationArguments operationArguments(boolean limited) { + return new OperationArguments(limited); + } + + @Override + public String parse(final StringReader reader) throws CommandSyntaxException { + return reader.readUnquotedString(); + } + + public static String getString(final CommandContext context, final String name) { + return context.getArgument(name, String.class); + } + + @Override + public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) { + return SharedSuggestionProvider.suggest(this.limited ? ARGUMENTS_LIMITED : ARGUMENTS, builder); + } + + @Override + public Collection getExamples() { + return ARGUMENTS; + } + + public static class Info implements ArgumentTypeInfo { + @Override + public void serializeToNetwork(Template template, FriendlyByteBuf buffer) { + buffer.writeBoolean(template.limited); + } + + @Override + public Template deserializeFromNetwork(FriendlyByteBuf buffer) { + boolean limited = buffer.readBoolean(); + return new Template(limited); + } + + @Override + public void serializeToJson(Template template, JsonObject json) { + json.addProperty("limited", template.limited); + } + + @Override + public Template unpack(OperationArguments argument) { + return new Template(argument.limited); + } + + public class Template implements ArgumentTypeInfo.Template { + final boolean limited; + + Template(boolean limited) { + this.limited = limited; + } + + @Override + public OperationArguments instantiate(CommandBuildContext p_223435_) { + return new OperationArguments(this.limited); + } + + @Override + public ArgumentTypeInfo type() { + return Info.this; + } + } + } +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/TypeArguments.java b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/TypeArguments.java new file mode 100644 index 00000000..8fa88263 --- /dev/null +++ b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/TypeArguments.java @@ -0,0 +1,83 @@ +package net.jomcraft.defaultsettings.commands; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import com.google.gson.JsonObject; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.network.FriendlyByteBuf; + +public class TypeArguments implements ArgumentType { + + private static final List ARGUMENTS = Arrays.asList("options", "keybinds", "servers"); + + public static TypeArguments typeArguments() { + return new TypeArguments(); + } + + @Override + public String parse(final StringReader reader) throws CommandSyntaxException { + return reader.readUnquotedString(); + } + + public static String getString(final CommandContext context, final String name) { + return context.getArgument(name, String.class); + } + + @Override + public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) { + return SharedSuggestionProvider.suggest(ARGUMENTS, builder); + } + + @Override + public Collection getExamples() { + return ARGUMENTS; + } + + public static class Info implements ArgumentTypeInfo { + @Override + public void serializeToNetwork(Template template, FriendlyByteBuf buffer) { + + } + + @Override + public Template deserializeFromNetwork(FriendlyByteBuf buffer) { + return new Template(); + } + + @Override + public void serializeToJson(Template template, JsonObject json) { + } + + @Override + public Template unpack(TypeArguments argument) { + return new Template(); + } + + public class Template implements ArgumentTypeInfo.Template { + + Template() { + + } + + @Override + public TypeArguments instantiate(CommandBuildContext p_223435_) { + return new TypeArguments(); + } + + @Override + public ArgumentTypeInfo type() { + return Info.this; + } + } + } +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.5/src/main/resources/META-INF/neoforge.mods.toml b/sources/NeoForge-1.21.5/src/main/resources/META-INF/neoforge.mods.toml new file mode 100644 index 00000000..e8ff9040 --- /dev/null +++ b/sources/NeoForge-1.21.5/src/main/resources/META-INF/neoforge.mods.toml @@ -0,0 +1,29 @@ +modLoader="javafml" +loaderVersion="[1,)" +logoFile="logo.png" +license="Apache License 2.0" +displayTest="IGNORE_ALL_VERSION" + +[[mods]] + modId="defaultsettings" + version="${version}" + displayName="DefaultSettings" + description='''Keep your game's local settings in case of an update to your modpack''' + side="CLIENT" + authors="PT400C - Jomcraft Network" + credits="Developed by Jomcraft Network" + displayURL="https://www.curseforge.com/minecraft/mc-mods/defaultsettings" + +[[dependencies.defaultsettings]] + modId="neoforge" + type="required" + versionRange="[21.5,)" + ordering="NONE" + side="CLIENT" + +[[dependencies.defaultsettings]] + modId="minecraft" + type="required" + versionRange="[1.21.5,)" + ordering="NONE" + side="CLIENT" \ No newline at end of file diff --git a/sources/NeoForge-1.21.5/src/main/resources/logo.png b/sources/NeoForge-1.21.5/src/main/resources/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6f345514da0f0b162d7759a1c9d62d85b82a638e GIT binary patch literal 51342 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 n!ZX~V14{r4{eOLYa%>)6=DYpuB{JC%{UXv& notNeoTask = { Task it -> !it.name.startsWith("neo") } as Spec + +tasks.withType(JavaCompile).matching(notNeoTask).configureEach { + source(project(":Core").sourceSets.main.allSource) +} + +task sourcesJar(type: Jar) { + from sourceSets.main.allSource + from(project(":Core").sourceSets.main.allSource) + archiveClassifier = 'sources' +} + +jar { + manifest { + attributes([ + 'FMLAT': 'accesstransformer.cfg', + "MixinConfigs" : "defaultsettings.mixin.json" + ]) + } +} + +artifacts { + archives jar + archives sourcesJar +} + +task publishCurseForge(type: net.darkhax.curseforgegradle.TaskPublishCurseForge) { + if (System.getenv("CURSE_API") != null && !System.getenv("CURSE_API").equals("")) { + disableVersionDetection() + apiToken = System.getenv("CURSE_API") + + def mainFile = upload(318012, jar) + mainFile.releaseType = project.ext.relType + mainFile.displayName = "$archivesBaseName-$version" + mainFile.changelogType = 'html' + mainFile.changelog = file('../../changelog.html') + mainFile.addRequirement('jcplugin') + mainFile.addModLoader('NeoForge') + mainFile.addJavaVersion('Java 21') + mainFile.addJavaVersion('Java 17') + mainFile.addGameVersion('1.20.6') + mainFile.addGameVersion('1.20.5') + mainFile.addGameVersion('1.20.4') + mainFile.addGameVersion('1.20.3') + mainFile.addGameVersion('1.20.2') + mainFile.addGameVersion('Client') + + def sourcesFile = mainFile.withAdditionalFile(sourcesJar) + sourcesFile.changelog = file('../../changelog.html') + sourcesFile.addRequirement('jcplugin') + sourcesFile.displayName = "$archivesBaseName-$version-sources" + } +} + +task("copyRelease") { + dependsOn "build" + + doFirst { + println "Gathering builds" + copy { + def libDir = project.projectDir.toPath().resolve("build/libs") + from(libDir) { + include "*.jar" + exclude "*-dev.jar", "*-sources.jar" + } + into "../../build/libs/" + duplicatesStrategy DuplicatesStrategy.INCLUDE + } + } +} \ No newline at end of file diff --git a/sources/NeoForge-1.21.9/gradle.properties b/sources/NeoForge-1.21.9/gradle.properties new file mode 100644 index 00000000..2c1dbc7e --- /dev/null +++ b/sources/NeoForge-1.21.9/gradle.properties @@ -0,0 +1 @@ +javaVersion = 21 \ No newline at end of file diff --git a/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java index 2fbc843d..d5cc4dc9 100644 --- a/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java +++ b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java @@ -45,7 +45,7 @@ public class DefaultSettings { public static String shutdownReason = null; public String getVersion() throws IOException, URISyntaxException { - Manifest manifest = readManifest(this.getClass()); + Manifest manifest = ManifestUtility.readManifest(this.getClass()); Attributes attr = manifest.getMainAttributes(); return attr.getValue("Implementation-Version"); } @@ -188,100 +188,4 @@ public static DefaultSettings getInstance() { return instance; } - public static Manifest readManifest(Class cls) throws IOException, URISyntaxException { - CodeSource cs = cls.getProtectionDomain().getCodeSource(); - if (cs == null) return null; - - URL url = cs.getLocation(); - if (url == null) return null; - - return readManifest(url); - } - - public static Path asPath(URL url) { - try { - return Paths.get(url.toURI()); - } catch (URISyntaxException e) { - return null; - } - } - - public static Manifest readManifest(URL codeSourceUrl) throws IOException, URISyntaxException { - Path path = asPath(codeSourceUrl); - - if (Files.isDirectory(path)) { - return readManifest(path); - } else { - URLConnection connection = new URL("jar:" + codeSourceUrl.toString() + "!/").openConnection(); - - if (connection instanceof JarURLConnection) { - return ((JarURLConnection) connection).getManifest(); - } - - try (FileSystemDelegate jarFs = getJarFileSystem(path.toUri(), false)) { - return readManifest(jarFs.get().getRootDirectories().iterator().next()); - } - } - } - - private static final Map jfsArgsCreate = Collections.singletonMap("create", "true"); - private static final Map jfsArgsEmpty = Collections.emptyMap(); - - public static FileSystemDelegate getJarFileSystem(URI uri, boolean create) throws IOException { - URI jarUri; - - try { - jarUri = new URI("jar:" + uri.getScheme(), uri.getHost(), uri.getPath(), uri.getFragment()); - } catch (URISyntaxException e) { - throw new IOException(e); - } - - boolean opened = false; - FileSystem ret = null; - - try { - ret = FileSystems.getFileSystem(jarUri); - } catch (FileSystemNotFoundException ignore) { - try { - ret = FileSystems.newFileSystem(jarUri, create ? jfsArgsCreate : jfsArgsEmpty); - opened = true; - } catch (FileSystemAlreadyExistsException ignore2) { - ret = FileSystems.getFileSystem(jarUri); - } catch (IOException | ZipError e) { - throw new IOException("Error accessing "+uri+": "+e, e); - } - } - - return new FileSystemDelegate(ret, opened); - } - - public static Manifest readManifest(Path basePath) throws IOException { - Path path = basePath.resolve("META-INF").resolve("MANIFEST.MF"); - if (!Files.exists(path)) return null; - - try (InputStream stream = Files.newInputStream(path)) { - return new Manifest(stream); - } - } - - public static class FileSystemDelegate implements AutoCloseable { - private final FileSystem fileSystem; - private final boolean owner; - - public FileSystemDelegate(FileSystem fileSystem, boolean owner) { - this.fileSystem = fileSystem; - this.owner = owner; - } - - public FileSystem get() { - return fileSystem; - } - - @Override - public void close() throws IOException { - if (owner) { - fileSystem.close(); - } - } - } } \ No newline at end of file diff --git a/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/ManifestUtility.java b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/ManifestUtility.java new file mode 100644 index 00000000..c9897a28 --- /dev/null +++ b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/ManifestUtility.java @@ -0,0 +1,113 @@ +//Part of fabric-loader (net.fabricmc.loader.impl.util.ManifestUtil) +package net.jomcraft.defaultsettings; + +import java.io.IOException; +import java.io.InputStream; +import java.net.*; +import java.nio.file.*; +import java.security.CodeSource; +import java.util.Collections; +import java.util.Map; +import java.util.jar.Manifest; +import java.util.zip.ZipError; + +public class ManifestUtility { + + private static final Map jfsArgsCreate = Collections.singletonMap("create", "true"); + private static final Map jfsArgsEmpty = Collections.emptyMap(); + + public static Manifest readManifest(Class cls) throws IOException, URISyntaxException { + CodeSource cs = cls.getProtectionDomain().getCodeSource(); + if (cs == null) return null; + + URL url = cs.getLocation(); + if (url == null) return null; + + return readManifest(url); + } + + public static Path asPath(URL url) { + try { + return Paths.get(url.toURI()); + } catch (URISyntaxException e) { + return null; + } + } + + public static Manifest readManifest(URL codeSourceUrl) throws IOException, URISyntaxException { + Path path = asPath(codeSourceUrl); + + if (Files.isDirectory(path)) { + return readManifest(path); + } else { + URLConnection connection = new URL("jar:" + codeSourceUrl.toString() + "!/").openConnection(); + + if (connection instanceof JarURLConnection) { + return ((JarURLConnection) connection).getManifest(); + } + + try (FileSystemDelegate jarFs = getJarFileSystem(path.toUri(), false)) { + return readManifest(jarFs.get().getRootDirectories().iterator().next()); + } + } + } + + public static FileSystemDelegate getJarFileSystem(URI uri, boolean create) throws IOException { + URI jarUri; + + try { + jarUri = new URI("jar:" + uri.getScheme(), uri.getHost(), uri.getPath(), uri.getFragment()); + } catch (URISyntaxException e) { + throw new IOException(e); + } + + boolean opened = false; + FileSystem ret = null; + + try { + ret = FileSystems.getFileSystem(jarUri); + } catch (FileSystemNotFoundException ignore) { + try { + ret = FileSystems.newFileSystem(jarUri, create ? jfsArgsCreate : jfsArgsEmpty); + opened = true; + } catch (FileSystemAlreadyExistsException ignore2) { + ret = FileSystems.getFileSystem(jarUri); + } catch (IOException | ZipError e) { + throw new IOException("Error accessing "+uri+": "+e, e); + } + } + + return new FileSystemDelegate(ret, opened); + } + + public static Manifest readManifest(Path basePath) throws IOException { + Path path = basePath.resolve("META-INF").resolve("MANIFEST.MF"); + if (!Files.exists(path)) return null; + + try (InputStream stream = Files.newInputStream(path)) { + return new Manifest(stream); + } + } + + public static class FileSystemDelegate implements AutoCloseable { + private final FileSystem fileSystem; + private final boolean owner; + + public FileSystemDelegate(FileSystem fileSystem, boolean owner) { + this.fileSystem = fileSystem; + this.owner = owner; + } + + public FileSystem get() { + return fileSystem; + } + + @Override + public void close() throws IOException { + if (owner) { + fileSystem.close(); + } + } + } + +} From dcc08bc9d60d8c7b0b794fece0796c7f7bccca90 Mon Sep 17 00:00:00 2001 From: PT400C Jomcraft Date: Sun, 5 Oct 2025 14:37:50 +0200 Subject: [PATCH 3/6] Enable building with sources --- sources/Fabric-1.20/build.gradle | 2 +- sources/Forge-1.20.6/build.gradle | 2 +- sources/Forge-1.20/build.gradle | 2 +- sources/NeoForge-1.20.2/build.gradle | 2 +- sources/NeoForge-1.21.5/build.gradle | 2 +- sources/NeoForge-1.21.9/build.gradle | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sources/Fabric-1.20/build.gradle b/sources/Fabric-1.20/build.gradle index 3ef53da1..afd0ba9e 100644 --- a/sources/Fabric-1.20/build.gradle +++ b/sources/Fabric-1.20/build.gradle @@ -119,7 +119,7 @@ task("copyRelease") { def libDir = project.projectDir.toPath().resolve("build/libs") from(libDir) { include "*.jar" - exclude "*-dev.jar", "*-sources.jar" + exclude "*-dev.jar" } into "../../build/libs/" duplicatesStrategy DuplicatesStrategy.INCLUDE diff --git a/sources/Forge-1.20.6/build.gradle b/sources/Forge-1.20.6/build.gradle index 12edc859..00a8bfe4 100644 --- a/sources/Forge-1.20.6/build.gradle +++ b/sources/Forge-1.20.6/build.gradle @@ -146,7 +146,7 @@ task("copyRelease") { def libDir = project.projectDir.toPath().resolve("build/libs") from(libDir) { include "*.jar" - exclude "*-dev.jar", "*-sources.jar" + exclude "*-dev.jar" } into "../../build/libs/" duplicatesStrategy DuplicatesStrategy.INCLUDE diff --git a/sources/Forge-1.20/build.gradle b/sources/Forge-1.20/build.gradle index db63f4e6..59d8882e 100644 --- a/sources/Forge-1.20/build.gradle +++ b/sources/Forge-1.20/build.gradle @@ -148,7 +148,7 @@ task("copyRelease") { def libDir = project.projectDir.toPath().resolve("build/libs") from(libDir) { include "*.jar" - exclude "*-dev.jar", "*-sources.jar" + exclude "*-dev.jar" } into "../../build/libs/" duplicatesStrategy DuplicatesStrategy.INCLUDE diff --git a/sources/NeoForge-1.20.2/build.gradle b/sources/NeoForge-1.20.2/build.gradle index f962b1ed..58c19754 100644 --- a/sources/NeoForge-1.20.2/build.gradle +++ b/sources/NeoForge-1.20.2/build.gradle @@ -125,7 +125,7 @@ task("copyRelease") { def libDir = project.projectDir.toPath().resolve("build/libs") from(libDir) { include "*.jar" - exclude "*-dev.jar", "*-sources.jar" + exclude "*-dev.jar" } into "../../build/libs/" duplicatesStrategy DuplicatesStrategy.INCLUDE diff --git a/sources/NeoForge-1.21.5/build.gradle b/sources/NeoForge-1.21.5/build.gradle index a593c1bf..bec18f20 100644 --- a/sources/NeoForge-1.21.5/build.gradle +++ b/sources/NeoForge-1.21.5/build.gradle @@ -137,7 +137,7 @@ task("copyRelease") { def libDir = project.projectDir.toPath().resolve("build/libs") from(libDir) { include "*.jar" - exclude "*-dev.jar", "*-sources.jar" + exclude "*-dev.jar" } into "../../build/libs/" duplicatesStrategy DuplicatesStrategy.INCLUDE diff --git a/sources/NeoForge-1.21.9/build.gradle b/sources/NeoForge-1.21.9/build.gradle index 8142b18c..da47f66b 100644 --- a/sources/NeoForge-1.21.9/build.gradle +++ b/sources/NeoForge-1.21.9/build.gradle @@ -137,7 +137,7 @@ task("copyRelease") { def libDir = project.projectDir.toPath().resolve("build/libs") from(libDir) { include "*.jar" - exclude "*-dev.jar", "*-sources.jar" + exclude "*-dev.jar" } into "../../build/libs/" duplicatesStrategy DuplicatesStrategy.INCLUDE From ba537d2bec08c5e8ef576045fc5fe4d083679e69 Mon Sep 17 00:00:00 2001 From: PT400C Jomcraft Date: Sun, 5 Oct 2025 15:58:14 +0200 Subject: [PATCH 4/6] Second stage of updating - Fabric: `1.21.5` - Forge: `1.21.5` and `1.21.6` --- gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle | 9 + sources/Fabric-1.21.5/build.gradle | 128 +++++++++++ sources/Fabric-1.21.5/gradle.properties | 1 + .../defaultsettings/DefaultSettings.java | 80 +++++++ .../defaultsettings/FabricCoreHook.java | 188 +++++++++++++++++ .../jomcraft/defaultsettings/FileUtil.java | 170 +++++++++++++++ .../defaultsettings/KeyContainer.java | 15 ++ .../jomcraft/defaultsettings/PreLaunch.java | 44 ++++ .../commands/CommandDefaultSettings.java | 51 +++++ .../commands/ConfigArguments.java | 118 +++++++++++ .../commands/OperationArguments.java | 92 ++++++++ .../commands/TypeArguments.java | 83 ++++++++ .../defaultsettings/mixin/MinecraftMixin.java | 15 ++ .../defaultsettings/defaultsettings.png | Bin 0 -> 60575 bytes .../resources/defaultsettings.accesswidener | 9 + .../resources/defaultsettings.mixins.json | 13 ++ .../src/main/resources/fabric.mod.json | 43 ++++ .../defaultsettings/EventHandlers.java | 5 - sources/Forge-1.21.5/build.gradle | 168 +++++++++++++++ sources/Forge-1.21.5/gradle.properties | 1 + .../defaultsettings/DefaultSettings.java | 198 ++++++++++++++++++ .../defaultsettings/EventHandlers.java | 15 ++ .../jomcraft/defaultsettings/FileUtil.java | 171 +++++++++++++++ .../defaultsettings/ForgeCoreHook.java | 194 +++++++++++++++++ .../defaultsettings/KeyContainer.java | 16 ++ .../defaultsettings/ManifestUtility.java | 113 ++++++++++ .../commands/CommandDefaultSettings.java | 52 +++++ .../commands/ConfigArguments.java | 118 +++++++++++ .../commands/OperationArguments.java | 92 ++++++++ .../commands/TypeArguments.java | 83 ++++++++ .../defaultsettings/mixin/MinecraftMixin.java | 15 ++ .../resources/META-INF/accesstransformer.cfg | 1 + .../src/main/resources/META-INF/mods.toml | 29 +++ .../main/resources/defaultsettings.mixin.json | 15 ++ .../Forge-1.21.5/src/main/resources/logo.png | Bin 0 -> 51342 bytes .../src/main/resources/pack.mcmeta | 8 + sources/Forge-1.21.6/build.gradle | 168 +++++++++++++++ sources/Forge-1.21.6/gradle.properties | 1 + .../defaultsettings/DefaultSettings.java | 196 +++++++++++++++++ .../defaultsettings/EventHandlers.java | 14 ++ .../jomcraft/defaultsettings/FileUtil.java | 171 +++++++++++++++ .../defaultsettings/ForgeCoreHook.java | 194 +++++++++++++++++ .../defaultsettings/KeyContainer.java | 16 ++ .../defaultsettings/ManifestUtility.java | 113 ++++++++++ .../commands/CommandDefaultSettings.java | 52 +++++ .../commands/ConfigArguments.java | 118 +++++++++++ .../commands/OperationArguments.java | 92 ++++++++ .../commands/TypeArguments.java | 83 ++++++++ .../defaultsettings/mixin/MinecraftMixin.java | 15 ++ .../resources/META-INF/accesstransformer.cfg | 1 + .../src/main/resources/META-INF/mods.toml | 29 +++ .../main/resources/defaultsettings.mixin.json | 15 ++ .../Forge-1.21.6/src/main/resources/logo.png | Bin 0 -> 51342 bytes .../src/main/resources/pack.mcmeta | 8 + .../defaultsettings/DefaultSettings.java | 10 +- 56 files changed, 3644 insertions(+), 7 deletions(-) create mode 100644 sources/Fabric-1.21.5/build.gradle create mode 100644 sources/Fabric-1.21.5/gradle.properties create mode 100644 sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java create mode 100644 sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/FabricCoreHook.java create mode 100644 sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/FileUtil.java create mode 100644 sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/KeyContainer.java create mode 100644 sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/PreLaunch.java create mode 100644 sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/CommandDefaultSettings.java create mode 100644 sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/ConfigArguments.java create mode 100644 sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/OperationArguments.java create mode 100644 sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/TypeArguments.java create mode 100644 sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/mixin/MinecraftMixin.java create mode 100644 sources/Fabric-1.21.5/src/main/resources/assets/defaultsettings/defaultsettings.png create mode 100644 sources/Fabric-1.21.5/src/main/resources/defaultsettings.accesswidener create mode 100644 sources/Fabric-1.21.5/src/main/resources/defaultsettings.mixins.json create mode 100644 sources/Fabric-1.21.5/src/main/resources/fabric.mod.json create mode 100644 sources/Forge-1.21.5/build.gradle create mode 100644 sources/Forge-1.21.5/gradle.properties create mode 100644 sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java create mode 100644 sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/EventHandlers.java create mode 100644 sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/FileUtil.java create mode 100644 sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/ForgeCoreHook.java create mode 100644 sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/KeyContainer.java create mode 100644 sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/ManifestUtility.java create mode 100644 sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/CommandDefaultSettings.java create mode 100644 sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/ConfigArguments.java create mode 100644 sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/OperationArguments.java create mode 100644 sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/TypeArguments.java create mode 100644 sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/mixin/MinecraftMixin.java create mode 100644 sources/Forge-1.21.5/src/main/resources/META-INF/accesstransformer.cfg create mode 100644 sources/Forge-1.21.5/src/main/resources/META-INF/mods.toml create mode 100644 sources/Forge-1.21.5/src/main/resources/defaultsettings.mixin.json create mode 100644 sources/Forge-1.21.5/src/main/resources/logo.png create mode 100644 sources/Forge-1.21.5/src/main/resources/pack.mcmeta create mode 100644 sources/Forge-1.21.6/build.gradle create mode 100644 sources/Forge-1.21.6/gradle.properties create mode 100644 sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java create mode 100644 sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/EventHandlers.java create mode 100644 sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/FileUtil.java create mode 100644 sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/ForgeCoreHook.java create mode 100644 sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/KeyContainer.java create mode 100644 sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/ManifestUtility.java create mode 100644 sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/commands/CommandDefaultSettings.java create mode 100644 sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/commands/ConfigArguments.java create mode 100644 sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/commands/OperationArguments.java create mode 100644 sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/commands/TypeArguments.java create mode 100644 sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/mixin/MinecraftMixin.java create mode 100644 sources/Forge-1.21.6/src/main/resources/META-INF/accesstransformer.cfg create mode 100644 sources/Forge-1.21.6/src/main/resources/META-INF/mods.toml create mode 100644 sources/Forge-1.21.6/src/main/resources/defaultsettings.mixin.json create mode 100644 sources/Forge-1.21.6/src/main/resources/logo.png create mode 100644 sources/Forge-1.21.6/src/main/resources/pack.mcmeta diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 43d6de63..23d6f929 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.13-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 382d38a2..c4b0c508 100644 --- a/settings.gradle +++ b/settings.gradle @@ -20,12 +20,21 @@ project(":Core").projectDir = file("./sources/Core") include("Fabric-1.20") project(":Fabric-1.20").projectDir = file("./sources/Fabric-1.20") +include("Fabric-1.21.5") +project(":Fabric-1.21.5").projectDir = file("./sources/Fabric-1.21.5") + include("Forge-1.20") project(":Forge-1.20").projectDir = file("./sources/Forge-1.20") include("Forge-1.20.6") project(":Forge-1.20.6").projectDir = file("./sources/Forge-1.20.6") +include("Forge-1.21.5") +project(":Forge-1.21.5").projectDir = file("./sources/Forge-1.21.5") + +include("Forge-1.21.6") +project(":Forge-1.21.6").projectDir = file("./sources/Forge-1.21.6") + include("NeoForge-1.20.2") project(":NeoForge-1.20.2").projectDir = file("./sources/NeoForge-1.20.2") diff --git a/sources/Fabric-1.21.5/build.gradle b/sources/Fabric-1.21.5/build.gradle new file mode 100644 index 00000000..547493b2 --- /dev/null +++ b/sources/Fabric-1.21.5/build.gradle @@ -0,0 +1,128 @@ +plugins { + id "fabric-loom" version "1.11-SNAPSHOT" + id 'net.darkhax.curseforgegradle' version '1.1.18' +} + +archivesBaseName = "${rootProject.name}" + +def file_version = version; + +version = "1.21.5-${version}-Fabric" + +repositories { + maven { + url "https://cursemaven.com" + content { + includeGroup "curse.maven" + } + } +} + +dependencies { + minecraft "com.mojang:minecraft:1.21.5" + mappings loom.officialMojangMappings() + + modImplementation "net.fabricmc:fabric-loader:0.16.10" + + modImplementation "net.fabricmc.fabric-api:fabric-api:0.128.2+1.21.5" + + modImplementation "curse.maven:jcp-${project.ext.jcplugin_id}:${project.ext.jcplugin_versions[3]}" + implementation project(":Core") +} + +processResources { + inputs.property "version", file_version + inputs.property "JCPluginVersion", rootProject.JCPluginVersion + + filesMatching(["**/fabric.mod.json", "**/mods.toml"]) { + expand "version": file_version, "JCPluginVersion": project.JCPluginVersion + } +} + +tasks.withType(JavaCompile).configureEach { + source(project(":Core").sourceSets.main.allSource) +} + +loom { + + accessWidenerPath = file("src/main/resources/defaultsettings.accesswidener") + + runs { + client { + client() + setConfigName("Fabric 1.21.5 Client") + ideConfigGenerated(true) + runDir("./run") + } + server { + server() + setConfigName("Fabric 1.21.5 Server") + ideConfigGenerated(true) + runDir("./run") + } + } + + //mixin { + // defaultRefmapName = "${project.rootProject.name}.refmap.json" + //} +} + +//java { +// withSourcesJar() +//} + +task sourcesJar(type: Jar) { + from sourceSets.main.allSource + from(project(":Core").sourceSets.main.allSource) + archiveClassifier = 'sources' +} + +artifacts { + archives jar + archives sourcesJar +} + +task publishCurseForge(type: net.darkhax.curseforgegradle.TaskPublishCurseForge) { + dependsOn "build" + if (System.getenv("CURSE_API") != null && !System.getenv("CURSE_API").equals("")) { + disableVersionDetection() + apiToken = System.getenv("CURSE_API") + + def mainFile = upload(451860, remapJar.archiveFile) + mainFile.releaseType = project.ext.relType + mainFile.displayName = "$archivesBaseName-$version" + mainFile.changelogType = 'html' + mainFile.changelog = file('../../changelog.html') + mainFile.addRequirement('jcplugin') + mainFile.addModLoader('Fabric') + mainFile.addJavaVersion('Java 17') + mainFile.addGameVersion('Client') + mainFile.addGameVersion('1.20.4') + mainFile.addGameVersion('1.20.3') + mainFile.addGameVersion('1.20.2') + mainFile.addGameVersion('1.20.1') + mainFile.addGameVersion('1.20') + + def sourcesFile = mainFile.withAdditionalFile(sourcesJar) + sourcesFile.changelog = file('../../changelog.html') + sourcesFile.addRequirement('jcplugin') + sourcesFile.displayName = "$archivesBaseName-$version-sources" + } +} + +task("copyRelease") { + dependsOn "build" + + doFirst { + println "Gathering builds" + copy { + def libDir = project.projectDir.toPath().resolve("build/libs") + from(libDir) { + include "*.jar" + exclude "*-dev.jar" + } + into "../../build/libs/" + duplicatesStrategy DuplicatesStrategy.INCLUDE + } + } +} \ No newline at end of file diff --git a/sources/Fabric-1.21.5/gradle.properties b/sources/Fabric-1.21.5/gradle.properties new file mode 100644 index 00000000..2c1dbc7e --- /dev/null +++ b/sources/Fabric-1.21.5/gradle.properties @@ -0,0 +1 @@ +javaVersion = 21 \ No newline at end of file diff --git a/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java b/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java new file mode 100644 index 00000000..2a3a8849 --- /dev/null +++ b/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java @@ -0,0 +1,80 @@ +package net.jomcraft.defaultsettings; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import com.mojang.brigadier.arguments.ArgumentType; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; +import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; +import net.jomcraft.defaultsettings.commands.CommandDefaultSettings; +import net.jomcraft.defaultsettings.commands.ConfigArguments; +import net.jomcraft.defaultsettings.commands.OperationArguments; +import net.jomcraft.defaultsettings.commands.TypeArguments; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.commands.synchronization.ArgumentTypeInfos; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import net.jomcraft.jcplugin.FileUtilNoMC; + +public class DefaultSettings implements ModInitializer { + + public static final String MODID = "defaultsettings"; + public static final Logger log = LogManager.getLogger(DefaultSettings.MODID); + public static String VERSION = "none"; + public static Map keyRebinds = new HashMap(); + public static DefaultSettings instance; + public static boolean shutDown = false; + + public static synchronized , T extends ArgumentTypeInfo.Template, I extends ArgumentTypeInfo> I registerByClass(Class infoClass, I argumentTypeInfo) { + ArgumentTypeInfos.BY_CLASS.put(infoClass, argumentTypeInfo); + return argumentTypeInfo; + } + + @Override + public void onInitialize() { + instance = this; + FabricCoreHook core = new FabricCoreHook(); + Core.setInstance(core); + + ConfigArguments.Info config = new ConfigArguments.Info(); + OperationArguments.Info operation = new OperationArguments.Info(); + TypeArguments.Info type = new TypeArguments.Info(); + Registry.register(BuiltInRegistries.COMMAND_ARGUMENT_TYPE, ResourceLocation.fromNamespaceAndPath(MODID, "config"), config); + Registry.register(BuiltInRegistries.COMMAND_ARGUMENT_TYPE, ResourceLocation.fromNamespaceAndPath(MODID, "operation"), operation); + Registry.register(BuiltInRegistries.COMMAND_ARGUMENT_TYPE, ResourceLocation.fromNamespaceAndPath(MODID, "type"), type); + registerByClass(ConfigArguments.class, config); + registerByClass(OperationArguments.class, operation); + registerByClass(TypeArguments.class, type); + + CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { + if (!environment.includeDedicated) { + CommandDefaultSettings.register(dispatcher); + } + }); + + ClientLifecycleEvents.CLIENT_STARTED.register((test) -> { + try { + FileUtil.restoreContents(); + } catch (Exception e) { + DefaultSettings.log.log(Level.ERROR, "An exception occurred while starting up the game:", e); + } + + try { + FileUtil.restoreKeys(true, FileUtilNoMC.privateJson.firstBootUp); + } catch (IOException e) { + DefaultSettings.log.log(Level.ERROR, "An exception occurred while starting up the game (Post):", e); + } catch (NullPointerException e) { + DefaultSettings.log.log(Level.ERROR, "An exception occurred while starting up the game (Post):", e); + } + }); + } + + public static DefaultSettings getInstance() { + return instance; + } +} \ No newline at end of file diff --git a/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/FabricCoreHook.java b/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/FabricCoreHook.java new file mode 100644 index 00000000..4deb2fc7 --- /dev/null +++ b/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/FabricCoreHook.java @@ -0,0 +1,188 @@ +package net.jomcraft.defaultsettings; + +import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import net.jomcraft.jcplugin.FileUtilNoMC; +import net.minecraft.ChatFormatting; +import net.minecraft.client.KeyMapping; +import net.minecraft.client.Minecraft; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.network.chat.Component; +import org.apache.logging.log4j.Logger; +import java.io.File; +import java.io.IOException; + +public class FabricCoreHook implements ICoreHook { + + private static final SimpleCommandExceptionType FAILED_EXCEPTION = new SimpleCommandExceptionType(Component.literal(ChatFormatting.RED + "Please wait until the last request has finished")); + + @Override + public File getMCDataDir() { + return FileUtilNoMC.mcDataDir; + } + + @Override + public File getMainFolder() { + return FileUtilNoMC.getMainFolder(); + } + + @Override + public String getActiveProfile() { + return FileUtilNoMC.activeProfile; + } + + @Override + public KeyPlaceholder[] getKeyMappings() { + KeyMapping[] mappings = Minecraft.getInstance().options.keyMappings; + if (mappings == null || mappings.length == 0) + return new KeyPlaceholder[0]; + + KeyPlaceholder[] keys = new KeyPlaceholder[mappings.length]; + + for (int i = 0; i < mappings.length; i++) { + keys[i] = new KeyPlaceholder(mappings[i].getName(), mappings[i].key.toString(), null); + } + return keys; + } + + @Override + public void resetMappings() { + KeyMapping.resetMapping(); + } + + @Override + public void clearKeyBinds() { + DefaultSettings.keyRebinds.clear(); + } + + @Override + public void putKeybind(String first, String second, String third) { + DefaultSettings.keyRebinds.put(first, new KeyContainer(InputConstants.getKey(second), null)); + } + + @Override + public boolean keybindExists(String key) { + return DefaultSettings.keyRebinds.containsKey(key); + } + + @Override + public void setKeybind(KeyPlaceholder key, boolean init) { + KeyMapping[] mappings = Minecraft.getInstance().options.keyMappings; + for (int i = 0; i < mappings.length; i++) { + if (mappings[i].getName().equals(key.name)) { + KeyContainer container = DefaultSettings.keyRebinds.get(key.name); + + if (init) + mappings[i].setKey(container.input); + + mappings[i].defaultKey = container.input; + + //ObfuscationReflectionHelper.setPrivateValue(KeyMapping.class, mappings[i], container.modifier, "keyModifierDefault"); + //mappings[i].setKeyModifierAndCode(mappings[i].getDefaultKeyModifier(), container.input); + break; + } + } + } + + @Override + public void sendSuccess(Object source, String text, int color) { + if (source instanceof CommandSourceStack) { + ((CommandSourceStack) source).sendSuccess(() -> Component.literal(text).withStyle(ChatFormatting.getById(color)), true); + } + } + + @Override + public Exception throwFailedException() { + return FAILED_EXCEPTION.create(); + } + + @Override + public boolean hasDSShutDown() { + return DefaultSettings.shutDown; + } + + @Override + public Logger getDSLog() { + return DefaultSettings.log; + } + + @Override + public String shutdownReason() { + return null; + } + + @Override + public boolean isOtherCreator() { + return FileUtilNoMC.otherCreator; + } + + @Override + public boolean disableCreatorCheck() { + return FileUtilNoMC.privateJson.disableCreatorCheck; + } + + @Override + public boolean checkChangedConfig() { + return FileUtilNoMC.checkChangedConfig(); + } + + @Override + public boolean checkForConfigFiles() { + return FileUtilNoMC.checkForConfigFiles(); + } + + @Override + public void checkMD5(boolean updateExisting, boolean configs, String file) throws IOException { + FileUtilNoMC.checkMD5(updateExisting, configs, file); + } + + @Override + public void copyAndHashPrivate(boolean options, boolean configs) throws NullPointerException, IOException { + FileUtilNoMC.copyAndHashPrivate(options, configs); + } + + @Override + public boolean keysFileExist() { + return FileUtilNoMC.keysFileExist(); + } + + @Override + public boolean optionsFilesExist() { + return FileUtilNoMC.optionsFilesExist(); + } + + @Override + public boolean serversFileExists() { + return FileUtilNoMC.serversFileExists(); + } + + @Override + public boolean checkChanged() { + return FileUtil.checkChanged(); + } + + @Override + public void saveKeys() throws IOException { + FileUtil.saveKeys(); + } + + @Override + public boolean saveOptions() throws IOException { + return FileUtil.saveOptions(); + } + + @Override + public void saveServers() throws IOException { + FileUtilNoMC.saveServers(); + } + + @Override + public void restoreKeys(boolean update, boolean initial) throws IOException { + FileUtil.restoreKeys(update, initial); + } + + @Override + public void saveOptionsFile() { + Minecraft.getInstance().options.save(); + } +} diff --git a/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/FileUtil.java b/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/FileUtil.java new file mode 100644 index 00000000..e934df0a --- /dev/null +++ b/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/FileUtil.java @@ -0,0 +1,170 @@ +package net.jomcraft.defaultsettings; + +import static net.jomcraft.jcplugin.FileUtilNoMC.*; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import org.apache.logging.log4j.Level; +import net.minecraft.client.Minecraft; + +public class FileUtil { + + public static void restoreContents() throws NullPointerException, IOException { + + final String version = getMainJSON().getVersion(); + + if (!DefaultSettings.VERSION.equals(version)) + mainJson.setVersion(DefaultSettings.VERSION).setPrevVersion(version); + + if (mainJson.generatedBy.equals("")) + mainJson.generatedBy = privateJson.privateIdentifier; + + activeProfile = privateJson.currentProfile; + + if (!privateJson.firstBootUp){ + copyAndHashPrivate(true, true); + } + + final File optionsOF = new File(mcDataDir, "optionsof.txt"); + if (!optionsOF.exists()) + restoreOptionsOF(); + + final File optionsShaders = new File(mcDataDir, "optionsshaders.txt"); + if (!optionsShaders.exists()) + restoreOptionsShaders(); + + final File optionsJEK = new File(mcDataDir, "options.justenoughkeys.txt"); + if (!optionsJEK.exists()) + restoreOptionsJEK(); + + final File optionsAmecs = new File(mcDataDir, "options.amecsapi.txt"); + if (!optionsAmecs.exists()) + restoreOptionsAmecs(); + + final File serversFile = new File(mcDataDir, "servers.dat"); + if (!serversFile.exists()) + restoreServers(); + + mainJson.save(); + } + + @SuppressWarnings("resource") + public static void restoreKeys(boolean update, boolean initial) throws NullPointerException, IOException, NumberFormatException { + CoreUtil.restoreKeys(update, initial); + } + + @SuppressWarnings("resource") + public static void saveKeys() throws IOException, NullPointerException { + CoreUtil.saveKeys(); + } + + @SuppressWarnings("resource") + public static boolean saveOptions() throws NullPointerException, IOException { + Minecraft.getInstance().options.save(); + return CoreUtil.saveOptions(); + } + + public static boolean checkChanged() { + boolean ret = false; + try { + + InputStream keys = CoreUtil.getKeysStream(true); + InputStream options = getOptionsStream(); + InputStream optionsOF = getOptionsOFStream(); + InputStream optionsShaders = getOptionsShadersStream(); + InputStream optionsJEK = getOptionsJEKStream(); + InputStream optionsAmecs = getOptionsAmecsStream(); + InputStream servers = getServersStream(); + + String hashO = ""; + String writtenHashO = ""; + + if (options != null) { + hashO = fileToHash(options); + writtenHashO = mainJson.hashes.get(activeProfile + "/options.txt"); + } + + String hashK = ""; + String writtenHashK = ""; + + if (keys != null) { + hashK = fileToHash(keys); + writtenHashK = mainJson.hashes.get(activeProfile + "/keys.txt"); + } + + String hashOF = ""; + String writtenHashOF = ""; + + if (optionsOF != null) { + hashOF = fileToHash(optionsOF); + writtenHashOF = mainJson.hashes.get(activeProfile + "/optionsof.txt"); + } + + String hashShaders = ""; + String writtenHashShaders = ""; + + if (optionsShaders != null) { + hashShaders = fileToHash(optionsShaders); + writtenHashShaders = mainJson.hashes.get(activeProfile + "/optionsshaders.txt"); + } + + String hashJEK = ""; + String writtenHashJEK = ""; + + if (optionsJEK != null) { + hashJEK = fileToHash(optionsJEK); + writtenHashJEK = mainJson.hashes.get(activeProfile + "/options.justenoughkeys.txt"); + } + + String hashAmecs = ""; + String writtenHashAmecs = ""; + + if (optionsAmecs != null) { + hashAmecs = fileToHash(optionsAmecs); + writtenHashAmecs = mainJson.hashes.get(activeProfile + "/options.amecsapi.txt"); + } + + String hashS = ""; + String writtenHashS = ""; + + if (servers != null) { + hashS = fileToHash(servers); + writtenHashS = mainJson.hashes.get(activeProfile + "/servers.dat"); + } + + if (mainJson.hashes.containsKey(activeProfile + "/options.txt") && !hashO.equals(writtenHashO)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/keys.txt") && !hashK.equals(writtenHashK)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/optionsof.txt") && !hashOF.equals(writtenHashOF)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/optionsshaders.txt") && !hashShaders.equals(writtenHashShaders)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/options.justenoughkeys.txt") && !hashJEK.equals(writtenHashJEK)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/options.amecsapi.txt") && !hashAmecs.equals(writtenHashAmecs)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/servers.dat") && !hashS.equals(writtenHashS)) { + ret = true; + } + + if (options != null) { + options.close(); + File fileO = new File(getMainFolder(), activeProfile + "/options.txt_temp"); + Files.delete(fileO.toPath()); + } + + if (keys != null) { + keys.close(); + File fileK = new File(getMainFolder(), activeProfile + "/keys.txt_temp"); + Files.delete(fileK.toPath()); + } + + } catch (Exception e) { + DefaultSettings.log.log(Level.ERROR, "Error while saving configs: ", e); + } + + return ret; + } +} \ No newline at end of file diff --git a/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/KeyContainer.java b/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/KeyContainer.java new file mode 100644 index 00000000..45e28443 --- /dev/null +++ b/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/KeyContainer.java @@ -0,0 +1,15 @@ +package net.jomcraft.defaultsettings; + +import com.mojang.blaze3d.platform.InputConstants; + +public class KeyContainer { + + public final InputConstants.Key input; + public final String modifier; + + public KeyContainer(final InputConstants.Key input, final String modifier) { + this.input = input; + this.modifier = modifier; + } + +} diff --git a/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/PreLaunch.java b/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/PreLaunch.java new file mode 100644 index 00000000..ed4aa5ad --- /dev/null +++ b/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/PreLaunch.java @@ -0,0 +1,44 @@ +package net.jomcraft.defaultsettings; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.jar.Attributes; +import java.util.jar.Manifest; +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.impl.util.ManifestUtil; +import net.jomcraft.jcplugin.FileUtilNoMC; +import org.apache.logging.log4j.Level; +import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint; + +public class PreLaunch implements PreLaunchEntrypoint { + + public String getVersion() throws IOException, URISyntaxException { + Manifest manifest = ManifestUtil.readManifest(this.getClass()); + Attributes attr = manifest.getMainAttributes(); + return attr.getValue("Implementation-Version"); + } + + @Override + public void onPreLaunch() { + try { + DefaultSettings.VERSION = getVersion(); + + File location = FabricLoader.getInstance().getGameDir().toFile(); + new File(location, "config").mkdir(); + + try { + Class.forName("net.jomcraft.jcplugin.JCLogger"); + } catch (ClassNotFoundException e) { + DefaultSettings.log.log(Level.ERROR, "DefaultSettings can't find JCPlugin!", e); + return; + } + + FileUtilNoMC.mcDataDir = location; + FileUtilNoMC.restoreContentsFirst(); + + } catch (Exception e) { + DefaultSettings.log.log(Level.ERROR, "An exception occurred while starting up the game:", e); + } + } +} \ No newline at end of file diff --git a/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/CommandDefaultSettings.java b/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/CommandDefaultSettings.java new file mode 100644 index 00000000..ac5915c8 --- /dev/null +++ b/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/CommandDefaultSettings.java @@ -0,0 +1,51 @@ +package net.jomcraft.defaultsettings.commands; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.tree.LiteralCommandNode; +import net.jomcraft.defaultsettings.CoreUtil; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +public class CommandDefaultSettings { + + public static void register(CommandDispatcher dispatcher) { + LiteralArgumentBuilder literalargumentbuilder = Commands.literal("defaultsettings"); + + literalargumentbuilder.then(Commands.literal("save").executes((command) -> { + return saveProcess(command.getSource(), null, null); + }).then(Commands.argument("operation", OperationArguments.operationArguments(false)).executes((command) -> { + return saveProcess(command.getSource(), OperationArguments.getString(command, "operation"), null); + }).then(Commands.argument("type", TypeArguments.typeArguments()).executes((command) -> { + return saveProcess(command.getSource(), OperationArguments.getString(command, "operation"), TypeArguments.getString(command, "type")); + })))).then(Commands.literal("saveconfigs").executes((command) -> { + return saveProcessConfigs(command.getSource(), null, null); + }).then(Commands.argument("operation", OperationArguments.operationArguments(true)).executes((command) -> { + return saveProcessConfigs(command.getSource(), OperationArguments.getString(command, "operation"), null); + }).then(Commands.argument("config", ConfigArguments.configArguments()).executes((command) -> { + return saveProcessConfigs(command.getSource(), OperationArguments.getString(command, "operation"), ConfigArguments.getString(command, "config")); + })))); + + LiteralCommandNode node = dispatcher.register(literalargumentbuilder); + dispatcher.register(Commands.literal("ds").redirect(node)); + } + + private static int saveProcessConfigs(CommandSourceStack source, String argument, String argument2) throws CommandSyntaxException { + try { + return CoreUtil.saveProcessConfigs(source, argument, argument2); + } catch (Exception e) { + if (e instanceof CommandSyntaxException) throw (CommandSyntaxException) e; + return 0; + } + } + + private static int saveProcess(CommandSourceStack source, String argument, String argument2) throws CommandSyntaxException { + try { + return CoreUtil.saveProcess(source, argument, argument2); + } catch (Exception e) { + if (e instanceof CommandSyntaxException) throw (CommandSyntaxException) e; + return 0; + } + } +} \ No newline at end of file diff --git a/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/ConfigArguments.java b/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/ConfigArguments.java new file mode 100644 index 00000000..a52b8d5f --- /dev/null +++ b/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/ConfigArguments.java @@ -0,0 +1,118 @@ +package net.jomcraft.defaultsettings.commands; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import com.google.gson.JsonObject; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.jomcraft.defaultsettings.DefaultSettings; +import net.jomcraft.jcplugin.FileUtilNoMC; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.network.FriendlyByteBuf; + +public class ConfigArguments implements ArgumentType { + + private static List ARGUMENTS = Arrays.asList("fml.toml", "forge-client.toml"); + + public static ConfigArguments configArguments() { + return new ConfigArguments(); + } + + @Override + public String parse(final StringReader reader) throws CommandSyntaxException { + return readQuotedString(reader); + } + + public String readQuotedString(final StringReader reader) throws CommandSyntaxException { + if (!reader.canRead()) { + return ""; + } + final char next = reader.getString().charAt(reader.getCursor()); + if (!reader.isQuotedStringStart(next)) { + + final int start = reader.getCursor(); + while (reader.canRead()) { + reader.skip(); + } + return reader.getString().substring(start, reader.getCursor()); + } + reader.skip(); + return reader.readStringUntil(next); + } + + public static String getString(final CommandContext context, final String name) { + return context.getArgument(name, String.class); + } + + @Override + public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) { + try { + ArrayList filtered = new ArrayList(); + ArrayList prevList = FileUtilNoMC.listConfigFiles(); + for(int i = 0; i < prevList.size(); i++){ + String name = prevList.get(i); + if(name.contains(" ")) + name = "\"" + name + "\""; + filtered.add(name); + } + ARGUMENTS = filtered; + } catch (IOException e) { + DefaultSettings.log.error(e); + } + return SharedSuggestionProvider.suggest(ARGUMENTS, builder); + } + + @Override + public Collection getExamples() { + return ARGUMENTS; + } + + public static class Info implements ArgumentTypeInfo { + @Override + public void serializeToNetwork(Template template, FriendlyByteBuf buffer) { + + } + + @Override + public Template deserializeFromNetwork(FriendlyByteBuf buffer) { + return new Template(); + } + + @Override + public void serializeToJson(Template template, JsonObject json) { + + } + + @Override + public Template unpack(ConfigArguments argument) { + return new Template(); + } + + public class Template implements ArgumentTypeInfo.Template { + + Template() { + + } + + @Override + public ConfigArguments instantiate(CommandBuildContext p_223435_) { + return new ConfigArguments(); + } + + @Override + public ArgumentTypeInfo type() { + return Info.this; + } + } + } +} \ No newline at end of file diff --git a/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/OperationArguments.java b/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/OperationArguments.java new file mode 100644 index 00000000..bb9f85b1 --- /dev/null +++ b/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/OperationArguments.java @@ -0,0 +1,92 @@ +package net.jomcraft.defaultsettings.commands; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import com.google.gson.JsonObject; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.network.FriendlyByteBuf; + +public class OperationArguments implements ArgumentType { + + private static final List ARGUMENTS = Arrays.asList("override", "forceOverride"); + private static final List ARGUMENTS_LIMITED = Arrays.asList("forceOverride"); + private final boolean limited; + + public OperationArguments(boolean limited) { + this.limited = limited; + } + + public static OperationArguments operationArguments(boolean limited) { + return new OperationArguments(limited); + } + + @Override + public String parse(final StringReader reader) throws CommandSyntaxException { + return reader.readUnquotedString(); + } + + public static String getString(final CommandContext context, final String name) { + return context.getArgument(name, String.class); + } + + @Override + public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) { + return SharedSuggestionProvider.suggest(this.limited ? ARGUMENTS_LIMITED : ARGUMENTS, builder); + } + + @Override + public Collection getExamples() { + return ARGUMENTS; + } + + public static class Info implements ArgumentTypeInfo { + @Override + public void serializeToNetwork(Template template, FriendlyByteBuf buffer) { + buffer.writeBoolean(template.limited); + } + + @Override + public Template deserializeFromNetwork(FriendlyByteBuf buffer) { + boolean limited = buffer.readBoolean(); + return new Template(limited); + } + + @Override + public void serializeToJson(Template template, JsonObject json) { + json.addProperty("limited", template.limited); + } + + @Override + public Template unpack(OperationArguments argument) { + return new Template(argument.limited); + } + + public class Template implements ArgumentTypeInfo.Template { + final boolean limited; + + Template(boolean limited) { + this.limited = limited; + } + + @Override + public OperationArguments instantiate(CommandBuildContext p_223435_) { + return new OperationArguments(this.limited); + } + + @Override + public ArgumentTypeInfo type() { + return Info.this; + } + } + } +} \ No newline at end of file diff --git a/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/TypeArguments.java b/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/TypeArguments.java new file mode 100644 index 00000000..8fa88263 --- /dev/null +++ b/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/TypeArguments.java @@ -0,0 +1,83 @@ +package net.jomcraft.defaultsettings.commands; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import com.google.gson.JsonObject; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.network.FriendlyByteBuf; + +public class TypeArguments implements ArgumentType { + + private static final List ARGUMENTS = Arrays.asList("options", "keybinds", "servers"); + + public static TypeArguments typeArguments() { + return new TypeArguments(); + } + + @Override + public String parse(final StringReader reader) throws CommandSyntaxException { + return reader.readUnquotedString(); + } + + public static String getString(final CommandContext context, final String name) { + return context.getArgument(name, String.class); + } + + @Override + public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) { + return SharedSuggestionProvider.suggest(ARGUMENTS, builder); + } + + @Override + public Collection getExamples() { + return ARGUMENTS; + } + + public static class Info implements ArgumentTypeInfo { + @Override + public void serializeToNetwork(Template template, FriendlyByteBuf buffer) { + + } + + @Override + public Template deserializeFromNetwork(FriendlyByteBuf buffer) { + return new Template(); + } + + @Override + public void serializeToJson(Template template, JsonObject json) { + } + + @Override + public Template unpack(TypeArguments argument) { + return new Template(); + } + + public class Template implements ArgumentTypeInfo.Template { + + Template() { + + } + + @Override + public TypeArguments instantiate(CommandBuildContext p_223435_) { + return new TypeArguments(); + } + + @Override + public ArgumentTypeInfo type() { + return Info.this; + } + } + } +} \ No newline at end of file diff --git a/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/mixin/MinecraftMixin.java b/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/mixin/MinecraftMixin.java new file mode 100644 index 00000000..67d391cf --- /dev/null +++ b/sources/Fabric-1.21.5/src/main/java/net/jomcraft/defaultsettings/mixin/MinecraftMixin.java @@ -0,0 +1,15 @@ +package net.jomcraft.defaultsettings.mixin; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.Options; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(Minecraft.class) +public class MinecraftMixin { + @Redirect(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Options;save()V")) + private void redirected(Options instance) { + + } +} \ No newline at end of file diff --git a/sources/Fabric-1.21.5/src/main/resources/assets/defaultsettings/defaultsettings.png b/sources/Fabric-1.21.5/src/main/resources/assets/defaultsettings/defaultsettings.png new file mode 100644 index 0000000000000000000000000000000000000000..5f783fac1714bcb532ed60fb8631c3085a3361d7 GIT binary patch literal 60575 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 RuNJ)5X=-co(#Y$7{|E6A{>cCU literal 0 HcmV?d00001 diff --git a/sources/Fabric-1.21.5/src/main/resources/defaultsettings.accesswidener b/sources/Fabric-1.21.5/src/main/resources/defaultsettings.accesswidener new file mode 100644 index 00000000..03f483d9 --- /dev/null +++ b/sources/Fabric-1.21.5/src/main/resources/defaultsettings.accesswidener @@ -0,0 +1,9 @@ +accessWidener v1 named + +accessible field net/minecraft/client/KeyMapping key Lcom/mojang/blaze3d/platform/InputConstants$Key; + +mutable field net/minecraft/client/KeyMapping defaultKey Lcom/mojang/blaze3d/platform/InputConstants$Key; + +accessible field net/minecraft/client/KeyMapping defaultKey Lcom/mojang/blaze3d/platform/InputConstants$Key; + +accessible field net/minecraft/commands/synchronization/ArgumentTypeInfos BY_CLASS Ljava/util/Map; \ No newline at end of file diff --git a/sources/Fabric-1.21.5/src/main/resources/defaultsettings.mixins.json b/sources/Fabric-1.21.5/src/main/resources/defaultsettings.mixins.json new file mode 100644 index 00000000..9cde1e35 --- /dev/null +++ b/sources/Fabric-1.21.5/src/main/resources/defaultsettings.mixins.json @@ -0,0 +1,13 @@ +{ + "required": true, + "package": "net.jomcraft.defaultsettings.mixin", + "compatibilityLevel": "JAVA_21", + "mixins": [ + ], + "client": [ + "MinecraftMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file diff --git a/sources/Fabric-1.21.5/src/main/resources/fabric.mod.json b/sources/Fabric-1.21.5/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..37c89f55 --- /dev/null +++ b/sources/Fabric-1.21.5/src/main/resources/fabric.mod.json @@ -0,0 +1,43 @@ +{ + "schemaVersion": 1, + "id": "defaultsettings", + "version": "${version}", + "accessWidener" : "defaultsettings.accesswidener", + "name": "DefaultSettings", + "description": "Keep your game's local settings in case of an update to your modpack", + "authors": [ + "PT400C - Jomcraft Network" + ], + "contributors": [ + "Compaszer - Jomcraft Network" + ], + "contact": { + "homepage": "https://www.curseforge.com/minecraft/mc-mods/defaultsettings-fabric", + "sources": "https://github.com/Jomcraft-Network/DefaultSettings-Fabric", + "issues": "https://github.com/Jomcraft-Network/DefaultSettings-Fabric/issues" + }, + + "license": "Apache License 2.0", + "icon": "assets/defaultsettings/defaultsettings.png", + "environment": "client", + + "entrypoints": { + "main": [ + "net.jomcraft.defaultsettings.DefaultSettings" + ], + "preLaunch": [ + "net.jomcraft.defaultsettings.PreLaunch" + ] + }, + "mixins": [ + "defaultsettings.mixins.json" + ], + + "depends": { + "fabricloader": ">=0.14.6", + "fabric": "*", + "minecraft": "~1.21", + "java": ">=21", + "jcplugin": "${JCPluginVersion}" + } +} diff --git a/sources/Forge-1.20.6/src/main/java/net/jomcraft/defaultsettings/EventHandlers.java b/sources/Forge-1.20.6/src/main/java/net/jomcraft/defaultsettings/EventHandlers.java index 399aa351..04d044bb 100644 --- a/sources/Forge-1.20.6/src/main/java/net/jomcraft/defaultsettings/EventHandlers.java +++ b/sources/Forge-1.20.6/src/main/java/net/jomcraft/defaultsettings/EventHandlers.java @@ -10,11 +10,6 @@ public class EventHandlers { @SubscribeEvent public void serverStarting(ServerStartingEvent event) { - Method[] l = event.getServer().getClass().getDeclaredMethods(); - for(Method i : l){ - System.out.println("NAME: " + i.getName()); - } CommandDefaultSettings.register(event.getServer().getCommands().getDispatcher()); - } } \ No newline at end of file diff --git a/sources/Forge-1.21.5/build.gradle b/sources/Forge-1.21.5/build.gradle new file mode 100644 index 00000000..af83ff74 --- /dev/null +++ b/sources/Forge-1.21.5/build.gradle @@ -0,0 +1,168 @@ +buildscript { + repositories { + maven { url = "https://repo.spongepowered.org/repository/maven-public/" } + mavenCentral() + } + dependencies { + classpath group: "org.spongepowered", name: "mixingradle", version: "0.7-SNAPSHOT" + } +} + +plugins { + id 'net.darkhax.curseforgegradle' version '1.1.18' + id 'net.minecraftforge.gradle' version '[6.0.24,6.2)' +} + +apply plugin: 'org.spongepowered.mixin' +apply plugin: 'java' +apply plugin: 'net.minecraftforge.gradle' + +archivesBaseName = "${rootProject.name}" + +def file_version = version; + +version = "1.21.5-${version}-Forge" + +minecraft { + mappings channel: 'official', version: '1.21.5' + + reobf = false + copyIdeResources = true + + runs { + client { + workingDirectory file('./run') + property 'forge.logging.markers', 'REGISTRIES' + ideaModule "DefaultSettings.Forge-1.21.5.main" + property 'forge.logging.console.level', 'debug' + arg "-mixin.config="+"defaultsettings.mixin.json" + mods { + "${rootProject.name}" { + source sourceSets.main + source project(":Core").sourceSets.main + } + } + } + + server { + workingDirectory file('./run') + property 'forge.logging.markers', 'REGISTRIES' + ideaModule "DefaultSettings.Forge-1.21.5.main" + property 'forge.logging.console.level', 'debug' + arg "-mixin.config="+"defaultsettings.mixin.json" + mods { + "${rootProject.name}" { + source sourceSets.main + source project(":Core").sourceSets.main + } + } + } + } + accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') +} + +repositories { + maven { + url "https://cursemaven.com" + content { + includeGroup "curse.maven" + } + } +} + +mixin { + add sourceSets.main, "defaultsettings.refmap.json" +} + +dependencies { + minecraft 'net.minecraftforge:forge:1.21.5-55.1.2' + implementation fg.deobf("curse.maven:jcp-${project.ext.jcplugin_id}:${project.ext.jcplugin_versions[0]}") + annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' + testAnnotationProcessor 'org.spongepowered:mixin:0.8.5:processor' + implementation project(":Core") + + //compileOnly fg.deobf("curse.maven:jcp-${project.ext.jcplugin_id}:${project.ext.jcplugin_versions[0]}") + //compileOnly project(":Core") +} + +processResources { + inputs.property "version", file_version + + filesMatching(["**/fabric.mod.json", "**/mods.toml"]) { + expand "version": file_version + } +} + +/*tasks.withType(JavaCompile) { + source(project(":Core").sourceSets.main.allSource) +}*/ + +tasks.withType(JavaCompile).configureEach { + source(project(":Core").sourceSets.main.allSource) +} +tasks.withType(Javadoc).configureEach { + source(project(":Core").sourceSets.main.allJava) +} +/*tasks.named("sourcesJar", Jar) { + from(project(":Core").sourceSets.main.allSource) +}*/ + +task sourcesJar(type: Jar) { + from sourceSets.main.allSource + from(project(":Core").sourceSets.main.allSource) + archiveClassifier = 'sources' +} + +jar { + manifest { + attributes([ + 'FMLAT': 'defaultsettings_at.cfg', + "MixinConfigs" : "defaultsettings.mixin.json" + ]) + } +} + +artifacts { + archives jar + archives sourcesJar +} + +task publishCurseForge(type: net.darkhax.curseforgegradle.TaskPublishCurseForge) { + if (System.getenv("CURSE_API") != null && !System.getenv("CURSE_API").equals("")) { + disableVersionDetection() + apiToken = System.getenv("CURSE_API") + + def mainFile = upload(318012, jar) + mainFile.releaseType = project.ext.relType + mainFile.displayName = "$archivesBaseName-$version" + mainFile.changelogType = 'html' + mainFile.changelog = file('../../changelog.html') + mainFile.addRequirement('jcplugin') + mainFile.addModLoader('Forge') + mainFile.addJavaVersion('Java 21') + mainFile.addGameVersion('Client') + mainFile.addGameVersion('1.20.6') + + def sourcesFile = mainFile.withAdditionalFile(sourcesJar) + sourcesFile.changelog = file('../../changelog.html') + sourcesFile.addRequirement('jcplugin') + sourcesFile.displayName = "$archivesBaseName-$version-sources" + } +} + +task("copyRelease") { + dependsOn "build" + + doFirst { + println "Gathering builds" + copy { + def libDir = project.projectDir.toPath().resolve("build/libs") + from(libDir) { + include "*.jar" + exclude "*-dev.jar" + } + into "../../build/libs/" + duplicatesStrategy DuplicatesStrategy.INCLUDE + } + } +} \ No newline at end of file diff --git a/sources/Forge-1.21.5/gradle.properties b/sources/Forge-1.21.5/gradle.properties new file mode 100644 index 00000000..2c1dbc7e --- /dev/null +++ b/sources/Forge-1.21.5/gradle.properties @@ -0,0 +1 @@ +javaVersion = 21 \ No newline at end of file diff --git a/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java new file mode 100644 index 00000000..b15c6472 --- /dev/null +++ b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java @@ -0,0 +1,198 @@ +package net.jomcraft.defaultsettings; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.Field; +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.zip.ZipEntry; +import cpw.mods.modlauncher.Launcher; +import cpw.mods.modlauncher.api.IEnvironment; +import net.jomcraft.defaultsettings.commands.ConfigArguments; +import net.jomcraft.defaultsettings.commands.OperationArguments; +import net.jomcraft.defaultsettings.commands.TypeArguments; +import net.jomcraft.jcplugin.JCLogger; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.commands.synchronization.ArgumentTypeInfos; +import net.minecraftforge.fml.loading.FMLEnvironment; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import net.jomcraft.jcplugin.FileUtilNoMC; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; + +@Mod(value = DefaultSettings.MODID) +public class DefaultSettings { + + public static final String MODID = "defaultsettings"; + public static final Logger log = LogManager.getLogger(DefaultSettings.MODID); + public static String VERSION = "none"; + public static Map keyRebinds = new HashMap(); + public static boolean setUp = false; + public static DefaultSettings instance; + public static boolean shutDown = false; + public static String shutdownReason = null; + private static final DeferredRegister> COMMAND_ARGUMENT_TYPES = DeferredRegister.create(ForgeRegistries.Keys.COMMAND_ARGUMENT_TYPES, DefaultSettings.MODID); + + public String getVersion() throws IOException, URISyntaxException { + Manifest manifest = ManifestUtility.readManifest(this.getClass()); + Attributes attr = manifest.getMainAttributes(); + return attr.getValue("Implementation-Version"); + } + + @SuppressWarnings({"deprecation"}) + public DefaultSettings(FMLJavaModLoadingContext context) { + instance = this; + ForgeCoreHook core = new ForgeCoreHook(); + Core.setInstance(core); + + try { + VERSION = getVersion(); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + + if (FMLEnvironment.dist.isClient()) { + if (setUp) return; + + try { + Field pluginClass = Class.forName("net.jomcraft.jcplugin.JCPlugin").getDeclaredField("checksSuccessful"); + + if (!pluginClass.getBoolean(null)) { + shutDown = true; + shutdownReason = "The JCPlugin mod couldn't be found! Please make sure that the correct version (probably " + VERSION + ") is installed!"; + DefaultSettings.log.log(Level.ERROR, "DefaultSettings can't start up! Something is hella broken! Shutting down..."); + } else { + + final Path location = Launcher.INSTANCE.environment().getProperty(IEnvironment.Keys.GAMEDIR.get()).get(); + + File mods = new File(location.toFile(), "mods"); + + boolean foundDefaultSettings = false; + String wantedVersion = null; + + for (File mod : mods.listFiles()) { + if (mod.getName().toLowerCase().contains("defaultsettings")) { + + JarFile jar = new JarFile(mod); + + ZipEntry toml = jar.getEntry("META-INF/MANIFEST.MF"); + if (toml != null) { + + BufferedReader result = new BufferedReader(new InputStreamReader(jar.getInputStream(toml))); + + String readerLine; + + while ((readerLine = result.readLine()) != null) { + if (readerLine.contains("Implementation-Title: DefaultSettings")) { + foundDefaultSettings = true; + } else if (readerLine.startsWith("JCPluginVersion")) { + wantedVersion = readerLine.split(": ")[1]; + } + } + + result.close(); + } + + jar.close(); + + if (foundDefaultSettings && wantedVersion != null) { + + if (wantedVersion.equals(JCLogger.class.getPackage().getImplementationVersion())) { + DefaultSettings.log.log(Level.INFO, "DefaultSettings found correct version of JCPlugin, starting up..."); + break; + } else { + shutDown = true; + shutdownReason = "The correct JCPlugin mod version couldn't be found! Please install version " + wantedVersion; + DefaultSettings.log.log(Level.ERROR, "DefaultSettings can't start up! JCPlugin version must be " + wantedVersion + "!"); + } + + } + } + } + + String launchTarget = Launcher.INSTANCE.environment().getProperty(IEnvironment.Keys.LAUNCHTARGET.get()).get(); + + if (!launchTarget.contains("dev") && (!foundDefaultSettings || wantedVersion == null)) { + shutDown = true; + shutdownReason = "Strange! We can't find the DefaultSettings mod, eventhough you're currently using it!"; + DefaultSettings.log.log(Level.ERROR, "DefaultSettings can't start up! Couldn't get requested version of JCPlugin!"); + } + } + } catch (ClassNotFoundException | NoSuchFieldException | SecurityException | IllegalArgumentException | + IllegalAccessException | IOException e) { + shutDown = true; + shutdownReason = "The JCPlugin mod couldn't be found! Please make sure that the correct version (probably " + VERSION + ") is installed!"; + DefaultSettings.log.log(Level.ERROR, "DefaultSettings is missing the JCPlugin mod! Shutting down...", e); + } + + context.getModEventBus().addListener(this::postInit); + + COMMAND_ARGUMENT_TYPES.register("ds_config", () -> ArgumentTypeInfos.registerByClass(ConfigArguments.class, new ConfigArguments.Info())); + COMMAND_ARGUMENT_TYPES.register("ds_operation", () -> ArgumentTypeInfos.registerByClass(OperationArguments.class, new OperationArguments.Info())); + COMMAND_ARGUMENT_TYPES.register("ds_type", () -> ArgumentTypeInfos.registerByClass(TypeArguments.class, new TypeArguments.Info())); + + COMMAND_ARGUMENT_TYPES.register(context.getModEventBus()); + + //ModLoadingContext.get().registerExtensionPoint(IExtensionPoint.DisplayTest.class, () -> new IExtensionPoint.DisplayTest(() -> "ANY", (remote, isServer) -> true)); + + MinecraftForge.EVENT_BUS.register(DefaultSettings.class); + + MinecraftForge.EVENT_BUS.register(new EventHandlers()); + + if (shutDown) return; + + try { + FileUtil.restoreContents(); + + } catch (Exception e) { + DefaultSettings.log.log(Level.ERROR, "An exception occurred while starting up the game:", e); + } + setUp = true; + + } + + if (FMLEnvironment.dist.isDedicatedServer()) { + DefaultSettings.log.log(Level.WARN, "DefaultSettings is a client-side mod only! It won't do anything on servers!"); + } + } + + @SuppressWarnings("deprecation") + public void postInit(FMLLoadCompleteEvent event) { + if (FMLEnvironment.dist.isClient()) { + + try { + if (!shutDown) FileUtil.restoreKeys(true, FileUtilNoMC.privateJson.firstBootUp); + } catch (IOException e) { + DefaultSettings.log.log(Level.ERROR, "An exception occurred while starting up the game (Post):", e); + } catch (NullPointerException e) { + DefaultSettings.log.log(Level.ERROR, "An exception occurred while starting up the game (Post):", e); + } + + } + + if (FMLEnvironment.dist.isDedicatedServer()) { + DefaultSettings.log.log(Level.WARN, "DefaultSettings is a client-side mod only! It won't do anything on servers!"); + } + + } + + public static DefaultSettings getInstance() { + return instance; + } +} \ No newline at end of file diff --git a/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/EventHandlers.java b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/EventHandlers.java new file mode 100644 index 00000000..04d044bb --- /dev/null +++ b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/EventHandlers.java @@ -0,0 +1,15 @@ +package net.jomcraft.defaultsettings; + +import net.jomcraft.defaultsettings.commands.CommandDefaultSettings; +import net.minecraftforge.event.server.ServerStartingEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +import java.lang.reflect.Method; + +public class EventHandlers { + + @SubscribeEvent + public void serverStarting(ServerStartingEvent event) { + CommandDefaultSettings.register(event.getServer().getCommands().getDispatcher()); + } +} \ No newline at end of file diff --git a/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/FileUtil.java b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/FileUtil.java new file mode 100644 index 00000000..89b00e12 --- /dev/null +++ b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/FileUtil.java @@ -0,0 +1,171 @@ +package net.jomcraft.defaultsettings; + +import static net.jomcraft.jcplugin.FileUtilNoMC.*; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import org.apache.logging.log4j.Level; +import net.minecraft.client.Minecraft; + +public class FileUtil { + + public static void restoreContents() throws NullPointerException, IOException { + + final String version = getMainJSON().getVersion(); + + if (!DefaultSettings.VERSION.equals(version)) + mainJson.setVersion(DefaultSettings.VERSION).setPrevVersion(version); + + if (mainJson.generatedBy.equals("")) + mainJson.generatedBy = privateJson.privateIdentifier; + + activeProfile = privateJson.currentProfile; + + if (!privateJson.firstBootUp) { + copyAndHashPrivate(true, true); + } + + final File optionsOF = new File(mcDataDir, "optionsof.txt"); + if (!optionsOF.exists()) + restoreOptionsOF(); + + final File optionsShaders = new File(mcDataDir, "optionsshaders.txt"); + if (!optionsShaders.exists()) + restoreOptionsShaders(); + + final File optionsJEK = new File(mcDataDir, "options.justenoughkeys.txt"); + if (!optionsJEK.exists()) + restoreOptionsJEK(); + + final File optionsAmecs = new File(mcDataDir, "options.amecsapi.txt"); + if (!optionsAmecs.exists()) + restoreOptionsAmecs(); + + final File serversFile = new File(mcDataDir, "servers.dat"); + if (!serversFile.exists()) + restoreServers(); + + mainJson.save(); + } + + @SuppressWarnings("resource") + public static void restoreKeys(boolean update, boolean initial) throws NullPointerException, IOException, NumberFormatException { + CoreUtil.restoreKeys(update, initial); + } + + @SuppressWarnings("resource") + public static void saveKeys() throws IOException, NullPointerException { + CoreUtil.saveKeys(); + } + + @SuppressWarnings("resource") + public static boolean saveOptions() throws NullPointerException, IOException { + Minecraft.getInstance().options.save(); + return CoreUtil.saveOptions(); + } + + public static boolean checkChanged() { + boolean ret = false; + try { + + InputStream keys = CoreUtil.getKeysStream(false); + InputStream options = getOptionsStream(); + InputStream optionsOF = getOptionsOFStream(); + InputStream optionsShaders = getOptionsShadersStream(); + InputStream optionsJEK = getOptionsJEKStream(); + InputStream optionsAmecs = getOptionsAmecsStream(); + InputStream servers = getServersStream(); + + String hashO = ""; + String writtenHashO = ""; + + if (options != null) { + hashO = fileToHash(options); + writtenHashO = mainJson.hashes.get(activeProfile + "/options.txt"); + } + + String hashK = ""; + String writtenHashK = ""; + + if (keys != null) { + hashK = fileToHash(keys); + writtenHashK = mainJson.hashes.get(activeProfile + "/keys.txt"); + } + + String hashOF = ""; + String writtenHashOF = ""; + + if (optionsOF != null) { + hashOF = fileToHash(optionsOF); + writtenHashOF = mainJson.hashes.get(activeProfile + "/optionsof.txt"); + } + + String hashShaders = ""; + String writtenHashShaders = ""; + + if (optionsShaders != null) { + hashShaders = fileToHash(optionsShaders); + writtenHashShaders = mainJson.hashes.get(activeProfile + "/optionsshaders.txt"); + } + + String hashJEK = ""; + String writtenHashJEK = ""; + + if (optionsJEK != null) { + hashJEK = fileToHash(optionsJEK); + writtenHashJEK = mainJson.hashes.get(activeProfile + "/options.justenoughkeys.txt"); + } + + String hashAmecs = ""; + String writtenHashAmecs = ""; + + if (optionsAmecs != null) { + hashAmecs = fileToHash(optionsAmecs); + writtenHashAmecs = mainJson.hashes.get(activeProfile + "/options.amecsapi.txt"); + } + + String hashS = ""; + String writtenHashS = ""; + + if (servers != null) { + hashS = fileToHash(servers); + writtenHashS = mainJson.hashes.get(activeProfile + "/servers.dat"); + } + + if (mainJson.hashes.containsKey(activeProfile + "/options.txt") && !hashO.equals(writtenHashO)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/keys.txt") && !hashK.equals(writtenHashK)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/optionsof.txt") && !hashOF.equals(writtenHashOF)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/optionsshaders.txt") && !hashShaders.equals(writtenHashShaders)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/options.justenoughkeys.txt") && !hashJEK.equals(writtenHashJEK)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/options.amecsapi.txt") && !hashAmecs.equals(writtenHashAmecs)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/servers.dat") && !hashS.equals(writtenHashS)) { + ret = true; + } + + if (options != null) { + options.close(); + File fileO = new File(getMainFolder(), activeProfile + "/options.txt_temp"); + Files.delete(fileO.toPath()); + } + + if (keys != null) { + keys.close(); + File fileK = new File(getMainFolder(), activeProfile + "/keys.txt_temp"); + Files.delete(fileK.toPath()); + } + + } catch (Exception e) { + DefaultSettings.log.log(Level.ERROR, "Error while saving configs: ", e); + } + + return ret; + } +} \ No newline at end of file diff --git a/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/ForgeCoreHook.java b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/ForgeCoreHook.java new file mode 100644 index 00000000..3690f55d --- /dev/null +++ b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/ForgeCoreHook.java @@ -0,0 +1,194 @@ +package net.jomcraft.defaultsettings; + +import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.brigadier.LiteralMessage; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import net.jomcraft.jcplugin.FileUtilNoMC; +import net.minecraft.ChatFormatting; +import net.minecraft.client.KeyMapping; +import net.minecraft.client.Minecraft; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.network.chat.Component; +import net.minecraftforge.client.settings.KeyModifier; +import net.minecraftforge.fml.util.ObfuscationReflectionHelper; +import org.apache.logging.log4j.Logger; +import java.io.File; +import java.io.IOException; + +public class ForgeCoreHook implements ICoreHook { + + private static final SimpleCommandExceptionType FAILED_EXCEPTION = new SimpleCommandExceptionType(new LiteralMessage("Expected whitespace to end one argument, but found trailing data")); + + @Override + public File getMCDataDir() { + return FileUtilNoMC.mcDataDir; + } + + @Override + public File getMainFolder() { + return FileUtilNoMC.getMainFolder(); + } + + @Override + public String getActiveProfile() { + return FileUtilNoMC.activeProfile; + } + + @Override + public KeyPlaceholder[] getKeyMappings() { + KeyMapping[] mappings = Minecraft.getInstance().options.keyMappings; + if (mappings == null || mappings.length == 0) + return new KeyPlaceholder[0]; + + KeyPlaceholder[] keys = new KeyPlaceholder[mappings.length]; + + for (int i = 0; i < mappings.length; i++) { + keys[i] = new KeyPlaceholder(mappings[i].getName(), mappings[i].getKey().toString(), mappings[i].getKeyModifier().name()); + } + return keys; + } + + @Override + public void resetMappings() { + KeyMapping.resetMapping(); + } + + @Override + public void clearKeyBinds() { + DefaultSettings.keyRebinds.clear(); + } + + @Override + public void putKeybind(String first, String second, String third) { + LiteralArgumentBuilder literalargumentbuilder = Commands.literal("defaultsettings"); + DefaultSettings.keyRebinds.put(first, new KeyContainer(InputConstants.getKey(second), third != null ? KeyModifier.valueFromString(third) : KeyModifier.NONE)); + } + + @Override + public boolean keybindExists(String key) { + return DefaultSettings.keyRebinds.containsKey(key); + } + + @Override + public void setKeybind(KeyPlaceholder key, boolean init) { + KeyMapping[] mappings = Minecraft.getInstance().options.keyMappings; + for (int i = 0; i < mappings.length; i++) { + if (mappings[i].getName().equals(key.name)) { + KeyContainer container = DefaultSettings.keyRebinds.get(key.name); + + if (init) + mappings[i].setKey(container.input); + + mappings[i].defaultKey = container.input; + + ObfuscationReflectionHelper.setPrivateValue(KeyMapping.class, mappings[i], container.modifier, "keyModifierDefault"); + mappings[i].setKeyModifierAndCode(mappings[i].getDefaultKeyModifier(), container.input); + break; + } + } + } + + @Override + public void sendSuccess(Object source, String text, int color) { + if (source instanceof CommandSourceStack) { + ((CommandSourceStack) source).sendSuccess(() -> Component.literal(text).withStyle(ChatFormatting.getById(color)), true); + } + } + + @Override + public Exception throwFailedException() { + return FAILED_EXCEPTION.create(); + } + + @Override + public boolean hasDSShutDown() { + return DefaultSettings.shutDown; + } + + @Override + public Logger getDSLog() { + return DefaultSettings.log; + } + + @Override + public String shutdownReason() { + return DefaultSettings.shutdownReason; + } + + @Override + public boolean isOtherCreator() { + return FileUtilNoMC.otherCreator; + } + + @Override + public boolean disableCreatorCheck() { + return FileUtilNoMC.privateJson.disableCreatorCheck; + } + + @Override + public boolean checkChangedConfig() { + return FileUtilNoMC.checkChangedConfig(); + } + + @Override + public boolean checkForConfigFiles() { + return FileUtilNoMC.checkForConfigFiles(); + } + + @Override + public void checkMD5(boolean updateExisting, boolean configs, String file) throws IOException { + FileUtilNoMC.checkMD5(updateExisting, configs, file); + } + + @Override + public void copyAndHashPrivate(boolean options, boolean configs) throws NullPointerException, IOException { + FileUtilNoMC.copyAndHashPrivate(options, configs); + } + + @Override + public boolean keysFileExist() { + return FileUtilNoMC.keysFileExist(); + } + + @Override + public boolean optionsFilesExist() { + return FileUtilNoMC.optionsFilesExist(); + } + + @Override + public boolean serversFileExists() { + return FileUtilNoMC.serversFileExists(); + } + + @Override + public boolean checkChanged() { + return FileUtil.checkChanged(); + } + + @Override + public void saveKeys() throws IOException { + FileUtil.saveKeys(); + } + + @Override + public boolean saveOptions() throws IOException { + return FileUtil.saveOptions(); + } + + @Override + public void saveServers() throws IOException { + FileUtilNoMC.saveServers(); + } + + @Override + public void restoreKeys(boolean update, boolean initial) throws IOException { + FileUtil.restoreKeys(update, initial); + } + + @Override + public void saveOptionsFile() { + Minecraft.getInstance().options.save(); + } +} diff --git a/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/KeyContainer.java b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/KeyContainer.java new file mode 100644 index 00000000..474e8545 --- /dev/null +++ b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/KeyContainer.java @@ -0,0 +1,16 @@ +package net.jomcraft.defaultsettings; + +import com.mojang.blaze3d.platform.InputConstants; +import net.minecraftforge.client.settings.KeyModifier; + +public class KeyContainer { + + public final InputConstants.Key input; + public final KeyModifier modifier; + + public KeyContainer(final InputConstants.Key input, final KeyModifier modifier) { + this.input = input; + this.modifier = modifier; + } + +} diff --git a/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/ManifestUtility.java b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/ManifestUtility.java new file mode 100644 index 00000000..c9897a28 --- /dev/null +++ b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/ManifestUtility.java @@ -0,0 +1,113 @@ +//Part of fabric-loader (net.fabricmc.loader.impl.util.ManifestUtil) +package net.jomcraft.defaultsettings; + +import java.io.IOException; +import java.io.InputStream; +import java.net.*; +import java.nio.file.*; +import java.security.CodeSource; +import java.util.Collections; +import java.util.Map; +import java.util.jar.Manifest; +import java.util.zip.ZipError; + +public class ManifestUtility { + + private static final Map jfsArgsCreate = Collections.singletonMap("create", "true"); + private static final Map jfsArgsEmpty = Collections.emptyMap(); + + public static Manifest readManifest(Class cls) throws IOException, URISyntaxException { + CodeSource cs = cls.getProtectionDomain().getCodeSource(); + if (cs == null) return null; + + URL url = cs.getLocation(); + if (url == null) return null; + + return readManifest(url); + } + + public static Path asPath(URL url) { + try { + return Paths.get(url.toURI()); + } catch (URISyntaxException e) { + return null; + } + } + + public static Manifest readManifest(URL codeSourceUrl) throws IOException, URISyntaxException { + Path path = asPath(codeSourceUrl); + + if (Files.isDirectory(path)) { + return readManifest(path); + } else { + URLConnection connection = new URL("jar:" + codeSourceUrl.toString() + "!/").openConnection(); + + if (connection instanceof JarURLConnection) { + return ((JarURLConnection) connection).getManifest(); + } + + try (FileSystemDelegate jarFs = getJarFileSystem(path.toUri(), false)) { + return readManifest(jarFs.get().getRootDirectories().iterator().next()); + } + } + } + + public static FileSystemDelegate getJarFileSystem(URI uri, boolean create) throws IOException { + URI jarUri; + + try { + jarUri = new URI("jar:" + uri.getScheme(), uri.getHost(), uri.getPath(), uri.getFragment()); + } catch (URISyntaxException e) { + throw new IOException(e); + } + + boolean opened = false; + FileSystem ret = null; + + try { + ret = FileSystems.getFileSystem(jarUri); + } catch (FileSystemNotFoundException ignore) { + try { + ret = FileSystems.newFileSystem(jarUri, create ? jfsArgsCreate : jfsArgsEmpty); + opened = true; + } catch (FileSystemAlreadyExistsException ignore2) { + ret = FileSystems.getFileSystem(jarUri); + } catch (IOException | ZipError e) { + throw new IOException("Error accessing "+uri+": "+e, e); + } + } + + return new FileSystemDelegate(ret, opened); + } + + public static Manifest readManifest(Path basePath) throws IOException { + Path path = basePath.resolve("META-INF").resolve("MANIFEST.MF"); + if (!Files.exists(path)) return null; + + try (InputStream stream = Files.newInputStream(path)) { + return new Manifest(stream); + } + } + + public static class FileSystemDelegate implements AutoCloseable { + private final FileSystem fileSystem; + private final boolean owner; + + public FileSystemDelegate(FileSystem fileSystem, boolean owner) { + this.fileSystem = fileSystem; + this.owner = owner; + } + + public FileSystem get() { + return fileSystem; + } + + @Override + public void close() throws IOException { + if (owner) { + fileSystem.close(); + } + } + } + +} diff --git a/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/CommandDefaultSettings.java b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/CommandDefaultSettings.java new file mode 100644 index 00000000..2c5a74e6 --- /dev/null +++ b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/CommandDefaultSettings.java @@ -0,0 +1,52 @@ +package net.jomcraft.defaultsettings.commands; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.tree.LiteralCommandNode; +import net.jomcraft.defaultsettings.CoreUtil; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraftforge.event.server.ServerStartingEvent; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +public class CommandDefaultSettings { + + public static void register(CommandDispatcher dispatcher) { + LiteralArgumentBuilder literalargumentbuilder = LiteralArgumentBuilder.literal("defaultsettings"); + + literalargumentbuilder.then(Commands.literal("save").executes((command) -> { + return saveProcess(command.getSource(), null, null); + }).then(Commands.argument("operation", OperationArguments.operationArguments(false)).executes((command) -> { + return saveProcess(command.getSource(), OperationArguments.getString(command, "operation"), null); + }).then(Commands.argument("type", TypeArguments.typeArguments()).executes((command) -> { + return saveProcess(command.getSource(), OperationArguments.getString(command, "operation"), TypeArguments.getString(command, "type")); + })))).then(Commands.literal("saveconfigs").executes((command) -> { + return saveProcessConfigs(command.getSource(), null, null); + }).then(Commands.argument("operation", OperationArguments.operationArguments(true)).executes((command) -> { + return saveProcessConfigs(command.getSource(), OperationArguments.getString(command, "operation"), null); + }).then(Commands.argument("config", ConfigArguments.configArguments()).executes((command) -> { + return saveProcessConfigs(command.getSource(), OperationArguments.getString(command, "operation"), ConfigArguments.getString(command, "config")); + })))); + + LiteralCommandNode node = dispatcher.register(literalargumentbuilder); + /*event.getServer().getCommands().getDispatcher()*/dispatcher.register(Commands.literal("ds").redirect(node)); + } + + private static int saveProcessConfigs(CommandSourceStack source, String argument, String argument2) throws CommandSyntaxException { + try { + return CoreUtil.saveProcessConfigs(source, argument, argument2); + } catch (Exception e) { + if (e instanceof CommandSyntaxException) throw (CommandSyntaxException) e; + return 0; + } + } + + private static int saveProcess(CommandSourceStack source, String argument, String argument2) throws CommandSyntaxException { + try { + return CoreUtil.saveProcess(source, argument, argument2); + } catch (Exception e) { + if (e instanceof CommandSyntaxException) throw (CommandSyntaxException) e; + return 0; + } + } +} \ No newline at end of file diff --git a/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/ConfigArguments.java b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/ConfigArguments.java new file mode 100644 index 00000000..a52b8d5f --- /dev/null +++ b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/ConfigArguments.java @@ -0,0 +1,118 @@ +package net.jomcraft.defaultsettings.commands; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import com.google.gson.JsonObject; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.jomcraft.defaultsettings.DefaultSettings; +import net.jomcraft.jcplugin.FileUtilNoMC; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.network.FriendlyByteBuf; + +public class ConfigArguments implements ArgumentType { + + private static List ARGUMENTS = Arrays.asList("fml.toml", "forge-client.toml"); + + public static ConfigArguments configArguments() { + return new ConfigArguments(); + } + + @Override + public String parse(final StringReader reader) throws CommandSyntaxException { + return readQuotedString(reader); + } + + public String readQuotedString(final StringReader reader) throws CommandSyntaxException { + if (!reader.canRead()) { + return ""; + } + final char next = reader.getString().charAt(reader.getCursor()); + if (!reader.isQuotedStringStart(next)) { + + final int start = reader.getCursor(); + while (reader.canRead()) { + reader.skip(); + } + return reader.getString().substring(start, reader.getCursor()); + } + reader.skip(); + return reader.readStringUntil(next); + } + + public static String getString(final CommandContext context, final String name) { + return context.getArgument(name, String.class); + } + + @Override + public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) { + try { + ArrayList filtered = new ArrayList(); + ArrayList prevList = FileUtilNoMC.listConfigFiles(); + for(int i = 0; i < prevList.size(); i++){ + String name = prevList.get(i); + if(name.contains(" ")) + name = "\"" + name + "\""; + filtered.add(name); + } + ARGUMENTS = filtered; + } catch (IOException e) { + DefaultSettings.log.error(e); + } + return SharedSuggestionProvider.suggest(ARGUMENTS, builder); + } + + @Override + public Collection getExamples() { + return ARGUMENTS; + } + + public static class Info implements ArgumentTypeInfo { + @Override + public void serializeToNetwork(Template template, FriendlyByteBuf buffer) { + + } + + @Override + public Template deserializeFromNetwork(FriendlyByteBuf buffer) { + return new Template(); + } + + @Override + public void serializeToJson(Template template, JsonObject json) { + + } + + @Override + public Template unpack(ConfigArguments argument) { + return new Template(); + } + + public class Template implements ArgumentTypeInfo.Template { + + Template() { + + } + + @Override + public ConfigArguments instantiate(CommandBuildContext p_223435_) { + return new ConfigArguments(); + } + + @Override + public ArgumentTypeInfo type() { + return Info.this; + } + } + } +} \ No newline at end of file diff --git a/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/OperationArguments.java b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/OperationArguments.java new file mode 100644 index 00000000..bb9f85b1 --- /dev/null +++ b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/OperationArguments.java @@ -0,0 +1,92 @@ +package net.jomcraft.defaultsettings.commands; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import com.google.gson.JsonObject; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.network.FriendlyByteBuf; + +public class OperationArguments implements ArgumentType { + + private static final List ARGUMENTS = Arrays.asList("override", "forceOverride"); + private static final List ARGUMENTS_LIMITED = Arrays.asList("forceOverride"); + private final boolean limited; + + public OperationArguments(boolean limited) { + this.limited = limited; + } + + public static OperationArguments operationArguments(boolean limited) { + return new OperationArguments(limited); + } + + @Override + public String parse(final StringReader reader) throws CommandSyntaxException { + return reader.readUnquotedString(); + } + + public static String getString(final CommandContext context, final String name) { + return context.getArgument(name, String.class); + } + + @Override + public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) { + return SharedSuggestionProvider.suggest(this.limited ? ARGUMENTS_LIMITED : ARGUMENTS, builder); + } + + @Override + public Collection getExamples() { + return ARGUMENTS; + } + + public static class Info implements ArgumentTypeInfo { + @Override + public void serializeToNetwork(Template template, FriendlyByteBuf buffer) { + buffer.writeBoolean(template.limited); + } + + @Override + public Template deserializeFromNetwork(FriendlyByteBuf buffer) { + boolean limited = buffer.readBoolean(); + return new Template(limited); + } + + @Override + public void serializeToJson(Template template, JsonObject json) { + json.addProperty("limited", template.limited); + } + + @Override + public Template unpack(OperationArguments argument) { + return new Template(argument.limited); + } + + public class Template implements ArgumentTypeInfo.Template { + final boolean limited; + + Template(boolean limited) { + this.limited = limited; + } + + @Override + public OperationArguments instantiate(CommandBuildContext p_223435_) { + return new OperationArguments(this.limited); + } + + @Override + public ArgumentTypeInfo type() { + return Info.this; + } + } + } +} \ No newline at end of file diff --git a/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/TypeArguments.java b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/TypeArguments.java new file mode 100644 index 00000000..8fa88263 --- /dev/null +++ b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/commands/TypeArguments.java @@ -0,0 +1,83 @@ +package net.jomcraft.defaultsettings.commands; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import com.google.gson.JsonObject; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.network.FriendlyByteBuf; + +public class TypeArguments implements ArgumentType { + + private static final List ARGUMENTS = Arrays.asList("options", "keybinds", "servers"); + + public static TypeArguments typeArguments() { + return new TypeArguments(); + } + + @Override + public String parse(final StringReader reader) throws CommandSyntaxException { + return reader.readUnquotedString(); + } + + public static String getString(final CommandContext context, final String name) { + return context.getArgument(name, String.class); + } + + @Override + public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) { + return SharedSuggestionProvider.suggest(ARGUMENTS, builder); + } + + @Override + public Collection getExamples() { + return ARGUMENTS; + } + + public static class Info implements ArgumentTypeInfo { + @Override + public void serializeToNetwork(Template template, FriendlyByteBuf buffer) { + + } + + @Override + public Template deserializeFromNetwork(FriendlyByteBuf buffer) { + return new Template(); + } + + @Override + public void serializeToJson(Template template, JsonObject json) { + } + + @Override + public Template unpack(TypeArguments argument) { + return new Template(); + } + + public class Template implements ArgumentTypeInfo.Template { + + Template() { + + } + + @Override + public TypeArguments instantiate(CommandBuildContext p_223435_) { + return new TypeArguments(); + } + + @Override + public ArgumentTypeInfo type() { + return Info.this; + } + } + } +} \ No newline at end of file diff --git a/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/mixin/MinecraftMixin.java b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/mixin/MinecraftMixin.java new file mode 100644 index 00000000..67d391cf --- /dev/null +++ b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/mixin/MinecraftMixin.java @@ -0,0 +1,15 @@ +package net.jomcraft.defaultsettings.mixin; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.Options; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(Minecraft.class) +public class MinecraftMixin { + @Redirect(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Options;save()V")) + private void redirected(Options instance) { + + } +} \ No newline at end of file diff --git a/sources/Forge-1.21.5/src/main/resources/META-INF/accesstransformer.cfg b/sources/Forge-1.21.5/src/main/resources/META-INF/accesstransformer.cfg new file mode 100644 index 00000000..584c6381 --- /dev/null +++ b/sources/Forge-1.21.5/src/main/resources/META-INF/accesstransformer.cfg @@ -0,0 +1 @@ +public-f net.minecraft.client.KeyMapping f_90814_ # defaultKey \ No newline at end of file diff --git a/sources/Forge-1.21.5/src/main/resources/META-INF/mods.toml b/sources/Forge-1.21.5/src/main/resources/META-INF/mods.toml new file mode 100644 index 00000000..75a64d47 --- /dev/null +++ b/sources/Forge-1.21.5/src/main/resources/META-INF/mods.toml @@ -0,0 +1,29 @@ +modLoader="javafml" +loaderVersion="[44,)" +logoFile="logo.png" +license="Apache License 2.0" + +[[mods]] + modId="defaultsettings" + version="${version}" + displayName="DefaultSettings" + description='''Keep your game's local settings in case of an update to your modpack''' + side="CLIENT" + authors="PT400C - Jomcraft Network" + credits="Developed by Jomcraft Network" + displayURL="https://www.curseforge.com/minecraft/mc-mods/defaultsettings" + displayTest="IGNORE_ALL_VERSION" + +[[dependencies.defaultsettings]] + modId="forge" + mandatory=true + versionRange="[44.1.0,)" + ordering="NONE" + side="CLIENT" + +[[dependencies.defaultsettings]] + modId="minecraft" + mandatory=true + versionRange="[1.19.3,)" + ordering="NONE" + side="CLIENT" \ No newline at end of file diff --git a/sources/Forge-1.21.5/src/main/resources/defaultsettings.mixin.json b/sources/Forge-1.21.5/src/main/resources/defaultsettings.mixin.json new file mode 100644 index 00000000..d6272800 --- /dev/null +++ b/sources/Forge-1.21.5/src/main/resources/defaultsettings.mixin.json @@ -0,0 +1,15 @@ +{ + "required": true, + "package": "net.jomcraft.defaultsettings.mixin", + "compatibilityLevel": "JAVA_21", + "refmap": "defaultsettings.refmap.json", + "mixins": [ + ], + "client": [ + "MinecraftMixin" + ], + "injectors": { + "defaultRequire": 1 + }, + "minVersion": "0.8" +} \ No newline at end of file diff --git a/sources/Forge-1.21.5/src/main/resources/logo.png b/sources/Forge-1.21.5/src/main/resources/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6f345514da0f0b162d7759a1c9d62d85b82a638e GIT binary patch literal 51342 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 n!ZX~V14{r4{eOLYa%>)6=DYpuB{JC%{UXv& keyRebinds = new HashMap(); + public static boolean setUp = false; + public static DefaultSettings instance; + public static boolean shutDown = false; + public static String shutdownReason = null; + private static final DeferredRegister> COMMAND_ARGUMENT_TYPES = DeferredRegister.create(ForgeRegistries.Keys.COMMAND_ARGUMENT_TYPES, DefaultSettings.MODID); + + public String getVersion() throws IOException, URISyntaxException { + Manifest manifest = ManifestUtility.readManifest(this.getClass()); + Attributes attr = manifest.getMainAttributes(); + return attr.getValue("Implementation-Version"); + } + + @SuppressWarnings({"deprecation"}) + public DefaultSettings(FMLJavaModLoadingContext context) { + instance = this; + ForgeCoreHook core = new ForgeCoreHook(); + Core.setInstance(core); + + try { + VERSION = getVersion(); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + + if (FMLEnvironment.dist.isClient()) { + if (setUp) return; + + try { + Field pluginClass = Class.forName("net.jomcraft.jcplugin.JCPlugin").getDeclaredField("checksSuccessful"); + + if (!pluginClass.getBoolean(null)) { + shutDown = true; + shutdownReason = "The JCPlugin mod couldn't be found! Please make sure that the correct version (probably " + VERSION + ") is installed!"; + DefaultSettings.log.log(Level.ERROR, "DefaultSettings can't start up! Something is hella broken! Shutting down..."); + } else { + + final Path location = Launcher.INSTANCE.environment().getProperty(IEnvironment.Keys.GAMEDIR.get()).get(); + + File mods = new File(location.toFile(), "mods"); + + boolean foundDefaultSettings = false; + String wantedVersion = null; + + for (File mod : mods.listFiles()) { + if (mod.getName().toLowerCase().contains("defaultsettings")) { + + JarFile jar = new JarFile(mod); + + ZipEntry toml = jar.getEntry("META-INF/MANIFEST.MF"); + if (toml != null) { + + BufferedReader result = new BufferedReader(new InputStreamReader(jar.getInputStream(toml))); + + String readerLine; + + while ((readerLine = result.readLine()) != null) { + if (readerLine.contains("Implementation-Title: DefaultSettings")) { + foundDefaultSettings = true; + } else if (readerLine.startsWith("JCPluginVersion")) { + wantedVersion = readerLine.split(": ")[1]; + } + } + + result.close(); + } + + jar.close(); + + if (foundDefaultSettings && wantedVersion != null) { + + if (wantedVersion.equals(JCLogger.class.getPackage().getImplementationVersion())) { + DefaultSettings.log.log(Level.INFO, "DefaultSettings found correct version of JCPlugin, starting up..."); + break; + } else { + shutDown = true; + shutdownReason = "The correct JCPlugin mod version couldn't be found! Please install version " + wantedVersion; + DefaultSettings.log.log(Level.ERROR, "DefaultSettings can't start up! JCPlugin version must be " + wantedVersion + "!"); + } + + } + } + } + + String launchTarget = Launcher.INSTANCE.environment().getProperty(IEnvironment.Keys.LAUNCHTARGET.get()).get(); + + if (!launchTarget.contains("dev") && (!foundDefaultSettings || wantedVersion == null)) { + shutDown = true; + shutdownReason = "Strange! We can't find the DefaultSettings mod, eventhough you're currently using it!"; + DefaultSettings.log.log(Level.ERROR, "DefaultSettings can't start up! Couldn't get requested version of JCPlugin!"); + } + } + } catch (ClassNotFoundException | NoSuchFieldException | SecurityException | IllegalArgumentException | + IllegalAccessException | IOException e) { + shutDown = true; + shutdownReason = "The JCPlugin mod couldn't be found! Please make sure that the correct version (probably " + VERSION + ") is installed!"; + DefaultSettings.log.log(Level.ERROR, "DefaultSettings is missing the JCPlugin mod! Shutting down...", e); + } + + FMLLoadCompleteEvent.getBus(context.getModBusGroup()).addListener(this::postInit); + + COMMAND_ARGUMENT_TYPES.register("ds_config", () -> ArgumentTypeInfos.registerByClass(ConfigArguments.class, new ConfigArguments.Info())); + COMMAND_ARGUMENT_TYPES.register("ds_operation", () -> ArgumentTypeInfos.registerByClass(OperationArguments.class, new OperationArguments.Info())); + COMMAND_ARGUMENT_TYPES.register("ds_type", () -> ArgumentTypeInfos.registerByClass(TypeArguments.class, new TypeArguments.Info())); + + COMMAND_ARGUMENT_TYPES.register(context.getModBusGroup()); + + //ModLoadingContext.get().registerExtensionPoint(IExtensionPoint.DisplayTest.class, () -> new IExtensionPoint.DisplayTest(() -> "ANY", (remote, isServer) -> true)); + + ServerStartingEvent.BUS.addListener(EventHandlers::serverStarting); + + if (shutDown) return; + + try { + FileUtil.restoreContents(); + + } catch (Exception e) { + DefaultSettings.log.log(Level.ERROR, "An exception occurred while starting up the game:", e); + } + setUp = true; + + } + + if (FMLEnvironment.dist.isDedicatedServer()) { + DefaultSettings.log.log(Level.WARN, "DefaultSettings is a client-side mod only! It won't do anything on servers!"); + } + } + + public void postInit(FMLLoadCompleteEvent event) { + if (FMLEnvironment.dist.isClient()) { + + try { + if (!shutDown) FileUtil.restoreKeys(true, FileUtilNoMC.privateJson.firstBootUp); + } catch (IOException e) { + DefaultSettings.log.log(Level.ERROR, "An exception occurred while starting up the game (Post):", e); + } catch (NullPointerException e) { + DefaultSettings.log.log(Level.ERROR, "An exception occurred while starting up the game (Post):", e); + } + + } + + if (FMLEnvironment.dist.isDedicatedServer()) { + DefaultSettings.log.log(Level.WARN, "DefaultSettings is a client-side mod only! It won't do anything on servers!"); + } + + } + + public static DefaultSettings getInstance() { + return instance; + } +} \ No newline at end of file diff --git a/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/EventHandlers.java b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/EventHandlers.java new file mode 100644 index 00000000..7e630fe7 --- /dev/null +++ b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/EventHandlers.java @@ -0,0 +1,14 @@ +package net.jomcraft.defaultsettings; + +import net.jomcraft.defaultsettings.commands.CommandDefaultSettings; +import net.minecraftforge.event.server.ServerStartingEvent; +import net.minecraftforge.eventbus.api.listener.SubscribeEvent; + +public class EventHandlers { + + @SubscribeEvent + public static void serverStarting(ServerStartingEvent event) { + CommandDefaultSettings.register(event.getServer().getCommands().getDispatcher()); + + } +} \ No newline at end of file diff --git a/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/FileUtil.java b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/FileUtil.java new file mode 100644 index 00000000..89b00e12 --- /dev/null +++ b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/FileUtil.java @@ -0,0 +1,171 @@ +package net.jomcraft.defaultsettings; + +import static net.jomcraft.jcplugin.FileUtilNoMC.*; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import org.apache.logging.log4j.Level; +import net.minecraft.client.Minecraft; + +public class FileUtil { + + public static void restoreContents() throws NullPointerException, IOException { + + final String version = getMainJSON().getVersion(); + + if (!DefaultSettings.VERSION.equals(version)) + mainJson.setVersion(DefaultSettings.VERSION).setPrevVersion(version); + + if (mainJson.generatedBy.equals("")) + mainJson.generatedBy = privateJson.privateIdentifier; + + activeProfile = privateJson.currentProfile; + + if (!privateJson.firstBootUp) { + copyAndHashPrivate(true, true); + } + + final File optionsOF = new File(mcDataDir, "optionsof.txt"); + if (!optionsOF.exists()) + restoreOptionsOF(); + + final File optionsShaders = new File(mcDataDir, "optionsshaders.txt"); + if (!optionsShaders.exists()) + restoreOptionsShaders(); + + final File optionsJEK = new File(mcDataDir, "options.justenoughkeys.txt"); + if (!optionsJEK.exists()) + restoreOptionsJEK(); + + final File optionsAmecs = new File(mcDataDir, "options.amecsapi.txt"); + if (!optionsAmecs.exists()) + restoreOptionsAmecs(); + + final File serversFile = new File(mcDataDir, "servers.dat"); + if (!serversFile.exists()) + restoreServers(); + + mainJson.save(); + } + + @SuppressWarnings("resource") + public static void restoreKeys(boolean update, boolean initial) throws NullPointerException, IOException, NumberFormatException { + CoreUtil.restoreKeys(update, initial); + } + + @SuppressWarnings("resource") + public static void saveKeys() throws IOException, NullPointerException { + CoreUtil.saveKeys(); + } + + @SuppressWarnings("resource") + public static boolean saveOptions() throws NullPointerException, IOException { + Minecraft.getInstance().options.save(); + return CoreUtil.saveOptions(); + } + + public static boolean checkChanged() { + boolean ret = false; + try { + + InputStream keys = CoreUtil.getKeysStream(false); + InputStream options = getOptionsStream(); + InputStream optionsOF = getOptionsOFStream(); + InputStream optionsShaders = getOptionsShadersStream(); + InputStream optionsJEK = getOptionsJEKStream(); + InputStream optionsAmecs = getOptionsAmecsStream(); + InputStream servers = getServersStream(); + + String hashO = ""; + String writtenHashO = ""; + + if (options != null) { + hashO = fileToHash(options); + writtenHashO = mainJson.hashes.get(activeProfile + "/options.txt"); + } + + String hashK = ""; + String writtenHashK = ""; + + if (keys != null) { + hashK = fileToHash(keys); + writtenHashK = mainJson.hashes.get(activeProfile + "/keys.txt"); + } + + String hashOF = ""; + String writtenHashOF = ""; + + if (optionsOF != null) { + hashOF = fileToHash(optionsOF); + writtenHashOF = mainJson.hashes.get(activeProfile + "/optionsof.txt"); + } + + String hashShaders = ""; + String writtenHashShaders = ""; + + if (optionsShaders != null) { + hashShaders = fileToHash(optionsShaders); + writtenHashShaders = mainJson.hashes.get(activeProfile + "/optionsshaders.txt"); + } + + String hashJEK = ""; + String writtenHashJEK = ""; + + if (optionsJEK != null) { + hashJEK = fileToHash(optionsJEK); + writtenHashJEK = mainJson.hashes.get(activeProfile + "/options.justenoughkeys.txt"); + } + + String hashAmecs = ""; + String writtenHashAmecs = ""; + + if (optionsAmecs != null) { + hashAmecs = fileToHash(optionsAmecs); + writtenHashAmecs = mainJson.hashes.get(activeProfile + "/options.amecsapi.txt"); + } + + String hashS = ""; + String writtenHashS = ""; + + if (servers != null) { + hashS = fileToHash(servers); + writtenHashS = mainJson.hashes.get(activeProfile + "/servers.dat"); + } + + if (mainJson.hashes.containsKey(activeProfile + "/options.txt") && !hashO.equals(writtenHashO)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/keys.txt") && !hashK.equals(writtenHashK)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/optionsof.txt") && !hashOF.equals(writtenHashOF)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/optionsshaders.txt") && !hashShaders.equals(writtenHashShaders)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/options.justenoughkeys.txt") && !hashJEK.equals(writtenHashJEK)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/options.amecsapi.txt") && !hashAmecs.equals(writtenHashAmecs)) { + ret = true; + } else if (mainJson.hashes.containsKey(activeProfile + "/servers.dat") && !hashS.equals(writtenHashS)) { + ret = true; + } + + if (options != null) { + options.close(); + File fileO = new File(getMainFolder(), activeProfile + "/options.txt_temp"); + Files.delete(fileO.toPath()); + } + + if (keys != null) { + keys.close(); + File fileK = new File(getMainFolder(), activeProfile + "/keys.txt_temp"); + Files.delete(fileK.toPath()); + } + + } catch (Exception e) { + DefaultSettings.log.log(Level.ERROR, "Error while saving configs: ", e); + } + + return ret; + } +} \ No newline at end of file diff --git a/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/ForgeCoreHook.java b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/ForgeCoreHook.java new file mode 100644 index 00000000..3690f55d --- /dev/null +++ b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/ForgeCoreHook.java @@ -0,0 +1,194 @@ +package net.jomcraft.defaultsettings; + +import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.brigadier.LiteralMessage; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import net.jomcraft.jcplugin.FileUtilNoMC; +import net.minecraft.ChatFormatting; +import net.minecraft.client.KeyMapping; +import net.minecraft.client.Minecraft; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.network.chat.Component; +import net.minecraftforge.client.settings.KeyModifier; +import net.minecraftforge.fml.util.ObfuscationReflectionHelper; +import org.apache.logging.log4j.Logger; +import java.io.File; +import java.io.IOException; + +public class ForgeCoreHook implements ICoreHook { + + private static final SimpleCommandExceptionType FAILED_EXCEPTION = new SimpleCommandExceptionType(new LiteralMessage("Expected whitespace to end one argument, but found trailing data")); + + @Override + public File getMCDataDir() { + return FileUtilNoMC.mcDataDir; + } + + @Override + public File getMainFolder() { + return FileUtilNoMC.getMainFolder(); + } + + @Override + public String getActiveProfile() { + return FileUtilNoMC.activeProfile; + } + + @Override + public KeyPlaceholder[] getKeyMappings() { + KeyMapping[] mappings = Minecraft.getInstance().options.keyMappings; + if (mappings == null || mappings.length == 0) + return new KeyPlaceholder[0]; + + KeyPlaceholder[] keys = new KeyPlaceholder[mappings.length]; + + for (int i = 0; i < mappings.length; i++) { + keys[i] = new KeyPlaceholder(mappings[i].getName(), mappings[i].getKey().toString(), mappings[i].getKeyModifier().name()); + } + return keys; + } + + @Override + public void resetMappings() { + KeyMapping.resetMapping(); + } + + @Override + public void clearKeyBinds() { + DefaultSettings.keyRebinds.clear(); + } + + @Override + public void putKeybind(String first, String second, String third) { + LiteralArgumentBuilder literalargumentbuilder = Commands.literal("defaultsettings"); + DefaultSettings.keyRebinds.put(first, new KeyContainer(InputConstants.getKey(second), third != null ? KeyModifier.valueFromString(third) : KeyModifier.NONE)); + } + + @Override + public boolean keybindExists(String key) { + return DefaultSettings.keyRebinds.containsKey(key); + } + + @Override + public void setKeybind(KeyPlaceholder key, boolean init) { + KeyMapping[] mappings = Minecraft.getInstance().options.keyMappings; + for (int i = 0; i < mappings.length; i++) { + if (mappings[i].getName().equals(key.name)) { + KeyContainer container = DefaultSettings.keyRebinds.get(key.name); + + if (init) + mappings[i].setKey(container.input); + + mappings[i].defaultKey = container.input; + + ObfuscationReflectionHelper.setPrivateValue(KeyMapping.class, mappings[i], container.modifier, "keyModifierDefault"); + mappings[i].setKeyModifierAndCode(mappings[i].getDefaultKeyModifier(), container.input); + break; + } + } + } + + @Override + public void sendSuccess(Object source, String text, int color) { + if (source instanceof CommandSourceStack) { + ((CommandSourceStack) source).sendSuccess(() -> Component.literal(text).withStyle(ChatFormatting.getById(color)), true); + } + } + + @Override + public Exception throwFailedException() { + return FAILED_EXCEPTION.create(); + } + + @Override + public boolean hasDSShutDown() { + return DefaultSettings.shutDown; + } + + @Override + public Logger getDSLog() { + return DefaultSettings.log; + } + + @Override + public String shutdownReason() { + return DefaultSettings.shutdownReason; + } + + @Override + public boolean isOtherCreator() { + return FileUtilNoMC.otherCreator; + } + + @Override + public boolean disableCreatorCheck() { + return FileUtilNoMC.privateJson.disableCreatorCheck; + } + + @Override + public boolean checkChangedConfig() { + return FileUtilNoMC.checkChangedConfig(); + } + + @Override + public boolean checkForConfigFiles() { + return FileUtilNoMC.checkForConfigFiles(); + } + + @Override + public void checkMD5(boolean updateExisting, boolean configs, String file) throws IOException { + FileUtilNoMC.checkMD5(updateExisting, configs, file); + } + + @Override + public void copyAndHashPrivate(boolean options, boolean configs) throws NullPointerException, IOException { + FileUtilNoMC.copyAndHashPrivate(options, configs); + } + + @Override + public boolean keysFileExist() { + return FileUtilNoMC.keysFileExist(); + } + + @Override + public boolean optionsFilesExist() { + return FileUtilNoMC.optionsFilesExist(); + } + + @Override + public boolean serversFileExists() { + return FileUtilNoMC.serversFileExists(); + } + + @Override + public boolean checkChanged() { + return FileUtil.checkChanged(); + } + + @Override + public void saveKeys() throws IOException { + FileUtil.saveKeys(); + } + + @Override + public boolean saveOptions() throws IOException { + return FileUtil.saveOptions(); + } + + @Override + public void saveServers() throws IOException { + FileUtilNoMC.saveServers(); + } + + @Override + public void restoreKeys(boolean update, boolean initial) throws IOException { + FileUtil.restoreKeys(update, initial); + } + + @Override + public void saveOptionsFile() { + Minecraft.getInstance().options.save(); + } +} diff --git a/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/KeyContainer.java b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/KeyContainer.java new file mode 100644 index 00000000..474e8545 --- /dev/null +++ b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/KeyContainer.java @@ -0,0 +1,16 @@ +package net.jomcraft.defaultsettings; + +import com.mojang.blaze3d.platform.InputConstants; +import net.minecraftforge.client.settings.KeyModifier; + +public class KeyContainer { + + public final InputConstants.Key input; + public final KeyModifier modifier; + + public KeyContainer(final InputConstants.Key input, final KeyModifier modifier) { + this.input = input; + this.modifier = modifier; + } + +} diff --git a/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/ManifestUtility.java b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/ManifestUtility.java new file mode 100644 index 00000000..c9897a28 --- /dev/null +++ b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/ManifestUtility.java @@ -0,0 +1,113 @@ +//Part of fabric-loader (net.fabricmc.loader.impl.util.ManifestUtil) +package net.jomcraft.defaultsettings; + +import java.io.IOException; +import java.io.InputStream; +import java.net.*; +import java.nio.file.*; +import java.security.CodeSource; +import java.util.Collections; +import java.util.Map; +import java.util.jar.Manifest; +import java.util.zip.ZipError; + +public class ManifestUtility { + + private static final Map jfsArgsCreate = Collections.singletonMap("create", "true"); + private static final Map jfsArgsEmpty = Collections.emptyMap(); + + public static Manifest readManifest(Class cls) throws IOException, URISyntaxException { + CodeSource cs = cls.getProtectionDomain().getCodeSource(); + if (cs == null) return null; + + URL url = cs.getLocation(); + if (url == null) return null; + + return readManifest(url); + } + + public static Path asPath(URL url) { + try { + return Paths.get(url.toURI()); + } catch (URISyntaxException e) { + return null; + } + } + + public static Manifest readManifest(URL codeSourceUrl) throws IOException, URISyntaxException { + Path path = asPath(codeSourceUrl); + + if (Files.isDirectory(path)) { + return readManifest(path); + } else { + URLConnection connection = new URL("jar:" + codeSourceUrl.toString() + "!/").openConnection(); + + if (connection instanceof JarURLConnection) { + return ((JarURLConnection) connection).getManifest(); + } + + try (FileSystemDelegate jarFs = getJarFileSystem(path.toUri(), false)) { + return readManifest(jarFs.get().getRootDirectories().iterator().next()); + } + } + } + + public static FileSystemDelegate getJarFileSystem(URI uri, boolean create) throws IOException { + URI jarUri; + + try { + jarUri = new URI("jar:" + uri.getScheme(), uri.getHost(), uri.getPath(), uri.getFragment()); + } catch (URISyntaxException e) { + throw new IOException(e); + } + + boolean opened = false; + FileSystem ret = null; + + try { + ret = FileSystems.getFileSystem(jarUri); + } catch (FileSystemNotFoundException ignore) { + try { + ret = FileSystems.newFileSystem(jarUri, create ? jfsArgsCreate : jfsArgsEmpty); + opened = true; + } catch (FileSystemAlreadyExistsException ignore2) { + ret = FileSystems.getFileSystem(jarUri); + } catch (IOException | ZipError e) { + throw new IOException("Error accessing "+uri+": "+e, e); + } + } + + return new FileSystemDelegate(ret, opened); + } + + public static Manifest readManifest(Path basePath) throws IOException { + Path path = basePath.resolve("META-INF").resolve("MANIFEST.MF"); + if (!Files.exists(path)) return null; + + try (InputStream stream = Files.newInputStream(path)) { + return new Manifest(stream); + } + } + + public static class FileSystemDelegate implements AutoCloseable { + private final FileSystem fileSystem; + private final boolean owner; + + public FileSystemDelegate(FileSystem fileSystem, boolean owner) { + this.fileSystem = fileSystem; + this.owner = owner; + } + + public FileSystem get() { + return fileSystem; + } + + @Override + public void close() throws IOException { + if (owner) { + fileSystem.close(); + } + } + } + +} diff --git a/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/commands/CommandDefaultSettings.java b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/commands/CommandDefaultSettings.java new file mode 100644 index 00000000..2c5a74e6 --- /dev/null +++ b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/commands/CommandDefaultSettings.java @@ -0,0 +1,52 @@ +package net.jomcraft.defaultsettings.commands; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.tree.LiteralCommandNode; +import net.jomcraft.defaultsettings.CoreUtil; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraftforge.event.server.ServerStartingEvent; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +public class CommandDefaultSettings { + + public static void register(CommandDispatcher dispatcher) { + LiteralArgumentBuilder literalargumentbuilder = LiteralArgumentBuilder.literal("defaultsettings"); + + literalargumentbuilder.then(Commands.literal("save").executes((command) -> { + return saveProcess(command.getSource(), null, null); + }).then(Commands.argument("operation", OperationArguments.operationArguments(false)).executes((command) -> { + return saveProcess(command.getSource(), OperationArguments.getString(command, "operation"), null); + }).then(Commands.argument("type", TypeArguments.typeArguments()).executes((command) -> { + return saveProcess(command.getSource(), OperationArguments.getString(command, "operation"), TypeArguments.getString(command, "type")); + })))).then(Commands.literal("saveconfigs").executes((command) -> { + return saveProcessConfigs(command.getSource(), null, null); + }).then(Commands.argument("operation", OperationArguments.operationArguments(true)).executes((command) -> { + return saveProcessConfigs(command.getSource(), OperationArguments.getString(command, "operation"), null); + }).then(Commands.argument("config", ConfigArguments.configArguments()).executes((command) -> { + return saveProcessConfigs(command.getSource(), OperationArguments.getString(command, "operation"), ConfigArguments.getString(command, "config")); + })))); + + LiteralCommandNode node = dispatcher.register(literalargumentbuilder); + /*event.getServer().getCommands().getDispatcher()*/dispatcher.register(Commands.literal("ds").redirect(node)); + } + + private static int saveProcessConfigs(CommandSourceStack source, String argument, String argument2) throws CommandSyntaxException { + try { + return CoreUtil.saveProcessConfigs(source, argument, argument2); + } catch (Exception e) { + if (e instanceof CommandSyntaxException) throw (CommandSyntaxException) e; + return 0; + } + } + + private static int saveProcess(CommandSourceStack source, String argument, String argument2) throws CommandSyntaxException { + try { + return CoreUtil.saveProcess(source, argument, argument2); + } catch (Exception e) { + if (e instanceof CommandSyntaxException) throw (CommandSyntaxException) e; + return 0; + } + } +} \ No newline at end of file diff --git a/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/commands/ConfigArguments.java b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/commands/ConfigArguments.java new file mode 100644 index 00000000..a52b8d5f --- /dev/null +++ b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/commands/ConfigArguments.java @@ -0,0 +1,118 @@ +package net.jomcraft.defaultsettings.commands; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import com.google.gson.JsonObject; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.jomcraft.defaultsettings.DefaultSettings; +import net.jomcraft.jcplugin.FileUtilNoMC; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.network.FriendlyByteBuf; + +public class ConfigArguments implements ArgumentType { + + private static List ARGUMENTS = Arrays.asList("fml.toml", "forge-client.toml"); + + public static ConfigArguments configArguments() { + return new ConfigArguments(); + } + + @Override + public String parse(final StringReader reader) throws CommandSyntaxException { + return readQuotedString(reader); + } + + public String readQuotedString(final StringReader reader) throws CommandSyntaxException { + if (!reader.canRead()) { + return ""; + } + final char next = reader.getString().charAt(reader.getCursor()); + if (!reader.isQuotedStringStart(next)) { + + final int start = reader.getCursor(); + while (reader.canRead()) { + reader.skip(); + } + return reader.getString().substring(start, reader.getCursor()); + } + reader.skip(); + return reader.readStringUntil(next); + } + + public static String getString(final CommandContext context, final String name) { + return context.getArgument(name, String.class); + } + + @Override + public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) { + try { + ArrayList filtered = new ArrayList(); + ArrayList prevList = FileUtilNoMC.listConfigFiles(); + for(int i = 0; i < prevList.size(); i++){ + String name = prevList.get(i); + if(name.contains(" ")) + name = "\"" + name + "\""; + filtered.add(name); + } + ARGUMENTS = filtered; + } catch (IOException e) { + DefaultSettings.log.error(e); + } + return SharedSuggestionProvider.suggest(ARGUMENTS, builder); + } + + @Override + public Collection getExamples() { + return ARGUMENTS; + } + + public static class Info implements ArgumentTypeInfo { + @Override + public void serializeToNetwork(Template template, FriendlyByteBuf buffer) { + + } + + @Override + public Template deserializeFromNetwork(FriendlyByteBuf buffer) { + return new Template(); + } + + @Override + public void serializeToJson(Template template, JsonObject json) { + + } + + @Override + public Template unpack(ConfigArguments argument) { + return new Template(); + } + + public class Template implements ArgumentTypeInfo.Template { + + Template() { + + } + + @Override + public ConfigArguments instantiate(CommandBuildContext p_223435_) { + return new ConfigArguments(); + } + + @Override + public ArgumentTypeInfo type() { + return Info.this; + } + } + } +} \ No newline at end of file diff --git a/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/commands/OperationArguments.java b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/commands/OperationArguments.java new file mode 100644 index 00000000..bb9f85b1 --- /dev/null +++ b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/commands/OperationArguments.java @@ -0,0 +1,92 @@ +package net.jomcraft.defaultsettings.commands; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import com.google.gson.JsonObject; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.network.FriendlyByteBuf; + +public class OperationArguments implements ArgumentType { + + private static final List ARGUMENTS = Arrays.asList("override", "forceOverride"); + private static final List ARGUMENTS_LIMITED = Arrays.asList("forceOverride"); + private final boolean limited; + + public OperationArguments(boolean limited) { + this.limited = limited; + } + + public static OperationArguments operationArguments(boolean limited) { + return new OperationArguments(limited); + } + + @Override + public String parse(final StringReader reader) throws CommandSyntaxException { + return reader.readUnquotedString(); + } + + public static String getString(final CommandContext context, final String name) { + return context.getArgument(name, String.class); + } + + @Override + public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) { + return SharedSuggestionProvider.suggest(this.limited ? ARGUMENTS_LIMITED : ARGUMENTS, builder); + } + + @Override + public Collection getExamples() { + return ARGUMENTS; + } + + public static class Info implements ArgumentTypeInfo { + @Override + public void serializeToNetwork(Template template, FriendlyByteBuf buffer) { + buffer.writeBoolean(template.limited); + } + + @Override + public Template deserializeFromNetwork(FriendlyByteBuf buffer) { + boolean limited = buffer.readBoolean(); + return new Template(limited); + } + + @Override + public void serializeToJson(Template template, JsonObject json) { + json.addProperty("limited", template.limited); + } + + @Override + public Template unpack(OperationArguments argument) { + return new Template(argument.limited); + } + + public class Template implements ArgumentTypeInfo.Template { + final boolean limited; + + Template(boolean limited) { + this.limited = limited; + } + + @Override + public OperationArguments instantiate(CommandBuildContext p_223435_) { + return new OperationArguments(this.limited); + } + + @Override + public ArgumentTypeInfo type() { + return Info.this; + } + } + } +} \ No newline at end of file diff --git a/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/commands/TypeArguments.java b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/commands/TypeArguments.java new file mode 100644 index 00000000..8fa88263 --- /dev/null +++ b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/commands/TypeArguments.java @@ -0,0 +1,83 @@ +package net.jomcraft.defaultsettings.commands; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import com.google.gson.JsonObject; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.network.FriendlyByteBuf; + +public class TypeArguments implements ArgumentType { + + private static final List ARGUMENTS = Arrays.asList("options", "keybinds", "servers"); + + public static TypeArguments typeArguments() { + return new TypeArguments(); + } + + @Override + public String parse(final StringReader reader) throws CommandSyntaxException { + return reader.readUnquotedString(); + } + + public static String getString(final CommandContext context, final String name) { + return context.getArgument(name, String.class); + } + + @Override + public CompletableFuture listSuggestions(final CommandContext context, final SuggestionsBuilder builder) { + return SharedSuggestionProvider.suggest(ARGUMENTS, builder); + } + + @Override + public Collection getExamples() { + return ARGUMENTS; + } + + public static class Info implements ArgumentTypeInfo { + @Override + public void serializeToNetwork(Template template, FriendlyByteBuf buffer) { + + } + + @Override + public Template deserializeFromNetwork(FriendlyByteBuf buffer) { + return new Template(); + } + + @Override + public void serializeToJson(Template template, JsonObject json) { + } + + @Override + public Template unpack(TypeArguments argument) { + return new Template(); + } + + public class Template implements ArgumentTypeInfo.Template { + + Template() { + + } + + @Override + public TypeArguments instantiate(CommandBuildContext p_223435_) { + return new TypeArguments(); + } + + @Override + public ArgumentTypeInfo type() { + return Info.this; + } + } + } +} \ No newline at end of file diff --git a/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/mixin/MinecraftMixin.java b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/mixin/MinecraftMixin.java new file mode 100644 index 00000000..67d391cf --- /dev/null +++ b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/mixin/MinecraftMixin.java @@ -0,0 +1,15 @@ +package net.jomcraft.defaultsettings.mixin; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.Options; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(Minecraft.class) +public class MinecraftMixin { + @Redirect(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Options;save()V")) + private void redirected(Options instance) { + + } +} \ No newline at end of file diff --git a/sources/Forge-1.21.6/src/main/resources/META-INF/accesstransformer.cfg b/sources/Forge-1.21.6/src/main/resources/META-INF/accesstransformer.cfg new file mode 100644 index 00000000..584c6381 --- /dev/null +++ b/sources/Forge-1.21.6/src/main/resources/META-INF/accesstransformer.cfg @@ -0,0 +1 @@ +public-f net.minecraft.client.KeyMapping f_90814_ # defaultKey \ No newline at end of file diff --git a/sources/Forge-1.21.6/src/main/resources/META-INF/mods.toml b/sources/Forge-1.21.6/src/main/resources/META-INF/mods.toml new file mode 100644 index 00000000..75a64d47 --- /dev/null +++ b/sources/Forge-1.21.6/src/main/resources/META-INF/mods.toml @@ -0,0 +1,29 @@ +modLoader="javafml" +loaderVersion="[44,)" +logoFile="logo.png" +license="Apache License 2.0" + +[[mods]] + modId="defaultsettings" + version="${version}" + displayName="DefaultSettings" + description='''Keep your game's local settings in case of an update to your modpack''' + side="CLIENT" + authors="PT400C - Jomcraft Network" + credits="Developed by Jomcraft Network" + displayURL="https://www.curseforge.com/minecraft/mc-mods/defaultsettings" + displayTest="IGNORE_ALL_VERSION" + +[[dependencies.defaultsettings]] + modId="forge" + mandatory=true + versionRange="[44.1.0,)" + ordering="NONE" + side="CLIENT" + +[[dependencies.defaultsettings]] + modId="minecraft" + mandatory=true + versionRange="[1.19.3,)" + ordering="NONE" + side="CLIENT" \ No newline at end of file diff --git a/sources/Forge-1.21.6/src/main/resources/defaultsettings.mixin.json b/sources/Forge-1.21.6/src/main/resources/defaultsettings.mixin.json new file mode 100644 index 00000000..d6272800 --- /dev/null +++ b/sources/Forge-1.21.6/src/main/resources/defaultsettings.mixin.json @@ -0,0 +1,15 @@ +{ + "required": true, + "package": "net.jomcraft.defaultsettings.mixin", + "compatibilityLevel": "JAVA_21", + "refmap": "defaultsettings.refmap.json", + "mixins": [ + ], + "client": [ + "MinecraftMixin" + ], + "injectors": { + "defaultRequire": 1 + }, + "minVersion": "0.8" +} \ No newline at end of file diff --git a/sources/Forge-1.21.6/src/main/resources/logo.png b/sources/Forge-1.21.6/src/main/resources/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6f345514da0f0b162d7759a1c9d62d85b82a638e GIT binary patch literal 51342 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 n!ZX~V14{r4{eOLYa%>)6=DYpuB{JC%{UXv& keyRebinds = new HashMap(); public static boolean setUp = false; public static DefaultSettings instance; @@ -59,6 +59,14 @@ public DefaultSettings(IEventBus modEventBus) { NeoForgeCoreHook core = new NeoForgeCoreHook(); Core.setInstance(core); + try { + VERSION = getVersion(); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + if (FMLLoader.getDist().isClient()) { if (setUp) return; From a69ad1277a890a911eda22ac37513ba42824e83a Mon Sep 17 00:00:00 2001 From: PT400C Jomcraft Date: Sun, 5 Oct 2025 16:01:53 +0200 Subject: [PATCH 5/6] Cleanup code --- .../net/jomcraft/defaultsettings/DefaultSettings.java | 8 ++------ .../net/jomcraft/defaultsettings/DefaultSettings.java | 9 ++------- .../net/jomcraft/defaultsettings/DefaultSettings.java | 7 ++----- .../net/jomcraft/defaultsettings/DefaultSettings.java | 11 ++--------- 4 files changed, 8 insertions(+), 27 deletions(-) diff --git a/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java index b15c6472..57d79f10 100644 --- a/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java +++ b/sources/Forge-1.21.5/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java @@ -28,7 +28,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import net.jomcraft.jcplugin.FileUtilNoMC; -import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; @@ -53,7 +52,6 @@ public String getVersion() throws IOException, URISyntaxException { return attr.getValue("Implementation-Version"); } - @SuppressWarnings({"deprecation"}) public DefaultSettings(FMLJavaModLoadingContext context) { instance = this; ForgeCoreHook core = new ForgeCoreHook(); @@ -61,10 +59,8 @@ public DefaultSettings(FMLJavaModLoadingContext context) { try { VERSION = getVersion(); - } catch (IOException e) { - throw new RuntimeException(e); - } catch (URISyntaxException e) { - throw new RuntimeException(e); + } catch (IOException | URISyntaxException e) { + DefaultSettings.log.log(Level.ERROR, "DefaultSettings couldn't determine the mod's current version!"); } if (FMLEnvironment.dist.isClient()) { diff --git a/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java index 5a99f5d3..e80ad58c 100644 --- a/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java +++ b/sources/Forge-1.21.6/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java @@ -29,8 +29,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import net.jomcraft.jcplugin.FileUtilNoMC; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; @@ -54,7 +52,6 @@ public String getVersion() throws IOException, URISyntaxException { return attr.getValue("Implementation-Version"); } - @SuppressWarnings({"deprecation"}) public DefaultSettings(FMLJavaModLoadingContext context) { instance = this; ForgeCoreHook core = new ForgeCoreHook(); @@ -62,10 +59,8 @@ public DefaultSettings(FMLJavaModLoadingContext context) { try { VERSION = getVersion(); - } catch (IOException e) { - throw new RuntimeException(e); - } catch (URISyntaxException e) { - throw new RuntimeException(e); + } catch (IOException | URISyntaxException e) { + DefaultSettings.log.log(Level.ERROR, "DefaultSettings couldn't determine the mod's current version!"); } if (FMLEnvironment.dist.isClient()) { diff --git a/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java index 32a69e49..9c836de1 100644 --- a/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java +++ b/sources/NeoForge-1.21.5/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java @@ -53,7 +53,6 @@ public String getVersion() throws IOException, URISyntaxException { private static final DeferredRegister> COMMAND_ARGUMENT_TYPES = DeferredRegister.create(Registries.COMMAND_ARGUMENT_TYPE, DefaultSettings.MODID); - @SuppressWarnings({"deprecation"}) public DefaultSettings(IEventBus modEventBus) { instance = this; NeoForgeCoreHook core = new NeoForgeCoreHook(); @@ -61,10 +60,8 @@ public DefaultSettings(IEventBus modEventBus) { try { VERSION = getVersion(); - } catch (IOException e) { - throw new RuntimeException(e); - } catch (URISyntaxException e) { - throw new RuntimeException(e); + } catch (IOException | URISyntaxException e) { + DefaultSettings.log.log(Level.ERROR, "DefaultSettings couldn't determine the mod's current version!"); } if (FMLLoader.getDist().isClient()) { diff --git a/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java index d5cc4dc9..fbd7b8d2 100644 --- a/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java +++ b/sources/NeoForge-1.21.9/src/main/java/net/jomcraft/defaultsettings/DefaultSettings.java @@ -4,16 +4,12 @@ import java.lang.reflect.Field; import java.net.*; import java.nio.file.*; -import java.security.CodeSource; -import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.Manifest; import java.util.zip.ZipEntry; -import java.util.zip.ZipError; - import net.jomcraft.defaultsettings.commands.ConfigArguments; import net.jomcraft.defaultsettings.commands.OperationArguments; import net.jomcraft.defaultsettings.commands.TypeArguments; @@ -52,7 +48,6 @@ public String getVersion() throws IOException, URISyntaxException { private static final DeferredRegister> COMMAND_ARGUMENT_TYPES = DeferredRegister.create(Registries.COMMAND_ARGUMENT_TYPE, DefaultSettings.MODID); - @SuppressWarnings({"deprecation"}) public DefaultSettings(IEventBus modEventBus) { instance = this; NeoForgeCoreHook core = new NeoForgeCoreHook(); @@ -60,10 +55,8 @@ public DefaultSettings(IEventBus modEventBus) { try { VERSION = getVersion(); - } catch (IOException e) { - throw new RuntimeException(e); - } catch (URISyntaxException e) { - throw new RuntimeException(e); + } catch (IOException | URISyntaxException e) { + DefaultSettings.log.log(Level.ERROR, "DefaultSettings couldn't determine the mod's current version!"); } if (FMLLoader.getCurrent().getDist().isClient()) { From 3b9afb0d22c7e4e8e64032e96a8edb1a3c0592ba Mon Sep 17 00:00:00 2001 From: PT400C Jomcraft Date: Sun, 5 Oct 2025 17:05:43 +0200 Subject: [PATCH 6/6] Fix fabric loom --- build.gradle | 4 ++++ sources/Fabric-1.20/build.gradle | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d4c04d52..ce1ca572 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,7 @@ +plugins { + id 'fabric-loom' version '1.11-SNAPSHOT' apply false +} + apply plugin: "idea" def jcpluginVersion = "4.0.4" diff --git a/sources/Fabric-1.20/build.gradle b/sources/Fabric-1.20/build.gradle index afd0ba9e..4695645e 100644 --- a/sources/Fabric-1.20/build.gradle +++ b/sources/Fabric-1.20/build.gradle @@ -1,5 +1,5 @@ plugins { - id "fabric-loom" version "1.0-SNAPSHOT" + id "fabric-loom" version "1.11-SNAPSHOT" id 'net.darkhax.curseforgegradle' version '1.1.18' }