diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c37caf --- /dev/null +++ b/.gitignore @@ -0,0 +1,118 @@ +# User-specific stuff +.idea/ + +*.iml +*.ipr +*.iws + +# IntelliJ +out/ +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +.gradle +build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Cache of project +.gradletasknamecache + +**/build/ + +# Common working directory +run/ + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..79dcb37 --- /dev/null +++ b/build.gradle @@ -0,0 +1,186 @@ +buildscript { + repositories { + // These repositories are only for Gradle plugins, put any other repositories in the repository block further below + maven { url = 'https://repo.spongepowered.org/repository/maven-public/' } + mavenCentral() + } + dependencies { + classpath 'org.spongepowered:mixingradle:0.7-SNAPSHOT' + } +} + +plugins { + id 'net.minecraftforge.gradle' version '5.1.+' +} + +apply plugin: 'org.spongepowered.mixin' + +group = 'xyz.nuark' +version = '1.0.0' + +java { + archivesBaseName = 'predench' + toolchain.languageVersion = JavaLanguageVersion.of(17) +} + +minecraft { + // The mappings can be changed at any time and must be in the following format. + // Channel: Version: + // official MCVersion Official field/method names from Mojang mapping files + // parchment YYYY.MM.DD-MCVersion Open community-sourced parameter names and javadocs layered on top of official + // + // You must be aware of the Mojang license when using the 'official' or 'parchment' mappings. + // See more information here: https://github.com/MinecraftForge/MCPConfig/blob/master/Mojang.md + // + // Parchment is an unofficial project maintained by ParchmentMC, separate from MinecraftForge + // Additional setup is needed to use their mappings: https://github.com/ParchmentMC/Parchment/wiki/Getting-Started + // + // Use non-default mappings at your own risk. They may not always work. + // Simply re-run your setup task after changing the mappings to update your workspace. + mappings channel: 'official', version: '1.18.2' + + // accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') + + // Default run configurations. + // These can be tweaked, removed, or duplicated as needed. + runs { + client { + workingDirectory project.file('run') + + // Recommended logging data for a userdev environment + // The markers can be added/remove as needed separated by commas. + // "SCAN": For mods scan. + // "REGISTRIES": For firing of registry events. + // "REGISTRYDUMP": For getting the contents of all registries. + property 'forge.logging.markers', 'REGISTRIES' + + + // Recommended logging level for the console + // You can set various levels here. + // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels + property 'forge.logging.console.level', 'debug' + + // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. + property 'forge.enabledGameTestNamespaces', 'predench' + + mods { + predench { + source sourceSets.main + } + } + } + + server { + workingDirectory project.file('run') + + property 'forge.logging.markers', 'REGISTRIES' + + property 'forge.logging.console.level', 'debug' + + property 'forge.enabledGameTestNamespaces', 'predench' + + mods { + predench { + source sourceSets.main + } + } + } + + // This run config launches GameTestServer and runs all registered gametests, then exits. + // By default, the server will crash when no gametests are provided. + // The gametest system is also enabled by default for other run configs under the /test command. + gameTestServer { + workingDirectory project.file('run') + + property 'forge.logging.markers', 'REGISTRIES' + + property 'forge.logging.console.level', 'debug' + + property 'forge.enabledGameTestNamespaces', 'predench' + + mods { + predench { + source sourceSets.main + } + } + } + + data { + workingDirectory project.file('run') + + property 'forge.logging.markers', 'REGISTRIES' + + property 'forge.logging.console.level', 'debug' + + // Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources. + args '--mod', 'predench', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') + + mods { + predench { + source sourceSets.main + } + } + } + } +} + +mixin { + add sourceSets.main, "predench.refmap.json" + + config "predench.mixins.json" +} + +// Include resources generated by data generators. +sourceSets.main.resources { srcDir 'src/generated/resources' } + +repositories { + // Put repositories for dependencies here + // ForgeGradle automatically adds the Forge maven and Maven Central for you + + // If you have mod jar dependencies in ./libs, you can declare them as a repository like so: + // flatDir { + // dir 'libs' + // } +} + +dependencies { + // Specify the version of Minecraft to use. If this is any group other than 'net.minecraft' it is assumed + // that the dep is a ForgeGradle 'patcher' dependency, and its patches will be applied. + // The userdev artifact is a special name and will get all sorts of transformations applied to it. + minecraft 'net.minecraftforge:forge:1.18.2-40.1.68' + + // Real mod deobf dependency examples - these get remapped to your current mappings + // compileOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}:api") // Adds JEI API as a compile dependency + // runtimeOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}") // Adds the full JEI mod as a runtime dependency + // implementation fg.deobf("com.tterrag.registrate:Registrate:MC${mc_version}-${registrate_version}") // Adds registrate as a dependency + + // Examples using mod jars from ./libs + // implementation fg.deobf("blank:coolmod-${mc_version}:${coolmod_version}") + + // For more info... + // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html + // http://www.gradle.org/docs/current/userguide/dependency_management.html + + annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' +} + +// Example for how to get properties into the manifest for reading at runtime. +jar { + manifest { + attributes([ + "Specification-Title" : "predench", + "Specification-Vendor" : "nuark", + "Specification-Version" : "1", // We are version 1 of ourselves + "Implementation-Title" : project.name, + "Implementation-Version" : project.jar.archiveVersion, + "Implementation-Vendor" : "nuark", + "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") + ]) + } +} + +jar.finalizedBy('reobfJar') + +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..29b2ac4 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,2 @@ +org.gradle.jvmargs=-Xmx3G +org.gradle.daemon=false diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..41d9927 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..aa991fc --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..1b6c787 --- /dev/null +++ b/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original 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 POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${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 "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# 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" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +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/icon.png b/icon.png new file mode 100644 index 0000000..66f5283 Binary files /dev/null and b/icon.png differ diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..cbb9996 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,8 @@ +pluginManagement { + repositories { + gradlePluginPortal() + maven { url = 'https://maven.minecraftforge.net/' } + } +} + +rootProject.name = 'predench' diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache new file mode 100644 index 0000000..9427cbd --- /dev/null +++ b/src/generated/resources/.cache/cache @@ -0,0 +1,4 @@ +b388f2daddf0d0c8bf442a294899b42da789c7c5 data/predench/advancements/recipes/predench/strange_writing_book.json +9743ab5fcdf849f71bda79573eaba034390f0996 data/predench/advancements/recipes/predench/vitriolic_feather.json +5ae3494cda14b080932ba55e3617137474dcce89 data/predench/recipes/strange_writing_book.json +e7496726b3f82b79d7aca49fe3cf9a375825e858 data/predench/recipes/vitriolic_feather.json diff --git a/src/generated/resources/data/predench/advancements/recipes/predench/strange_writing_book.json b/src/generated/resources/data/predench/advancements/recipes/predench/strange_writing_book.json new file mode 100644 index 0000000..fd25f46 --- /dev/null +++ b/src/generated/resources/data/predench/advancements/recipes/predench/strange_writing_book.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "predench:strange_writing_book" + ] + }, + "criteria": { + "has_vitriolic_feather": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "predench:vitriolic_feather" + ] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "predench:strange_writing_book" + } + } + }, + "requirements": [ + [ + "has_vitriolic_feather", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/predench/advancements/recipes/predench/vitriolic_feather.json b/src/generated/resources/data/predench/advancements/recipes/predench/vitriolic_feather.json new file mode 100644 index 0000000..9618c96 --- /dev/null +++ b/src/generated/resources/data/predench/advancements/recipes/predench/vitriolic_feather.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "predench:vitriolic_feather" + ] + }, + "criteria": { + "has_copper": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:ingots/copper" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "predench:vitriolic_feather" + } + } + }, + "requirements": [ + [ + "has_copper", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/predench/recipes/strange_writing_book.json b/src/generated/resources/data/predench/recipes/strange_writing_book.json new file mode 100644 index 0000000..994a53c --- /dev/null +++ b/src/generated/resources/data/predench/recipes/strange_writing_book.json @@ -0,0 +1,17 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "item": "predench:vitriolic_feather" + }, + { + "item": "minecraft:book" + }, + { + "item": "minecraft:glow_ink_sac" + } + ], + "result": { + "item": "predench:strange_writing_book" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/predench/recipes/vitriolic_feather.json b/src/generated/resources/data/predench/recipes/vitriolic_feather.json new file mode 100644 index 0000000..3b5f12d --- /dev/null +++ b/src/generated/resources/data/predench/recipes/vitriolic_feather.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + " C ", + "CFC", + " C " + ], + "key": { + "C": { + "item": "minecraft:copper_block" + }, + "F": { + "tag": "forge:feathers" + } + }, + "result": { + "item": "predench:vitriolic_feather" + } +} \ No newline at end of file diff --git a/src/main/java/xyz/nuark/predench/EnchantmentData.java b/src/main/java/xyz/nuark/predench/EnchantmentData.java new file mode 100644 index 0000000..773db49 --- /dev/null +++ b/src/main/java/xyz/nuark/predench/EnchantmentData.java @@ -0,0 +1,63 @@ +package xyz.nuark.predench; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.mojang.datafixers.types.templates.CompoundList; +import com.mojang.datafixers.types.templates.TypeTemplate; +import net.minecraft.nbt.*; +import net.minecraft.util.StringUtil; +import org.apache.commons.lang3.StringUtils; + +import java.io.DataOutput; +import java.io.IOException; +import java.util.LinkedList; + +public class EnchantmentData { + private final LinkedList> tiers; + + public EnchantmentData() { + this.tiers = new LinkedList<>(); + tiers.add(new LinkedList<>()); + tiers.add(new LinkedList<>()); + tiers.add(new LinkedList<>()); + } + + public void addToTier(int tier, Enchantment enchantment) { + tiers.get(tier).add(enchantment); + } + + public LinkedList getTier(int tier) { + return tiers.get(tier); + } + + public ListTag convertToBookPages() { + String[] pages = {"", "", ""}; + + for (int i = 0; i < 3; i++) { + if (tiers.get(i).isEmpty()) { + pages[i] += "Tier " + (i + 1) + "\n"; + pages[i] += "======\n"; + pages[i] += "No enchantments"; + } else { + pages[i] += "Tier " + (i + 1) + " at " + tiers.get(i).get(0).cost + "\n"; + pages[i] += "======\n"; + for (Enchantment enchantment : tiers.get(i)) { + pages[i] += enchantment.name + "\n"; + } + } + } + + ListTag list = new ListTag(); + + for (int i = 0; i < 3; i++) { + JsonObject json = new JsonObject(); + json.addProperty("text", pages[i]); + list.add(StringTag.valueOf(json.toString())); + } + + return list; + } + + public record Enchantment(String name, int level, int cost) { + } +} diff --git a/src/main/java/xyz/nuark/predench/Predench.java b/src/main/java/xyz/nuark/predench/Predench.java new file mode 100644 index 0000000..b2ed45b --- /dev/null +++ b/src/main/java/xyz/nuark/predench/Predench.java @@ -0,0 +1,38 @@ +package xyz.nuark.predench; + +import com.mojang.logging.LogUtils; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Rarity; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegistryObject; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; + +@Mod(Predench.MOD_ID) +public class Predench { + public static final String MOD_ID = "predench"; + public static final Logger LOGGER = LogUtils.getLogger(); + + // Really necessary to create item group for two items :) + public static final CreativeModeTab ITEM_GROUP = new CreativeModeTab("predench") { + @Override + public @NotNull ItemStack makeIcon() { + return new ItemStack(VITRIOLIC_FEATHER_ITEM.get()); + } + }; + + // Only two items, no need to create holder class + private static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, Predench.MOD_ID); + public static final RegistryObject VITRIOLIC_FEATHER_ITEM = ITEMS.register("vitriolic_feather", () -> new Item(new Item.Properties().tab(Predench.ITEM_GROUP).stacksTo(16).fireResistant().rarity(Rarity.RARE))); + public static final RegistryObject STRANGE_WRITING_BOOK_ITEM = ITEMS.register("strange_writing_book", () -> new Item(new Item.Properties().tab(Predench.ITEM_GROUP).stacksTo(1).fireResistant().rarity(Rarity.EPIC))); + + public Predench() { + ITEMS.register(FMLJavaModLoadingContext.get().getModEventBus()); + } +} diff --git a/src/main/java/xyz/nuark/predench/PredenchEnchantmentDataExtractor.java b/src/main/java/xyz/nuark/predench/PredenchEnchantmentDataExtractor.java new file mode 100644 index 0000000..8b9243f --- /dev/null +++ b/src/main/java/xyz/nuark/predench/PredenchEnchantmentDataExtractor.java @@ -0,0 +1,11 @@ +package xyz.nuark.predench; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; + +import java.util.Optional; + +public interface PredenchEnchantmentDataExtractor { + Optional getEnchantmentData(Level level, BlockPos tablePos, ItemStack itemstack); +} diff --git a/src/main/java/xyz/nuark/predench/PredenchSeedUpdater.java b/src/main/java/xyz/nuark/predench/PredenchSeedUpdater.java new file mode 100644 index 0000000..06e84ba --- /dev/null +++ b/src/main/java/xyz/nuark/predench/PredenchSeedUpdater.java @@ -0,0 +1,9 @@ +package xyz.nuark.predench; + +import net.minecraft.world.entity.player.Player; + +import java.util.OptionalInt; + +public interface PredenchSeedUpdater { + OptionalInt updatePlayerEnchantmentSeed(Player player); +} diff --git a/src/main/java/xyz/nuark/predench/datagen/DataGenerator.java b/src/main/java/xyz/nuark/predench/datagen/DataGenerator.java new file mode 100644 index 0000000..bb7d762 --- /dev/null +++ b/src/main/java/xyz/nuark/predench/datagen/DataGenerator.java @@ -0,0 +1,17 @@ +package xyz.nuark.predench.datagen; + +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.forge.event.lifecycle.GatherDataEvent; +import xyz.nuark.predench.Predench; + +@Mod.EventBusSubscriber(modid = Predench.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) +public class DataGenerator { + @SubscribeEvent + public static void gatherData(GatherDataEvent event) { + if (event.includeServer()) { + Predench.LOGGER.info("Generating recipes data"); + event.getGenerator().addProvider(new RecipeGenerator(event.getGenerator())); + } + } +} diff --git a/src/main/java/xyz/nuark/predench/datagen/RecipeGenerator.java b/src/main/java/xyz/nuark/predench/datagen/RecipeGenerator.java new file mode 100644 index 0000000..fe7ac39 --- /dev/null +++ b/src/main/java/xyz/nuark/predench/datagen/RecipeGenerator.java @@ -0,0 +1,38 @@ +package xyz.nuark.predench.datagen; + +import net.minecraft.data.DataGenerator; +import net.minecraft.data.recipes.FinishedRecipe; +import net.minecraft.data.recipes.RecipeProvider; +import net.minecraft.data.recipes.ShapedRecipeBuilder; +import net.minecraft.data.recipes.ShapelessRecipeBuilder; +import net.minecraft.world.item.Items; +import net.minecraftforge.common.Tags; +import org.jetbrains.annotations.NotNull; +import xyz.nuark.predench.Predench; + +import java.util.function.Consumer; + +public class RecipeGenerator extends RecipeProvider { + public RecipeGenerator(DataGenerator generator) { + super(generator); + } + + @Override + protected void buildCraftingRecipes(@NotNull Consumer consumer) { + ShapedRecipeBuilder.shaped(Predench.VITRIOLIC_FEATHER_ITEM.get()) + .define('C', Items.COPPER_BLOCK) + .define('F', Tags.Items.FEATHERS) + .pattern(" C ") + .pattern("CFC") + .pattern(" C ") + .unlockedBy("has_copper", has(Tags.Items.INGOTS_COPPER)) + .save(consumer); + + ShapelessRecipeBuilder.shapeless(Predench.STRANGE_WRITING_BOOK_ITEM.get()) + .requires(Predench.VITRIOLIC_FEATHER_ITEM.get()) + .requires(Items.BOOK) + .requires(Items.GLOW_INK_SAC) + .unlockedBy("has_vitriolic_feather", has(Predench.VITRIOLIC_FEATHER_ITEM.get())) + .save(consumer); + } +} diff --git a/src/main/java/xyz/nuark/predench/mixin/MixinEnchantmentMenu.java b/src/main/java/xyz/nuark/predench/mixin/MixinEnchantmentMenu.java new file mode 100644 index 0000000..a7c67d0 --- /dev/null +++ b/src/main/java/xyz/nuark/predench/mixin/MixinEnchantmentMenu.java @@ -0,0 +1,96 @@ +package xyz.nuark.predench.mixin; + +import com.google.gson.Gson; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.DataSlot; +import net.minecraft.world.inventory.EnchantmentMenu; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.item.enchantment.EnchantmentInstance; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.EnchantmentTableBlock; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import xyz.nuark.predench.EnchantmentData; +import xyz.nuark.predench.Predench; +import xyz.nuark.predench.PredenchEnchantmentDataExtractor; +import xyz.nuark.predench.PredenchSeedUpdater; + +import java.util.List; +import java.util.Optional; +import java.util.OptionalInt; +import java.util.Random; + +@Mixin(EnchantmentMenu.class) +public abstract class MixinEnchantmentMenu implements PredenchSeedUpdater, PredenchEnchantmentDataExtractor { + @Shadow protected abstract List getEnchantmentList(ItemStack p_39472_, int p_39473_, int p_39474_); + + public OptionalInt updatePlayerEnchantmentSeed(Player player) { + try { + player.onEnchantmentPerformed(null, 0); + int seed = player.getEnchantmentSeed(); + enchantmentSeed.set(seed); + return OptionalInt.of(seed); + } catch (Exception e) { + Predench.LOGGER.error("Failed to update enchantment seed for player " + player.getName().getString(), e); + } + return OptionalInt.empty(); + } + + @Override + public Optional getEnchantmentData(Level level, BlockPos tablePos, ItemStack itemstack) { + try { + int[] costs = new int[3]; + float j = 0; + + for(BlockPos blockpos : EnchantmentTableBlock.BOOKSHELF_OFFSETS) { + if (EnchantmentTableBlock.isValidBookShelf(level, tablePos, blockpos)) { + j += level.getBlockState(tablePos.offset(blockpos)).getEnchantPowerBonus(level, tablePos.offset(blockpos)); + } + } + + Random random = new Random(); + random.setSeed(this.enchantmentSeed.get()); + + for(int k = 0; k < 3; ++k) { + costs[k] = EnchantmentHelper.getEnchantmentCost(random, k, (int)j, itemstack); + if (costs[k] < k + 1) { + costs[k] = 0; + } + costs[k] = net.minecraftforge.event.ForgeEventFactory.onEnchantmentLevelSet(level, tablePos, k, (int)j, itemstack, costs[k]); + } + + EnchantmentData enchantmentData = new EnchantmentData(); + + for(int l = 0; l < 3; ++l) { + if (costs[l] > 0) { + List list = this.getEnchantmentList(itemstack, l, costs[l]); + if (list != null && !list.isEmpty()) { + for (EnchantmentInstance enchantmentInstance : list) { + enchantmentData.addToTier(l, new EnchantmentData.Enchantment( + enchantmentInstance.enchantment.getFullname(enchantmentInstance.level).getString(), + enchantmentInstance.level, + costs[l] + )); + } + } + } + } + + Predench.LOGGER.info("Enchantment data: " + new Gson().toJson(enchantmentData)); + + return Optional.of(enchantmentData); + } catch (Exception e) { + Predench.LOGGER.error("Failed to get enchantment data for itemstack " + itemstack.toString(), e); + } + + return Optional.empty(); + } + + @Final + @Shadow + private final DataSlot enchantmentSeed = DataSlot.standalone(); +} + diff --git a/src/main/java/xyz/nuark/predench/mixin/MixinEnchantmentTableBlock.java b/src/main/java/xyz/nuark/predench/mixin/MixinEnchantmentTableBlock.java new file mode 100644 index 0000000..c7f8f30 --- /dev/null +++ b/src/main/java/xyz/nuark/predench/mixin/MixinEnchantmentTableBlock.java @@ -0,0 +1,99 @@ +package xyz.nuark.predench.mixin; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.util.StringUtil; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.*; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.EnchantmentTableBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraftforge.common.Tags; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import xyz.nuark.predench.EnchantmentData; +import xyz.nuark.predench.Predench; +import xyz.nuark.predench.PredenchEnchantmentDataExtractor; +import xyz.nuark.predench.PredenchSeedUpdater; + +import java.util.Optional; +import java.util.OptionalInt; + +@Mixin(EnchantmentTableBlock.class) +public class MixinEnchantmentTableBlock { + @Inject(method = "use", at = @At("HEAD"), cancellable = true) + private void use(BlockState blockState, Level level, BlockPos blockPos, Player player, InteractionHand interactionHand, BlockHitResult blockHitResult, CallbackInfoReturnable cir) { + Predench.LOGGER.info("EnchantmentTableBlock use finished, injecting our code..."); + if (!level.isClientSide) { + cir.cancel(); + ItemStack main = player.getMainHandItem(); + ItemStack off = player.getOffhandItem(); + Predench.LOGGER.info("Main hand: " + main); + Predench.LOGGER.info("Offhand: " + off); + + OptionalInt optionalInt = player.openMenu(blockState.getMenuProvider(level, blockPos)); + if (optionalInt.isPresent() && player.containerMenu.getType() == MenuType.ENCHANTMENT) { + if (main.is(Items.SPONGE) && off.is(Items.WATER_BUCKET)) { + if (main.getCount() > 1) { + player.displayClientMessage(new TextComponent("You should have exactly one sponge in your hand."), true); + } else { + updatePlayerEnchantmentSeed(player); + } + } else if (main.is(Predench.STRANGE_WRITING_BOOK_ITEM.get()) && off.getItem().isEnchantable(off)) { + writeBookWithEnchantmentsData(level, blockPos, player, off); + } + } + + cir.setReturnValue(InteractionResult.CONSUME); + } + } + + private void updatePlayerEnchantmentSeed(Player player) { + if (player.experienceLevel < 3) { + player.displayClientMessage(new TextComponent("You need at least 3 levels to use this."), true); + } else { + OptionalInt newSeed = ((PredenchSeedUpdater) player.containerMenu).updatePlayerEnchantmentSeed(player); + if (newSeed.isPresent()) { + player.displayClientMessage(new TextComponent("New enchantment seed: " + newSeed.getAsInt()), true); + player.giveExperienceLevels(-3); + player.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(Items.WET_SPONGE)); + player.setItemSlot(EquipmentSlot.OFFHAND, new ItemStack(Items.BUCKET)); + } else { + player.displayClientMessage(new TextComponent("Failed to update enchantment seed."), true); + } + } + player.closeContainer(); + } + + private void writeBookWithEnchantmentsData(Level level, BlockPos blockPos, Player player, ItemStack off) { + if (player.experienceLevel < 3) { + player.displayClientMessage(new TextComponent("You need at least 3 levels to use this."), true); + } else { + ItemStack enchantmentInfoBook = new ItemStack(Items.WRITTEN_BOOK); + Optional data = ((PredenchEnchantmentDataExtractor) player.containerMenu).getEnchantmentData(level, blockPos, off); + if (data.isPresent()) { + CompoundTag nbt = enchantmentInfoBook.getOrCreateTag(); + nbt.putString("title", "Predench report"); + nbt.putString("author", "nuark"); + nbt.put("pages", data.get().convertToBookPages()); + player.setItemSlot(EquipmentSlot.MAINHAND, enchantmentInfoBook); + player.giveExperienceLevels(-10); + } else { + player.displayClientMessage(new TextComponent("Couldn't retrieve enchantment data."), true); + } + } + player.closeContainer(); + } +} diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..216894a --- /dev/null +++ b/src/main/resources/META-INF/mods.toml @@ -0,0 +1,58 @@ +# This is an example mods.toml file. It contains the data relating to the loading mods. +# There are several mandatory fields (#mandatory), and many more that are optional (#optional). +# The overall format is standard TOML format, v0.5.0. +# Note that there are a couple of TOML lists in this file. +# Find more information on toml format here: https://github.com/toml-lang/toml +# The name of the mod loader type to load - for regular FML @Mod mods it should be javafml +modLoader = "javafml" #mandatory +# A version range to match for said mod loader - for regular FML @Mod it will be the forge version +loaderVersion = "[40,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions. +# The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties. +# Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here. +license = "MIT" +# A URL to refer people to when problems occur with this mod +#issueTrackerURL="http://my.issue.tracker/" #optional +# A list of mods - how many allowed here is determined by the individual mod loader +[[mods]] #mandatory +# The modid of the mod +modId = "predench" #mandatory +# The version number of the mod - there's a few well known ${} variables useable here or just hardcode it +# ${file.jarVersion} will substitute the value of the Implementation-Version as read from the mod's JAR file metadata +# see the associated build.gradle script for how to populate this completely automatically during a build +version = "1.0.0" #mandatory +# A display name for the mod +displayName = "Predench" #mandatory +# A URL to query for updates for this mod. See the JSON update specification +#updateJSONURL="http://myurl.me/" #optional +# A URL for the "homepage" for this mod, displayed in the mod UI +#displayURL="http://example.com/" #optional +# A file name (in the root of the mod JAR) containing a logo for display +#logoFile="predench.png" #optional +# A text field displayed in the mod UI +#credits="Thanks for this example mod goes to Java" #optional +# A text field displayed in the mod UI +authors = "nuark" #optional +# The description text for the mod (multi line!) (#mandatory) +description = ''' +Predench - predictable enchantments and re-rolls for enchanting table +''' +# A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional. +[[dependencies.predench]] #optional +# the modid of the dependency +modId = "forge" #mandatory +# Does this dependency have to exist - if not, ordering below must be specified +mandatory = true #mandatory +# The version range of the dependency +versionRange = "[40,)" #mandatory +# An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory +ordering = "NONE" +# Side this dependency is applied on - BOTH, CLIENT or SERVER +side = "BOTH" +# Here's another dependency +[[dependencies.predench]] +modId = "minecraft" +mandatory = true +# This version range declares a minimum of the current minecraft version up to but not including the next major version +versionRange = "[1.18.2,1.19)" +ordering = "NONE" +side = "BOTH" diff --git a/src/main/resources/assets/predench/lang/en_us.json b/src/main/resources/assets/predench/lang/en_us.json new file mode 100644 index 0000000..4b56965 --- /dev/null +++ b/src/main/resources/assets/predench/lang/en_us.json @@ -0,0 +1,4 @@ +{ + "item.predench.vitriolic_feather": "Vitriolic Feather", + "item.predench.strange_writing_book": "Strange Writing Book" +} \ No newline at end of file diff --git a/src/main/resources/assets/predench/models/item/strange_writing_book.json b/src/main/resources/assets/predench/models/item/strange_writing_book.json new file mode 100644 index 0000000..d6fe889 --- /dev/null +++ b/src/main/resources/assets/predench/models/item/strange_writing_book.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "predench:item/strange_writing_book" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/predench/models/item/vitriolic_feather.json b/src/main/resources/assets/predench/models/item/vitriolic_feather.json new file mode 100644 index 0000000..f256785 --- /dev/null +++ b/src/main/resources/assets/predench/models/item/vitriolic_feather.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "predench:item/vitriolic_feather" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/predench/textures/item/strange_writing_book.png b/src/main/resources/assets/predench/textures/item/strange_writing_book.png new file mode 100644 index 0000000..6c452b7 Binary files /dev/null and b/src/main/resources/assets/predench/textures/item/strange_writing_book.png differ diff --git a/src/main/resources/assets/predench/textures/item/vitriolic_feather.png b/src/main/resources/assets/predench/textures/item/vitriolic_feather.png new file mode 100644 index 0000000..c6fca90 Binary files /dev/null and b/src/main/resources/assets/predench/textures/item/vitriolic_feather.png differ diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta new file mode 100644 index 0000000..29e2829 --- /dev/null +++ b/src/main/resources/pack.mcmeta @@ -0,0 +1,8 @@ +{ + "pack": { + "description": "predench resources", + "pack_format": 8, + "forge:resource_pack_format": 8, + "forge:data_pack_format": 9 + } +} diff --git a/src/main/resources/predench.mixins.json b/src/main/resources/predench.mixins.json new file mode 100644 index 0000000..3451c20 --- /dev/null +++ b/src/main/resources/predench.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "xyz.nuark.predench.mixin", + "compatibilityLevel": "JAVA_8", + "refmap": "predench.refmap.json", + "mixins": [ + "MixinEnchantmentMenu", + "MixinEnchantmentTableBlock" + ], + "injectors": { + "defaultRequire": 1 + } +}