From 15e52332e5932a622a0ac7beeb01df4ddf35506a Mon Sep 17 00:00:00 2001 From: Moritz Ruth Date: Fri, 19 Aug 2022 17:40:02 +0200 Subject: [PATCH] Initial commit --- .editorconfig | 7 + .gitignore | 4 + LICENSE | 21 ++ README.md | 37 ++++ build.gradle.kts | 58 ++++++ gradle.properties | 5 + gradle/wrapper/gradle-wrapper.properties | 1 + gradlew | 185 ++++++++++++++++++ gradlew.bat | 89 +++++++++ logo.png | Bin 0 -> 5908 bytes settings.gradle.kts | 9 + .../onetimeoverrides/OneTimeOverrides.kt | 68 +++++++ .../assets/one-time-overrides/icon.png | Bin 0 -> 23924 bytes src/main/resources/fabric.mod.json | 29 +++ 14 files changed, 513 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 build.gradle.kts create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 logo.png create mode 100644 settings.gradle.kts create mode 100644 src/main/kotlin/xyz/horizr/onetimeoverrides/OneTimeOverrides.kt create mode 100644 src/main/resources/assets/one-time-overrides/icon.png create mode 100644 src/main/resources/fabric.mod.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..38906a2 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,7 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +trim_trailing_whitespace = true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..685a759 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/.idea/ +/run/ +/build/ +/.gradle/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c35f8c7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 The horizr contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3b9e403 --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +

+ +

+ +

+ + + +

+ +

+ A Fabric mod allowing modpack authors to add non-overwriting override files. +

+ +# OneTimeOverrides +Some override files, such as `options.txt`, should only be copied the first time a player plays a modpack. +Otherwise, their changes would be lost every time the modpack is updated. + +This mod allows modpack authors to place files in the `one-time-overrides` directory +that will only be copied to their intended destination if the target file does not exist. + +Example: +``` +.minecraft +├── config +│ └── first_mod.toml +└── one-time-overrides + │ └── config + │ └── first_mod.toml # already exists in .minecraft/config -> will not be copied + └── options.txt # does not exist in .minecraft -> will be copied +``` + +As it does not use any Minecraft-specific APIs, the mod should work with any version of the game. +`1.18.2` and `1.19.2` were tested. + +The only dependency is [fabric-language-kotlin](https://github.com/FabricMC/fabric-language-kotlin). +[Fabric API](https://github.com/FabricMC/fabric) is not required. diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..c2fd299 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,58 @@ +plugins { + val kotlinVersion: String by System.getProperties() + + java + kotlin("jvm") version kotlinVersion + id("fabric-loom") version "0.12.+" +} + +group = "xyz.horizr.onetimeoverrides" +version = "1.0.0" + +repositories { + mavenCentral() +} + +val kotlinVersion: String by System.getProperties() +val fabricLoaderVersion = "0.14.9" +val fabricLanguageKotlinVersion = "1.8.2+kotlin.$kotlinVersion" + +dependencies { + minecraft("com.mojang:minecraft:1.18.2") + mappings("net.fabricmc:yarn:1.18.2+build.4:v2") + modImplementation("net.fabricmc:fabric-loader:$fabricLoaderVersion") + modImplementation("net.fabricmc:fabric-language-kotlin:$fabricLanguageKotlinVersion") + + include("io.github.microutils:kotlin-logging-jvm:2.1.23") + implementation("io.github.microutils:kotlin-logging-jvm:2.1.23") +} + +kotlin { + jvmToolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +tasks { + processResources { + inputs.property("version", project.version) + + filesMatching("fabric.mod.json") { + expand( + mutableMapOf( + "version" to project.version, + "fabricLoaderVersion" to fabricLoaderVersion, + "fabricLanguageKotlinVersion" to fabricLanguageKotlinVersion + ) + ) + } + } + + remapJar { + addNestedDependencies.set(true) + } +} + +loom { + runtimeOnlyLog4j.set(true) +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..7aa6bb1 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,5 @@ +org.gradle.jvmargs=-Xmx2G +kotlin.code.style=official + +# has to be a system prop because it is accessed in the plugins block +systemProp.kotlinVersion=1.7.10 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..73bb918 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..744e882 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MSYS* | MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/logo.png b/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..12aa42d37d6bd19c5e2ac460a9053c4afe152b8a GIT binary patch literal 5908 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 S?1BHL0svG&L%vkjEc8EEXIta| literal 0 HcmV?d00001 diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..bd520ae --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,9 @@ +pluginManagement { + repositories { + mavenCentral() + gradlePluginPortal() + maven("https://maven.fabricmc.net") + } +} + +rootProject.name = "one-time-overrides" diff --git a/src/main/kotlin/xyz/horizr/onetimeoverrides/OneTimeOverrides.kt b/src/main/kotlin/xyz/horizr/onetimeoverrides/OneTimeOverrides.kt new file mode 100644 index 0000000..d0eb523 --- /dev/null +++ b/src/main/kotlin/xyz/horizr/onetimeoverrides/OneTimeOverrides.kt @@ -0,0 +1,68 @@ +package xyz.horizr.onetimeoverrides + +import kotlinx.atomicfu.atomic +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import mu.KotlinLogging +import net.fabricmc.loader.api.FabricLoader +import java.nio.file.FileAlreadyExistsException +import java.nio.file.LinkOption +import java.nio.file.Path +import kotlin.io.path.* + +val fabricLoader: FabricLoader = FabricLoader.getInstance() + +fun Path.getPathsRecursively(relativeTo: Path = this): Set { + return buildSet { + for (path in listDirectoryEntries()) { + if (path.isRegularFile(LinkOption.NOFOLLOW_LINKS)) add(path.relativeTo(relativeTo)) + else if (path.isDirectory(LinkOption.NOFOLLOW_LINKS)) addAll(path.getPathsRecursively(relativeTo)) + } + } +} + +const val OVERRIDES_DIRECTORY_NAME = "one-time-overrides" + +@Suppress("unused") +fun init() { + val logger = KotlinLogging.logger("OneTimeOverrides") + + val oneTimeOverridesDirectory = fabricLoader.gameDir.resolve(OVERRIDES_DIRECTORY_NAME) + if (!oneTimeOverridesDirectory.isDirectory()) { + logger.warn("$OVERRIDES_DIRECTORY_NAME directory does not exist.") + return + } + + val allOverrides = oneTimeOverridesDirectory.getPathsRecursively() + if (allOverrides.isEmpty()) { + logger.warn("$OVERRIDES_DIRECTORY_NAME directory does not contain any overrides.") + return + } + + fun copyOverrideFile(relativePath: Path): Boolean = try { + val outputPath = fabricLoader.gameDir.resolve(relativePath) + outputPath.parent.createDirectories() + oneTimeOverridesDirectory.resolve(relativePath).copyTo(outputPath, false) + true + } catch (e: FileAlreadyExistsException) { + false + } + + var newCount by atomic(0) + + runBlocking(Dispatchers.IO) { + for (relativePath in allOverrides) { + launch { + val wasNew = copyOverrideFile(relativePath) + + if (wasNew) { + logger.debug("Copied new override: $relativePath") + newCount++ + } + } + } + } + + logger.info("Copied $newCount new override(s).") +} diff --git a/src/main/resources/assets/one-time-overrides/icon.png b/src/main/resources/assets/one-time-overrides/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4f9592586b5441135bf62f2fcdeeb35d3230c479 GIT binary patch literal 23924 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 #Xv? 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