From def11e7487316360182ccf39e2ecf7d2f5aca9cb Mon Sep 17 00:00:00 2001 From: lothrazar Date: Fri, 28 Jun 2024 23:47:48 -0700 Subject: [PATCH 01/29] mc1.21 gradle executions fixed and updated, code does not compile yet --- build.gradle | 186 +++++++----------- gradle.properties | 18 +- gradle/wrapper/gradle-wrapper.jar | Bin 61574 -> 43453 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 29 +-- gradlew.bat | 20 +- settings.gradle | 10 +- .../{mods.toml => neoforge.mods.toml} | 12 +- 8 files changed, 126 insertions(+), 152 deletions(-) rename src/main/resources/META-INF/{mods.toml => neoforge.mods.toml} (89%) diff --git a/build.gradle b/build.gradle index 1281512..9c40f99 100644 --- a/build.gradle +++ b/build.gradle @@ -1,134 +1,125 @@ plugins { + id 'java-library' id 'eclipse' id 'idea' id 'maven-publish' - id 'net.neoforged.gradle' version '[6.0.18,6.2)' + id 'net.neoforged.moddev' version '0.1.99' +} +tasks.named('wrapper', Wrapper).configure { + // Define wrapper values here so as to not have to always do so when updating gradlew.properties. + // Switching this to Wrapper.DistributionType.ALL will download the full gradle sources that comes with + // documentation attached on cursor hover of gradle classes and methods. However, this comes with increased + // file size for Gradle. If you do switch this to ALL, run the Gradle wrapper task twice afterwards. + // (Verify by checking gradle/wrapper/gradle-wrapper.properties to see if distributionUrl now points to `-all`) + distributionType = Wrapper.DistributionType.BIN } version = "${mc_version}-${mod_version}" group = mod_group_id +repositories { + mavenLocal() +// flatDir { dir 'libs' } + + // maven { +// name = "curios" + // url = 'https://maven.theillusivec4.top/' + // } + // maven { url = 'https://maven.blamejared.com' } +// maven { url = 'https://www.cursemaven.com' } +} + base { archivesName = mod_id } // Mojang ships Java 17 to end users in 1.18+, so your mod should target Java 17. -java.toolchain.languageVersion = JavaLanguageVersion.of(17) -import net.minecraftforge.gradle.common.tasks.SignJar +java.toolchain.languageVersion = JavaLanguageVersion.of(21) println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}" -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://parchmentmc.org/docs/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: mapping_channel, version: mapping_version - - // When true, this property will have all Eclipse/IntelliJ IDEA run configurations run the "prepareX" task for the given run configuration before launching the game. - // In most cases, it is not necessary to enable. - // enableEclipsePrepareRuns = true - // enableIdeaPrepareRuns = true - - // This property allows configuring Gradle's ProcessResources task(s) to run on IDE output locations before launching the game. - // It is REQUIRED to be set to true for this template to function. - // See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html - copyIdeResources = true - - // When true, this property will add the folder name of all declared run configurations to generated IDE run configurations. - // The folder name can be set on a run configuration using the "folderName" property. - // By default, the folder name of a run configuration is the name of the Gradle project containing it. - // generateRunFolders = true - - // This property enables access transformers for use in development. - // They will be applied to the Minecraft artifact. - // The access transformer file can be anywhere in the project. - // However, it must be at "META-INF/accesstransformer.cfg" in the final mod jar to be loaded by Forge. - // This default location is a best practice to automatically put the file in the right place in the final jar. - // See https://docs.minecraftforge.net/en/latest/advanced/accesstransformers/ for more information. - accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') - - // Default run configurations. - // These can be tweaked, removed, or duplicated as needed. +neoForge { + // Specify the version of NeoForge to use. + version = project.neo_version + + parchment { + mappingsVersion = project.parchment_mappings_version + minecraftVersion = project.parchment_minecraft_version + } runs { // applies to all the run configs below configureEach { - workingDirectory project.file('run') + // 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' + systemProperty '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' - mods { - "${mod_id}" { - source sourceSets.main - } - } + logLevel = org.slf4j.event.Level.DEBUG + // systemProperty 'forge.logging.console.level', 'debug' + + // modSource project.sourceSets.main } client { + client() // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. - property 'forge.enabledGameTestNamespaces', mod_id + systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id } server { - property 'forge.enabledGameTestNamespaces', mod_id - args '--nogui' + server() + systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id + // programArgument '--nogui' } // 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 { - property 'forge.enabledGameTestNamespaces', mod_id + type = "gameTestServer" + systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id } data { + data() // example of overriding the workingDirectory set in configureEach above - workingDirectory project.file('run-data') + // workingDirectory project.file('run-data') // Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources. - args '--mod', mod_id, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') + programArguments.addAll '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath() + } + } + mods { + // define mod <-> source bindings + // these are used to tell the game which sources are for which mod + // mostly optional in a single mod project + // but multi mod projects should define one per mod + "${mod_id}" { + sourceSet(sourceSets.main) } } } // Include resources generated by data generators. //sourceSets.main.resources { srcDir 'src/generated/resources' } - -repositories { -// flatDir { dir 'libs' } - - maven { - name = "curios" - url = 'https://maven.theillusivec4.top/' - } - maven { url = 'https://maven.blamejared.com' } -// maven { url = 'https://www.cursemaven.com' } +configurations { + runtimeClasspath.extendsFrom localRuntime } + dependencies { // Specify the version of Minecraft to use. // Any artifact can be supplied so long as it has a "userdev" classifier artifact and is a compatible patcher artifact. // The "userdev" classifier will be requested and setup by ForgeGradle. // If the group id is "net.minecraft" and the artifact id is one of ["client", "server", "joined"], // then special handling is done to allow a setup of a vanilla dependency without the use of an external repository. - minecraft "net.neoforged:forge:${minecraft_version}-${neo_version}" + // implementation "net.neoforged:neoforge:${neo_version}" // Example mod dependency with JEI - using fg.deobf() ensures the dependency is remapped to your development mappings // The JEI API is declared for compile time use, while the full JEI artifact is used at runtime @@ -150,48 +141,24 @@ dependencies { // A missing property will result in an error. Properties are expanded using ${} Groovy notation. // When "copyIdeResources" is enabled, this will also run before the game launches in IDE environments. // See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html -tasks.named('processResources', ProcessResources).configure { +tasks.withType(ProcessResources).configureEach { var replaceProperties = [ - minecraft_version: minecraft_version, minecraft_version_range: minecraft_version_range, + minecraft_version_range: minecraft_version_range, loader_version_range: loader_version_range, mod_id: mod_id, mod_name: mod_name, mod_license: mod_license, mod_version: mod_version, mod_authors: mod_authors, mod_description: mod_description, ] inputs.properties replaceProperties - filesMatching(['META-INF/mods.toml', 'pack.mcmeta']) { - expand replaceProperties + [project: project] - } -} - -// Example for how to get properties into the manifest for reading at runtime. -tasks.named('jar', Jar).configure { - manifest { - attributes([ - 'Specification-Title' : mod_id, - 'Specification-Vendor' : mod_authors, - 'Specification-Version' : '1', // We are version 1 of ourselves - 'Implementation-Title' : project.name, - 'Implementation-Version' : project.jar.archiveVersion, - 'Implementation-Vendor' : mod_authors, - 'Implementation-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") - ]) + filesMatching(['META-INF/neoforge.mods.toml']) { + expand replaceProperties } - - // This is the preferred method to reobfuscate your jar file - finalizedBy 'reobfJar' } -// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing: -// tasks.named('publish').configure { -// dependsOn 'reobfJar' -// } - -// Example configuration to allow publishing using the maven-publish plugin publishing { publications { register('mavenJava', MavenPublication) { - artifact jar + from components.java } } repositories { @@ -201,24 +168,19 @@ publishing { } } -task signJar(type: SignJar, dependsOn: jar) { - - // findProperty allows us to reference the property without it existing. - // Using project.propName would cause the script to fail validation if - // the property did not exist. - keyStore = project.findProperty('keyStore') - alias = project.findProperty('keyStoreAlias') - storePass = project.findProperty('keyStorePass') - keyPass = project.findProperty('keyStoreKeyPass') - inputFile = jar.archivePath - outputFile = jar.archivePath -} - task cleanJar { delete 'build/libs' } - tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation } + +// IDEA no longer automatically downloads sources/javadoc jars for dependencies, so we need to explicitly enable the behavior. +idea { + module { + downloadSources = true + downloadJavadoc = true + } +} + diff --git a/gradle.properties b/gradle.properties index 5778bc9..6341253 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,15 +2,24 @@ # This is required to provide enough memory for the Minecraft decompilation process. org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false +org.gradle.debug=false +org.gradle.caching=true +org.gradle.configuration-cache=true + +#read more on this at https://github.com/neoforged/NeoGradle/blob/NG_7.0/README.md#apply-parchment-mappings +# you can also find the latest versions at: https://parchmentmc.org/docs/getting-started +parchment_minecraft_version=1.20.6 +parchment_mappings_version=2024.06.02 # your properties # https://www.curseforge.com/minecraft/mc-mods/flib mod_id=flib curse_id=661261 mod_version=0.0.12 +minecraft_version=1.21 +mc_version=1.21 +neo_version=21.0.0-beta -mc_version=1.20.1 -neo_version=47.1.28 mod_name=flib @@ -21,12 +30,11 @@ mod_group_id=com.lothrazar.flib mod_license=SeeGithub mod_authors=Lothrazar mod_description=mod -minecraft_version_range=[1.20.1,) +minecraft_version_range=[1.21,) forge_version_range=[47,) loader_version_range=[47,) mapping_channel=official -minecraft_version=1.20.1 -mapping_version=1.20.1 +mapping_version=1.21 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 943f0cbfa754578e88a3dae77fce6e3dea56edbf..e6441136f3d4ba8a0da8d277868979cfbc8ad796 100644 GIT binary patch literal 43453 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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
NnX)EH+Nua)3Y(c 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 ScNgau(U?ep-K_E5zy1%ZQTdPn diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37aef8d..b82aa23 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ 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.7-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 65dcd68..1aa94a4 100644 --- a/gradlew +++ b/gradlew @@ -83,10 +83,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# 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"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,10 +131,13 @@ 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. + if ! command -v java >/dev/null 2>&1 + then + 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 fi # Increase the maximum file descriptors if we can. @@ -144,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -197,11 +198,15 @@ if "$cygwin" || "$msys" ; then 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. + +# 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"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/gradlew.bat b/gradlew.bat index 93e3f59..25da30d 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -43,11 +43,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 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. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +57,11 @@ 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. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/settings.gradle b/settings.gradle index 24584e9..ada876e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,13 +1,11 @@ pluginManagement { repositories { + mavenLocal() gradlePluginPortal() - maven { - name = 'NeoForged' - url = 'https://maven.neoforged.net/releases' - } + maven { url = 'https://maven.neoforged.net/releases' } } } plugins { - id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0' -} \ No newline at end of file + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' +} diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/neoforge.mods.toml similarity index 89% rename from src/main/resources/META-INF/mods.toml rename to src/main/resources/META-INF/neoforge.mods.toml index 01abcac..2f2954d 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/neoforge.mods.toml @@ -1,4 +1,4 @@ -# This is an example mods.toml file. It contains the data relating to the loading mods. +# This is an example neoforge.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. @@ -7,7 +7,7 @@ modLoader="javafml" #mandatory license="MIT" # A version range to match for said mod loader - for regular FML @Mod it will be the forge version -loaderVersion="[26,)" #mandatory (26 is current forge version) +loaderVersion="[4,)" #mandatory (26 is current forge version) # A URL to refer people to when problems occur with this mod issueTrackerURL="https://github.com/Lothrazar/FLib/issues" #optional # A list of mods - how many allowed here is determined by the individual mod loader @@ -36,9 +36,9 @@ description=''' Future Library. Empowers many forge mods. by Lothrazar ''' # A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional. -[[dependencies.flib]] #optional +[[dependencies.${mod_id}]] #optional # the modid of the dependency - modId="forge" #mandatory + modId="neoforge" #mandatory # Does this dependency have to exist - if not, ordering below must be specified mandatory=true #mandatory # The version range of the dependency @@ -48,9 +48,9 @@ Future Library. Empowers many forge mods. by Lothrazar # Side this dependency is applied on - BOTH, CLIENT or SERVER side="BOTH" # Here's another dependency -[[dependencies.flib]] +[[dependencies.${mod_id}]] modId="minecraft" mandatory=true - versionRange="[1.20.1,)" + versionRange="[1.21,)" ordering="NONE" side="BOTH" \ No newline at end of file From 571217ebfe8847eca07c9f2d79973efe229e884b Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 31 Mar 2026 16:11:31 -0700 Subject: [PATCH 02/29] neoforge 1.21.1 restart the update --- .gitattributes | 2 +- build.gradle | 144 +++++++++++++---------- gradle.properties | 10 +- gradle/wrapper/gradle-wrapper.jar | Bin 43453 -> 43764 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 12 +- gradlew.bat | 6 +- settings.gradle | 4 +- 8 files changed, 103 insertions(+), 77 deletions(-) diff --git a/.gitattributes b/.gitattributes index f811f6a..b7bbcc4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,5 @@ # Disable autocrlf on generated files, they always generate with LF # Add any extra files or paths here to make git stop saying they # are changed when only line endings change. -src/generated/**/.cache/cache text eol=lf +src/generated/**/.cache/* text eol=lf src/generated/**/*.json text eol=lf diff --git a/build.gradle b/build.gradle index 9c40f99..0237b66 100644 --- a/build.gradle +++ b/build.gradle @@ -1,9 +1,8 @@ plugins { id 'java-library' - id 'eclipse' - id 'idea' id 'maven-publish' - id 'net.neoforged.moddev' version '0.1.99' + id 'net.neoforged.moddev' version '2.0.141' + id 'idea' } tasks.named('wrapper', Wrapper).configure { // Define wrapper values here so as to not have to always do so when updating gradlew.properties. @@ -17,8 +16,19 @@ tasks.named('wrapper', Wrapper).configure { version = "${mc_version}-${mod_version}" group = mod_group_id +sourceSets.main.resources { + // Include resources generated by data generators. + srcDir('src/generated/resources') + + // Exclude common development only resources from finalized outputs + exclude("**/*.bbmodel") // BlockBench project files + exclude("src/generated/**/.cache") // datagen cache files +} + + + repositories { - mavenLocal() +// mavenLocal() // flatDir { dir 'libs' } // maven { @@ -33,9 +43,10 @@ base { archivesName = mod_id } -// Mojang ships Java 17 to end users in 1.18+, so your mod should target Java 17. +// Mojang ships Java 21 to end users in 1.21.1, so mods should target Java 21. java.toolchain.languageVersion = JavaLanguageVersion.of(21) println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}" + neoForge { // Specify the version of NeoForge to use. version = project.neo_version @@ -44,38 +55,23 @@ neoForge { mappingsVersion = project.parchment_mappings_version minecraftVersion = project.parchment_minecraft_version } - runs { - // applies to all the run configs below - configureEach { - // 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. - - systemProperty '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 - - logLevel = org.slf4j.event.Level.DEBUG - // systemProperty 'forge.logging.console.level', 'debug' - - // modSource project.sourceSets.main - } + // TODO: fix this. This line is optional. Access Transformers are automatically detected + // accessTransformers = project.files('src/main/resources/META-INF/accesstransformer.cfg') + // Default run configurations. + // These can be tweaked, removed, or duplicated as needed. + runs { client { client() + // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id } server { server() + programArgument '--nogui' systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id - // programArgument '--nogui' } // This run config launches GameTestServer and runs all registered gametests, then exits. @@ -88,49 +84,68 @@ neoForge { data { data() - // example of overriding the workingDirectory set in configureEach above - // workingDirectory project.file('run-data') + + // example of overriding the workingDirectory set in configureEach above, uncomment if you want to use it + // gameDirectory = project.file('run-data') // Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources. programArguments.addAll '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath() } + + // applies to all the run configs above + configureEach { + // 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. + systemProperty '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 + logLevel = org.slf4j.event.Level.DEBUG + } } + mods { // define mod <-> source bindings // these are used to tell the game which sources are for which mod - // mostly optional in a single mod project - // but multi mod projects should define one per mod + // multi mod projects should define one per mod "${mod_id}" { sourceSet(sourceSets.main) } } } -// Include resources generated by data generators. -//sourceSets.main.resources { srcDir 'src/generated/resources' } +// Sets up a dependency configuration called 'localRuntime'. +// This configuration should be used instead of 'runtimeOnly' to declare +// a dependency that will be present for runtime testing but that is +// "optional", meaning it will not be pulled by dependents of this mod. configurations { runtimeClasspath.extendsFrom localRuntime } dependencies { - // Specify the version of Minecraft to use. - // Any artifact can be supplied so long as it has a "userdev" classifier artifact and is a compatible patcher artifact. - // The "userdev" classifier will be requested and setup by ForgeGradle. - // If the group id is "net.minecraft" and the artifact id is one of ["client", "server", "joined"], - // then special handling is done to allow a setup of a vanilla dependency without the use of an external repository. - // implementation "net.neoforged:neoforge:${neo_version}" - - // Example mod dependency with JEI - using fg.deobf() ensures the dependency is remapped to your development mappings + + // Example optional mod dependency with JEI // The JEI API is declared for compile time use, while the full JEI artifact is used at runtime - // compileOnly fg.deobf("mezz.jei:jei-${mc_version}-common-api:${jei_version}") - // compileOnly fg.deobf("mezz.jei:jei-${mc_version}-forge-api:${jei_version}") - // runtimeOnly fg.deobf("mezz.jei:jei-${mc_version}-forge:${jei_version}") + // compileOnly "mezz.jei:jei-${mc_version}-common-api:${jei_version}" + // compileOnly "mezz.jei:jei-${mc_version}-neoforge-api:${jei_version}" + // We add the full version to localRuntime, not runtimeOnly, so that we do not publish a dependency on it + // localRuntime "mezz.jei:jei-${mc_version}-neoforge:${jei_version}" // Example mod dependency using a mod jar from ./libs with a flat dir repository // This maps to ./libs/coolmod-${mc_version}-${coolmod_version}.jar // The group id is ignored when searching -- in this case, it is "blank" - // implementation fg.deobf("blank:coolmod-${mc_version}:${coolmod_version}") + // implementation "blank:coolmod-${mc_version}:${coolmod_version}" + + // Example mod dependency using a file as dependency + // implementation files("libs/coolmod-${mc_version}-${coolmod_version}.jar") + + // Example project dependency using a sister or child project: + // implementation project(":myproject") // For more info: // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html @@ -139,22 +154,29 @@ dependencies { // This block of code expands all declared replace properties in the specified resource targets. // A missing property will result in an error. Properties are expanded using ${} Groovy notation. -// When "copyIdeResources" is enabled, this will also run before the game launches in IDE environments. -// See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html -tasks.withType(ProcessResources).configureEach { +var generateModMetadata = tasks.register("generateModMetadata", ProcessResources) { var replaceProperties = [ + minecraft_version : minecraft_version, minecraft_version_range: minecraft_version_range, - loader_version_range: loader_version_range, - mod_id: mod_id, mod_name: mod_name, mod_license: mod_license, mod_version: mod_version, - mod_authors: mod_authors, mod_description: mod_description, + neo_version : neo_version, + loader_version_range : loader_version_range, + mod_id : mod_id, + mod_name : mod_name, + mod_license : mod_license, + mod_version : mod_version, ] inputs.properties replaceProperties - - filesMatching(['META-INF/neoforge.mods.toml']) { - expand replaceProperties - } + expand replaceProperties + from "src/main/templates" + into "build/generated/sources/modMetadata" } +// Include the output of "generateModMetadata" as an input directory for the build +// this works with both building through Gradle and the IDE. +sourceSets.main.resources.srcDir generateModMetadata +// To avoid having to run "generateModMetadata" manually, make it run on every project reload +neoForge.ideSyncTask generateModMetadata +// Example configuration to allow publishing using the maven-publish plugin publishing { publications { register('mavenJava', MavenPublication) { @@ -163,15 +185,11 @@ publishing { } repositories { maven { - url "file://${project.projectDir}/mcmodsrepo" + url "file://${project.projectDir}/repo" } } } -task cleanJar { - delete 'build/libs' -} - tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation } @@ -184,3 +202,9 @@ idea { } } + +// custom tasks +task cleanJar { + delete 'build/libs' +} + diff --git a/gradle.properties b/gradle.properties index 6341253..6ecf636 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,17 +8,17 @@ org.gradle.configuration-cache=true #read more on this at https://github.com/neoforged/NeoGradle/blob/NG_7.0/README.md#apply-parchment-mappings # you can also find the latest versions at: https://parchmentmc.org/docs/getting-started -parchment_minecraft_version=1.20.6 -parchment_mappings_version=2024.06.02 +parchment_minecraft_version=1.21.1 +parchment_mappings_version=2024.11.17 # your properties # https://www.curseforge.com/minecraft/mc-mods/flib mod_id=flib curse_id=661261 mod_version=0.0.12 -minecraft_version=1.21 -mc_version=1.21 -neo_version=21.0.0-beta +minecraft_version=1.21.1 +mc_version=1.21.1 +neo_version=21.1.222 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136f3d4ba8a0da8d277868979cfbc8ad796..1b33c55baabb587c669f562ae36f953de2481846 100644 GIT binary patch delta 35073 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 delta 34912 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

Gn4F+B~IivciU9^t0j-Mgao3 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 dDuazZG^u*-) zCV{{p$D*4m=Z;!QJ0C3EBfaUv#@3CmRgS-#a4+Uk9LtR(mzdSt-?*B-Q{Jgs!F;+_ zT&Jc~{N951OskjVtnWOLnfUacmSEkQ#fQojqa=HN?aN#ubFA){K&TrfoSnBphJ<43S zS5?OUrqPYpEqf;(zc;IIty0d`-n-Ke%PlArJt^DN>ZYW)ZS5z$Rnx=cxbM1#zPRNS1N0u>c z*gpBeTvyKAjdr#Uz%$J3C+p2~l9`-P6`=_1Y83#nAp`Kd5jfb*H#u;=%w#=&g~|Q% z1!N9S7n+#|tj#t98*^$X3S9)i3I*n?N+YghXJ9Z!QN%wvV7|W$;;Lx|1{)Ol%c4L- zlz|txtAK4ozLL`xMPZR7Sm6grRj@+Db&BXF9#sG|gMywm=IO1O01imHv3 zFjX9ri>su;HX}wK85k5$R0A&?fdtA5_Q_vX$jc(elo%M~QB>A-K~#2igOjH$d^80Z zC8#NjzZarXrcVZJJEF73z+ix4=7c`5N>TJt7>~rfl$^E}UAMlP2$P)vS26{cE?ONf_&Vd@-E2?PMU+S~pB diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b82aa23..23449a2 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.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a4..23d15a9 100644 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -112,7 +114,7 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar +CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -203,7 +205,7 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. @@ -211,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 25da30d..db3a6ac 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -68,11 +70,11 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/settings.gradle b/settings.gradle index ada876e..7a488e3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,11 +1,9 @@ pluginManagement { repositories { - mavenLocal() gradlePluginPortal() - maven { url = 'https://maven.neoforged.net/releases' } } } plugins { - id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' + id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0' } From debae9481dad859b4a6e7f9f73cad1ac74bc009b Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 31 Mar 2026 16:14:47 -0700 Subject: [PATCH 03/29] neoforge package renames --- src/main/java/com/lothrazar/library/FutureLibMod.java | 8 ++++---- .../java/com/lothrazar/library/block/BlockFlib.java | 6 +++--- .../com/lothrazar/library/cap/CustomEnergyStorage.java | 4 ++-- .../com/lothrazar/library/cap/ItemStackHandlerEx.java | 2 +- .../lothrazar/library/cap/ItemStackHandlerWrapper.java | 8 ++++---- .../cap/item/CapabilityProviderEnergyStack.java | 4 ++-- .../library/cap/item/EnergyCapabilityItemStack.java | 4 ++-- .../library/cap/item/FluidHandlerCapabilityStack.java | 8 ++++---- .../library/cap/player/PlayerCapProvider.java | 4 ++-- .../com/lothrazar/library/config/ConfigTemplate.java | 2 +- .../java/com/lothrazar/library/core/IHasFluid.java | 2 +- .../com/lothrazar/library/dim/DimensionTransit.java | 2 +- .../com/lothrazar/library/entity/BlockEntityFlib.java | 2 +- .../com/lothrazar/library/events/CapabilityEvents.java | 6 +++--- .../java/com/lothrazar/library/events/EventFlib.java | 2 +- .../com/lothrazar/library/events/FlibBlockEvents.java | 4 ++-- .../java/com/lothrazar/library/fluid/FluidHolder.java | 4 ++-- .../java/com/lothrazar/library/gui/ContainerFlib.java | 2 +- src/main/java/com/lothrazar/library/gui/FluidBar.java | 2 +- .../java/com/lothrazar/library/item/BlockItemFlib.java | 4 ++-- src/main/java/com/lothrazar/library/item/ItemFlib.java | 4 ++-- .../java/com/lothrazar/library/mod/CommandModule.java | 4 ++-- .../com/lothrazar/library/mod/FlibRegistrations.java | 8 ++++---- .../com/lothrazar/library/packet/PacketSyncFluid.java | 2 +- .../library/particle/AbstractSingleQuadParticle.java | 4 ++-- .../library/particle/data/ParticleOptionsTwoInt.java | 2 +- .../lothrazar/library/recipe/BrewingRecipeFlib.java | 2 +- .../recipe/conditions/EntityExistsCondition.java | 2 +- .../library/recipe/ingredient/FluidTagIngredient.java | 4 ++-- .../lothrazar/library/registry/GameRuleFactory.java | 2 +- .../library/registry/RecipeCauldronFactory.java | 2 +- .../com/lothrazar/library/render/FluidRenderMap.java | 4 ++-- .../lothrazar/library/render/RenderBlockOverlay.java | 4 ++-- .../library/render/RenderEntityToBlockLaser.java | 2 +- .../com/lothrazar/library/util/AttributesUtil.java | 2 +- .../com/lothrazar/library/util/AutoSprintUtil.java | 4 ++-- .../com/lothrazar/library/util/BlockstatesUtil.java | 2 +- .../java/com/lothrazar/library/util/EnchantUtil.java | 2 +- .../java/com/lothrazar/library/util/EntityUtil.java | 2 +- .../com/lothrazar/library/util/FakePlayerUtil.java | 10 +++++----- .../java/com/lothrazar/library/util/ItemStackUtil.java | 4 ++-- .../java/com/lothrazar/library/util/ParticleUtil.java | 4 ++-- .../java/com/lothrazar/library/util/RecipeUtil.java | 4 ++-- .../com/lothrazar/library/util/RenderBlockUtils.java | 6 +++--- .../java/com/lothrazar/library/util/RenderUtil.java | 4 ++-- .../java/com/lothrazar/library/util/SoundUtil.java | 2 +- .../com/lothrazar/library/util/StringParseUtil.java | 2 +- 47 files changed, 87 insertions(+), 87 deletions(-) diff --git a/src/main/java/com/lothrazar/library/FutureLibMod.java b/src/main/java/com/lothrazar/library/FutureLibMod.java index f90dd29..04f3c6c 100644 --- a/src/main/java/com/lothrazar/library/FutureLibMod.java +++ b/src/main/java/com/lothrazar/library/FutureLibMod.java @@ -6,10 +6,10 @@ import com.lothrazar.library.mod.CommandModule; import com.lothrazar.library.mod.ConfigModule; import com.lothrazar.library.mod.PacketRegistry; -import net.minecraftforge.eventbus.api.IEventBus; -import net.minecraftforge.fml.InterModComms; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.fml.InterModComms; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; @Mod(FutureLibMod.MODID) diff --git a/src/main/java/com/lothrazar/library/block/BlockFlib.java b/src/main/java/com/lothrazar/library/block/BlockFlib.java index 3fa249a..7814d8e 100644 --- a/src/main/java/com/lothrazar/library/block/BlockFlib.java +++ b/src/main/java/com/lothrazar/library/block/BlockFlib.java @@ -29,9 +29,9 @@ import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.level.block.state.properties.EnumProperty; import net.minecraft.world.phys.BlockHitResult; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.event.entity.player.PlayerInteractEvent.RightClickBlock; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent.RightClickBlock; public class BlockFlib extends Block { diff --git a/src/main/java/com/lothrazar/library/cap/CustomEnergyStorage.java b/src/main/java/com/lothrazar/library/cap/CustomEnergyStorage.java index 4946e4a..632cd81 100644 --- a/src/main/java/com/lothrazar/library/cap/CustomEnergyStorage.java +++ b/src/main/java/com/lothrazar/library/cap/CustomEnergyStorage.java @@ -1,8 +1,8 @@ package com.lothrazar.library.cap; import net.minecraft.nbt.CompoundTag; -import net.minecraftforge.common.util.INBTSerializable; -import net.minecraftforge.energy.EnergyStorage; +import net.neoforged.neoforge.common.util.INBTSerializable; +import net.neoforged.neoforge.energy.EnergyStorage; /** * For use with items, tile entities, etc. diff --git a/src/main/java/com/lothrazar/library/cap/ItemStackHandlerEx.java b/src/main/java/com/lothrazar/library/cap/ItemStackHandlerEx.java index 5dd75ad..4af99e4 100644 --- a/src/main/java/com/lothrazar/library/cap/ItemStackHandlerEx.java +++ b/src/main/java/com/lothrazar/library/cap/ItemStackHandlerEx.java @@ -3,7 +3,7 @@ import java.util.ArrayList; import java.util.List; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.ItemStackHandler; +import net.neoforged.neoforge.items.ItemStackHandler; public class ItemStackHandlerEx extends ItemStackHandler { diff --git a/src/main/java/com/lothrazar/library/cap/ItemStackHandlerWrapper.java b/src/main/java/com/lothrazar/library/cap/ItemStackHandlerWrapper.java index ba4823a..199dfc8 100644 --- a/src/main/java/com/lothrazar/library/cap/ItemStackHandlerWrapper.java +++ b/src/main/java/com/lothrazar/library/cap/ItemStackHandlerWrapper.java @@ -2,10 +2,10 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.common.util.INBTSerializable; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.IItemHandlerModifiable; -import net.minecraftforge.items.ItemStackHandler; +import net.neoforged.neoforge.common.util.INBTSerializable; +import net.neoforged.neoforge.items.IItemHandler; +import net.neoforged.neoforge.items.IItemHandlerModifiable; +import net.neoforged.neoforge.items.ItemStackHandler; /** * Wraps two {@link ItemStackHandler}s: Input and Output. Input's slots come first then the Output's slots come after. Items can only be inserted into Input. Items can only be extracted from Output. diff --git a/src/main/java/com/lothrazar/library/cap/item/CapabilityProviderEnergyStack.java b/src/main/java/com/lothrazar/library/cap/item/CapabilityProviderEnergyStack.java index e3dfc65..646cd01 100644 --- a/src/main/java/com/lothrazar/library/cap/item/CapabilityProviderEnergyStack.java +++ b/src/main/java/com/lothrazar/library/cap/item/CapabilityProviderEnergyStack.java @@ -6,8 +6,8 @@ import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.ForgeCapabilities; import net.minecraftforge.common.capabilities.ICapabilitySerializable; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.energy.IEnergyStorage; +import net.neoforged.neoforge.common.util.LazyOptional; +import net.neoforged.neoforge.energy.IEnergyStorage; public class CapabilityProviderEnergyStack implements ICapabilitySerializable { diff --git a/src/main/java/com/lothrazar/library/cap/item/EnergyCapabilityItemStack.java b/src/main/java/com/lothrazar/library/cap/item/EnergyCapabilityItemStack.java index 2392eb4..9cc01c0 100644 --- a/src/main/java/com/lothrazar/library/cap/item/EnergyCapabilityItemStack.java +++ b/src/main/java/com/lothrazar/library/cap/item/EnergyCapabilityItemStack.java @@ -7,8 +7,8 @@ import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.ForgeCapabilities; import net.minecraftforge.common.capabilities.ICapabilityProvider; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.energy.IEnergyStorage; +import net.neoforged.neoforge.common.util.LazyOptional; +import net.neoforged.neoforge.energy.IEnergyStorage; public class EnergyCapabilityItemStack implements ICapabilityProvider { diff --git a/src/main/java/com/lothrazar/library/cap/item/FluidHandlerCapabilityStack.java b/src/main/java/com/lothrazar/library/cap/item/FluidHandlerCapabilityStack.java index de46697..2be6aa9 100644 --- a/src/main/java/com/lothrazar/library/cap/item/FluidHandlerCapabilityStack.java +++ b/src/main/java/com/lothrazar/library/cap/item/FluidHandlerCapabilityStack.java @@ -6,10 +6,10 @@ import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.ForgeCapabilities; import net.minecraftforge.common.capabilities.ICapabilityProvider; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.capability.IFluidHandlerItem; -import net.minecraftforge.fluids.capability.templates.FluidHandlerItemStack; +import net.neoforged.neoforge.common.util.LazyOptional; +import net.neoforged.neoforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.capability.IFluidHandlerItem; +import net.neoforged.neoforge.fluids.capability.templates.FluidHandlerItemStack; public class FluidHandlerCapabilityStack implements IFluidHandlerItem, ICapabilityProvider { diff --git a/src/main/java/com/lothrazar/library/cap/player/PlayerCapProvider.java b/src/main/java/com/lothrazar/library/cap/player/PlayerCapProvider.java index 03e2e5c..accd056 100644 --- a/src/main/java/com/lothrazar/library/cap/player/PlayerCapProvider.java +++ b/src/main/java/com/lothrazar/library/cap/player/PlayerCapProvider.java @@ -6,8 +6,8 @@ import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.common.capabilities.CapabilityToken; import net.minecraftforge.common.capabilities.ICapabilityProvider; -import net.minecraftforge.common.util.INBTSerializable; -import net.minecraftforge.common.util.LazyOptional; +import net.neoforged.neoforge.common.util.INBTSerializable; +import net.neoforged.neoforge.common.util.LazyOptional; public class PlayerCapProvider implements ICapabilityProvider, INBTSerializable { diff --git a/src/main/java/com/lothrazar/library/config/ConfigTemplate.java b/src/main/java/com/lothrazar/library/config/ConfigTemplate.java index 92dad8f..0d60031 100644 --- a/src/main/java/com/lothrazar/library/config/ConfigTemplate.java +++ b/src/main/java/com/lothrazar/library/config/ConfigTemplate.java @@ -4,7 +4,7 @@ import com.electronwill.nightconfig.core.io.WritingMode; import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.common.ForgeConfigSpec.Builder; -import net.minecraftforge.fml.loading.FMLPaths; +import net.neoforged.fml.loading.FMLPaths; public abstract class ConfigTemplate { diff --git a/src/main/java/com/lothrazar/library/core/IHasFluid.java b/src/main/java/com/lothrazar/library/core/IHasFluid.java index 4521acc..e2ddc05 100644 --- a/src/main/java/com/lothrazar/library/core/IHasFluid.java +++ b/src/main/java/com/lothrazar/library/core/IHasFluid.java @@ -1,6 +1,6 @@ package com.lothrazar.library.core; -import net.minecraftforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.FluidStack; public interface IHasFluid { diff --git a/src/main/java/com/lothrazar/library/dim/DimensionTransit.java b/src/main/java/com/lothrazar/library/dim/DimensionTransit.java index 7eaf0b2..3f9766e 100644 --- a/src/main/java/com/lothrazar/library/dim/DimensionTransit.java +++ b/src/main/java/com/lothrazar/library/dim/DimensionTransit.java @@ -14,7 +14,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.portal.PortalInfo; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.common.util.ITeleporter; +import net.neoforged.neoforge.common.util.ITeleporter; /** * diff --git a/src/main/java/com/lothrazar/library/entity/BlockEntityFlib.java b/src/main/java/com/lothrazar/library/entity/BlockEntityFlib.java index f935ccf..a29db45 100644 --- a/src/main/java/com/lothrazar/library/entity/BlockEntityFlib.java +++ b/src/main/java/com/lothrazar/library/entity/BlockEntityFlib.java @@ -17,7 +17,7 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.common.util.FakePlayer; +import net.neoforged.neoforge.common.util.FakePlayer; public abstract class BlockEntityFlib extends BlockEntity { diff --git a/src/main/java/com/lothrazar/library/events/CapabilityEvents.java b/src/main/java/com/lothrazar/library/events/CapabilityEvents.java index bce9744..93cecec 100644 --- a/src/main/java/com/lothrazar/library/events/CapabilityEvents.java +++ b/src/main/java/com/lothrazar/library/events/CapabilityEvents.java @@ -6,11 +6,11 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; -import net.minecraftforge.common.MinecraftForge; +import net.neoforged.neoforge.common.NeoForge; import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; import net.minecraftforge.event.AttachCapabilitiesEvent; -import net.minecraftforge.event.entity.player.PlayerEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; +import net.neoforged.bus.api.SubscribeEvent; /** * NOT loaded by default load this into your event bus to pull in diff --git a/src/main/java/com/lothrazar/library/events/EventFlib.java b/src/main/java/com/lothrazar/library/events/EventFlib.java index 99b0ccb..560d9d1 100644 --- a/src/main/java/com/lothrazar/library/events/EventFlib.java +++ b/src/main/java/com/lothrazar/library/events/EventFlib.java @@ -1,6 +1,6 @@ package com.lothrazar.library.events; -import net.minecraftforge.common.MinecraftForge; +import net.neoforged.neoforge.common.NeoForge; public abstract class EventFlib { diff --git a/src/main/java/com/lothrazar/library/events/FlibBlockEvents.java b/src/main/java/com/lothrazar/library/events/FlibBlockEvents.java index 70ddf6c..c6249e0 100644 --- a/src/main/java/com/lothrazar/library/events/FlibBlockEvents.java +++ b/src/main/java/com/lothrazar/library/events/FlibBlockEvents.java @@ -2,8 +2,8 @@ import com.lothrazar.library.block.BlockFlib; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.event.entity.player.PlayerInteractEvent.RightClickBlock; -import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent.RightClickBlock; +import net.neoforged.bus.api.SubscribeEvent; public class FlibBlockEvents extends EventFlib { diff --git a/src/main/java/com/lothrazar/library/fluid/FluidHolder.java b/src/main/java/com/lothrazar/library/fluid/FluidHolder.java index 1be713a..f2bc9f1 100644 --- a/src/main/java/com/lothrazar/library/fluid/FluidHolder.java +++ b/src/main/java/com/lothrazar/library/fluid/FluidHolder.java @@ -5,8 +5,8 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.material.PushReaction; -import net.minecraftforge.common.SoundActions; -import net.minecraftforge.fluids.FluidType; +import net.neoforged.neoforge.common.SoundActions; +import net.neoforged.neoforge.fluids.FluidType; public class FluidHolder { diff --git a/src/main/java/com/lothrazar/library/gui/ContainerFlib.java b/src/main/java/com/lothrazar/library/gui/ContainerFlib.java index 77ed96f..417d4b1 100644 --- a/src/main/java/com/lothrazar/library/gui/ContainerFlib.java +++ b/src/main/java/com/lothrazar/library/gui/ContainerFlib.java @@ -11,7 +11,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.energy.IEnergyStorage; +import net.neoforged.neoforge.energy.IEnergyStorage; public abstract class ContainerFlib extends AbstractContainerMenu { diff --git a/src/main/java/com/lothrazar/library/gui/FluidBar.java b/src/main/java/com/lothrazar/library/gui/FluidBar.java index e121f82..d1c617b 100644 --- a/src/main/java/com/lothrazar/library/gui/FluidBar.java +++ b/src/main/java/com/lothrazar/library/gui/FluidBar.java @@ -11,7 +11,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.material.Fluids; -import net.minecraftforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.FluidStack; public class FluidBar { diff --git a/src/main/java/com/lothrazar/library/item/BlockItemFlib.java b/src/main/java/com/lothrazar/library/item/BlockItemFlib.java index 77a8e72..9b01bc1 100644 --- a/src/main/java/com/lothrazar/library/item/BlockItemFlib.java +++ b/src/main/java/com/lothrazar/library/item/BlockItemFlib.java @@ -9,8 +9,8 @@ import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; public class BlockItemFlib extends BlockItem { diff --git a/src/main/java/com/lothrazar/library/item/ItemFlib.java b/src/main/java/com/lothrazar/library/item/ItemFlib.java index 3258cb2..74ae569 100644 --- a/src/main/java/com/lothrazar/library/item/ItemFlib.java +++ b/src/main/java/com/lothrazar/library/item/ItemFlib.java @@ -16,8 +16,8 @@ import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; public class ItemFlib extends Item { diff --git a/src/main/java/com/lothrazar/library/mod/CommandModule.java b/src/main/java/com/lothrazar/library/mod/CommandModule.java index 1936981..6e17225 100644 --- a/src/main/java/com/lothrazar/library/mod/CommandModule.java +++ b/src/main/java/com/lothrazar/library/mod/CommandModule.java @@ -37,8 +37,8 @@ import net.minecraft.world.scores.Objective; import net.minecraft.world.scores.Score; import net.minecraft.world.scores.Scoreboard; -import net.minecraftforge.event.RegisterCommandsEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.neoforged.neoforge.event.RegisterCommandsEvent; +import net.neoforged.bus.api.SubscribeEvent; public class CommandModule extends EventFlib { diff --git a/src/main/java/com/lothrazar/library/mod/FlibRegistrations.java b/src/main/java/com/lothrazar/library/mod/FlibRegistrations.java index 43a15dc..b239b62 100644 --- a/src/main/java/com/lothrazar/library/mod/FlibRegistrations.java +++ b/src/main/java/com/lothrazar/library/mod/FlibRegistrations.java @@ -2,10 +2,10 @@ import com.lothrazar.library.recipe.conditions.EntityExistsCondition; import net.minecraftforge.common.crafting.CraftingHelper; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.RegisterEvent; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; +import net.neoforged.neoforge.registries.ForgeRegistries; +import net.neoforged.neoforge.registries.RegisterEvent; @Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) public class FlibRegistrations { diff --git a/src/main/java/com/lothrazar/library/packet/PacketSyncFluid.java b/src/main/java/com/lothrazar/library/packet/PacketSyncFluid.java index 97e5238..e6709cc 100644 --- a/src/main/java/com/lothrazar/library/packet/PacketSyncFluid.java +++ b/src/main/java/com/lothrazar/library/packet/PacketSyncFluid.java @@ -30,7 +30,7 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.FluidStack; import net.minecraftforge.network.NetworkEvent; public class PacketSyncFluid extends PacketFlib { diff --git a/src/main/java/com/lothrazar/library/particle/AbstractSingleQuadParticle.java b/src/main/java/com/lothrazar/library/particle/AbstractSingleQuadParticle.java index 9dd7d2b..29b2224 100644 --- a/src/main/java/com/lothrazar/library/particle/AbstractSingleQuadParticle.java +++ b/src/main/java/com/lothrazar/library/particle/AbstractSingleQuadParticle.java @@ -14,8 +14,8 @@ import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; /** * used by ParticleCasting diff --git a/src/main/java/com/lothrazar/library/particle/data/ParticleOptionsTwoInt.java b/src/main/java/com/lothrazar/library/particle/data/ParticleOptionsTwoInt.java index 85d8121..8a54142 100644 --- a/src/main/java/com/lothrazar/library/particle/data/ParticleOptionsTwoInt.java +++ b/src/main/java/com/lothrazar/library/particle/data/ParticleOptionsTwoInt.java @@ -6,7 +6,7 @@ import net.minecraft.core.particles.ParticleOptions; import net.minecraft.core.particles.ParticleType; import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.neoforge.registries.ForgeRegistries; /** * used by ParticleBlinkingAura diff --git a/src/main/java/com/lothrazar/library/recipe/BrewingRecipeFlib.java b/src/main/java/com/lothrazar/library/recipe/BrewingRecipeFlib.java index d838c6c..9c24372 100644 --- a/src/main/java/com/lothrazar/library/recipe/BrewingRecipeFlib.java +++ b/src/main/java/com/lothrazar/library/recipe/BrewingRecipeFlib.java @@ -3,7 +3,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.alchemy.PotionUtils; import net.minecraft.world.item.crafting.Ingredient; -import net.minecraftforge.common.brewing.BrewingRecipe; +import net.neoforged.neoforge.common.brewing.BrewingRecipe; public class BrewingRecipeFlib extends BrewingRecipe { diff --git a/src/main/java/com/lothrazar/library/recipe/conditions/EntityExistsCondition.java b/src/main/java/com/lothrazar/library/recipe/conditions/EntityExistsCondition.java index e57567d..c53d78f 100644 --- a/src/main/java/com/lothrazar/library/recipe/conditions/EntityExistsCondition.java +++ b/src/main/java/com/lothrazar/library/recipe/conditions/EntityExistsCondition.java @@ -5,7 +5,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraftforge.common.crafting.conditions.ICondition; import net.minecraftforge.common.crafting.conditions.IConditionSerializer; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.neoforge.registries.ForgeRegistries; /** * Example: "conditions": [ {"type": "flib:entity_exists", "value": "veincreeper:coal_creeper" } ] diff --git a/src/main/java/com/lothrazar/library/recipe/ingredient/FluidTagIngredient.java b/src/main/java/com/lothrazar/library/recipe/ingredient/FluidTagIngredient.java index 5a893c3..38515ad 100644 --- a/src/main/java/com/lothrazar/library/recipe/ingredient/FluidTagIngredient.java +++ b/src/main/java/com/lothrazar/library/recipe/ingredient/FluidTagIngredient.java @@ -7,8 +7,8 @@ import net.minecraft.tags.FluidTags; import net.minecraft.tags.TagKey; import net.minecraft.world.level.material.Fluid; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.neoforge.fluids.FluidStack; +import net.neoforged.neoforge.registries.ForgeRegistries; public class FluidTagIngredient { diff --git a/src/main/java/com/lothrazar/library/registry/GameRuleFactory.java b/src/main/java/com/lothrazar/library/registry/GameRuleFactory.java index 6bea537..08acc51 100644 --- a/src/main/java/com/lothrazar/library/registry/GameRuleFactory.java +++ b/src/main/java/com/lothrazar/library/registry/GameRuleFactory.java @@ -8,7 +8,7 @@ import net.minecraft.world.level.GameRules.Category; import net.minecraft.world.level.GameRules.Key; import net.minecraft.world.level.GameRules.Type; -import net.minecraftforge.fml.util.ObfuscationReflectionHelper; +import net.neoforged.fml.util.ObfuscationReflectionHelper; /** * accesstransformers.cfg: diff --git a/src/main/java/com/lothrazar/library/registry/RecipeCauldronFactory.java b/src/main/java/com/lothrazar/library/registry/RecipeCauldronFactory.java index 52a4cb1..5097942 100644 --- a/src/main/java/com/lothrazar/library/registry/RecipeCauldronFactory.java +++ b/src/main/java/com/lothrazar/library/registry/RecipeCauldronFactory.java @@ -7,7 +7,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.block.LayeredCauldronBlock; -import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; public class RecipeCauldronFactory { diff --git a/src/main/java/com/lothrazar/library/render/FluidRenderMap.java b/src/main/java/com/lothrazar/library/render/FluidRenderMap.java index d29da79..3e7354f 100644 --- a/src/main/java/com/lothrazar/library/render/FluidRenderMap.java +++ b/src/main/java/com/lothrazar/library/render/FluidRenderMap.java @@ -7,8 +7,8 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.inventory.InventoryMenu; import net.minecraft.world.level.material.Fluid; -import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions; -import net.minecraftforge.fluids.FluidStack; +import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions; +import net.neoforged.neoforge.fluids.FluidStack; /** * Source from MIT open source https://github.com/mekanism/Mekanism/tree/1.15x diff --git a/src/main/java/com/lothrazar/library/render/RenderBlockOverlay.java b/src/main/java/com/lothrazar/library/render/RenderBlockOverlay.java index 9966df3..6aa93fd 100644 --- a/src/main/java/com/lothrazar/library/render/RenderBlockOverlay.java +++ b/src/main/java/com/lothrazar/library/render/RenderBlockOverlay.java @@ -17,8 +17,8 @@ import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.client.event.RenderHighlightEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.neoforged.neoforge.client.event.RenderHighlightEvent; +import net.neoforged.bus.api.SubscribeEvent; /** * Copyright (c) 2015 Vorquel (modified by Lothrazar 2016-2023) diff --git a/src/main/java/com/lothrazar/library/render/RenderEntityToBlockLaser.java b/src/main/java/com/lothrazar/library/render/RenderEntityToBlockLaser.java index 45d9c26..6de96ff 100644 --- a/src/main/java/com/lothrazar/library/render/RenderEntityToBlockLaser.java +++ b/src/main/java/com/lothrazar/library/render/RenderEntityToBlockLaser.java @@ -18,7 +18,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.client.event.RenderLevelStageEvent; +import net.neoforged.neoforge.client.event.RenderLevelStageEvent; /** * Citation/source/author diff --git a/src/main/java/com/lothrazar/library/util/AttributesUtil.java b/src/main/java/com/lothrazar/library/util/AttributesUtil.java index f1c4930..0909bd9 100644 --- a/src/main/java/com/lothrazar/library/util/AttributesUtil.java +++ b/src/main/java/com/lothrazar/library/util/AttributesUtil.java @@ -10,7 +10,7 @@ import net.minecraft.world.entity.ai.attributes.AttributeModifier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.player.Player; -import net.minecraftforge.common.ForgeMod; +import net.neoforged.neoforge.common.NeoForgeMod; public class AttributesUtil { diff --git a/src/main/java/com/lothrazar/library/util/AutoSprintUtil.java b/src/main/java/com/lothrazar/library/util/AutoSprintUtil.java index 81d3f32..c81a1f8 100644 --- a/src/main/java/com/lothrazar/library/util/AutoSprintUtil.java +++ b/src/main/java/com/lothrazar/library/util/AutoSprintUtil.java @@ -9,8 +9,8 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; @OnlyIn(Dist.CLIENT) public class AutoSprintUtil { diff --git a/src/main/java/com/lothrazar/library/util/BlockstatesUtil.java b/src/main/java/com/lothrazar/library/util/BlockstatesUtil.java index 58f8423..8977553 100644 --- a/src/main/java/com/lothrazar/library/util/BlockstatesUtil.java +++ b/src/main/java/com/lothrazar/library/util/BlockstatesUtil.java @@ -9,7 +9,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.common.Tags; +import net.neoforged.neoforge.common.Tags; public class BlockstatesUtil { diff --git a/src/main/java/com/lothrazar/library/util/EnchantUtil.java b/src/main/java/com/lothrazar/library/util/EnchantUtil.java index 4a9f155..1ffc3f7 100644 --- a/src/main/java/com/lothrazar/library/util/EnchantUtil.java +++ b/src/main/java/com/lothrazar/library/util/EnchantUtil.java @@ -10,7 +10,7 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.neoforge.registries.ForgeRegistries; public class EnchantUtil { diff --git a/src/main/java/com/lothrazar/library/util/EntityUtil.java b/src/main/java/com/lothrazar/library/util/EntityUtil.java index bfb988d..b705955 100644 --- a/src/main/java/com/lothrazar/library/util/EntityUtil.java +++ b/src/main/java/com/lothrazar/library/util/EntityUtil.java @@ -51,7 +51,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.common.util.FakePlayer; +import net.neoforged.neoforge.common.util.FakePlayer; public class EntityUtil { diff --git a/src/main/java/com/lothrazar/library/util/FakePlayerUtil.java b/src/main/java/com/lothrazar/library/util/FakePlayerUtil.java index edb7b5a..fc0476d 100644 --- a/src/main/java/com/lothrazar/library/util/FakePlayerUtil.java +++ b/src/main/java/com/lothrazar/library/util/FakePlayerUtil.java @@ -39,11 +39,11 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.phys.BlockHitResult; -import net.minecraftforge.common.util.FakePlayer; -import net.minecraftforge.common.util.FakePlayerFactory; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.ItemStackHandler; +import net.neoforged.neoforge.common.util.FakePlayer; +import net.neoforged.neoforge.common.util.FakePlayerFactory; +import net.neoforged.neoforge.common.util.LazyOptional; +import net.neoforged.neoforge.items.IItemHandler; +import net.neoforged.neoforge.items.ItemStackHandler; public class FakePlayerUtil { diff --git a/src/main/java/com/lothrazar/library/util/ItemStackUtil.java b/src/main/java/com/lothrazar/library/util/ItemStackUtil.java index 3b35f26..db08bb4 100644 --- a/src/main/java/com/lothrazar/library/util/ItemStackUtil.java +++ b/src/main/java/com/lothrazar/library/util/ItemStackUtil.java @@ -17,8 +17,8 @@ import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.neoforge.items.IItemHandler; +import net.neoforged.neoforge.registries.ForgeRegistries; public class ItemStackUtil { diff --git a/src/main/java/com/lothrazar/library/util/ParticleUtil.java b/src/main/java/com/lothrazar/library/util/ParticleUtil.java index 8651a66..edaafb6 100644 --- a/src/main/java/com/lothrazar/library/util/ParticleUtil.java +++ b/src/main/java/com/lothrazar/library/util/ParticleUtil.java @@ -12,8 +12,8 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.Level; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; public class ParticleUtil { diff --git a/src/main/java/com/lothrazar/library/util/RecipeUtil.java b/src/main/java/com/lothrazar/library/util/RecipeUtil.java index d7ad7d2..acdd9f2 100644 --- a/src/main/java/com/lothrazar/library/util/RecipeUtil.java +++ b/src/main/java/com/lothrazar/library/util/RecipeUtil.java @@ -10,8 +10,8 @@ import net.minecraft.util.GsonHelper; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.material.Fluid; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.neoforge.fluids.FluidStack; +import net.neoforged.neoforge.registries.ForgeRegistries; public class RecipeUtil { diff --git a/src/main/java/com/lothrazar/library/util/RenderBlockUtils.java b/src/main/java/com/lothrazar/library/util/RenderBlockUtils.java index 69f2984..be31b9c 100644 --- a/src/main/java/com/lothrazar/library/util/RenderBlockUtils.java +++ b/src/main/java/com/lothrazar/library/util/RenderBlockUtils.java @@ -34,9 +34,9 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.client.event.RenderLevelStageEvent; -import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions; -import net.minecraftforge.fluids.FluidStack; +import net.neoforged.neoforge.client.event.RenderLevelStageEvent; +import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions; +import net.neoforged.neoforge.fluids.FluidStack; /** * legacy ref https://www.minecraftforge.net/forum/topic/79556-1151-rendering-block-manually-clientside/?tab=comments#comment-379808 diff --git a/src/main/java/com/lothrazar/library/util/RenderUtil.java b/src/main/java/com/lothrazar/library/util/RenderUtil.java index b0e4876..87d126d 100644 --- a/src/main/java/com/lothrazar/library/util/RenderUtil.java +++ b/src/main/java/com/lothrazar/library/util/RenderUtil.java @@ -11,8 +11,8 @@ import net.minecraft.client.renderer.RenderType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; public class RenderUtil { diff --git a/src/main/java/com/lothrazar/library/util/SoundUtil.java b/src/main/java/com/lothrazar/library/util/SoundUtil.java index 4ee600d..9808d80 100644 --- a/src/main/java/com/lothrazar/library/util/SoundUtil.java +++ b/src/main/java/com/lothrazar/library/util/SoundUtil.java @@ -11,7 +11,7 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.neoforge.registries.ForgeRegistries; public class SoundUtil { diff --git a/src/main/java/com/lothrazar/library/util/StringParseUtil.java b/src/main/java/com/lothrazar/library/util/StringParseUtil.java index 1385785..28cec25 100644 --- a/src/main/java/com/lothrazar/library/util/StringParseUtil.java +++ b/src/main/java/com/lothrazar/library/util/StringParseUtil.java @@ -26,7 +26,7 @@ import java.util.List; import com.lothrazar.library.FutureLibMod; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.fluids.capability.IFluidHandler; +import net.neoforged.neoforge.fluids.capability.IFluidHandler; public class StringParseUtil { From 9578fe95cdcb43c3ed4401a6b8d48686020a811b Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 31 Mar 2026 19:10:53 -0700 Subject: [PATCH 04/29] update capabilities gui packets enchants resourcelocation transit --- .../com/lothrazar/library/FutureLibMod.java | 25 ++--- .../item/CapabilityProviderEnergyStack.java | 28 ++--- .../cap/item/EnergyCapabilityItemStack.java | 100 ++++++++++-------- .../cap/item/FluidHandlerCapabilityStack.java | 73 ++++++------- .../library/cap/player/PlayerCapProvider.java | 77 ++++++-------- .../cap/player/PlayerCapabilityStorage.java | 12 ++- .../library/config/ConfigTemplate.java | 19 +--- .../library/dim/DimensionTransit.java | 8 ++ .../library/enchant/EnchantmentFlib.java | 85 ++++++--------- .../library/events/CapabilityEvents.java | 62 ++++------- .../lothrazar/library/events/EventFlib.java | 2 +- .../lothrazar/library/gui/ContainerFlib.java | 7 +- .../com/lothrazar/library/gui/EnergyBar.java | 4 +- .../com/lothrazar/library/gui/FluidBar.java | 4 +- .../lothrazar/library/item/BlockItemFlib.java | 3 +- .../com/lothrazar/library/item/ItemFlib.java | 8 +- .../lothrazar/library/mod/CommandModule.java | 8 +- .../lothrazar/library/mod/ConfigModule.java | 17 +-- .../library/mod/FlibRegistrations.java | 25 +++-- .../lothrazar/library/mod/PacketRegistry.java | 32 +++--- .../lothrazar/library/packet/PacketFlib.java | 13 ++- .../library/packet/PacketItemToggle.java | 61 ++++++----- .../packet/PacketPlayerFalldamage.java | 44 ++++---- .../library/packet/PacketRotateBlock.java | 93 ++++++++-------- .../library/packet/PacketSyncEnergy.java | 84 ++++++--------- .../library/packet/PacketSyncFluid.java | 90 ++++++---------- .../particle/AbstractSingleQuadParticle.java | 2 +- .../conditions/EntityExistsCondition.java | 64 ++++------- .../recipe/ingredient/FluidTagIngredient.java | 8 +- .../registry/RecipeCauldronFactory.java | 7 +- .../render/type/FakeBlockRenderTypes.java | 2 +- .../library/render/type/LaserRenderType.java | 6 +- .../lothrazar/library/util/EntityUtil.java | 2 +- .../library/util/FakePlayerUtil.java | 23 ++-- .../library/util/LevelWorldUtil.java | 2 +- .../lothrazar/library/util/PacketUtil.java | 17 ++- .../lothrazar/library/util/RecipeUtil.java | 8 +- .../com/lothrazar/library/util/SoundUtil.java | 4 +- .../library/util/StringParseUtil.java | 2 +- 39 files changed, 512 insertions(+), 619 deletions(-) diff --git a/src/main/java/com/lothrazar/library/FutureLibMod.java b/src/main/java/com/lothrazar/library/FutureLibMod.java index 04f3c6c..3d87402 100644 --- a/src/main/java/com/lothrazar/library/FutureLibMod.java +++ b/src/main/java/com/lothrazar/library/FutureLibMod.java @@ -2,15 +2,15 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import com.lothrazar.library.cap.player.PlayerCapProvider; import com.lothrazar.library.events.FlibBlockEvents; import com.lothrazar.library.mod.CommandModule; import com.lothrazar.library.mod.ConfigModule; +import com.lothrazar.library.mod.FlibRegistrations; import com.lothrazar.library.mod.PacketRegistry; import net.neoforged.bus.api.IEventBus; -import net.neoforged.fml.InterModComms; +import net.neoforged.fml.ModContainer; import net.neoforged.fml.common.Mod; -import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; @Mod(FutureLibMod.MODID) public class FutureLibMod { @@ -18,21 +18,12 @@ public class FutureLibMod { public static final String MODID = "flib"; public static final Logger LOGGER = LogManager.getLogger(); - /** - * all "content" of the mod such as built in commands are in the 'library.mod' package, to keep it split up from the rest of the library code - */ - public FutureLibMod() { - new ConfigModule(); + public FutureLibMod(IEventBus modEventBus, ModContainer modContainer) { + new ConfigModule(modContainer); new CommandModule(); new FlibBlockEvents(); - IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus(); - bus.addListener(this::setup); - } - - private void setup(final FMLCommonSetupEvent event) { - PacketRegistry.setup(); - InterModComms.getMessages(MODID).forEach(x -> { - LOGGER.info("registration from " + x.senderModId() + " | " + x.messageSupplier().get()); - }); + PlayerCapProvider.ATTACHMENT_TYPES.register(modEventBus); + FlibRegistrations.register(modEventBus); + modEventBus.addListener(PacketRegistry::onRegisterPayloads); } } diff --git a/src/main/java/com/lothrazar/library/cap/item/CapabilityProviderEnergyStack.java b/src/main/java/com/lothrazar/library/cap/item/CapabilityProviderEnergyStack.java index 646cd01..a7700ea 100644 --- a/src/main/java/com/lothrazar/library/cap/item/CapabilityProviderEnergyStack.java +++ b/src/main/java/com/lothrazar/library/cap/item/CapabilityProviderEnergyStack.java @@ -1,41 +1,33 @@ package com.lothrazar.library.cap.item; import com.lothrazar.library.cap.CustomEnergyStorage; -import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.common.capabilities.ICapabilitySerializable; -import net.neoforged.neoforge.common.util.LazyOptional; -import net.neoforged.neoforge.energy.IEnergyStorage; -public class CapabilityProviderEnergyStack implements ICapabilitySerializable { +/** + * Simple energy storage wrapper for items. + * In NeoForge 1.21+, attach this to an item via RegisterCapabilitiesEvent: + * event.registerItem(Capabilities.EnergyStorage.ITEM, + * (stack, ctx) -> new CapabilityProviderEnergyStack(maxEnergy).getEnergyStorage(), myItem); + */ +public class CapabilityProviderEnergyStack { private static final String NBTENERGY = "energy"; - CustomEnergyStorage energy; - private LazyOptional energyCap = LazyOptional.of(() -> energy); + private final CustomEnergyStorage energy; public CapabilityProviderEnergyStack(int max) { energy = new CustomEnergyStorage(max, max); - energyCap = LazyOptional.of(() -> energy); } - @Override - public LazyOptional getCapability(Capability cap, Direction side) { - if (cap == ForgeCapabilities.ENERGY) { - return energyCap.cast(); - } - return LazyOptional.empty(); + public CustomEnergyStorage getEnergyStorage() { + return energy; } - @Override public CompoundTag serializeNBT() { CompoundTag tag = new CompoundTag(); tag.put(NBTENERGY, energy.serializeNBT()); return tag; } - @Override public void deserializeNBT(CompoundTag nbt) { energy.deserializeNBT(nbt.getCompound(NBTENERGY)); } diff --git a/src/main/java/com/lothrazar/library/cap/item/EnergyCapabilityItemStack.java b/src/main/java/com/lothrazar/library/cap/item/EnergyCapabilityItemStack.java index 9cc01c0..8be8fcd 100644 --- a/src/main/java/com/lothrazar/library/cap/item/EnergyCapabilityItemStack.java +++ b/src/main/java/com/lothrazar/library/cap/item/EnergyCapabilityItemStack.java @@ -1,63 +1,75 @@ package com.lothrazar.library.cap.item; -import com.lothrazar.library.cap.CustomEnergyStorage; -import net.minecraft.core.Direction; +import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.common.capabilities.ICapabilityProvider; -import net.neoforged.neoforge.common.util.LazyOptional; +import net.minecraft.world.item.component.CustomData; import net.neoforged.neoforge.energy.IEnergyStorage; -public class EnergyCapabilityItemStack implements ICapabilityProvider { +/** + * IEnergyStorage that reads/writes energy to an ItemStack's CustomData component. + * In NeoForge 1.21+, register this via RegisterCapabilitiesEvent: + * event.registerItem(Capabilities.EnergyStorage.ITEM, + * (stack, ctx) -> new EnergyCapabilityItemStack(stack, maxEnergy), myItem); + */ +public class EnergyCapabilityItemStack implements IEnergyStorage { public static final String NBTENERGY = "energy"; - private LazyOptional energy = LazyOptional.of(this::createEnergy); - // private ItemStack stack; - private int max; - private ItemStack stack; - - private IEnergyStorage createEnergy() { - return new CustomEnergyStorage(max, max / 4) { - - @Override - public int getEnergyStored() { - if (stack.hasTag()) { - return stack.getTag().getInt(NBTENERGY); - } - else { - return super.getEnergyStored(); - } - } - - @Override - public void setEnergy(int energy) { - if (!stack.hasTag()) { - stack.setTag(new CompoundTag()); - } - stack.getTag().putInt(NBTENERGY, energy); - super.setEnergy(energy); - } - }; - } + private final ItemStack stack; + private final int max; public EnergyCapabilityItemStack(final ItemStack stack, int capacity) { - this.max = capacity; this.stack = stack; - energy = LazyOptional.of(this::createEnergy); + this.max = capacity; } @Override - public String toString() { - return "EnergyCapabilityItemStack [energy=" + energy + ", max=" + max + "]"; + public int receiveEnergy(int maxReceive, boolean simulate) { + if (!canReceive()) return 0; + int stored = getEnergyStored(); + int received = Math.min(max - stored, Math.min(max / 4, maxReceive)); + if (!simulate) setEnergyStored(stored + received); + return received; + } + + @Override + public int extractEnergy(int maxExtract, boolean simulate) { + if (!canExtract()) return 0; + int stored = getEnergyStored(); + int extracted = Math.min(stored, maxExtract); + if (!simulate) setEnergyStored(stored - extracted); + return extracted; + } + + @Override + public int getEnergyStored() { + CustomData data = stack.get(DataComponents.CUSTOM_DATA); + return data != null ? data.copyTag().getInt(NBTENERGY) : 0; + } + + @Override + public int getMaxEnergyStored() { + return max; + } + + @Override + public boolean canExtract() { + return true; } @Override - public LazyOptional getCapability(Capability capability, Direction facing) { - if (ForgeCapabilities.ENERGY == capability) { - return energy.cast(); - } - return LazyOptional.empty(); + public boolean canReceive() { + return true; + } + + private void setEnergyStored(int value) { + CompoundTag tag = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag(); + tag.putInt(NBTENERGY, Math.max(0, Math.min(value, max))); + stack.set(DataComponents.CUSTOM_DATA, CustomData.of(tag)); + } + + @Override + public String toString() { + return "EnergyCapabilityItemStack [energy=" + getEnergyStored() + ", max=" + max + "]"; } } diff --git a/src/main/java/com/lothrazar/library/cap/item/FluidHandlerCapabilityStack.java b/src/main/java/com/lothrazar/library/cap/item/FluidHandlerCapabilityStack.java index 2be6aa9..67ff6ee 100644 --- a/src/main/java/com/lothrazar/library/cap/item/FluidHandlerCapabilityStack.java +++ b/src/main/java/com/lothrazar/library/cap/item/FluidHandlerCapabilityStack.java @@ -1,29 +1,24 @@ package com.lothrazar.library.cap.item; -import net.minecraft.core.Direction; +import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.common.capabilities.ICapabilityProvider; -import net.neoforged.neoforge.common.util.LazyOptional; +import net.minecraft.world.item.component.CustomData; import net.neoforged.neoforge.fluids.FluidStack; import net.neoforged.neoforge.fluids.capability.IFluidHandlerItem; -import net.neoforged.neoforge.fluids.capability.templates.FluidHandlerItemStack; -public class FluidHandlerCapabilityStack implements IFluidHandlerItem, ICapabilityProvider { +/** + * IFluidHandlerItem that reads/writes a single fluid to an ItemStack's CustomData component. + * In NeoForge 1.21+, register this via RegisterCapabilitiesEvent: + * event.registerItem(Capabilities.FluidHandler.ITEM, + * (stack, ctx) -> new FluidHandlerCapabilityStack(stack, capacity), myItem); + */ +public class FluidHandlerCapabilityStack implements IFluidHandlerItem { - public static final String FLUID_NBT_KEY = FluidHandlerItemStack.FLUID_NBT_KEY; - private final LazyOptional holder = LazyOptional.of(() -> this); + public static final String FLUID_NBT_KEY = "Fluid"; protected ItemStack container; protected int capacity; - /** - * @param container - * The container itemStack, data is stored on it directly as NBT. - * @param capacity - * The maximum capacity of this fluid tank. - */ public FluidHandlerCapabilityStack(ItemStack container, int capacity) { this.container = container; this.capacity = capacity; @@ -34,21 +29,32 @@ public ItemStack getContainer() { return container; } + private CompoundTag getContainerTag() { + return container.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag(); + } + + private void setContainerTag(CompoundTag tag) { + container.set(DataComponents.CUSTOM_DATA, CustomData.of(tag)); + } + public FluidStack getFluid() { - CompoundTag tagCompound = container.getTag(); - if (tagCompound == null || !tagCompound.contains(FLUID_NBT_KEY)) { + CompoundTag tag = getContainerTag(); + if (!tag.contains(FLUID_NBT_KEY)) { return FluidStack.EMPTY; } - return FluidStack.loadFluidStackFromNBT(tagCompound.getCompound(FLUID_NBT_KEY)); + return FluidStack.parseOptional(null, tag.getCompound(FLUID_NBT_KEY)); } public void setFluid(FluidStack fluid) { - if (!container.hasTag()) { - container.setTag(new CompoundTag()); + CompoundTag tag = getContainerTag(); + if (fluid.isEmpty()) { + tag.remove(FLUID_NBT_KEY); + } else { + CompoundTag fluidTag = new CompoundTag(); + fluid.save(null, fluidTag); + tag.put(FLUID_NBT_KEY, fluidTag); } - CompoundTag fluidTag = new CompoundTag(); - fluid.writeToNBT(fluidTag); - container.getTag().put(FLUID_NBT_KEY, fluidTag); + setContainerTag(tag); } @Override @@ -85,8 +91,7 @@ public int fill(FluidStack resource, FluidAction doFill) { setFluid(filled); } return fillAmount; - } - else { + } else { if (contained.isFluidEqual(resource)) { int fillAmount = Math.min(capacity - contained.getAmount(), resource.getAmount()); if (doFill.execute() && fillAmount > 0) { @@ -123,8 +128,7 @@ public FluidStack drain(int maxDrain, FluidAction action) { contained.shrink(drainAmount); if (contained.isEmpty()) { setContainerToEmpty(); - } - else { + } else { setFluid(contained); } } @@ -139,19 +143,10 @@ public boolean canDrainFluidType(FluidStack fluid) { return true; } - /** - * Override this method for special handling. Can be used to swap out or destroy the container. - */ protected void setContainerToEmpty() { - container.removeTagKey(FLUID_NBT_KEY); - } - - @Override - public LazyOptional getCapability(Capability capability, Direction facing) { - if (ForgeCapabilities.FLUID_HANDLER_ITEM == capability) { - return holder.cast(); - } - return LazyOptional.empty(); + CompoundTag tag = getContainerTag(); + tag.remove(FLUID_NBT_KEY); + setContainerTag(tag); } @Override diff --git a/src/main/java/com/lothrazar/library/cap/player/PlayerCapProvider.java b/src/main/java/com/lothrazar/library/cap/player/PlayerCapProvider.java index accd056..a3ebc97 100644 --- a/src/main/java/com/lothrazar/library/cap/player/PlayerCapProvider.java +++ b/src/main/java/com/lothrazar/library/cap/player/PlayerCapProvider.java @@ -1,49 +1,34 @@ package com.lothrazar.library.cap.player; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.CapabilityManager; -import net.minecraftforge.common.capabilities.CapabilityToken; -import net.minecraftforge.common.capabilities.ICapabilityProvider; -import net.neoforged.neoforge.common.util.INBTSerializable; -import net.neoforged.neoforge.common.util.LazyOptional; - -public class PlayerCapProvider implements ICapabilityProvider, INBTSerializable { - - public static Capability PLAYERCAP = CapabilityManager.get(new CapabilityToken<>() { - //empty by design - }); - private PlayerCapabilityStorage playerMana = null; - private final LazyOptional opt = LazyOptional.of(this::createMe); - - private PlayerCapabilityStorage createMe() { - if (playerMana == null) { - playerMana = new PlayerCapabilityStorage(); - } - return playerMana; - } - - @Override - public LazyOptional getCapability(Capability cap) { - if (cap == PLAYERCAP) { - return opt.cast(); - } - return LazyOptional.empty(); - } - - @Override - public LazyOptional getCapability(Capability cap, Direction side) { - return getCapability(cap); - } - - @Override - public CompoundTag serializeNBT() { - return createMe().write(); - } - - @Override - public void deserializeNBT(CompoundTag nbt) { - createMe().read(nbt); - } +import com.lothrazar.library.FutureLibMod; +import java.util.function.Supplier; +import net.minecraft.resources.ResourceLocation; +import net.neoforged.neoforge.attachment.AttachmentType; +import net.neoforged.neoforge.capabilities.EntityCapability; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.neoforge.registries.NeoForgeRegistries; + +public class PlayerCapProvider { + + public static final DeferredRegister> ATTACHMENT_TYPES = + DeferredRegister.create(NeoForgeRegistries.Keys.ATTACHMENT_TYPES, FutureLibMod.MODID); + + /** + * Per-player mana storage, persists across death and dimension changes via AttachmentType serialization. + */ + public static final Supplier> PLAYER_MANA = + ATTACHMENT_TYPES.register("player_mana", () -> + AttachmentType.builder(PlayerCapabilityStorage::new) + .serialize(PlayerCapabilityStorage.CODEC) + .build()); + + /** + * EntityCapability key for accessing player mana. + * Usage: player.getCapability(PlayerCapProvider.PLAYER_MANA_CAP) + * Returns null for non-player entities. + */ + public static final EntityCapability PLAYER_MANA_CAP = + EntityCapability.createVoid( + ResourceLocation.fromNamespaceAndPath(FutureLibMod.MODID, "player_mana"), + PlayerCapabilityStorage.class); } diff --git a/src/main/java/com/lothrazar/library/cap/player/PlayerCapabilityStorage.java b/src/main/java/com/lothrazar/library/cap/player/PlayerCapabilityStorage.java index 9b03adf..399ce6e 100644 --- a/src/main/java/com/lothrazar/library/cap/player/PlayerCapabilityStorage.java +++ b/src/main/java/com/lothrazar/library/cap/player/PlayerCapabilityStorage.java @@ -1,13 +1,19 @@ package com.lothrazar.library.cap.player; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.nbt.CompoundTag; public class PlayerCapabilityStorage { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> + instance.group(Codec.INT.fieldOf("mana").forGetter(PlayerCapabilityStorage::getMana)) + .apply(instance, PlayerCapabilityStorage::new)); + int mana; - public PlayerCapabilityStorage(int readInt) { - mana = readInt; + public PlayerCapabilityStorage(int mana) { + this.mana = mana; } public PlayerCapabilityStorage() {} @@ -46,4 +52,4 @@ public void read(CompoundTag compound) { public String toString() { return "PlayerCapabilityStorage [mana=" + mana + "]"; } -} \ No newline at end of file +} diff --git a/src/main/java/com/lothrazar/library/config/ConfigTemplate.java b/src/main/java/com/lothrazar/library/config/ConfigTemplate.java index 0d60031..93d267a 100644 --- a/src/main/java/com/lothrazar/library/config/ConfigTemplate.java +++ b/src/main/java/com/lothrazar/library/config/ConfigTemplate.java @@ -1,24 +1,11 @@ package com.lothrazar.library.config; -import com.electronwill.nightconfig.core.file.CommentedFileConfig; -import com.electronwill.nightconfig.core.io.WritingMode; -import net.minecraftforge.common.ForgeConfigSpec; -import net.minecraftforge.common.ForgeConfigSpec.Builder; -import net.neoforged.fml.loading.FMLPaths; +import net.neoforged.neoforge.common.ModConfigSpec; +import net.neoforged.neoforge.common.ModConfigSpec.Builder; public abstract class ConfigTemplate { - public CommentedFileConfig setup(final String modid) { - final CommentedFileConfig configData = CommentedFileConfig.builder(FMLPaths.CONFIGDIR.get().resolve(modid + ".toml")) - .sync() - .autosave() - .writingMode(WritingMode.REPLACE) - .build(); - configData.load(); - return configData; - } - public static Builder builder() { - return new ForgeConfigSpec.Builder(); + return new ModConfigSpec.Builder(); } } diff --git a/src/main/java/com/lothrazar/library/dim/DimensionTransit.java b/src/main/java/com/lothrazar/library/dim/DimensionTransit.java index 3f9766e..42eff81 100644 --- a/src/main/java/com/lothrazar/library/dim/DimensionTransit.java +++ b/src/main/java/com/lothrazar/library/dim/DimensionTransit.java @@ -12,6 +12,7 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.portal.DimensionTransition; import net.minecraft.world.level.portal.PortalInfo; import net.minecraft.world.phys.Vec3; import net.neoforged.neoforge.common.util.ITeleporter; @@ -58,6 +59,10 @@ public Entity placeEntity(Entity newEntity, ServerLevel currentWorld, ServerLeve return repositionEntity.apply(false); //Must be false or we fall on vanilla. thanks /Mrbysco/TelePastries/ } + /** + * wrapper for Player::changeDimension + * @param player + */ public void teleport(Player player) { if (!player.isCreative() && !player.level().isClientSide) { player.addEffect(new MobEffectInstance(MobEffects.DAMAGE_RESISTANCE, 200, 200, false, false)); @@ -67,6 +72,9 @@ public void teleport(Player player) { this.world.playSound(player, target.getX() + 0.5D, target.getY() + 0.5D, target.getZ() + 0.5D, SoundEvents.PORTAL_TRAVEL, SoundSource.MASTER, 0.25F, this.world.random.nextFloat() * 0.4F + 0.8F); // player.changeDimension(dim, this); } + //now actually teleport + + player.changeDimension(new DimensionTransition()); } public ServerLevel getTargetLevel() { diff --git a/src/main/java/com/lothrazar/library/enchant/EnchantmentFlib.java b/src/main/java/com/lothrazar/library/enchant/EnchantmentFlib.java index cadd86b..a72d649 100644 --- a/src/main/java/com/lothrazar/library/enchant/EnchantmentFlib.java +++ b/src/main/java/com/lothrazar/library/enchant/EnchantmentFlib.java @@ -1,80 +1,61 @@ package com.lothrazar.library.enchant; +import net.minecraft.core.Holder; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.enchantment.Enchantment; -import net.minecraft.world.item.enchantment.EnchantmentCategory; import net.minecraft.world.item.enchantment.EnchantmentHelper; -public abstract class EnchantmentFlib extends Enchantment { - - protected EnchantmentFlib(Rarity rarityIn, EnchantmentCategory typeIn, EquipmentSlot[] slots) { - super(rarityIn, typeIn, slots); +/** + * Utility helpers for working with enchantments. + * + * In Minecraft 1.21+, enchantments are data-driven and cannot be subclassed directly. + * Define enchantments as JSON data files and obtain their Holder via + * level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).getOrThrow(myKey) + */ +public class EnchantmentFlib { + + public static int getCurrentLevelTool(Holder enchantment, ItemStack stack) { + if (stack.isEmpty() || stack.getItem() == Items.ENCHANTED_BOOK) return -1; + return EnchantmentHelper.getTagEnchantmentLevel(enchantment, stack); } - public abstract boolean isEnabled(); - - public int getCurrentLevelTool(ItemStack stack) { - if (stack.isEmpty() == false && EnchantmentHelper.getEnchantments(stack).containsKey(this) - && stack.getItem() != Items.ENCHANTED_BOOK) { - return EnchantmentHelper.getEnchantments(stack).get(this); - } - return -1; + public static int getCurrentArmorLevelSlot(Holder enchantment, LivingEntity entity, EquipmentSlot type) { + ItemStack armor = entity.getItemBySlot(type); + if (armor.isEmpty()) return 0; + return EnchantmentHelper.getTagEnchantmentLevel(enchantment, armor); } - protected int getCurrentArmorLevelSlot(LivingEntity player, EquipmentSlot type) { - ItemStack armor = player.getItemBySlot(type); - int level = 0; - if (armor.isEmpty() == false && EnchantmentHelper.getEnchantments(armor) != null - && EnchantmentHelper.getEnchantments(armor).containsKey(this)) { - level = EnchantmentHelper.getEnchantments(armor).get(this); - } - return level; - } - - protected int getCurrentArmorLevel(LivingEntity player) { - EquipmentSlot[] armors = new EquipmentSlot[] { - EquipmentSlot.CHEST, EquipmentSlot.FEET, EquipmentSlot.HEAD, EquipmentSlot.LEGS - }; + public static int getCurrentArmorLevel(Holder enchantment, LivingEntity entity) { + EquipmentSlot[] armors = { EquipmentSlot.CHEST, EquipmentSlot.FEET, EquipmentSlot.HEAD, EquipmentSlot.LEGS }; int level = 0; for (EquipmentSlot slot : armors) { - ItemStack armor = player.getItemBySlot(slot); - if (armor.isEmpty() == false - && EnchantmentHelper.getEnchantments(armor) != null - && EnchantmentHelper.getEnchantments(armor).containsKey(this)) { - int newlevel = EnchantmentHelper.getEnchantments(armor).get(this); - if (newlevel > level) { - level = newlevel; - } - } + int slotLevel = getCurrentArmorLevelSlot(enchantment, entity, slot); + if (slotLevel > level) level = slotLevel; } return level; } - protected int getLevelAll(LivingEntity p) { - return Math.max(getCurrentArmorLevel(p), getCurrentLevelTool(p)); + public static int getLevelAll(Holder enchantment, LivingEntity entity) { + return Math.max(getCurrentArmorLevel(enchantment, entity), getCurrentLevelTool(enchantment, entity)); } - protected ItemStack getFirstArmorStackWithEnchant(LivingEntity player) { - if (player == null) { - return ItemStack.EMPTY; - } - for (ItemStack main : player.getArmorSlots()) { - if ((main.isEmpty() == false) && EnchantmentHelper.getEnchantments(main).containsKey(this)) { - return main; + public static ItemStack getFirstArmorStackWithEnchant(Holder enchantment, LivingEntity entity) { + if (entity == null) return ItemStack.EMPTY; + for (ItemStack armor : entity.getArmorSlots()) { + if (!armor.isEmpty() && EnchantmentHelper.getTagEnchantmentLevel(enchantment, armor) > 0) { + return armor; } } return ItemStack.EMPTY; } - protected int getCurrentLevelTool(LivingEntity player) { - if (player == null) { - return -1; - } - ItemStack main = player.getMainHandItem(); - ItemStack off = player.getOffhandItem(); - return Math.max(getCurrentLevelTool(main), getCurrentLevelTool(off)); + public static int getCurrentLevelTool(Holder enchantment, LivingEntity entity) { + if (entity == null) return -1; + ItemStack main = entity.getMainHandItem(); + ItemStack off = entity.getOffhandItem(); + return Math.max(getCurrentLevelTool(enchantment, main), getCurrentLevelTool(enchantment, off)); } } diff --git a/src/main/java/com/lothrazar/library/events/CapabilityEvents.java b/src/main/java/com/lothrazar/library/events/CapabilityEvents.java index 93cecec..98f92ca 100644 --- a/src/main/java/com/lothrazar/library/events/CapabilityEvents.java +++ b/src/main/java/com/lothrazar/library/events/CapabilityEvents.java @@ -3,62 +3,40 @@ import com.lothrazar.library.FutureLibMod; import com.lothrazar.library.cap.player.PlayerCapProvider; import com.lothrazar.library.cap.player.PlayerCapabilityStorage; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.player.Player; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent; import net.neoforged.neoforge.common.NeoForge; -import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; -import net.minecraftforge.event.AttachCapabilitiesEvent; import net.neoforged.neoforge.event.entity.player.PlayerEvent; -import net.neoforged.bus.api.SubscribeEvent; /** - * NOT loaded by default load this into your event bus to pull in + * NOT loaded by default. Call {@link #register(IEventBus)} from inside your @Mod constructor to enable + * the FLib player mana capability. * - * - * Import @MinecraftForge and run - * - * MinecraftForge.EVENT_BUS.register(new CapabilityEvents()); - * - * inside of the event @FMLCommonSetupEvent + * Example: + * CapabilityEvents.register(modEventBus); */ public class CapabilityEvents { - public CapabilityEvents() { - MinecraftForge.EVENT_BUS.addGenericListener(Entity.class, CapabilityEvents::onAttachCapabilitiesPlayer); + public static void register(IEventBus modBus) { + NeoForge.EVENT_BUS.addListener(CapabilityEvents::onPlayerCloned); + modBus.addListener(CapabilityEvents::onRegisterCapabilities); + FutureLibMod.LOGGER.info("CapabilityEvents registered"); } - // When a player dies or teleports from the end capabilities are cleared. Using the PlayerEvent.Clone event - // we can detect this and copy our capability from the old player to the new one - @SubscribeEvent - public void onPlayerCloned(PlayerEvent.Clone event) { + public static void onPlayerCloned(PlayerEvent.Clone event) { if (event.isWasDeath()) { - // We need to copyFrom the capabilities - event.getOriginal().getCapability(PlayerCapProvider.PLAYERCAP).ifPresent(oldStore -> { - event.getEntity().getCapability(PlayerCapProvider.PLAYERCAP).ifPresent(newStore -> { - newStore.copyFrom(oldStore); - }); - }); + PlayerCapabilityStorage oldData = event.getOriginal().getData(PlayerCapProvider.PLAYER_MANA.get()); + event.getEntity().getData(PlayerCapProvider.PLAYER_MANA.get()).copyFrom(oldData); } } - @SubscribeEvent - public void onRegisterCapabilities(RegisterCapabilitiesEvent event) { - event.register(PlayerCapabilityStorage.class); - FutureLibMod.LOGGER.info("RegisterCapabilitiesEvent success for ManaManager"); - } - // Whenever a new object of some type is created the AttachCapabilitiesEvent will fire. In our case we want to know - // when a new player arrives so that we can attach our capability here - - // @SubscribeEvent not sub, uses MinecraftForge.EVENT_BUS.addGenericListener instead - public static void onAttachCapabilitiesPlayer(AttachCapabilitiesEvent event) { - if (event.getObject() instanceof Player) { - if (!event.getObject().getCapability(PlayerCapProvider.PLAYERCAP).isPresent()) { - // The player does not already have this capability so we need to add the capability provider here - //TODO: Data keyword string from IMC? - event.addCapability(new ResourceLocation(FutureLibMod.MODID, "data"), new PlayerCapProvider()); - FutureLibMod.LOGGER.info("CapabilityRegistry success for data"); - } - } + public static void onRegisterCapabilities(RegisterCapabilitiesEvent event) { + event.registerEntity( + PlayerCapProvider.PLAYER_MANA_CAP, + (entity, ctx) -> entity instanceof Player ? entity.getData(PlayerCapProvider.PLAYER_MANA.get()) : null, + EntityType.PLAYER); + FutureLibMod.LOGGER.info("RegisterCapabilitiesEvent success for PlayerMana"); } } diff --git a/src/main/java/com/lothrazar/library/events/EventFlib.java b/src/main/java/com/lothrazar/library/events/EventFlib.java index 560d9d1..2057f1a 100644 --- a/src/main/java/com/lothrazar/library/events/EventFlib.java +++ b/src/main/java/com/lothrazar/library/events/EventFlib.java @@ -18,6 +18,6 @@ public EventFlib() { * * inside of the event @FMLCommonSetupEvent */ - MinecraftForge.EVENT_BUS.register(this); + NeoForge.EVENT_BUS.register(this); } } diff --git a/src/main/java/com/lothrazar/library/gui/ContainerFlib.java b/src/main/java/com/lothrazar/library/gui/ContainerFlib.java index 417d4b1..784d98a 100644 --- a/src/main/java/com/lothrazar/library/gui/ContainerFlib.java +++ b/src/main/java/com/lothrazar/library/gui/ContainerFlib.java @@ -10,7 +10,7 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.common.capabilities.ForgeCapabilities; +import net.neoforged.neoforge.capabilities.Capabilities; import net.neoforged.neoforge.energy.IEnergyStorage; public abstract class ContainerFlib extends AbstractContainerMenu { @@ -30,7 +30,10 @@ protected void trackEnergy(BlockEntity tile) { @Override public int get() { - return tile.getCapability(ForgeCapabilities.ENERGY).map(IEnergyStorage::getEnergyStored).orElse(0); + IEnergyStorage storage = tile.getLevel() != null + ? tile.getLevel().getCapability(Capabilities.EnergyStorage.BLOCK, tile.getBlockPos(), tile.getBlockState(), tile, null) + : null; + return storage != null ? storage.getEnergyStored() : 0; } @Override diff --git a/src/main/java/com/lothrazar/library/gui/EnergyBar.java b/src/main/java/com/lothrazar/library/gui/EnergyBar.java index 779907b..75d4cc2 100644 --- a/src/main/java/com/lothrazar/library/gui/EnergyBar.java +++ b/src/main/java/com/lothrazar/library/gui/EnergyBar.java @@ -2,6 +2,8 @@ import java.util.ArrayList; import java.util.List; + +import com.lothrazar.library.FutureLibMod; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.network.chat.Component; @@ -9,7 +11,7 @@ public class EnergyBar { - public static final ResourceLocation ENERGY_BAR = new ResourceLocation("flib", "textures/gui/energy_bar.png"); + public static final ResourceLocation ENERGY_BAR = ResourceLocation.fromNamespaceAndPath(FutureLibMod.MODID, "textures/gui/energy_bar.png"); private int x = 154; private int y = 8; public int capacity; diff --git a/src/main/java/com/lothrazar/library/gui/FluidBar.java b/src/main/java/com/lothrazar/library/gui/FluidBar.java index d1c617b..ad38da2 100644 --- a/src/main/java/com/lothrazar/library/gui/FluidBar.java +++ b/src/main/java/com/lothrazar/library/gui/FluidBar.java @@ -2,6 +2,8 @@ import java.util.ArrayList; import java.util.List; + +import com.lothrazar.library.FutureLibMod; import com.lothrazar.library.render.FluidRenderMap; import com.lothrazar.library.render.FluidRenderMap.FluidFlow; import com.mojang.blaze3d.systems.RenderSystem; @@ -15,7 +17,7 @@ public class FluidBar { - public static final ResourceLocation FLUID_WIDGET = new ResourceLocation("flib", "textures/gui/fluid.png"); + public static final ResourceLocation FLUID_WIDGET = ResourceLocation.fromNamespaceAndPath(FutureLibMod.MODID, "textures/gui/fluid.png"); public String emtpyTooltip = "0"; private Font font; private int x; diff --git a/src/main/java/com/lothrazar/library/item/BlockItemFlib.java b/src/main/java/com/lothrazar/library/item/BlockItemFlib.java index 9b01bc1..bb06783 100644 --- a/src/main/java/com/lothrazar/library/item/BlockItemFlib.java +++ b/src/main/java/com/lothrazar/library/item/BlockItemFlib.java @@ -4,6 +4,7 @@ import com.lothrazar.library.item.ItemFlib.Settings; import net.minecraft.network.chat.Component; import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.item.crafting.RecipeType; @@ -27,7 +28,7 @@ public BlockItemFlib(Block b, Properties prop) { @Override @OnlyIn(Dist.CLIENT) - public void appendHoverText(ItemStack stack, Level worldIn, List tooltip, TooltipFlag flagIn) { + public void appendHoverText(ItemStack stack, Item.TooltipContext worldIn, List tooltip, TooltipFlag flagIn) { if (me.tooltip) { me.tooltipApply(this, tooltip); } diff --git a/src/main/java/com/lothrazar/library/item/ItemFlib.java b/src/main/java/com/lothrazar/library/item/ItemFlib.java index 74ae569..d74109f 100644 --- a/src/main/java/com/lothrazar/library/item/ItemFlib.java +++ b/src/main/java/com/lothrazar/library/item/ItemFlib.java @@ -1,6 +1,8 @@ package com.lothrazar.library.item; import java.util.List; + +import net.minecraft.world.entity.LivingEntity; import org.joml.Quaternionf; import org.joml.Vector3f; import com.lothrazar.library.util.ChatUtil; @@ -68,7 +70,7 @@ public int getBurnTime(ItemStack itemStack, RecipeType recipeType) { @Override @OnlyIn(Dist.CLIENT) - public void appendHoverText(ItemStack stack, Level worldIn, List tooltip, TooltipFlag flagIn) { + public void appendHoverText(ItemStack stack, Item.TooltipContext worldIn, List tooltip, TooltipFlag flagIn) { if (me.tooltip) { me.tooltipApply(this, tooltip); } @@ -112,7 +114,7 @@ protected ItemStack findAmmo(Player player, Item item) { return ItemStack.EMPTY; } - public float getChargedPercent(ItemStack stack, int chargeTimer) { - return BowItem.getPowerForTime(this.getUseDuration(stack) - chargeTimer); + public float getChargedPercent(ItemStack stack, int chargeTimer, LivingEntity entity) { + return BowItem.getPowerForTime(this.getUseDuration(stack, entity) - chargeTimer); } } diff --git a/src/main/java/com/lothrazar/library/mod/CommandModule.java b/src/main/java/com/lothrazar/library/mod/CommandModule.java index 6e17225..e87ec3b 100644 --- a/src/main/java/com/lothrazar/library/mod/CommandModule.java +++ b/src/main/java/com/lothrazar/library/mod/CommandModule.java @@ -461,10 +461,10 @@ public static int executePrintPlayerNbt(CommandContext ctx, public static int executePrintNbt(CommandContext ctx) throws CommandSyntaxException { ServerPlayer player = ctx.getSource().getPlayerOrException(); ItemStack held = player.getMainHandItem(); - if (held.hasTag()) { - ChatUtil.sendFeedback(ctx, held.getTag().toString()); - } - else { + net.minecraft.world.item.component.CustomData customData = held.get(net.minecraft.core.component.DataComponents.CUSTOM_DATA); + if (customData != null) { + ChatUtil.sendFeedback(ctx, customData.copyTag().toString()); + } else { ChatUtil.sendFeedback(ctx, "command.flib.nbtprint.null"); } return 0; diff --git a/src/main/java/com/lothrazar/library/mod/ConfigModule.java b/src/main/java/com/lothrazar/library/mod/ConfigModule.java index d282162..b8c10f4 100644 --- a/src/main/java/com/lothrazar/library/mod/ConfigModule.java +++ b/src/main/java/com/lothrazar/library/mod/ConfigModule.java @@ -2,23 +2,26 @@ import com.lothrazar.library.FutureLibMod; import com.lothrazar.library.config.ConfigTemplate; -import net.minecraftforge.common.ForgeConfigSpec; -import net.minecraftforge.common.ForgeConfigSpec.BooleanValue; -import net.minecraftforge.common.ForgeConfigSpec.Builder; +import net.neoforged.fml.ModContainer; +import net.neoforged.fml.config.ModConfig; +import net.neoforged.neoforge.common.ModConfigSpec; +import net.neoforged.neoforge.common.ModConfigSpec.BooleanValue; +import net.neoforged.neoforge.common.ModConfigSpec.Builder; public class ConfigModule extends ConfigTemplate { - private static ForgeConfigSpec CONFIG; + private static final ModConfigSpec CONFIG; public static BooleanValue ENABLE_COMMANDS; + static { final Builder builder = builder(); builder.comment("General settings").push(FutureLibMod.MODID); ENABLE_COMMANDS = builder.comment("If true, the /flib command will be registered").define("command.enabled", true); - builder.pop(); // one pop for every push + builder.pop(); CONFIG = builder.build(); } - public ConfigModule() { - CONFIG.setConfig(setup(FutureLibMod.MODID)); + public ConfigModule(ModContainer modContainer) { + modContainer.registerConfig(ModConfig.Type.COMMON, CONFIG); } } diff --git a/src/main/java/com/lothrazar/library/mod/FlibRegistrations.java b/src/main/java/com/lothrazar/library/mod/FlibRegistrations.java index b239b62..c47e0fd 100644 --- a/src/main/java/com/lothrazar/library/mod/FlibRegistrations.java +++ b/src/main/java/com/lothrazar/library/mod/FlibRegistrations.java @@ -1,20 +1,23 @@ package com.lothrazar.library.mod; +import com.lothrazar.library.FutureLibMod; import com.lothrazar.library.recipe.conditions.EntityExistsCondition; -import net.minecraftforge.common.crafting.CraftingHelper; -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.Mod; -import net.neoforged.neoforge.registries.ForgeRegistries; -import net.neoforged.neoforge.registries.RegisterEvent; +import com.mojang.serialization.MapCodec; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.common.conditions.ICondition; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.neoforge.registries.NeoForgeRegistries; -@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) public class FlibRegistrations { - public static final EntityExistsCondition.Serializer ENTITY_EXISTS = new EntityExistsCondition.Serializer(); + private static final DeferredRegister> CONDITIONS = + DeferredRegister.create(NeoForgeRegistries.Keys.CONDITION_CODECS, FutureLibMod.MODID); - @SubscribeEvent - public static void onRegistry(RegisterEvent event) { - event.register(ForgeRegistries.Keys.RECIPE_SERIALIZERS, - helper -> CraftingHelper.register(ENTITY_EXISTS)); + static { + CONDITIONS.register("entity_exists", () -> EntityExistsCondition.CODEC); + } + + public static void register(IEventBus modBus) { + CONDITIONS.register(modBus); } } diff --git a/src/main/java/com/lothrazar/library/mod/PacketRegistry.java b/src/main/java/com/lothrazar/library/mod/PacketRegistry.java index 63a79ed..ccc0eaf 100644 --- a/src/main/java/com/lothrazar/library/mod/PacketRegistry.java +++ b/src/main/java/com/lothrazar/library/mod/PacketRegistry.java @@ -1,23 +1,27 @@ package com.lothrazar.library.mod; -import com.lothrazar.library.FutureLibMod; +import com.lothrazar.library.packet.PacketItemToggle; import com.lothrazar.library.packet.PacketPlayerFalldamage; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.network.NetworkRegistry; -import net.minecraftforge.network.simple.SimpleChannel; +import com.lothrazar.library.packet.PacketRotateBlock; +import com.lothrazar.library.packet.PacketSyncEnergy; +import com.lothrazar.library.packet.PacketSyncFluid; +import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; +import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; +import net.neoforged.neoforge.network.registration.PayloadRegistrar; public class PacketRegistry { - private static final String PROTOCOL_VERSION = Integer.toString(1); - public static final SimpleChannel INSTANCE = NetworkRegistry.ChannelBuilder - .named(new ResourceLocation(FutureLibMod.MODID, "main_channel")) - .clientAcceptedVersions(PROTOCOL_VERSION::equals) - .serverAcceptedVersions(PROTOCOL_VERSION::equals) - .networkProtocolVersion(() -> PROTOCOL_VERSION) - .simpleChannel(); + public static void setup(FMLCommonSetupEvent event) { + // Registration now happens via RegisterPayloadHandlersEvent on the mod bus. + // This method is kept for API compatibility but does nothing. + } - public static void setup() { - int id = 0; - INSTANCE.registerMessage(id++, PacketPlayerFalldamage.class, PacketPlayerFalldamage::encode, PacketPlayerFalldamage::decode, PacketPlayerFalldamage::handle); + public static void onRegisterPayloads(RegisterPayloadHandlersEvent event) { + final PayloadRegistrar registrar = event.registrar("1"); + registrar.playToServer(PacketPlayerFalldamage.TYPE, PacketPlayerFalldamage.STREAM_CODEC, PacketPlayerFalldamage::handle); + registrar.playToServer(PacketItemToggle.TYPE, PacketItemToggle.STREAM_CODEC, PacketItemToggle::handle); + registrar.playToServer(PacketRotateBlock.TYPE, PacketRotateBlock.STREAM_CODEC, PacketRotateBlock::handle); + registrar.playToClient(PacketSyncEnergy.TYPE, PacketSyncEnergy.STREAM_CODEC, PacketSyncEnergy::handle); + registrar.playToClient(PacketSyncFluid.TYPE, PacketSyncFluid.STREAM_CODEC, PacketSyncFluid::handle); } } diff --git a/src/main/java/com/lothrazar/library/packet/PacketFlib.java b/src/main/java/com/lothrazar/library/packet/PacketFlib.java index 895fe4b..852490f 100644 --- a/src/main/java/com/lothrazar/library/packet/PacketFlib.java +++ b/src/main/java/com/lothrazar/library/packet/PacketFlib.java @@ -1,11 +1,10 @@ package com.lothrazar.library.packet; -import java.util.function.Supplier; -import net.minecraftforge.network.NetworkEvent.Context; - +/** + * Base class for FLib packets. Subclasses implement CustomPacketPayload. + * With the NeoForge 1.21+ payload system, packets are marked as handled automatically + * once the handler method returns — no explicit done() call is needed. + */ public class PacketFlib { - - public void done(Supplier ctx) { - ctx.get().setPacketHandled(true); - } + // intentionally empty } diff --git a/src/main/java/com/lothrazar/library/packet/PacketItemToggle.java b/src/main/java/com/lothrazar/library/packet/PacketItemToggle.java index c5cc076..37c28a6 100644 --- a/src/main/java/com/lothrazar/library/packet/PacketItemToggle.java +++ b/src/main/java/com/lothrazar/library/packet/PacketItemToggle.java @@ -1,52 +1,55 @@ package com.lothrazar.library.packet; -import java.util.function.Supplier; +import com.lothrazar.library.FutureLibMod; import com.lothrazar.library.core.IHasClickToggle; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.network.NetworkEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; -public class PacketItemToggle extends PacketFlib { +public class PacketItemToggle extends PacketFlib implements CustomPacketPayload { - private int slot; + public static final CustomPacketPayload.Type TYPE = + new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(FutureLibMod.MODID, "item_toggle")); + + public static final StreamCodec STREAM_CODEC = + StreamCodec.composite( + ByteBufCodecs.INT, PacketItemToggle::getSlot, + PacketItemToggle::new); + + private final int slot; public PacketItemToggle(int slot) { this.slot = slot; } - public static void handle(PacketItemToggle message, Supplier ctx) { - ctx.get().enqueueWork(() -> { - ServerPlayer player = ctx.get().getSender(); - if (player.containerMenu == null) { - return; - } + public int getSlot() { + return slot; + } + + @Override + public CustomPacketPayload.Type type() { + return TYPE; + } + + public static void handle(PacketItemToggle msg, IPayloadContext context) { + context.enqueueWork(() -> { + ServerPlayer player = (ServerPlayer) context.player(); + if (player.containerMenu == null) return; int scount = player.containerMenu.slots.size(); - //this is an edge case but it DID happen: put charmin your hotbar and then open a creative inventory tab. avoid index OOB - if (message.slot >= scount) { - //will NOT work in creative mode. slots are messed up - return; - } - Slot slotObj = player.containerMenu.getSlot(message.slot); + if (msg.slot >= scount) return; + Slot slotObj = player.containerMenu.getSlot(msg.slot); if (slotObj != null && !slotObj.getItem().isEmpty()) { ItemStack maybeCharm = slotObj.getItem(); - if (maybeCharm.getItem() instanceof IHasClickToggle) { - //example: is a charm or something - IHasClickToggle c = (IHasClickToggle) maybeCharm.getItem(); + if (maybeCharm.getItem() instanceof IHasClickToggle c) { c.toggle(player, maybeCharm); } } }); - message.done(ctx); - } - - public static PacketItemToggle decode(FriendlyByteBuf buf) { - PacketItemToggle p = new PacketItemToggle(buf.readInt()); - return p; - } - - public static void encode(PacketItemToggle msg, FriendlyByteBuf buf) { - buf.writeInt(msg.slot); } } diff --git a/src/main/java/com/lothrazar/library/packet/PacketPlayerFalldamage.java b/src/main/java/com/lothrazar/library/packet/PacketPlayerFalldamage.java index 1ebdfd2..1e24193 100644 --- a/src/main/java/com/lothrazar/library/packet/PacketPlayerFalldamage.java +++ b/src/main/java/com/lothrazar/library/packet/PacketPlayerFalldamage.java @@ -1,36 +1,36 @@ package com.lothrazar.library.packet; -import java.util.function.Supplier; +import com.lothrazar.library.FutureLibMod; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; -import net.minecraftforge.network.NetworkEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; /** - * Used by: Fan block; Launch enchant; Air charm; Climbing Glove; Scaffolding Block + * Sent client→server to reset fall distance (used by climbing, fan blocks, etc.). */ -public class PacketPlayerFalldamage extends PacketFlib { +public class PacketPlayerFalldamage extends PacketFlib implements CustomPacketPayload { - public static final int TICKS_FALLDIST_SYNC = 22; //tick every so often + public static final int TICKS_FALLDIST_SYNC = 22; - public static void handle(PacketPlayerFalldamage message, Supplier ctx) { - ctx.get().enqueueWork(() -> { - ServerPlayer player = ctx.get().getSender(); - /** - * if fall damage gets high, they take damage on landing - */ + public static final CustomPacketPayload.Type TYPE = + new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(FutureLibMod.MODID, "fall_damage")); + + public static final StreamCodec STREAM_CODEC = + StreamCodec.unit(new PacketPlayerFalldamage()); + + @Override + public CustomPacketPayload.Type type() { + return TYPE; + } + + public static void handle(PacketPlayerFalldamage msg, IPayloadContext context) { + context.enqueueWork(() -> { + ServerPlayer player = (ServerPlayer) context.player(); player.fallDistance = 0.0F; - /** - * Used to keep track of how the player is floating while gamerules should prevent that. Surpassing 80 ticks means kick - */ player.connection.aboveGroundTickCount = 0; }); - message.done(ctx); } - - public static PacketPlayerFalldamage decode(FriendlyByteBuf buf) { - PacketPlayerFalldamage message = new PacketPlayerFalldamage(); - return message; - } - - public static void encode(PacketPlayerFalldamage msg, FriendlyByteBuf buf) {} } diff --git a/src/main/java/com/lothrazar/library/packet/PacketRotateBlock.java b/src/main/java/com/lothrazar/library/packet/PacketRotateBlock.java index 54d6f69..294baf2 100644 --- a/src/main/java/com/lothrazar/library/packet/PacketRotateBlock.java +++ b/src/main/java/com/lothrazar/library/packet/PacketRotateBlock.java @@ -1,79 +1,70 @@ -/******************************************************************************* - * The MIT License (MIT) - * - * Copyright (C) 2014-2018 Sam Bassett (aka Lothrazar) - * - * 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. - ******************************************************************************/ package com.lothrazar.library.packet; -import java.util.function.Supplier; +import com.lothrazar.library.FutureLibMod; import com.lothrazar.library.util.BlockUtil; import com.lothrazar.library.util.ItemStackUtil; import com.lothrazar.library.util.SoundUtil; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import net.minecraftforge.network.NetworkEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; -public class PacketRotateBlock extends PacketFlib { +public class PacketRotateBlock extends PacketFlib implements CustomPacketPayload { - private BlockPos pos; - private Direction side; - private InteractionHand hand; + public static final CustomPacketPayload.Type TYPE = + new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(FutureLibMod.MODID, "rotate_block")); - public PacketRotateBlock(BlockPos mouseover, Direction s, InteractionHand hand) { - pos = mouseover; - side = s; + private static final StreamCodec DIRECTION_CODEC = + StreamCodec.of((buf, dir) -> buf.writeEnum(dir), buf -> buf.readEnum(Direction.class)); + + private static final StreamCodec HAND_CODEC = + StreamCodec.of((buf, hand) -> buf.writeEnum(hand), buf -> buf.readEnum(InteractionHand.class)); + + public static final StreamCodec STREAM_CODEC = + StreamCodec.composite( + BlockPos.STREAM_CODEC, PacketRotateBlock::getPos, + DIRECTION_CODEC, PacketRotateBlock::getSide, + HAND_CODEC, PacketRotateBlock::getHand, + PacketRotateBlock::new); + + private final BlockPos pos; + private final Direction side; + private final InteractionHand hand; + + public PacketRotateBlock(BlockPos pos, Direction side, InteractionHand hand) { + this.pos = pos; + this.side = side; this.hand = hand; } - public static PacketRotateBlock decode(FriendlyByteBuf buf) { - return new PacketRotateBlock(buf.readBlockPos(), - Direction.values()[buf.readInt()], - InteractionHand.values()[buf.readInt()]); - } + public BlockPos getPos() { return pos; } + public Direction getSide() { return side; } + public InteractionHand getHand() { return hand; } - public static void encode(PacketRotateBlock msg, FriendlyByteBuf buf) { - buf.writeBlockPos(msg.pos); - buf.writeInt(msg.side.ordinal()); - buf.writeInt(msg.hand.ordinal()); + @Override + public CustomPacketPayload.Type type() { + return TYPE; } - public static void handle(PacketRotateBlock message, Supplier ctx) { - ctx.get().enqueueWork(() -> { - //rotate type - Level level = ctx.get().getSender().level(); - boolean succ = BlockUtil.rotateBlockValidState(level, message.pos, message.side); + public static void handle(PacketRotateBlock msg, IPayloadContext context) { + context.enqueueWork(() -> { + ServerPlayer player = (ServerPlayer) context.player(); + Level level = player.level(); + boolean succ = BlockUtil.rotateBlockValidState(level, msg.pos, msg.side); if (succ) { - ServerPlayer player = ctx.get().getSender(); - ItemStack itemStackHeld = player.getItemInHand(message.hand); + ItemStack itemStackHeld = player.getItemInHand(msg.hand); ItemStackUtil.damageItem(player, itemStackHeld); - if (level.getBlockState(message.pos).getSoundType() != null) { - SoundUtil.playSoundFromServer(player, level.getBlockState(message.pos).getSoundType().getPlaceSound(), 1F, 1F); + if (level.getBlockState(msg.pos).getSoundType() != null) { + SoundUtil.playSoundFromServer(player, level.getBlockState(msg.pos).getSoundType().getPlaceSound(), 1F, 1F); } } }); - message.done(ctx); } } diff --git a/src/main/java/com/lothrazar/library/packet/PacketSyncEnergy.java b/src/main/java/com/lothrazar/library/packet/PacketSyncEnergy.java index 8f64840..4e08098 100644 --- a/src/main/java/com/lothrazar/library/packet/PacketSyncEnergy.java +++ b/src/main/java/com/lothrazar/library/packet/PacketSyncEnergy.java @@ -1,71 +1,53 @@ -/******************************************************************************* - * The MIT License (MIT) - * - * Copyright (C) 2014-2018 Sam Bassett (aka Lothrazar) - * - * 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. - ******************************************************************************/ package com.lothrazar.library.packet; -import java.util.function.Supplier; +import com.lothrazar.library.FutureLibMod; import com.lothrazar.library.core.IHasEnergy; import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.network.NetworkEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; /** - * Forge docs suggest using a direct packet to keep capabilities, such as power, in sync with the client according to https://mcforge.readthedocs.io/en/latest/datastorage/capabilities/ + * Sent server→client to sync energy level on a block entity. */ -public class PacketSyncEnergy extends PacketFlib { +public class PacketSyncEnergy extends PacketFlib implements CustomPacketPayload { - private BlockPos pos; - private int energy; + public static final CustomPacketPayload.Type TYPE = + new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(FutureLibMod.MODID, "sync_energy")); - public PacketSyncEnergy(BlockPos p, int fluid) { - pos = p; - this.energy = fluid; - } + public static final StreamCodec STREAM_CODEC = + StreamCodec.composite( + BlockPos.STREAM_CODEC, PacketSyncEnergy::getPos, + ByteBufCodecs.INT, PacketSyncEnergy::getEnergy, + PacketSyncEnergy::new); - public static void handle(PacketSyncEnergy message, Supplier ctx) { - ctx.get().enqueueWork(() -> { - doWork(message); - }); - message.done(ctx); - } + private final BlockPos pos; + private final int energy; - private static void doWork(PacketSyncEnergy message) { - BlockEntity te = Minecraft.getInstance().level.getBlockEntity(message.pos); - if (te instanceof IHasEnergy tile) { - tile.setEnergy(message.energy); - } + public PacketSyncEnergy(BlockPos pos, int energy) { + this.pos = pos; + this.energy = energy; } - public static PacketSyncEnergy decode(FriendlyByteBuf buf) { - PacketSyncEnergy msg = new PacketSyncEnergy(buf.readBlockPos(), - buf.readInt()); - return msg; + public BlockPos getPos() { return pos; } + public int getEnergy() { return energy; } + + @Override + public CustomPacketPayload.Type type() { + return TYPE; } - public static void encode(PacketSyncEnergy msg, FriendlyByteBuf buf) { - buf.writeBlockPos(msg.pos); - buf.writeInt(msg.energy); + public static void handle(PacketSyncEnergy msg, IPayloadContext context) { + context.enqueueWork(() -> { + BlockEntity te = Minecraft.getInstance().level.getBlockEntity(msg.pos); + if (te instanceof IHasEnergy tile) { + tile.setEnergy(msg.energy); + } + }); } } diff --git a/src/main/java/com/lothrazar/library/packet/PacketSyncFluid.java b/src/main/java/com/lothrazar/library/packet/PacketSyncFluid.java index e6709cc..02f9801 100644 --- a/src/main/java/com/lothrazar/library/packet/PacketSyncFluid.java +++ b/src/main/java/com/lothrazar/library/packet/PacketSyncFluid.java @@ -1,74 +1,54 @@ -/******************************************************************************* - * The MIT License (MIT) - * - * Copyright (C) 2014-2018 Sam Bassett (aka Lothrazar) - * - * 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. - ******************************************************************************/ package com.lothrazar.library.packet; -import java.util.function.Supplier; +import com.lothrazar.library.FutureLibMod; import com.lothrazar.library.core.IHasFluid; import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.entity.BlockEntity; import net.neoforged.neoforge.fluids.FluidStack; -import net.minecraftforge.network.NetworkEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; -public class PacketSyncFluid extends PacketFlib { +/** + * Sent server→client to sync fluid content on a block entity. + */ +public class PacketSyncFluid extends PacketFlib implements CustomPacketPayload { - private BlockPos pos; - private FluidStack fluid; + public static final CustomPacketPayload.Type TYPE = + new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(FutureLibMod.MODID, "sync_fluid")); - public PacketSyncFluid(BlockPos p, FluidStack fluid) { - pos = p; - this.fluid = fluid; - } + public static final StreamCodec STREAM_CODEC = + StreamCodec.composite( + BlockPos.STREAM_CODEC, PacketSyncFluid::getPos, + FluidStack.STREAM_CODEC, PacketSyncFluid::getFluid, + PacketSyncFluid::new); - public static void handle(PacketSyncFluid message, Supplier ctx) { - ctx.get().enqueueWork(() -> { - doWork(message); - }); - message.done(ctx); - } + private final BlockPos pos; + private final FluidStack fluid; - private static void doWork(PacketSyncFluid message) { - BlockEntity te = Minecraft.getInstance().level.getBlockEntity(message.pos); - if (te instanceof IHasFluid tile) { - tile.setFluid(message.fluid); - } + public PacketSyncFluid(BlockPos pos, FluidStack fluid) { + this.pos = pos; + this.fluid = fluid; } - public static PacketSyncFluid decode(FriendlyByteBuf buf) { - PacketSyncFluid msg = new PacketSyncFluid(buf.readBlockPos(), - FluidStack.loadFluidStackFromNBT(buf.readNbt())); - return msg; + public BlockPos getPos() { return pos; } + public FluidStack getFluid() { return fluid; } + + @Override + public CustomPacketPayload.Type type() { + return TYPE; } - public static void encode(PacketSyncFluid msg, FriendlyByteBuf buf) { - buf.writeBlockPos(msg.pos); - CompoundTag tags = new CompoundTag(); - if (msg.fluid != null) { - msg.fluid.writeToNBT(tags); - } - buf.writeNbt(tags); + public static void handle(PacketSyncFluid msg, IPayloadContext context) { + context.enqueueWork(() -> { + BlockEntity te = Minecraft.getInstance().level.getBlockEntity(msg.pos); + if (te instanceof IHasFluid tile) { + tile.setFluid(msg.fluid); + } + }); } } diff --git a/src/main/java/com/lothrazar/library/particle/AbstractSingleQuadParticle.java b/src/main/java/com/lothrazar/library/particle/AbstractSingleQuadParticle.java index 29b2224..554d06e 100644 --- a/src/main/java/com/lothrazar/library/particle/AbstractSingleQuadParticle.java +++ b/src/main/java/com/lothrazar/library/particle/AbstractSingleQuadParticle.java @@ -38,7 +38,7 @@ protected AbstractSingleQuadParticle(ClientLevel world, double x, double y, doub @Override public void render(VertexConsumer buffer, Camera entityIn, float partialTicks) { - TextureManager textureManager = Minecraft.getInstance().textureManager; + TextureManager textureManager = Minecraft.getInstance().getTextureManager(); // Lighting.turnOff(); RenderSystem.depthMask(false); textureManager.bindForSetup(getTexture()); diff --git a/src/main/java/com/lothrazar/library/recipe/conditions/EntityExistsCondition.java b/src/main/java/com/lothrazar/library/recipe/conditions/EntityExistsCondition.java index c53d78f..e7deb83 100644 --- a/src/main/java/com/lothrazar/library/recipe/conditions/EntityExistsCondition.java +++ b/src/main/java/com/lothrazar/library/recipe/conditions/EntityExistsCondition.java @@ -1,63 +1,41 @@ package com.lothrazar.library.recipe.conditions; -import com.google.gson.JsonObject; -import com.lothrazar.library.FutureLibMod; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.common.crafting.conditions.ICondition; -import net.minecraftforge.common.crafting.conditions.IConditionSerializer; -import net.neoforged.neoforge.registries.ForgeRegistries; +import net.neoforged.neoforge.common.conditions.ICondition; /** - * Example: "conditions": [ {"type": "flib:entity_exists", "value": "veincreeper:coal_creeper" } ] + * Recipe condition that passes only if the given entity type is registered. + * Example JSON: + * "conditions": [{"type": "flib:entity_exists", "value": "veincreeper:coal_creeper"}] */ public class EntityExistsCondition implements ICondition { - private static final ResourceLocation ID = new ResourceLocation(FutureLibMod.MODID, "entity_exists"); - private ResourceLocation entityId; + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> + instance.group( + ResourceLocation.CODEC.fieldOf("value").forGetter(c -> c.entityId) + ).apply(instance, EntityExistsCondition::new)); - public EntityExistsCondition(ResourceLocation resourceLocation) { - this.entityId = resourceLocation; - } + private final ResourceLocation entityId; - @Override - public String toString() { - return "entity_exists(\"" + entityId + "\")"; + public EntityExistsCondition(ResourceLocation entityId) { + this.entityId = entityId; } @Override - public ResourceLocation getID() { - return ID; + public boolean test(ICondition.Context context) { + return entityId != null && BuiltInRegistries.ENTITY_TYPE.containsKey(entityId); } - // "conditions": [ - // { - // "type": "flib:entity_exists", - // "value": "veincreeper:copper_creeper" - // } - // ], @Override - public boolean test(IContext context) { - return this.entityId != null && ForgeRegistries.ENTITY_TYPES.containsKey(this.entityId); + public MapCodec codec() { + return CODEC; } - public static class Serializer implements IConditionSerializer { - - public static final Serializer INSTANCE = new Serializer(); - - @Override - public void write(JsonObject json, EntityExistsCondition value) { - json.addProperty("value", value.entityId.toString()); - } - - @Override - public EntityExistsCondition read(JsonObject json) { - String entityId = json.get("value").getAsString(); - return new EntityExistsCondition(new ResourceLocation(entityId)); - } - - @Override - public ResourceLocation getID() { - return ID; - } + @Override + public String toString() { + return "entity_exists(\"" + entityId + "\")"; } } diff --git a/src/main/java/com/lothrazar/library/recipe/ingredient/FluidTagIngredient.java b/src/main/java/com/lothrazar/library/recipe/ingredient/FluidTagIngredient.java index 38515ad..a28b9f3 100644 --- a/src/main/java/com/lothrazar/library/recipe/ingredient/FluidTagIngredient.java +++ b/src/main/java/com/lothrazar/library/recipe/ingredient/FluidTagIngredient.java @@ -8,7 +8,7 @@ import net.minecraft.tags.TagKey; import net.minecraft.world.level.material.Fluid; import net.neoforged.neoforge.fluids.FluidStack; -import net.neoforged.neoforge.registries.ForgeRegistries; +import net.neoforged.neoforge.registries.NeoForgeRegistries; public class FluidTagIngredient { @@ -42,10 +42,10 @@ public List list() { if (!hasTag()) { return List.of(fluid.getFluid()); } - TagKey ft = FluidTags.create(new ResourceLocation(tag)); + TagKey ft = FluidTags.create(ResourceLocation.parse(tag)); if (ft != null) { - TagKey key = ForgeRegistries.FLUIDS.tags().createTagKey(new ResourceLocation(tag)); - return ForgeRegistries.FLUIDS.tags().getTag(key).stream().toList(); + TagKey key = ForgeRegistries.FLUIDS.tags().createTagKey(ResourceLocation.parse(tag)); + return NeoForgeRegistries.FLUID_INGREDIENT_TYPES.tags().getTag(key).stream().toList(); } return null; } diff --git a/src/main/java/com/lothrazar/library/registry/RecipeCauldronFactory.java b/src/main/java/com/lothrazar/library/registry/RecipeCauldronFactory.java index 5097942..9e427a5 100644 --- a/src/main/java/com/lothrazar/library/registry/RecipeCauldronFactory.java +++ b/src/main/java/com/lothrazar/library/registry/RecipeCauldronFactory.java @@ -4,6 +4,7 @@ import java.util.List; import net.minecraft.core.cauldron.CauldronInteraction; import net.minecraft.world.InteractionResult; +import net.minecraft.world.ItemInteractionResult; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.block.LayeredCauldronBlock; @@ -59,11 +60,11 @@ public static void setup(FMLCommonSetupEvent event) { if (rec.lowerFillLevel) { LayeredCauldronBlock.lowerFillLevel(state, level, pos); } - return InteractionResult.sidedSuccess(level.isClientSide); + return ItemInteractionResult.sidedSuccess(level.isClientSide); } - return InteractionResult.PASS; + return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; }; - CauldronInteraction.WATER.put(rec.input.asItem(), interaction); + CauldronInteraction.WATER.map(rec.input.asItem(), interaction); } } } diff --git a/src/main/java/com/lothrazar/library/render/type/FakeBlockRenderTypes.java b/src/main/java/com/lothrazar/library/render/type/FakeBlockRenderTypes.java index f9fb403..bd7c9d1 100644 --- a/src/main/java/com/lothrazar/library/render/type/FakeBlockRenderTypes.java +++ b/src/main/java/com/lothrazar/library/render/type/FakeBlockRenderTypes.java @@ -22,7 +22,7 @@ public FakeBlockRenderTypes(String nameIn, VertexFormat formatIn, VertexFormat.M super(nameIn, formatIn, drawModeIn, bufferSizeIn, useDelegateIn, needsSortingIn, setupTaskIn, clearTaskIn); } - public final static ResourceLocation BEAM = new ResourceLocation(FutureLibMod.MODID, "textures/effect/beam.png"); + public final static ResourceLocation BEAM = ResourceLocation.fromNamespaceAndPath(FutureLibMod.MODID, "textures/effect/beam.png"); public static final RenderType LASER_MAIN_BEAM = create(FutureLibMod.MODID + ":mininglasermainbeam", DefaultVertexFormat.POSITION_COLOR_TEX, VertexFormat.Mode.QUADS, BUFFERSIZE, CRUMBLING, SORT, RenderType.CompositeState.builder() diff --git a/src/main/java/com/lothrazar/library/render/type/LaserRenderType.java b/src/main/java/com/lothrazar/library/render/type/LaserRenderType.java index 9226d1d..14d7516 100644 --- a/src/main/java/com/lothrazar/library/render/type/LaserRenderType.java +++ b/src/main/java/com/lothrazar/library/render/type/LaserRenderType.java @@ -19,9 +19,9 @@ public LaserRenderType(String nameIn, VertexFormat formatIn, VertexFormat.Mode d super(nameIn, formatIn, drawModeIn, bufferSizeIn, useDelegateIn, needsSortingIn, setupTaskIn, clearTaskIn); } - private final static ResourceLocation RL_LASER = new ResourceLocation(FutureLibMod.MODID, "textures/effect/laser.png"); - private final static ResourceLocation RL_BEAM = new ResourceLocation(FutureLibMod.MODID, "textures/effect/beam.png"); - private final static ResourceLocation RL_GLOW = new ResourceLocation(FutureLibMod.MODID, "textures/effect/glow.png"); + private final static ResourceLocation RL_LASER = ResourceLocation.fromNamespaceAndPath(FutureLibMod.MODID, "textures/effect/laser.png"); + private final static ResourceLocation RL_BEAM = ResourceLocation.fromNamespaceAndPath(FutureLibMod.MODID, "textures/effect/beam.png"); + private final static ResourceLocation RL_GLOW = ResourceLocation.fromNamespaceAndPath(FutureLibMod.MODID, "textures/effect/glow.png"); public static final RenderType LASER_MAIN_BEAM = create("MAIN_", DefaultVertexFormat.POSITION_COLOR_TEX, VertexFormat.Mode.QUADS, 256, false, false, RenderType.CompositeState.builder().setTextureState(new TextureStateShard(RL_BEAM, false, false)) diff --git a/src/main/java/com/lothrazar/library/util/EntityUtil.java b/src/main/java/com/lothrazar/library/util/EntityUtil.java index b705955..85e6931 100644 --- a/src/main/java/com/lothrazar/library/util/EntityUtil.java +++ b/src/main/java/com/lothrazar/library/util/EntityUtil.java @@ -49,6 +49,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.level.Level; +import net.minecraft.world.level.portal.DimensionTransition; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import net.neoforged.neoforge.common.util.FakePlayer; @@ -479,7 +480,6 @@ public static void dimensionTeleport(ServerPlayer player, ServerLevel world, Blo if (!world.isClientSide) { DimensionTransit transit = new DimensionTransit(world, loc); transit.teleport(player); - player.changeDimension(transit.getTargetLevel(), transit); } } } diff --git a/src/main/java/com/lothrazar/library/util/FakePlayerUtil.java b/src/main/java/com/lothrazar/library/util/FakePlayerUtil.java index fc0476d..6945729 100644 --- a/src/main/java/com/lothrazar/library/util/FakePlayerUtil.java +++ b/src/main/java/com/lothrazar/library/util/FakePlayerUtil.java @@ -41,7 +41,6 @@ import net.minecraft.world.phys.BlockHitResult; import net.neoforged.neoforge.common.util.FakePlayer; import net.neoforged.neoforge.common.util.FakePlayerFactory; -import net.neoforged.neoforge.common.util.LazyOptional; import net.neoforged.neoforge.items.IItemHandler; import net.neoforged.neoforge.items.ItemStackHandler; @@ -72,21 +71,17 @@ public void send(Packet packetIn) {} return fakePlayer; } - public static void tryEquipItem(LazyOptional i, WeakReference fp, int slot, InteractionHand hand) { - if (fp == null) { + public static void tryEquipItem(IItemHandler inv, WeakReference fp, int slot, InteractionHand hand) { + if (fp == null || inv == null) { return; } - i.ifPresent(inv -> { - ItemStack maybeTool = inv.getStackInSlot(0); - if (!maybeTool.isEmpty()) { - if (maybeTool.getCount() <= 0) { - maybeTool = ItemStack.EMPTY; - } - } - if (!maybeTool.equals(fp.get().getItemInHand(hand))) { - fp.get().setItemInHand(hand, maybeTool); - } - }); + ItemStack maybeTool = inv.getStackInSlot(0); + if (!maybeTool.isEmpty() && maybeTool.getCount() <= 0) { + maybeTool = ItemStack.EMPTY; + } + if (!maybeTool.equals(fp.get().getItemInHand(hand))) { + fp.get().setItemInHand(hand, maybeTool); + } } public static InteractionResult interactUseOnBlock(WeakReference fakePlayer, diff --git a/src/main/java/com/lothrazar/library/util/LevelWorldUtil.java b/src/main/java/com/lothrazar/library/util/LevelWorldUtil.java index a290fe1..b352f67 100644 --- a/src/main/java/com/lothrazar/library/util/LevelWorldUtil.java +++ b/src/main/java/com/lothrazar/library/util/LevelWorldUtil.java @@ -61,7 +61,7 @@ else if (nukeOption) { public static String dimensionToString(Level world) { //example: returns "minecraft:overworld" resource location return world.dimension().location().toString(); - //RegistryKey.create(Registry.WORLD_KEY, new ResourceLocation("twilightforest", "twilightforest")); + //RegistryKey.create(Registry.WORLD_KEY, ResourceLocation.fromNamespaceAndPath("twilightforest", "twilightforest")); } public static ResourceKey stringToDimension(String key) { diff --git a/src/main/java/com/lothrazar/library/util/PacketUtil.java b/src/main/java/com/lothrazar/library/util/PacketUtil.java index 7a6c299..e1bb9c6 100644 --- a/src/main/java/com/lothrazar/library/util/PacketUtil.java +++ b/src/main/java/com/lothrazar/library/util/PacketUtil.java @@ -1,22 +1,29 @@ package com.lothrazar.library.util; import com.lothrazar.library.packet.PacketFlib; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; -import net.minecraftforge.network.NetworkDirection; -import net.minecraftforge.network.simple.SimpleChannel; +import net.neoforged.neoforge.network.PacketDistributor; public class PacketUtil { - public static void sendToAllClients(SimpleChannel instance, Level world, PacketFlib packet) { - if (world.isClientSide) { + public static void sendToAllClients(Level world, PacketFlib packet) { + if (world.isClientSide || !(packet instanceof CustomPacketPayload payload)) { return; } for (Player player : world.players()) { if (player instanceof ServerPlayer sp) { - instance.sendTo(packet, sp.connection.connection, NetworkDirection.PLAY_TO_CLIENT); + PacketDistributor.sendToPlayer(sp, payload); } } } + + /** + * Send a packet to a specific player. + */ + public static void sendToPlayer(ServerPlayer player, CustomPacketPayload packet) { + PacketDistributor.sendToPlayer(player, packet); + } } diff --git a/src/main/java/com/lothrazar/library/util/RecipeUtil.java b/src/main/java/com/lothrazar/library/util/RecipeUtil.java index acdd9f2..eea1f4e 100644 --- a/src/main/java/com/lothrazar/library/util/RecipeUtil.java +++ b/src/main/java/com/lothrazar/library/util/RecipeUtil.java @@ -12,6 +12,7 @@ import net.minecraft.world.level.material.Fluid; import net.neoforged.neoforge.fluids.FluidStack; import net.neoforged.neoforge.registries.ForgeRegistries; +import net.neoforged.neoforge.registries.NeoForgeRegistries; public class RecipeUtil { @@ -25,7 +26,7 @@ public static boolean matchFluid(FluidStack tileFluid, FluidTagIngredient ing) { //either recipe has no fluid or didnt match, try for tag if (ing.hasTag()) { //see /data//tags/fluids/ - TagKey ft = FluidTags.create(new ResourceLocation(ing.getTag())); + TagKey ft = FluidTags.create(ResourceLocation.parse(ing.getTag())); if (FluidHelpersUtil.matches(tileFluid.getFluid(), ft)) { return true; } @@ -42,8 +43,9 @@ public static FluidTagIngredient parseFluid(JsonObject json, String key) { FluidStack fluidstack = FluidStack.EMPTY; if (mix.has("fluid")) { String fluidId = mix.get("fluid").getAsString(); // JSONUtils.getString(mix, "fluid"); - ResourceLocation resourceLocation = new ResourceLocation(fluidId); + ResourceLocation resourceLocation = ResourceLocation.parse(fluidId); Fluid fluid = ForgeRegistries.FLUIDS.getValue(resourceLocation); +// fluid = NeoForgeRegistries.FLUID_TYPES.getValue(resourceLocation); // TODO what for 1.21 ?? fluidstack = (fluid == null) ? FluidStack.EMPTY : new FluidStack(fluid, count); } String ftag = mix.has("tag") ? mix.get("tag").getAsString() : ""; @@ -67,7 +69,7 @@ public static FluidStack getFluid(JsonObject fluidJson) { // String fluidTag = fluidJson.get("fluidTag").getAsString(); } String fluidId = GsonHelper.getAsString(fluidJson, "fluid"); - ResourceLocation resourceLocation = new ResourceLocation(fluidId); + ResourceLocation resourceLocation = ResourceLocation.parse(fluidId); Fluid fluid = ForgeRegistries.FLUIDS.getValue(resourceLocation); int count = fluidJson.get("count").getAsInt(); if (count < 1) { diff --git a/src/main/java/com/lothrazar/library/util/SoundUtil.java b/src/main/java/com/lothrazar/library/util/SoundUtil.java index 9808d80..eee32c8 100644 --- a/src/main/java/com/lothrazar/library/util/SoundUtil.java +++ b/src/main/java/com/lothrazar/library/util/SoundUtil.java @@ -70,7 +70,7 @@ public static void playSoundFromServer(ServerLevel world, BlockPos pos, SoundEve } public static void playSoundFromServerById(ServerLevel world, BlockPos pos, String sid) { - SoundEvent sound = ForgeRegistries.SOUND_EVENTS.getValue(new ResourceLocation(sid)); + SoundEvent sound = ForgeRegistries.SOUND_EVENTS.getValue(ResourceLocation.parse(sid)); if (sound != null) { for (ServerPlayer sp : world.players()) { playSoundFromServer(sp, pos, sound, 1F, 1F); @@ -80,7 +80,7 @@ public static void playSoundFromServerById(ServerLevel world, BlockPos pos, Stri public static void playSoundById(Player player, String sid) { //do the thing - SoundEvent sound = ForgeRegistries.SOUND_EVENTS.getValue(new ResourceLocation(sid)); + SoundEvent sound = ForgeRegistries.SOUND_EVENTS.getValue(ResourceLocation.parse(sid)); if (sound != null && player.level().isClientSide) { SoundUtil.playSound(player, sound); } diff --git a/src/main/java/com/lothrazar/library/util/StringParseUtil.java b/src/main/java/com/lothrazar/library/util/StringParseUtil.java index 28cec25..d3fed92 100644 --- a/src/main/java/com/lothrazar/library/util/StringParseUtil.java +++ b/src/main/java/com/lothrazar/library/util/StringParseUtil.java @@ -37,7 +37,7 @@ public static boolean isInList(final List list, ResourceLocati public static String getFluidRatioName(IFluidHandler handler) { String ratio = handler.getFluidInTank(0).getAmount() + "/" + handler.getTankCapacity(0); if (!handler.getFluidInTank(0).isEmpty()) { - ratio += " " + handler.getFluidInTank(0).getDisplayName().getString(); + ratio += " " + handler.getFluidInTank(0).getHoverName().getString(); } return ratio; } From 2bd2d195386f224cfb1b32bce5ba79c70ada6d4a Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 31 Mar 2026 19:26:05 -0700 Subject: [PATCH 05/29] partial work on utils. refactor portal wrapper and rename --- .../cap/item/FluidHandlerCapabilityStack.java | 15 +++- .../library/dim/DimensionTransit.java | 83 ------------------ .../library/entity/BlockEntityFlib.java | 21 +++-- .../particle/data/ParticleOptionsTwoInt.java | 4 +- .../portal/DimensionTransitionWrapper.java | 87 +++++++++++++++++++ .../recipe/ingredient/FluidTagIngredient.java | 30 ++++--- .../lothrazar/library/util/EnchantUtil.java | 14 ++- .../lothrazar/library/util/EntityUtil.java | 14 +-- .../lothrazar/library/util/ItemStackUtil.java | 4 +- .../lothrazar/library/util/RecipeUtil.java | 11 ++- .../com/lothrazar/library/util/SoundUtil.java | 6 +- 11 files changed, 155 insertions(+), 134 deletions(-) delete mode 100644 src/main/java/com/lothrazar/library/dim/DimensionTransit.java create mode 100644 src/main/java/com/lothrazar/library/portal/DimensionTransitionWrapper.java diff --git a/src/main/java/com/lothrazar/library/cap/item/FluidHandlerCapabilityStack.java b/src/main/java/com/lothrazar/library/cap/item/FluidHandlerCapabilityStack.java index 67ff6ee..f8e42f4 100644 --- a/src/main/java/com/lothrazar/library/cap/item/FluidHandlerCapabilityStack.java +++ b/src/main/java/com/lothrazar/library/cap/item/FluidHandlerCapabilityStack.java @@ -1,9 +1,13 @@ package com.lothrazar.library.cap.item; import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.Fluids; import net.neoforged.neoforge.fluids.FluidStack; import net.neoforged.neoforge.fluids.capability.IFluidHandlerItem; @@ -42,7 +46,13 @@ public FluidStack getFluid() { if (!tag.contains(FLUID_NBT_KEY)) { return FluidStack.EMPTY; } - return FluidStack.parseOptional(null, tag.getCompound(FLUID_NBT_KEY)); + CompoundTag fluidTag = tag.getCompound(FLUID_NBT_KEY); + ResourceLocation fluidId = ResourceLocation.tryParse(fluidTag.getString("id")); + int amount = fluidTag.getInt("amount"); + if (fluidId == null) return FluidStack.EMPTY; + Fluid fluid = BuiltInRegistries.FLUID.getOptional(fluidId).orElse(null); + if (fluid == null || fluid == Fluids.EMPTY) return FluidStack.EMPTY; + return new FluidStack(fluid, amount); } public void setFluid(FluidStack fluid) { @@ -51,7 +61,8 @@ public void setFluid(FluidStack fluid) { tag.remove(FLUID_NBT_KEY); } else { CompoundTag fluidTag = new CompoundTag(); - fluid.save(null, fluidTag); + fluidTag.putString("id", BuiltInRegistries.FLUID.getKey(fluid.getFluid()).toString()); + fluidTag.putInt("amount", fluid.getAmount()); tag.put(FLUID_NBT_KEY, fluidTag); } setContainerTag(tag); diff --git a/src/main/java/com/lothrazar/library/dim/DimensionTransit.java b/src/main/java/com/lothrazar/library/dim/DimensionTransit.java deleted file mode 100644 index 42eff81..0000000 --- a/src/main/java/com/lothrazar/library/dim/DimensionTransit.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.lothrazar.library.dim; - -import java.util.function.Function; -import com.lothrazar.library.core.BlockPosDim; -import com.lothrazar.library.util.LevelWorldUtil; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.portal.DimensionTransition; -import net.minecraft.world.level.portal.PortalInfo; -import net.minecraft.world.phys.Vec3; -import net.neoforged.neoforge.common.util.ITeleporter; - -/** - * - * @see com/lothrazar/cyclic/world/ - */ -public class DimensionTransit implements ITeleporter { - - protected ServerLevel world; - private BlockPosDim target; - - public DimensionTransit(ServerLevel world, BlockPosDim target) { - this.world = world; - this.target = target; - } - - @Override - public PortalInfo getPortalInfo(Entity entity, ServerLevel destWorld, Function defaultPortalInfo) { - BlockPos myPos = moveToSafeCoords(destWorld, target.getPos()); - return new PortalInfo(new Vec3(myPos.getX() + 0.5F, myPos.getY() + 0.5F, myPos.getZ() + 0.5F), Vec3.ZERO, entity.getYRot(), entity.getXRot()); - } - - @SuppressWarnings("deprecation") - private BlockPos moveToSafeCoords(ServerLevel world, BlockPos pos) { - int tries = 10; - while (tries > 0) { - tries--; - if (world.getBlockState(pos).isSolid()) { - pos = pos.above(); - } - } - return pos; - } - - @Override - public Entity placeEntity(Entity newEntity, ServerLevel currentWorld, ServerLevel destWorld, float yaw, Function repositionEntity) { - if (newEntity instanceof LivingEntity) { - ((LivingEntity) newEntity).addEffect(new MobEffectInstance(MobEffects.DAMAGE_RESISTANCE, 200, 200, false, false)); - ((LivingEntity) newEntity).addEffect(new MobEffectInstance(MobEffects.SLOW_FALLING, 20, 20, false, false)); - } - newEntity.fallDistance = 0; - return repositionEntity.apply(false); //Must be false or we fall on vanilla. thanks /Mrbysco/TelePastries/ - } - - /** - * wrapper for Player::changeDimension - * @param player - */ - public void teleport(Player player) { - if (!player.isCreative() && !player.level().isClientSide) { - player.addEffect(new MobEffectInstance(MobEffects.DAMAGE_RESISTANCE, 200, 200, false, false)); - } - if (this.world != null) { - // ServerLevel dim = getTargetLevel(); - this.world.playSound(player, target.getX() + 0.5D, target.getY() + 0.5D, target.getZ() + 0.5D, SoundEvents.PORTAL_TRAVEL, SoundSource.MASTER, 0.25F, this.world.random.nextFloat() * 0.4F + 0.8F); - // player.changeDimension(dim, this); - } - //now actually teleport - - player.changeDimension(new DimensionTransition()); - } - - public ServerLevel getTargetLevel() { - return world == null ? null : world.getServer().getLevel(LevelWorldUtil.stringToDimension(target.getDimension())); - } -} diff --git a/src/main/java/com/lothrazar/library/entity/BlockEntityFlib.java b/src/main/java/com/lothrazar/library/entity/BlockEntityFlib.java index a29db45..d617db3 100644 --- a/src/main/java/com/lothrazar/library/entity/BlockEntityFlib.java +++ b/src/main/java/com/lothrazar/library/entity/BlockEntityFlib.java @@ -6,8 +6,8 @@ import com.lothrazar.library.util.FakePlayerUtil; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.Connection; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; import net.minecraft.server.level.ServerLevel; @@ -26,15 +26,15 @@ public BlockEntityFlib(BlockEntityType type, BlockPos pos, BlockState state) } @Override - public void load(CompoundTag tag) { + public void load(CompoundTag tag, HolderLookup.Provider registries) { // timer = tag.getInt("timer"); - super.load(tag); + super.load(tag, registries); } @Override - public void saveAdditional(CompoundTag tag) { + public void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) { // tag.putInt("timer", timer); - super.saveAdditional(tag); + super.saveAdditional(tag, registries); } public abstract void setField(int field, int value); @@ -52,16 +52,15 @@ public void setLitProperty(boolean lit) { } @Override - public CompoundTag getUpdateTag() { - CompoundTag syncData = super.getUpdateTag(); - this.saveAdditional(syncData); + public CompoundTag getUpdateTag(HolderLookup.Provider registries) { + CompoundTag syncData = super.getUpdateTag(registries); + this.saveAdditional(syncData, registries); return syncData; } @Override - public void onDataPacket(Connection net, ClientboundBlockEntityDataPacket pkt) { - this.load(pkt.getTag()); - super.onDataPacket(net, pkt); + public void handleUpdateTag(CompoundTag tag, HolderLookup.Provider registries) { + this.load(tag, registries); } @Override diff --git a/src/main/java/com/lothrazar/library/particle/data/ParticleOptionsTwoInt.java b/src/main/java/com/lothrazar/library/particle/data/ParticleOptionsTwoInt.java index 8a54142..6c46cc2 100644 --- a/src/main/java/com/lothrazar/library/particle/data/ParticleOptionsTwoInt.java +++ b/src/main/java/com/lothrazar/library/particle/data/ParticleOptionsTwoInt.java @@ -6,7 +6,7 @@ import net.minecraft.core.particles.ParticleOptions; import net.minecraft.core.particles.ParticleType; import net.minecraft.network.FriendlyByteBuf; -import net.neoforged.neoforge.registries.ForgeRegistries; +import net.minecraft.core.registries.BuiltInRegistries; /** * used by ParticleBlinkingAura @@ -62,6 +62,6 @@ public void writeToNetwork(FriendlyByteBuf buf) { @Override public String writeToString() { - return String.format(Locale.ROOT, "%s %d %d", ForgeRegistries.PARTICLE_TYPES.getKey(getType()), this.oneInt, this.twoInt); + return String.format(Locale.ROOT, "%s %d %d", BuiltInRegistries.PARTICLE_TYPE.getKey(getType()), this.oneInt, this.twoInt); } } diff --git a/src/main/java/com/lothrazar/library/portal/DimensionTransitionWrapper.java b/src/main/java/com/lothrazar/library/portal/DimensionTransitionWrapper.java new file mode 100644 index 0000000..3dbf6ac --- /dev/null +++ b/src/main/java/com/lothrazar/library/portal/DimensionTransitionWrapper.java @@ -0,0 +1,87 @@ +package com.lothrazar.library.portal; + +import com.lothrazar.library.core.BlockPosDim; +import com.lothrazar.library.util.LevelWorldUtil; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.portal.DimensionTransition; +import net.minecraft.world.phys.Vec3; + +/** + * Handles cross-dimension teleportation via the vanilla 1.21 DimensionTransition API. + * ITeleporter (Forge) no longer exists — entity.changeDimension(DimensionTransition) is the replacement. + * + * @see com/lothrazar/cyclic/world/ + */ +public class DimensionTransitionWrapper { + + protected ServerLevel world; + private BlockPosDim target; + + public DimensionTransitionWrapper(ServerLevel world, BlockPosDim target) { + this.world = world; + this.target = target; + } + + private BlockPos moveToSafeCoords(ServerLevel destWorld, BlockPos pos) { + int tries = 10; + while (tries > 0) { + tries--; + if (destWorld.getBlockState(pos).isSolid()) { + pos = pos.above(); + } + } + return pos; + } + + /** + * Builds the DimensionTransition for use with entity.changeDimension(). + * The PostDimensionTransition callback applies effects on the entity after arrival. + */ + public DimensionTransition buildTransition(Player player) { + ServerLevel targetLevel = getTargetLevel(); + BlockPos safePos = moveToSafeCoords(targetLevel, target.getPos()); + return new DimensionTransition( + targetLevel, + new Vec3(safePos.getX() + 0.5, safePos.getY() + 0.5, safePos.getZ() + 0.5), + Vec3.ZERO, + player.getYRot(), + player.getXRot(), + false, + entity -> { + // PostDimensionTransition: runs on the entity after it arrives in the new dimension + if (entity instanceof LivingEntity living) { + living.addEffect(new MobEffectInstance(MobEffects.DAMAGE_RESISTANCE, 200, 200, false, false)); + living.addEffect(new MobEffectInstance(MobEffects.SLOW_FALLING, 20, 20, false, false)); + } + entity.fallDistance = 0; + } + ); + } + + /** + * Applies pre-teleport effects and plays the portal sound at the destination. + * Call this before changeDimension(). + */ + public void applyPreTeleportEffects(Player player) { + if (!player.isCreative() && !player.level().isClientSide) { + player.addEffect(new MobEffectInstance(MobEffects.DAMAGE_RESISTANCE, 200, 200, false, false)); + } + if (this.world != null) { + this.world.playSound(null, + target.getX() + 0.5D, target.getY() + 0.5D, target.getZ() + 0.5D, + SoundEvents.PORTAL_TRAVEL, SoundSource.MASTER, + 0.25F, this.world.random.nextFloat() * 0.4F + 0.8F); + } + } + + public ServerLevel getTargetLevel() { + return world == null ? null : world.getServer().getLevel(LevelWorldUtil.stringToDimension(target.getDimension())); + } +} diff --git a/src/main/java/com/lothrazar/library/recipe/ingredient/FluidTagIngredient.java b/src/main/java/com/lothrazar/library/recipe/ingredient/FluidTagIngredient.java index a28b9f3..d9ff65c 100644 --- a/src/main/java/com/lothrazar/library/recipe/ingredient/FluidTagIngredient.java +++ b/src/main/java/com/lothrazar/library/recipe/ingredient/FluidTagIngredient.java @@ -2,13 +2,16 @@ import java.util.ArrayList; import java.util.List; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; -import net.minecraft.tags.FluidTags; import net.minecraft.tags.TagKey; import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.Fluids; import net.neoforged.neoforge.fluids.FluidStack; -import net.neoforged.neoforge.registries.NeoForgeRegistries; public class FluidTagIngredient { @@ -42,12 +45,10 @@ public List list() { if (!hasTag()) { return List.of(fluid.getFluid()); } - TagKey ft = FluidTags.create(ResourceLocation.parse(tag)); - if (ft != null) { - TagKey key = ForgeRegistries.FLUIDS.tags().createTagKey(ResourceLocation.parse(tag)); - return NeoForgeRegistries.FLUID_INGREDIENT_TYPES.tags().getTag(key).stream().toList(); - } - return null; + TagKey key = TagKey.create(Registries.FLUID, ResourceLocation.parse(tag)); + return BuiltInRegistries.FLUID.getTag(key) + .map(set -> set.stream().map(Holder::value).collect(java.util.stream.Collectors.toList())) + .orElseGet(List::of); } /** @@ -65,11 +66,20 @@ public List getMatchingFluids() { } public static FluidTagIngredient readFromPacket(FriendlyByteBuf buffer) { - return new FluidTagIngredient(FluidStack.readFromPacket(buffer), buffer.readUtf(), buffer.readInt()); + ResourceLocation fluidId = buffer.readResourceLocation(); + int fluidAmount = buffer.readInt(); + String tagStr = buffer.readUtf(); + int cnt = buffer.readInt(); + Fluid fluid = BuiltInRegistries.FLUID.getOptional(fluidId).orElse(Fluids.EMPTY); + FluidStack stack = fluid == Fluids.EMPTY ? FluidStack.EMPTY : new FluidStack(fluid, fluidAmount); + return new FluidTagIngredient(stack, tagStr, cnt); } public void writeToPacket(FriendlyByteBuf buffer) { - fluid.writeToPacket(buffer); + ResourceKey key = BuiltInRegistries.FLUID.getResourceKey(fluid.getFluid()) + .orElseThrow(() -> new IllegalStateException("Unknown fluid: " + fluid.getFluid())); + buffer.writeResourceLocation(key.location()); + buffer.writeInt(fluid.getAmount()); buffer.writeUtf(tag); buffer.writeInt(amount); } diff --git a/src/main/java/com/lothrazar/library/util/EnchantUtil.java b/src/main/java/com/lothrazar/library/util/EnchantUtil.java index 1ffc3f7..d7def2c 100644 --- a/src/main/java/com/lothrazar/library/util/EnchantUtil.java +++ b/src/main/java/com/lothrazar/library/util/EnchantUtil.java @@ -1,16 +1,15 @@ package com.lothrazar.library.util; import java.util.ArrayList; -import java.util.Collection; import java.util.List; -import net.minecraft.nbt.ListTag; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectCategory; -import net.minecraft.world.item.EnchantedBookItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; -import net.neoforged.neoforge.registries.ForgeRegistries; +import net.minecraft.world.item.enchantment.ItemEnchantments; public class EnchantUtil { @@ -31,9 +30,8 @@ public static List getAllEffects() { } public static List getEffects(MobEffectCategory effectType) { - Collection effects = ForgeRegistries.MOB_EFFECTS.getValues(); List effectsList = new ArrayList<>(); - for (MobEffect effect : effects) { + for (MobEffect effect : BuiltInRegistries.MOB_EFFECT) { if (effectType == null || effect.getCategory() == effectType) { effectsList.add(effect); } @@ -45,8 +43,8 @@ public static boolean doBookEnchantmentsMatch(ItemStack stack1, ItemStack stack2 Item item1 = stack1.getItem(); Item item2 = stack2.getItem(); if (item1 == Items.ENCHANTED_BOOK && item2 == Items.ENCHANTED_BOOK) { - ListTag ench1 = EnchantedBookItem.getEnchantments(stack1); - ListTag ench2 = EnchantedBookItem.getEnchantments(stack2); + ItemEnchantments ench1 = stack1.get(DataComponents.STORED_ENCHANTMENTS); + ItemEnchantments ench2 = stack2.get(DataComponents.STORED_ENCHANTMENTS); if (ench1 == null || ench2 == null) { return false; } diff --git a/src/main/java/com/lothrazar/library/util/EntityUtil.java b/src/main/java/com/lothrazar/library/util/EntityUtil.java index 85e6931..93bce23 100644 --- a/src/main/java/com/lothrazar/library/util/EntityUtil.java +++ b/src/main/java/com/lothrazar/library/util/EntityUtil.java @@ -27,9 +27,9 @@ import java.util.List; import com.lothrazar.library.core.BlockPosDim; import com.lothrazar.library.core.Vector3; -import com.lothrazar.library.dim.DimensionTransit; -import com.lothrazar.library.mod.PacketRegistry; +import com.lothrazar.library.portal.DimensionTransitionWrapper; import com.lothrazar.library.packet.PacketPlayerFalldamage; +import net.neoforged.neoforge.network.PacketDistributor; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; @@ -49,7 +49,6 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.level.Level; -import net.minecraft.world.level.portal.DimensionTransition; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import net.neoforged.neoforge.common.util.FakePlayer; @@ -466,7 +465,7 @@ else if (entity.zza > 0.0F && entity.getDeltaMovement().y < climbSpeed) { entity.fallDistance = 0.0F; } //setting fall distance on clientside wont work if (worldIn.isClientSide && entity.tickCount % TICKS_FALLDIST_SYNC == 0) { - PacketRegistry.INSTANCE.sendToServer(new PacketPlayerFalldamage()); + PacketDistributor.sendToServer(new PacketPlayerFalldamage()); } } @@ -474,12 +473,13 @@ public static void dimensionTeleport(ServerPlayer player, ServerLevel world, Blo if (player instanceof FakePlayer) { return; } - if (!player.canChangeDimensions()) { + if (!player.canChangeDimensions(player.getCommandSenderWorld(), world)) { return; } if (!world.isClientSide) { - DimensionTransit transit = new DimensionTransit(world, loc); - transit.teleport(player); + DimensionTransitionWrapper transit = new DimensionTransitionWrapper(world, loc); + transit.applyPreTeleportEffects(player); + player.changeDimension(transit.buildTransition(player)); } } } diff --git a/src/main/java/com/lothrazar/library/util/ItemStackUtil.java b/src/main/java/com/lothrazar/library/util/ItemStackUtil.java index db08bb4..04cfdfc 100644 --- a/src/main/java/com/lothrazar/library/util/ItemStackUtil.java +++ b/src/main/java/com/lothrazar/library/util/ItemStackUtil.java @@ -18,7 +18,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.neoforged.neoforge.items.IItemHandler; -import net.neoforged.neoforge.registries.ForgeRegistries; +import net.minecraft.core.registries.BuiltInRegistries; public class ItemStackUtil { @@ -91,7 +91,7 @@ public static int countEmptySlots(IItemHandler handler) { } public static ItemStack findItem(String id) { - Item head = ForgeRegistries.ITEMS.getValue(ResourceLocation.tryParse(id)); + Item head = BuiltInRegistries.ITEM.getOptional(ResourceLocation.tryParse(id)).orElse(null); if (head != null) { return new ItemStack(head); } diff --git a/src/main/java/com/lothrazar/library/util/RecipeUtil.java b/src/main/java/com/lothrazar/library/util/RecipeUtil.java index eea1f4e..5309365 100644 --- a/src/main/java/com/lothrazar/library/util/RecipeUtil.java +++ b/src/main/java/com/lothrazar/library/util/RecipeUtil.java @@ -3,7 +3,9 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.lothrazar.library.recipe.ingredient.FluidTagIngredient; +import com.mojang.serialization.JsonOps; import net.minecraft.core.NonNullList; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.FluidTags; import net.minecraft.tags.TagKey; @@ -11,8 +13,6 @@ import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.material.Fluid; import net.neoforged.neoforge.fluids.FluidStack; -import net.neoforged.neoforge.registries.ForgeRegistries; -import net.neoforged.neoforge.registries.NeoForgeRegistries; public class RecipeUtil { @@ -44,8 +44,7 @@ public static FluidTagIngredient parseFluid(JsonObject json, String key) { if (mix.has("fluid")) { String fluidId = mix.get("fluid").getAsString(); // JSONUtils.getString(mix, "fluid"); ResourceLocation resourceLocation = ResourceLocation.parse(fluidId); - Fluid fluid = ForgeRegistries.FLUIDS.getValue(resourceLocation); -// fluid = NeoForgeRegistries.FLUID_TYPES.getValue(resourceLocation); // TODO what for 1.21 ?? + Fluid fluid = BuiltInRegistries.FLUID.getOptional(resourceLocation).orElse(null); fluidstack = (fluid == null) ? FluidStack.EMPTY : new FluidStack(fluid, count); } String ftag = mix.has("tag") ? mix.get("tag").getAsString() : ""; @@ -56,7 +55,7 @@ public static NonNullList getIngredientsArray(JsonObject obj) { JsonArray array = GsonHelper.getAsJsonArray(obj, "ingredients"); NonNullList nonnulllist = NonNullList.create(); for (int i = 0; i < array.size(); ++i) { - Ingredient ingredient = Ingredient.fromJson(array.get(i)); + Ingredient ingredient = Ingredient.CODEC.parse(JsonOps.INSTANCE, array.get(i)).result().orElse(Ingredient.EMPTY); if (!ingredient.isEmpty()) { nonnulllist.add(ingredient); } @@ -70,7 +69,7 @@ public static FluidStack getFluid(JsonObject fluidJson) { } String fluidId = GsonHelper.getAsString(fluidJson, "fluid"); ResourceLocation resourceLocation = ResourceLocation.parse(fluidId); - Fluid fluid = ForgeRegistries.FLUIDS.getValue(resourceLocation); + Fluid fluid = BuiltInRegistries.FLUID.getOptional(resourceLocation).orElse(null); int count = fluidJson.get("count").getAsInt(); if (count < 1) { count = 1; diff --git a/src/main/java/com/lothrazar/library/util/SoundUtil.java b/src/main/java/com/lothrazar/library/util/SoundUtil.java index eee32c8..a03c2cd 100644 --- a/src/main/java/com/lothrazar/library/util/SoundUtil.java +++ b/src/main/java/com/lothrazar/library/util/SoundUtil.java @@ -11,7 +11,7 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; -import net.neoforged.neoforge.registries.ForgeRegistries; +import net.minecraft.core.registries.BuiltInRegistries; public class SoundUtil { @@ -70,7 +70,7 @@ public static void playSoundFromServer(ServerLevel world, BlockPos pos, SoundEve } public static void playSoundFromServerById(ServerLevel world, BlockPos pos, String sid) { - SoundEvent sound = ForgeRegistries.SOUND_EVENTS.getValue(ResourceLocation.parse(sid)); + SoundEvent sound = BuiltInRegistries.SOUND_EVENT.getOptional(ResourceLocation.parse(sid)).orElse(null); if (sound != null) { for (ServerPlayer sp : world.players()) { playSoundFromServer(sp, pos, sound, 1F, 1F); @@ -80,7 +80,7 @@ public static void playSoundFromServerById(ServerLevel world, BlockPos pos, Stri public static void playSoundById(Player player, String sid) { //do the thing - SoundEvent sound = ForgeRegistries.SOUND_EVENTS.getValue(ResourceLocation.parse(sid)); + SoundEvent sound = BuiltInRegistries.SOUND_EVENT.getOptional(ResourceLocation.parse(sid)).orElse(null); if (sound != null && player.level().isClientSide) { SoundUtil.playSound(player, sound); } From 26a06878cfc4cfeda95345b5f66ae6c1fa7615f4 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 31 Mar 2026 19:27:35 -0700 Subject: [PATCH 06/29] fix nbt providers --- .../library/cap/CustomEnergyStorage.java | 34 ++++++++++++++----- .../library/cap/ItemStackHandlerWrapper.java | 13 +++---- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/lothrazar/library/cap/CustomEnergyStorage.java b/src/main/java/com/lothrazar/library/cap/CustomEnergyStorage.java index 632cd81..2bc981d 100644 --- a/src/main/java/com/lothrazar/library/cap/CustomEnergyStorage.java +++ b/src/main/java/com/lothrazar/library/cap/CustomEnergyStorage.java @@ -1,15 +1,16 @@ package com.lothrazar.library.cap; +import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; -import net.neoforged.neoforge.common.util.INBTSerializable; +import net.minecraft.nbt.IntTag; import net.neoforged.neoforge.energy.EnergyStorage; /** * For use with items, tile entities, etc. - * + * * @see cyclic */ -public class CustomEnergyStorage extends EnergyStorage implements INBTSerializable { +public class CustomEnergyStorage extends EnergyStorage { public static final String NBTENERGY = "energy"; @@ -22,21 +23,36 @@ public void setEnergy(int energyIn) { energyIn = 0; } if (energyIn > getMaxEnergyStored()) { - energyIn = getEnergyStored(); + energyIn = getMaxEnergyStored(); } this.energy = energyIn; } - @Override - public CompoundTag serializeNBT() { + /** + * Serialize energy to a CompoundTag (e.g. for block entity NBT). + * Use this instead of serializeNBT() when embedding energy inside a larger compound. + */ + public CompoundTag saveToTag() { CompoundTag tag = new CompoundTag(); tag.putInt(NBTENERGY, getEnergyStored()); return tag; } + /** + * Deserialize energy from a CompoundTag (e.g. from block entity NBT). + */ + public void loadFromTag(CompoundTag tag) { + setEnergy(tag.getInt(NBTENERGY)); + } + + // Override INBTSerializable from EnergyStorage with provider signatures + @Override + public IntTag serializeNBT(HolderLookup.Provider provider) { + return IntTag.valueOf(getEnergyStored()); + } + @Override - public void deserializeNBT(net.minecraft.nbt.Tag nbt) { - CompoundTag real = (CompoundTag) nbt; - setEnergy(real.getInt(NBTENERGY)); + public void deserializeNBT(HolderLookup.Provider provider, IntTag nbt) { + setEnergy(nbt.getAsInt()); } } diff --git a/src/main/java/com/lothrazar/library/cap/ItemStackHandlerWrapper.java b/src/main/java/com/lothrazar/library/cap/ItemStackHandlerWrapper.java index 199dfc8..6af73be 100644 --- a/src/main/java/com/lothrazar/library/cap/ItemStackHandlerWrapper.java +++ b/src/main/java/com/lothrazar/library/cap/ItemStackHandlerWrapper.java @@ -1,5 +1,6 @@ package com.lothrazar.library.cap; +import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.item.ItemStack; import net.neoforged.neoforge.common.util.INBTSerializable; @@ -85,17 +86,17 @@ public void setStackInSlot(int slot, ItemStack stack) { } @Override - public CompoundTag serializeNBT() { + public CompoundTag serializeNBT(HolderLookup.Provider provider) { CompoundTag cmp = new CompoundTag(); - cmp.put(NBT_INPUT, input.serializeNBT()); - cmp.put(NBT_OUTPUT, output.serializeNBT()); + cmp.put(NBT_INPUT, input.serializeNBT(provider)); + cmp.put(NBT_OUTPUT, output.serializeNBT(provider)); return cmp; } @Override - public void deserializeNBT(CompoundTag nbt) { - input.deserializeNBT(nbt.getCompound(NBT_INPUT)); - output.deserializeNBT(nbt.getCompound(NBT_OUTPUT)); + public void deserializeNBT(HolderLookup.Provider provider, CompoundTag nbt) { + input.deserializeNBT(provider, nbt.getCompound(NBT_INPUT)); + output.deserializeNBT(provider, nbt.getCompound(NBT_OUTPUT)); } @FunctionalInterface From 23c22a48da8d4459fd1d4627bce7d400c15fd82f Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 31 Mar 2026 20:25:47 -0700 Subject: [PATCH 07/29] registries and datatags updated --- .../item/CapabilityProviderEnergyStack.java | 6 ++-- .../lothrazar/library/data/RelativeShape.java | 8 +++-- .../library/render/FluidRenderMap.java | 4 +-- .../lothrazar/library/util/ItemStackUtil.java | 35 ++++++++----------- .../lothrazar/library/util/TagDataUtil.java | 21 ++++++++--- 5 files changed, 40 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/lothrazar/library/cap/item/CapabilityProviderEnergyStack.java b/src/main/java/com/lothrazar/library/cap/item/CapabilityProviderEnergyStack.java index a7700ea..fad2e6b 100644 --- a/src/main/java/com/lothrazar/library/cap/item/CapabilityProviderEnergyStack.java +++ b/src/main/java/com/lothrazar/library/cap/item/CapabilityProviderEnergyStack.java @@ -23,13 +23,11 @@ public CustomEnergyStorage getEnergyStorage() { } public CompoundTag serializeNBT() { - CompoundTag tag = new CompoundTag(); - tag.put(NBTENERGY, energy.serializeNBT()); - return tag; + return energy.saveToTag(); } public void deserializeNBT(CompoundTag nbt) { - energy.deserializeNBT(nbt.getCompound(NBTENERGY)); + energy.loadFromTag(nbt); } @Override diff --git a/src/main/java/com/lothrazar/library/data/RelativeShape.java b/src/main/java/com/lothrazar/library/data/RelativeShape.java index 078f1d3..202af1b 100644 --- a/src/main/java/com/lothrazar/library/data/RelativeShape.java +++ b/src/main/java/com/lothrazar/library/data/RelativeShape.java @@ -3,8 +3,10 @@ import java.util.ArrayList; import java.util.List; import net.minecraft.core.BlockPos; +import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.CustomData; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; @@ -93,7 +95,8 @@ public static RelativeShape read(CompoundTag tag) { } public static RelativeShape read(ItemStack item) { - CompoundTag tag = item.getTag(); + CustomData data = item.get(DataComponents.CUSTOM_DATA); + CompoundTag tag = data != null ? data.copyTag() : null; return read(tag); } @@ -113,8 +116,9 @@ public CompoundTag write(CompoundTag tag) { } public void write(ItemStack shapeCard) { - CompoundTag tag = shapeCard.getOrCreateTag(); + CompoundTag tag = shapeCard.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag(); write(tag); + shapeCard.set(DataComponents.CUSTOM_DATA, CustomData.of(tag)); } public void setShape(List list) { diff --git a/src/main/java/com/lothrazar/library/render/FluidRenderMap.java b/src/main/java/com/lothrazar/library/render/FluidRenderMap.java index 3e7354f..4529b24 100644 --- a/src/main/java/com/lothrazar/library/render/FluidRenderMap.java +++ b/src/main/java/com/lothrazar/library/render/FluidRenderMap.java @@ -59,8 +59,8 @@ public int hashCode(FluidStack stack) { } int code = 1; code = 31 * code + stack.getFluid().hashCode(); - if (stack.hasTag()) { - code = 31 * code + stack.getTag().hashCode(); + if (!stack.getComponents().isEmpty()) { + code = 31 * code + stack.getComponents().hashCode(); } return code; } diff --git a/src/main/java/com/lothrazar/library/util/ItemStackUtil.java b/src/main/java/com/lothrazar/library/util/ItemStackUtil.java index 04cfdfc..909a2b3 100644 --- a/src/main/java/com/lothrazar/library/util/ItemStackUtil.java +++ b/src/main/java/com/lothrazar/library/util/ItemStackUtil.java @@ -1,10 +1,11 @@ package com.lothrazar.library.util; import java.util.List; +import net.minecraft.ChatFormatting; import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.StringTag; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.RandomSource; import net.minecraft.world.Containers; @@ -14,11 +15,10 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.item.component.ItemLore; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.neoforged.neoforge.items.IItemHandler; -import net.minecraft.core.registries.BuiltInRegistries; public class ItemStackUtil { @@ -38,24 +38,18 @@ public class ItemStackUtil { * @param color */ public static void addLoreToStack(ItemStack crafting, String lore, String color) { - CompoundTag displayTag = new CompoundTag(); - ListTag tagList = new ListTag(); if (color == null) { color = "gold"; } - String escaped = "{\"text\":\"" + lore + "\",\"color\":\"" + color + "\"}"; - tagList.add(StringTag.valueOf(escaped)); - displayTag.put(NBT_LORE, tagList); - crafting.getTag().put(NBT_DISPLAY, displayTag); + ChatFormatting fmt = ChatFormatting.getByName(color); + Component loreText = fmt != null + ? Component.literal(lore).withStyle(fmt) + : Component.literal(lore); + crafting.set(DataComponents.LORE, new ItemLore(List.of(loreText))); } - public static void applyRandomEnch(RandomSource random, ItemStack crafting) { - crafting = EnchantmentHelper.enchantItem(random, crafting, 1, false); - } - - public static void applyRandomEnch(RandomSource random, ItemStack crafting, int level, boolean allowTreasure) { - applyRandomEnch(random, crafting); - } + // NOTE: EnchantmentHelper.enchantItem signature changed in 1.21 - now requires HolderLookup.Provider. + // Call EnchantmentHelper.enchantItem(random, stack, level, registries, Optional.empty()) directly from your code. // private void merge(Map oldEnch, ItemStack crafting) { // Map newEnch = EnchantmentHelper.getEnchantments(crafting); // //anything in new thats also in old, merge it over @@ -158,8 +152,7 @@ public static void drop(Level world, BlockPos pos, ItemStack drop) { public static boolean matches(ItemStack current, ItemStack in) { //first one fails if size is off - return ItemStack.matches(current, in) - && ItemStack.isSameItemSameTags(current, in); + return ItemStack.isSameItemSameComponents(current, in); } public static void shrink(Player player, ItemStack stac) { @@ -194,7 +187,7 @@ public static void dropItemStackMotionless(Level world, BlockPos pos, ItemStack */ public static void deleteTag(ItemStack itemstack) { int dmg = itemstack.getDamageValue(); - itemstack.setTag(null); + itemstack.remove(DataComponents.CUSTOM_DATA); itemstack.setDamageValue(dmg); } diff --git a/src/main/java/com/lothrazar/library/util/TagDataUtil.java b/src/main/java/com/lothrazar/library/util/TagDataUtil.java index 3273703..209f65c 100644 --- a/src/main/java/com/lothrazar/library/util/TagDataUtil.java +++ b/src/main/java/com/lothrazar/library/util/TagDataUtil.java @@ -1,10 +1,12 @@ package com.lothrazar.library.util; import net.minecraft.core.BlockPos; +import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; +import net.minecraft.world.item.component.CustomData; public class TagDataUtil { @@ -22,7 +24,7 @@ public static ItemStack buildNamedPlayerSkull(String displayNameString) { public static ItemStack buildSkullFromTag(CompoundTag player) { ItemStack skull = new ItemStack(Items.PLAYER_HEAD); - skull.setTag(player); + skull.set(DataComponents.CUSTOM_DATA, CustomData.of(player)); return skull; } @@ -42,10 +44,17 @@ public static void putBlockPos(CompoundTag tag, BlockPos pos) { } public static BlockPos getItemStackBlockPos(ItemStack item) { - if (item.isEmpty() || item.getTag() == null || !item.getTag().contains("xpos")) { + if (item.isEmpty()) { + return null; + } + CustomData data = item.get(DataComponents.CUSTOM_DATA); + if (data == null) { + return null; + } + CompoundTag tag = data.copyTag(); + if (!tag.contains("xpos")) { return null; } - CompoundTag tag = item.getOrCreateTag(); return getBlockPos(tag); } @@ -57,10 +66,12 @@ public static void setItemStackNBTVal(ItemStack item, String prop, int value) { if (item.isEmpty()) { return; } - item.getOrCreateTag().putInt(prop, value); + CompoundTag tag = item.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag(); + tag.putInt(prop, value); + item.set(DataComponents.CUSTOM_DATA, CustomData.of(tag)); } public static CompoundTag getItemStackNBT(ItemStack held) { - return held.getOrCreateTag(); + return held.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag(); } } From c02edce45badcb3a20c3b7e122d104abf32a1e45 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 31 Mar 2026 20:40:44 -0700 Subject: [PATCH 08/29] command module and attributes --- .../lothrazar/library/mod/CommandModule.java | 44 +++++++------- .../library/util/AttributesUtil.java | 60 ++++++++++--------- 2 files changed, 51 insertions(+), 53 deletions(-) diff --git a/src/main/java/com/lothrazar/library/mod/CommandModule.java b/src/main/java/com/lothrazar/library/mod/CommandModule.java index e87ec3b..ee1a07e 100644 --- a/src/main/java/com/lothrazar/library/mod/CommandModule.java +++ b/src/main/java/com/lothrazar/library/mod/CommandModule.java @@ -34,9 +34,7 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.GameType; -import net.minecraft.world.scores.Objective; -import net.minecraft.world.scores.Score; -import net.minecraft.world.scores.Scoreboard; +import net.minecraft.world.scores.*; import net.neoforged.neoforge.event.RegisterCommandsEvent; import net.neoforged.bus.api.SubscribeEvent; @@ -229,7 +227,7 @@ public void onRegisterCommandsEvent(RegisterCommandsEvent event) { .then(Commands.argument(ARG_MIN, IntegerArgumentType.integer()) .then(Commands.argument(ARG_MAX, IntegerArgumentType.integer()) .then(Commands.argument(ARG_OBJECTIVE, StringArgumentType.greedyString()) - .executes(x -> { + .executes(x -> { // TODO: fix ScoreHolder instead of x as string return CommandScoreboard.scoreboardRng(x, ScoreHolderArgument.getNamesWithDefaultWildcard(x, ARG_TARGETS), ObjectiveArgument.getObjective(x, ARG_OBJECTIVE), IntegerArgumentType.getInteger(x, ARG_MIN), @@ -272,25 +270,25 @@ public void onRegisterCommandsEvent(RegisterCommandsEvent event) { .then(Commands.argument(ARG_PLAYER, EntityArgument.players()) .then(Commands.argument(ARG_VALUE, IntegerArgumentType.integer(-10000, 10000)) .executes(x -> { - return AttributesUtil.add(ResourceArgument.getAttribute(x, ARG_ATTR).get(), EntityArgument.getPlayers(x, ARG_PLAYER), IntegerArgumentType.getInteger(x, ARG_VALUE)); + return AttributesUtil.add(ResourceArgument.getAttribute(x, ARG_ATTR), EntityArgument.getPlayers(x, ARG_PLAYER), IntegerArgumentType.getInteger(x, ARG_VALUE)); })))) .then(Commands.literal(FORK_RANDOM) .then(Commands.argument(ARG_PLAYER, EntityArgument.players()) .then(Commands.argument(ARG_MIN, IntegerArgumentType.integer(-10000, 10000)) .then(Commands.argument(ARG_MAX, IntegerArgumentType.integer(-10000, 10000)) .executes(x -> { - return AttributesUtil.addRandom(ResourceArgument.getAttribute(x, ARG_ATTR).get(), EntityArgument.getPlayers(x, ARG_PLAYER), IntegerArgumentType.getInteger(x, ARG_MIN), IntegerArgumentType.getInteger(x, ARG_MAX)); + return AttributesUtil.addRandom(ResourceArgument.getAttribute(x, ARG_ATTR), EntityArgument.getPlayers(x, ARG_PLAYER), IntegerArgumentType.getInteger(x, ARG_MIN), IntegerArgumentType.getInteger(x, ARG_MAX)); }))))) .then(Commands.literal(FORK_FACTOR) .then(Commands.argument(ARG_PLAYER, EntityArgument.players()) .then(Commands.argument(ARG_VALUE, DoubleArgumentType.doubleArg(0, 100)) .executes(x -> { - return AttributesUtil.multiply(ResourceArgument.getAttribute(x, ARG_ATTR).get(), EntityArgument.getPlayers(x, ARG_PLAYER), DoubleArgumentType.getDouble(x, ARG_VALUE)); + return AttributesUtil.multiply(ResourceArgument.getAttribute(x, ARG_ATTR), EntityArgument.getPlayers(x, ARG_PLAYER), DoubleArgumentType.getDouble(x, ARG_VALUE)); })))) .then(Commands.literal(FORK_RESET) .then(Commands.argument(ARG_PLAYER, EntityArgument.players()) .executes(x -> { - return AttributesUtil.reset(ResourceArgument.getAttribute(x, ARG_ATTR).get(), EntityArgument.getPlayers(x, ARG_PLAYER)); + return AttributesUtil.reset(ResourceArgument.getAttribute(x, ARG_ATTR), EntityArgument.getPlayers(x, ARG_PLAYER)); }))))) //new commands here ); @@ -369,43 +367,41 @@ public static int addRandom(CommandContext x, Collection x, Collection scoreHolderTargets, Objective objective) { + public static int scoreboardRngTest(CommandContext x, Collection scoreHolderTargets, Objective objective) { Scoreboard scoreboard = x.getSource().getServer().getScoreboard(); int i = 0; - for (String s : scoreHolderTargets) { - Score score = scoreboard.getOrCreatePlayerScore(s, objective); - // ModCyclic.LOGGER.error("[test cmd]" + score.getScore()); - i += score.getScore(); + for (ScoreHolder s : scoreHolderTargets) { + ScoreAccess score = scoreboard.getOrCreatePlayerScore(s, objective); + i += score.get(); } return i; } - public static int scoreboardAdd(CommandContext x, Collection scoreHolderTargets, Objective objective, int integer) { + public static int scoreboardAdd(CommandContext x, Collection scoreHolderTargets, Objective objective, int integer) { Scoreboard scoreboard = x.getSource().getServer().getScoreboard(); int i = 0; - for (String s : scoreHolderTargets) { - Score score = scoreboard.getOrCreatePlayerScore(s, objective); + for (ScoreHolder s : scoreHolderTargets) { + ScoreAccess score = scoreboard.getOrCreatePlayerScore(s, objective); score.add(integer); - // ModCyclic.LOGGER.info("objective add " + score.getScore()); - i += score.getScore(); + i += score.get(); } return i; } - public static int scoreboardRng(CommandContext x, Collection scoreHolderTargets, Objective objective, int min, int max) { + public static int scoreboardRng(CommandContext x, Collection scoreHolderTargets, Objective objective, int min, int max) { Scoreboard scoreboard = x.getSource().getServer().getScoreboard(); int i = 0; - for (String s : scoreHolderTargets) { - Score score = scoreboard.getOrCreatePlayerScore(s, objective); + for (ScoreHolder s : scoreHolderTargets) { // TODO: s used to be a string + ScoreAccess score = scoreboard.getOrCreatePlayerScore(s, objective); if (min < max) { - score.setScore(RAND.nextInt(min, max)); + score.set(RAND.nextInt(min, max)); } else { //either equal, or max is lower than min - score.setScore(min); + score.set(min); } // ModCyclic.LOGGER.info("objective rng " + score.getScore()); - i += score.getScore(); + i += score.get(); } return i; } diff --git a/src/main/java/com/lothrazar/library/util/AttributesUtil.java b/src/main/java/com/lothrazar/library/util/AttributesUtil.java index 0909bd9..ea6072b 100644 --- a/src/main/java/com/lothrazar/library/util/AttributesUtil.java +++ b/src/main/java/com/lothrazar/library/util/AttributesUtil.java @@ -2,27 +2,29 @@ import java.util.Collection; import java.util.Random; -import java.util.UUID; -import com.lothrazar.library.FutureLibMod; +import net.minecraft.core.Holder; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.ai.attributes.Attribute; import net.minecraft.world.entity.ai.attributes.AttributeInstance; import net.minecraft.world.entity.ai.attributes.AttributeModifier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.player.Player; -import net.neoforged.neoforge.common.NeoForgeMod; + +import static com.lothrazar.library.FutureLibMod.MODID; public class AttributesUtil { static final Random RAND = new Random(); - public static final UUID DEFAULT_ID = UUID.fromString("06d30aa2-eff2-4a81-b92b-a1cb95f115c6"); - public static final UUID MULT_ID = UUID.fromString("c6d30aa2-eff2-4a81-b92b-a1cb95f115cd"); - public static final UUID ID_STEP_HEIGHT = UUID.fromString("66d30aa2-eaa2-4a81-b92b-a1cb95f115ca"); + // TODO: we should take id as input? instead of just hardcoding? + public static final ResourceLocation DEFAULT_ID = ResourceLocation.fromNamespaceAndPath(MODID, "default"); + public static final ResourceLocation MULT_ID = ResourceLocation.fromNamespaceAndPath(MODID, "multi"); + public static final ResourceLocation ID_STEP_HEIGHT = ResourceLocation.fromNamespaceAndPath(MODID, "step_height"); static final float VANILLA = 0.6F; // player.maxUpStep = 0.6F; // LivingEntity.class constructor defaults to this public static void disableStepHeight(Player player) { - AttributeInstance attr = player.getAttribute(ForgeMod.STEP_HEIGHT_ADDITION.get()); + AttributeInstance attr = player.getAttribute(Attributes.STEP_HEIGHT); attr.removeModifier(ID_STEP_HEIGHT); } @@ -36,46 +38,45 @@ public static void enableStepHeight(Player player) { newVal = 1.0F + (1F / 16F) - VANILLA; //PATH BLOCKS etc are 1/16th downif MY feature turns this on, then do it } // player.maxUpStep = newVal; // Deprecated - AttributeInstance attr = player.getAttribute(ForgeMod.STEP_HEIGHT_ADDITION.get()); + AttributeInstance attr = player.getAttribute(Attributes.STEP_HEIGHT); AttributeModifier oldModifier = attr.getModifier(AttributesUtil.ID_STEP_HEIGHT); - double old = oldModifier == null ? 0 : oldModifier.getAmount(); + double old = oldModifier == null ? 0 : oldModifier.amount(); if (newVal != old) { AttributesUtil.setStepHeightInternal(player, newVal); } } - private static void setStepHeightInternal(Player player, double newVal) { // player.maxUpStep = 0.6F; // LivingEntity.class constructor defaults to this - AttributeInstance attr = player.getAttribute(ForgeMod.STEP_HEIGHT_ADDITION.get()); + AttributeInstance attr = player.getAttribute(Attributes.STEP_HEIGHT); attr.removeModifier(ID_STEP_HEIGHT); if (newVal != 0) { - AttributeModifier healthModifier = new AttributeModifier(ID_STEP_HEIGHT, FutureLibMod.MODID, newVal, AttributeModifier.Operation.ADDITION); + AttributeModifier healthModifier = new AttributeModifier(ID_STEP_HEIGHT, newVal, AttributeModifier.Operation.ADD_VALUE); attr.addPermanentModifier(healthModifier); } } - public static int add(Attribute attribute, Collection players, int integer) { + public static int add(Holder attribute, Collection players, int integer) { for (ServerPlayer playerIn : players) { updateAttrModifierBy(attribute, DEFAULT_ID, playerIn, integer); } return 0; } - public static int addRandom(Attribute attribute, Collection players, int min, int max) { + public static int addRandom(Holder attribute, Collection players, int min, int max) { for (ServerPlayer playerIn : players) { updateAttrModifierBy(attribute, DEFAULT_ID, playerIn, RAND.nextInt(min, max)); } return 0; } - public static int multiply(Attribute attribute, Collection players, double integer) { + public static int multiply(Holder attribute, Collection players, double integer) { for (ServerPlayer playerIn : players) { multiplyAttrModifierBy(attribute, playerIn, integer); } return 0; } - public static int reset(Attribute attribute, Collection players) { + public static int reset(Holder attribute, Collection players) { for (ServerPlayer playerIn : players) { AttributeInstance attr = playerIn.getAttribute(attribute); attr.removeModifier(DEFAULT_ID); @@ -84,29 +85,30 @@ public static int reset(Attribute attribute, Collection players) { return 0; } - //ench - public static void removePlayerReach(UUID id, Player player) { - AttributeInstance attr = player.getAttribute(ForgeMod.BLOCK_REACH.get()); + // this is block reach not entity reach + public static void removePlayerReach(ResourceLocation id, Player player) { + + AttributeInstance attr = player.getAttribute(Attributes.BLOCK_INTERACTION_RANGE); attr.removeModifier(id); } - // ench - public static void setPlayerReach(UUID id, Player player, int reachBoost) { + // this is block reach not entity reach + public static void setPlayerReach(ResourceLocation id, Player player, int reachBoost) { removePlayerReach(id, player); - AttributeInstance attr = player.getAttribute(ForgeMod.BLOCK_REACH.get()); + AttributeInstance attr = player.getAttribute(Attributes.BLOCK_INTERACTION_RANGE); //vanilla is 5, so +11 it becomes 16 - AttributeModifier enchantment = new AttributeModifier(id, "ReachFLIB", reachBoost, AttributeModifier.Operation.ADDITION); + AttributeModifier enchantment = new AttributeModifier(id, reachBoost, AttributeModifier.Operation.ADD_VALUE); attr.addPermanentModifier(enchantment); } - public static void updateAttrModifierBy(Attribute attr, UUID id, Player playerIn, int value) { + public static void updateAttrModifierBy(Holder attr, ResourceLocation id, Player playerIn, int value) { AttributeInstance healthAttribute = playerIn.getAttribute(attr); AttributeModifier oldHealthModifier = healthAttribute.getModifier(id); //what is our value - double old = oldHealthModifier == null ? 0 : oldHealthModifier.getAmount(); + double old = oldHealthModifier == null ? 0 : oldHealthModifier.amount(); double newVal = value + old; healthAttribute.removeModifier(id); - AttributeModifier healthModifier = new AttributeModifier(id, "Bonus", newVal, AttributeModifier.Operation.ADDITION); + AttributeModifier healthModifier = new AttributeModifier(id, newVal, AttributeModifier.Operation.ADD_VALUE); healthAttribute.addPermanentModifier(healthModifier); if (attr == Attributes.MAX_HEALTH && playerIn.getHealth() > healthAttribute.getValue()) { @@ -114,11 +116,11 @@ public static void updateAttrModifierBy(Attribute attr, UUID id, Player playerIn } } - public static void multiplyAttrModifierBy(Attribute attr, Player playerIn, double value) { + public static void multiplyAttrModifierBy(Holder attr, Player playerIn, double value) { AttributeInstance healthAttribute = playerIn.getAttribute(attr); //what is our value healthAttribute.removeModifier(MULT_ID); - AttributeModifier healthModifier = new AttributeModifier(MULT_ID, "Bonus from Cyclic", value, AttributeModifier.Operation.MULTIPLY_BASE); + AttributeModifier healthModifier = new AttributeModifier(MULT_ID, value, AttributeModifier.Operation.ADD_MULTIPLIED_BASE); healthAttribute.addPermanentModifier(healthModifier); if (attr == Attributes.MAX_HEALTH && playerIn.getHealth() > healthAttribute.getValue()) { @@ -138,7 +140,7 @@ private static void setHearts(int finalHearts, ServerPlayer playerIn) { AttributeInstance healthAttribute = playerIn.getAttribute(Attributes.MAX_HEALTH); healthAttribute.removeModifier(DEFAULT_ID); //just remove and replace the modifier - AttributeModifier healthModifier = new AttributeModifier(DEFAULT_ID, "HP Bonus from Cyclic", (modifiedHearts * 2), AttributeModifier.Operation.ADDITION); + AttributeModifier healthModifier = new AttributeModifier(DEFAULT_ID, (modifiedHearts * 2), AttributeModifier.Operation.ADD_VALUE); healthAttribute.addPermanentModifier(healthModifier); if (playerIn.getHealth() > healthAttribute.getValue()) { playerIn.setHealth((float) healthAttribute.getValue()); From 7797414e41dc9c8d7a2b49aa655c932d7d0ab99c Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 31 Mar 2026 21:19:31 -0700 Subject: [PATCH 09/29] update some render jank --- .../lothrazar/library/block/BlockFlib.java | 5 ++-- .../particle/AbstractSingleQuadParticle.java | 26 ++++++------------- .../library/recipe/BrewingRecipeFlib.java | 8 ++++-- .../conditions/EntityExistsCondition.java | 3 ++- .../render/type/ParticleRenderTypes.java | 19 +++++++++----- .../library/util/RenderBlockUtils.java | 4 +-- 6 files changed, 34 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/lothrazar/library/block/BlockFlib.java b/src/main/java/com/lothrazar/library/block/BlockFlib.java index 7814d8e..88f1b09 100644 --- a/src/main/java/com/lothrazar/library/block/BlockFlib.java +++ b/src/main/java/com/lothrazar/library/block/BlockFlib.java @@ -16,6 +16,7 @@ import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.DyeItem; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Item; import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.BlockGetter; @@ -212,10 +213,10 @@ public void setConnectedColour(Level world, BlockPos pos, DyeColor oldColour, Dy @Override @OnlyIn(Dist.CLIENT) - public void appendHoverText(ItemStack stack, BlockGetter worldIn, List tooltip, TooltipFlag flagIn) { + public void appendHoverText(ItemStack stack, Item.TooltipContext context, List tooltip, TooltipFlag flagIn) { if (me.tooltip) { me.tooltipApply(this, tooltip); } - super.appendHoverText(stack, worldIn, tooltip, flagIn); + super.appendHoverText(stack, context, tooltip, flagIn); } } diff --git a/src/main/java/com/lothrazar/library/particle/AbstractSingleQuadParticle.java b/src/main/java/com/lothrazar/library/particle/AbstractSingleQuadParticle.java index 554d06e..0567126 100644 --- a/src/main/java/com/lothrazar/library/particle/AbstractSingleQuadParticle.java +++ b/src/main/java/com/lothrazar/library/particle/AbstractSingleQuadParticle.java @@ -2,26 +2,21 @@ import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.blaze3d.vertex.Tesselator; -import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.blaze3d.vertex.VertexFormat; import net.minecraft.client.Camera; -import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.particle.ParticleRenderType; import net.minecraft.client.particle.SingleQuadParticle; -import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.phys.Vec3; +import com.mojang.blaze3d.vertex.VertexConsumer; import net.neoforged.api.distmarker.Dist; import net.neoforged.api.distmarker.OnlyIn; /** * used by ParticleCasting - * - * @author lothr * + * @author lothr */ @OnlyIn(Dist.CLIENT) public abstract class AbstractSingleQuadParticle extends SingleQuadParticle { @@ -38,19 +33,14 @@ protected AbstractSingleQuadParticle(ClientLevel world, double x, double y, doub @Override public void render(VertexConsumer buffer, Camera entityIn, float partialTicks) { - TextureManager textureManager = Minecraft.getInstance().getTextureManager(); - // Lighting.turnOff(); + // For CUSTOM render type, we set up the texture/blend state then delegate to super. + // The VertexConsumer writes into the buffer provided by the particle engine. + RenderSystem.setShaderTexture(0, getTexture()); RenderSystem.depthMask(false); - textureManager.bindForSetup(getTexture()); RenderSystem.enableBlend(); RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); - // RenderSystem.alphaFunc(516, 0.003921569F); - // Tesselator.getInstance().getBuilder().begin(7, DefaultVertexFormat.PARTICLE); - RenderSystem.setShader(GameRenderer::getParticleShader); - RenderSystem.setShaderTexture(0, getTexture()); - Tesselator.getInstance().getBuilder().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.PARTICLE); // QUADS == tuess super.render(buffer, entityIn, partialTicks); - Tesselator.getInstance().end(); + RenderSystem.depthMask(true); } @Override diff --git a/src/main/java/com/lothrazar/library/recipe/BrewingRecipeFlib.java b/src/main/java/com/lothrazar/library/recipe/BrewingRecipeFlib.java index 9c24372..3b2589d 100644 --- a/src/main/java/com/lothrazar/library/recipe/BrewingRecipeFlib.java +++ b/src/main/java/com/lothrazar/library/recipe/BrewingRecipeFlib.java @@ -1,7 +1,8 @@ package com.lothrazar.library.recipe; +import net.minecraft.core.component.DataComponents; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.alchemy.PotionUtils; +import net.minecraft.world.item.alchemy.PotionContents; import net.minecraft.world.item.crafting.Ingredient; import net.neoforged.neoforge.common.brewing.BrewingRecipe; @@ -16,6 +17,9 @@ public BrewingRecipeFlib(ItemStack inputStack, Ingredient ingredient, ItemStack @Override public boolean isInput(ItemStack stack) { - return super.isInput(stack) && PotionUtils.getPotion(stack) == PotionUtils.getPotion(inputStack); + // PotionUtils.getPotion() removed in 1.21.1 — use DataComponents.POTION_CONTENTS + PotionContents p1 = stack.get(DataComponents.POTION_CONTENTS); + PotionContents p2 = inputStack.get(DataComponents.POTION_CONTENTS); + return super.isInput(stack) && p1 != null && p1.equals(p2); } } diff --git a/src/main/java/com/lothrazar/library/recipe/conditions/EntityExistsCondition.java b/src/main/java/com/lothrazar/library/recipe/conditions/EntityExistsCondition.java index e7deb83..f82d330 100644 --- a/src/main/java/com/lothrazar/library/recipe/conditions/EntityExistsCondition.java +++ b/src/main/java/com/lothrazar/library/recipe/conditions/EntityExistsCondition.java @@ -24,8 +24,9 @@ public EntityExistsCondition(ResourceLocation entityId) { this.entityId = entityId; } + // used to be ICondition.Context @Override - public boolean test(ICondition.Context context) { + public boolean test(IContext context) { return entityId != null && BuiltInRegistries.ENTITY_TYPE.containsKey(entityId); } diff --git a/src/main/java/com/lothrazar/library/render/type/ParticleRenderTypes.java b/src/main/java/com/lothrazar/library/render/type/ParticleRenderTypes.java index 1a5211d..87f5ad8 100644 --- a/src/main/java/com/lothrazar/library/render/type/ParticleRenderTypes.java +++ b/src/main/java/com/lothrazar/library/render/type/ParticleRenderTypes.java @@ -4,9 +4,9 @@ import com.mojang.blaze3d.platform.GlStateManager.SourceFactor; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.BufferBuilder; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.BufferUploader; +import com.mojang.blaze3d.vertex.MeshData; import com.mojang.blaze3d.vertex.Tesselator; -import com.mojang.blaze3d.vertex.VertexFormat; import net.minecraft.client.particle.ParticleRenderType; import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.texture.TextureManager; @@ -14,12 +14,15 @@ /** * https://github.com/Lothrazar/RootsClassic * + * In 1.21.1, the ParticleEngine calls Tesselator.begin(Mode, Format) BEFORE + * calling type.begin(buffer, textureManager), so begin() only sets up GL state. + * end() must call BufferUploader.drawWithShader(tessellator.end()) since + * Tesselator.end() now returns MeshData instead of uploading directly. */ public class ParticleRenderTypes { public static final ParticleRenderType MAGIC_RENDER = new ParticleRenderType() { - @SuppressWarnings("deprecation") @Override public void begin(BufferBuilder buffer, TextureManager textureManager) { RenderSystem.enableBlend(); @@ -27,15 +30,19 @@ public void begin(BufferBuilder buffer, TextureManager textureManager) { RenderSystem.setShaderTexture(0, TextureAtlas.LOCATION_PARTICLES); RenderSystem.depthMask(false); RenderSystem.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); - buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.PARTICLE); + // Note: do NOT call buffer.begin() here - the ParticleEngine already started + // the buffer via Tesselator.begin(Mode, Format) before calling this method. } @Override public void end(Tesselator tessellator) { - tessellator.end(); + MeshData meshData = tessellator.end(); + if (meshData != null) { + BufferUploader.drawWithShader(meshData); + } RenderSystem.enableDepthTest(); RenderSystem.depthMask(true); - RenderSystem.blendFunc(SourceFactor.SRC_ALPHA.value, DestFactor.ONE_MINUS_SRC_ALPHA.value); + RenderSystem.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); RenderSystem.disableCull(); } diff --git a/src/main/java/com/lothrazar/library/util/RenderBlockUtils.java b/src/main/java/com/lothrazar/library/util/RenderBlockUtils.java index be31b9c..566b6b8 100644 --- a/src/main/java/com/lothrazar/library/util/RenderBlockUtils.java +++ b/src/main/java/com/lothrazar/library/util/RenderBlockUtils.java @@ -17,7 +17,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.color.block.BlockColors; import net.minecraft.client.player.LocalPlayer; -import net.minecraft.client.renderer.GameRenderer; + import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.block.BlockRenderDispatcher; @@ -192,7 +192,7 @@ public static void renderAsBlock(Level level, final BlockPos centerPos, final Li */ public static void renderAsBlock(Level world, final BlockPos centerPos, final List shape, PoseStack matrix, BlockState renderBlockState, float alpha, float scale) { - RenderSystem.setShader(GameRenderer::getPositionTexShader); + // GameRenderer::getPositionTexShader removed in 1.21.1; shader is managed by the RenderType RenderSystem.setShaderTexture(0, InventoryMenu.BLOCK_ATLAS); Minecraft mc = Minecraft.getInstance(); From 2fe5506eccd7fa5147f6665abd24b9ed4527fff5 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 31 Mar 2026 21:55:24 -0700 Subject: [PATCH 10/29] more minor fixes --- .../lothrazar/library/block/BlockFlib.java | 7 -- .../library/cap/CustomEnergyStorage.java | 9 +- .../library/cap/player/PlayerCapProvider.java | 2 +- .../cap/player/PlayerCapabilityStorage.java | 4 +- .../lothrazar/library/core/BlockPosDim.java | 12 ++- .../library/data/BlockStatePosWrapper.java | 7 +- .../library/entity/BlockEntityFlib.java | 6 +- .../library/events/CapabilityEvents.java | 7 +- .../particle/data/ParticleOptionsTwoInt.java | 84 +++++++++++-------- 9 files changed, 78 insertions(+), 60 deletions(-) diff --git a/src/main/java/com/lothrazar/library/block/BlockFlib.java b/src/main/java/com/lothrazar/library/block/BlockFlib.java index 88f1b09..c3d754a 100644 --- a/src/main/java/com/lothrazar/library/block/BlockFlib.java +++ b/src/main/java/com/lothrazar/library/block/BlockFlib.java @@ -167,13 +167,6 @@ public int getDirectSignal(BlockState blockState, BlockGetter blockAccess, Block return super.getDirectSignal(blockState, blockAccess, pos, side); } - @SuppressWarnings("deprecation") - @Override - public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { - // ItemStack heldStack = player.getItemInHand(hand); - return super.use(state, world, pos, player, hand, hit); - } - public void onRightClickBlock(RightClickBlock event, BlockState state) { if (me.rotateColour && event.getItemStack().getItem() instanceof DyeItem newColor) { diff --git a/src/main/java/com/lothrazar/library/cap/CustomEnergyStorage.java b/src/main/java/com/lothrazar/library/cap/CustomEnergyStorage.java index 2bc981d..726e5da 100644 --- a/src/main/java/com/lothrazar/library/cap/CustomEnergyStorage.java +++ b/src/main/java/com/lothrazar/library/cap/CustomEnergyStorage.java @@ -3,6 +3,7 @@ import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.IntTag; +import net.minecraft.nbt.Tag; import net.neoforged.neoforge.energy.EnergyStorage; /** @@ -52,7 +53,11 @@ public IntTag serializeNBT(HolderLookup.Provider provider) { } @Override - public void deserializeNBT(HolderLookup.Provider provider, IntTag nbt) { - setEnergy(nbt.getAsInt()); + public void deserializeNBT(HolderLookup.Provider provider, Tag nbt) { + if (nbt instanceof IntTag intNbt) { + setEnergy(intNbt.getAsInt()); + } else { + throw new IllegalArgumentException("Can not deserialize to an instance that isn't the default implementation"); + } } } diff --git a/src/main/java/com/lothrazar/library/cap/player/PlayerCapProvider.java b/src/main/java/com/lothrazar/library/cap/player/PlayerCapProvider.java index a3ebc97..a5118e7 100644 --- a/src/main/java/com/lothrazar/library/cap/player/PlayerCapProvider.java +++ b/src/main/java/com/lothrazar/library/cap/player/PlayerCapProvider.java @@ -18,7 +18,7 @@ public class PlayerCapProvider { */ public static final Supplier> PLAYER_MANA = ATTACHMENT_TYPES.register("player_mana", () -> - AttachmentType.builder(PlayerCapabilityStorage::new) + AttachmentType.builder(() -> new PlayerCapabilityStorage()) .serialize(PlayerCapabilityStorage.CODEC) .build()); diff --git a/src/main/java/com/lothrazar/library/cap/player/PlayerCapabilityStorage.java b/src/main/java/com/lothrazar/library/cap/player/PlayerCapabilityStorage.java index 399ce6e..af55d48 100644 --- a/src/main/java/com/lothrazar/library/cap/player/PlayerCapabilityStorage.java +++ b/src/main/java/com/lothrazar/library/cap/player/PlayerCapabilityStorage.java @@ -3,12 +3,13 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.nbt.CompoundTag; +import net.neoforged.neoforge.attachment.IAttachmentHolder; public class PlayerCapabilityStorage { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group(Codec.INT.fieldOf("mana").forGetter(PlayerCapabilityStorage::getMana)) - .apply(instance, PlayerCapabilityStorage::new)); + .apply(instance, mana -> new PlayerCapabilityStorage(mana))); int mana; @@ -18,6 +19,7 @@ public PlayerCapabilityStorage(int mana) { public PlayerCapabilityStorage() {} + @Deprecated // i think public PlayerCapabilityStorage(CompoundTag tag) { this.read(tag); } diff --git a/src/main/java/com/lothrazar/library/core/BlockPosDim.java b/src/main/java/com/lothrazar/library/core/BlockPosDim.java index 8f844c6..772462f 100644 --- a/src/main/java/com/lothrazar/library/core/BlockPosDim.java +++ b/src/main/java/com/lothrazar/library/core/BlockPosDim.java @@ -5,7 +5,10 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; +import com.google.gson.JsonParser; +import com.mojang.serialization.JsonOps; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.ComponentSerialization; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; @@ -46,8 +49,13 @@ public BlockPosDim(BlockPos pos, String dimension, CompoundTag stackTag) { // CompoundTag displayTag = stackTag.getCompound("display"); if (displayTag != null && displayTag.contains("Name", 8)) { - // - Component namec = Component.Serializer.fromJson(displayTag.getString("Name")); + String nameJson = displayTag.getString("Name"); + Component namec = ComponentSerialization.CODEC + .parse(JsonOps.INSTANCE, JsonParser.parseString(nameJson)) + .result() + .orElseGet(() -> Component.literal(nameJson)); + +// this.name = displayTag.getString("Name"); this.name = namec.getString(); } } diff --git a/src/main/java/com/lothrazar/library/data/BlockStatePosWrapper.java b/src/main/java/com/lothrazar/library/data/BlockStatePosWrapper.java index 22262a8..8df2d95 100644 --- a/src/main/java/com/lothrazar/library/data/BlockStatePosWrapper.java +++ b/src/main/java/com/lothrazar/library/data/BlockStatePosWrapper.java @@ -24,7 +24,7 @@ public BlockStatePosWrapper(Level world, BlockPos chunkPosition, BlockState bloc this.blockPos = chunkPosition; BlockEntity te = world.getBlockEntity(chunkPosition); if (te != null) { - this.tileEntityTag = te.saveWithoutMetadata(); + this.tileEntityTag = te.saveWithoutMetadata(world.registryAccess()); } } @@ -44,7 +44,7 @@ public CompoundTag getTileEntityTag() { public void readFromNBT(CompoundTag tag, Level level) { this.blockState = NbtUtils.readBlockState(level.holderLookup(Registries.BLOCK), tag.getCompound("block")); - this.blockPos = NbtUtils.readBlockPos(tag.getCompound("pos")); + this.blockPos = NbtUtils.readBlockPos(tag,"pos").orElse(null); if (tag.contains("tileentity")) { this.tileEntityTag = tag.getCompound("tileentity"); } @@ -53,8 +53,7 @@ public void readFromNBT(CompoundTag tag, Level level) { public void writeToNBT(CompoundTag tag) { CompoundTag encoded = NbtUtils.writeBlockState(this.blockState); tag.put("block", encoded); - CompoundTag epos = NbtUtils.writeBlockPos(this.blockPos); - tag.put("pos", epos); + tag.put("pos", NbtUtils.writeBlockPos(this.blockPos)); if (this.tileEntityTag != null) { tag.put("tileentity", this.tileEntityTag); } diff --git a/src/main/java/com/lothrazar/library/entity/BlockEntityFlib.java b/src/main/java/com/lothrazar/library/entity/BlockEntityFlib.java index d617db3..5115839 100644 --- a/src/main/java/com/lothrazar/library/entity/BlockEntityFlib.java +++ b/src/main/java/com/lothrazar/library/entity/BlockEntityFlib.java @@ -26,9 +26,9 @@ public BlockEntityFlib(BlockEntityType type, BlockPos pos, BlockState state) } @Override - public void load(CompoundTag tag, HolderLookup.Provider registries) { + public void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) { // timer = tag.getInt("timer"); - super.load(tag, registries); + super.loadAdditional(tag, registries); } @Override @@ -60,7 +60,7 @@ public CompoundTag getUpdateTag(HolderLookup.Provider registries) { @Override public void handleUpdateTag(CompoundTag tag, HolderLookup.Provider registries) { - this.load(tag, registries); + this.loadAdditional(tag, registries); } @Override diff --git a/src/main/java/com/lothrazar/library/events/CapabilityEvents.java b/src/main/java/com/lothrazar/library/events/CapabilityEvents.java index 98f92ca..b7968bd 100644 --- a/src/main/java/com/lothrazar/library/events/CapabilityEvents.java +++ b/src/main/java/com/lothrazar/library/events/CapabilityEvents.java @@ -35,8 +35,9 @@ public static void onPlayerCloned(PlayerEvent.Clone event) { public static void onRegisterCapabilities(RegisterCapabilitiesEvent event) { event.registerEntity( PlayerCapProvider.PLAYER_MANA_CAP, - (entity, ctx) -> entity instanceof Player ? entity.getData(PlayerCapProvider.PLAYER_MANA.get()) : null, - EntityType.PLAYER); - FutureLibMod.LOGGER.info("RegisterCapabilitiesEvent success for PlayerMana"); + EntityType.PLAYER, + (entity, ctx) -> entity.getData(PlayerCapProvider.PLAYER_MANA.get())); + + FutureLibMod.LOGGER.info("RegisterCapabilitiesEvent success"); } } diff --git a/src/main/java/com/lothrazar/library/particle/data/ParticleOptionsTwoInt.java b/src/main/java/com/lothrazar/library/particle/data/ParticleOptionsTwoInt.java index 6c46cc2..9809793 100644 --- a/src/main/java/com/lothrazar/library/particle/data/ParticleOptionsTwoInt.java +++ b/src/main/java/com/lothrazar/library/particle/data/ParticleOptionsTwoInt.java @@ -1,45 +1,36 @@ package com.lothrazar.library.particle.data; -import java.util.Locale; -import com.mojang.brigadier.StringReader; -import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.core.particles.ParticleOptions; import net.minecraft.core.particles.ParticleType; -import net.minecraft.network.FriendlyByteBuf; import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; /** - * used by ParticleBlinkingAura + * ParticleOptions implementation carrying two ints (e.g. two RGB color values). + * Used by ParticleBlinkingAura and similar effects. * + *

In 1.21.1, ParticleOptions no longer has Deserializer, writeToNetwork, or + * writeToString. Instead, the ParticleType provides a MapCodec and a StreamCodec. + * Use the static factory methods here when registering your ParticleType:

+ * + *
+ * PARTICLES.register("my_particle", () -> new ParticleType<<>;ParticleOptionsTwoInt>;(false) {
+ *   public MapCodec; codec() {
+ *     return ParticleOptionsTwoInt.codec(this);
+ *   }
+ *  public StreamCodec; streamCodec() {
+ *     return ParticleOptionsTwoInt.streamCodec(this);
+ *   }
+ * });
+ * 
*/ public class ParticleOptionsTwoInt implements ParticleOptions { - @SuppressWarnings("deprecation") - public static final Deserializer DESERIALIZER = new Deserializer() { - - @Override - public ParticleOptionsTwoInt fromCommand(ParticleType particleType, StringReader reader) throws CommandSyntaxException { - if (reader.canRead()) { - reader.expect(' '); - } - int oneInt = 0xffffff, twoInt = 0xffffff; - if (reader.canRead()) { - oneInt = reader.readInt(); - } - if (reader.canRead()) { - reader.expect(' '); - } - if (reader.canRead()) { - twoInt = reader.readInt(); - } - return new ParticleOptionsTwoInt(particleType, oneInt, twoInt); - } - - @Override - public ParticleOptionsTwoInt fromNetwork(ParticleType particleType, FriendlyByteBuf buf) { - return new ParticleOptionsTwoInt(particleType, buf.readInt(), buf.readInt()); - } - }; private final ParticleType particleType; public int oneInt, twoInt; @@ -54,14 +45,33 @@ public ParticleType getType() { return this.particleType; } - @Override - public void writeToNetwork(FriendlyByteBuf buf) { - buf.writeInt(this.oneInt); - buf.writeInt(this.twoInt); + /** + * Returns a MapCodec for command/config serialization. + * Call this from your ParticleType's codec() override, passing {@code this}. + */ + public static MapCodec codec(ParticleType type) { + return RecordCodecBuilder.mapCodec(instance -> + instance.group( + Codec.INT.fieldOf("oneInt").forGetter(p -> p.oneInt), + Codec.INT.fieldOf("twoInt").forGetter(p -> p.twoInt) + ).apply(instance, (a, b) -> new ParticleOptionsTwoInt(type, a, b)) + ); + } + + /** + * Returns a StreamCodec for network serialization. + * Call this from your ParticleType's streamCodec() override, passing {@code this}. + */ + public static StreamCodec streamCodec(ParticleType type) { + return StreamCodec.composite( + ByteBufCodecs.INT, p -> p.oneInt, + ByteBufCodecs.INT, p -> p.twoInt, + (a, b) -> new ParticleOptionsTwoInt(type, a, b) + ); } @Override - public String writeToString() { - return String.format(Locale.ROOT, "%s %d %d", BuiltInRegistries.PARTICLE_TYPE.getKey(getType()), this.oneInt, this.twoInt); + public String toString() { + return String.format("%s %d %d", BuiltInRegistries.PARTICLE_TYPE.getKey(getType()), oneInt, twoInt); } } From ede5197a5a060ef41334526d0b57bcca8b5892af Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 31 Mar 2026 22:25:14 -0700 Subject: [PATCH 11/29] at.cfg fix --- build.gradle | 3 +-- src/main/java/com/lothrazar/library/core/BlockPosDim.java | 2 +- src/main/resources/META-INF/accesstransformer.cfg | 2 ++ 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 0237b66..41ac1b4 100644 --- a/build.gradle +++ b/build.gradle @@ -55,8 +55,7 @@ neoForge { mappingsVersion = project.parchment_mappings_version minecraftVersion = project.parchment_minecraft_version } - // TODO: fix this. This line is optional. Access Transformers are automatically detected - // accessTransformers = project.files('src/main/resources/META-INF/accesstransformer.cfg') + accessTransformers = project.files('src/main/resources/META-INF/accesstransformer.cfg') // Default run configurations. // These can be tweaked, removed, or duplicated as needed. diff --git a/src/main/java/com/lothrazar/library/core/BlockPosDim.java b/src/main/java/com/lothrazar/library/core/BlockPosDim.java index 772462f..4d693db 100644 --- a/src/main/java/com/lothrazar/library/core/BlockPosDim.java +++ b/src/main/java/com/lothrazar/library/core/BlockPosDim.java @@ -54,7 +54,7 @@ public BlockPosDim(BlockPos pos, String dimension, CompoundTag stackTag) { .parse(JsonOps.INSTANCE, JsonParser.parseString(nameJson)) .result() .orElseGet(() -> Component.literal(nameJson)); - + // TODO: is this a waste of overcomplication? should it just be name string? // this.name = displayTag.getString("Name"); this.name = namec.getString(); } diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index e9374bf..1cd6566 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -50,3 +50,5 @@ public net.minecraft.world.level.GameRules$BooleanValue m_46250_(Z)Lnet/minecraf public net.minecraft.server.network.ServerGamePacketListenerImpl f_9737_ # aboveGroundTickCount public net.minecraft.world.level.block.state.BlockBehaviour$BlockStateBase f_60599_ # destroySpeed +# neoforge does not use SRG name, just mojang names. TODO: fix or remove all above this line +public net.minecraft.server.network.ServerGamePacketListenerImpl aboveGroundTickCount From e4ed05f495b7cd320b7dfd1e794f4c66929ae43f Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 31 Mar 2026 22:35:44 -0700 Subject: [PATCH 12/29] fix recipe cauldron factory --- .../lothrazar/library/registry/RecipeCauldronFactory.java | 2 +- src/main/java/com/lothrazar/library/util/EntityUtil.java | 6 +++--- src/main/resources/META-INF/accesstransformer.cfg | 7 +++++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/lothrazar/library/registry/RecipeCauldronFactory.java b/src/main/java/com/lothrazar/library/registry/RecipeCauldronFactory.java index 9e427a5..1aa970f 100644 --- a/src/main/java/com/lothrazar/library/registry/RecipeCauldronFactory.java +++ b/src/main/java/com/lothrazar/library/registry/RecipeCauldronFactory.java @@ -64,7 +64,7 @@ public static void setup(FMLCommonSetupEvent event) { } return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; }; - CauldronInteraction.WATER.map(rec.input.asItem(), interaction); + CauldronInteraction.WATER.map().put(rec.input.asItem(), interaction); } } } diff --git a/src/main/java/com/lothrazar/library/util/EntityUtil.java b/src/main/java/com/lothrazar/library/util/EntityUtil.java index 93bce23..4e88f91 100644 --- a/src/main/java/com/lothrazar/library/util/EntityUtil.java +++ b/src/main/java/com/lothrazar/library/util/EntityUtil.java @@ -350,7 +350,7 @@ public static void centerEntityHoriz(Entity entity, BlockPos pos) { public static List getVillagers(Level world, BlockPos p, int r) { BlockPos start = p.offset(-r, -r, -r); BlockPos end = p.offset(r, r, r); - return world.getEntitiesOfClass(Villager.class, new AABB(start, end)); + return world.getEntitiesOfClass(Villager.class, AABB.encapsulatingFullBlocks(start, end)); } public static LivingEntity getClosestEntity(Level world, Player player, List list) { @@ -449,11 +449,11 @@ public static void setCooldownItem(Player player, Item item, int cooldown) { } public static Attribute getAttributeJump(Horse ahorse) { - return Attributes.JUMP_STRENGTH; //was reflection lol + return Attributes.JUMP_STRENGTH.value(); } public static void eatingHorse(Horse ahorse) { - ahorse.eating(); // requires accesstransformer.cfg + ahorse.eating(); // requires accesstransformer.cfg } public static void tryMakeEntityClimb(Level worldIn, LivingEntity entity, double climbSpeed) { diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 1cd6566..05e5c20 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -35,7 +35,6 @@ public net.minecraft.world.entity.LivingEntity f_20922_ # ticksSinceLastSwing public net.minecraft.world.entity.player.Player f_36110_ # sleepCounter public net.minecraft.world.entity.LivingEntity m_21329_()V # updatingUsingItem -public net.minecraft.world.entity.animal.horse.AbstractHorse m_30610_()V # eating public net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer f_108823_ # shieldModel @@ -48,7 +47,11 @@ public net.minecraft.world.entity.decoration.ArmorStand func_175413_k(Z)V # setS public net.minecraft.world.level.GameRules$BooleanValue m_46250_(Z)Lnet/minecraft/world/level/GameRules$Type; # create boolean gamerule public net.minecraft.server.network.ServerGamePacketListenerImpl f_9737_ # aboveGroundTickCount -public net.minecraft.world.level.block.state.BlockBehaviour$BlockStateBase f_60599_ # destroySpeed # neoforge does not use SRG name, just mojang names. TODO: fix or remove all above this line public net.minecraft.server.network.ServerGamePacketListenerImpl aboveGroundTickCount + +public net.minecraft.world.entity.animal.horse.AbstractHorse eating()V # m_30610_ + +# net.minecraft.world.level.block.state.BlockBehaviour$BlockStateBase destroySpeed +public net.minecraft.world.level.block.state.BlockBehaviour$BlockStateBase destroySpeed # f_60599_ From a0dfff3367b401d56bbb1668a8d6ee29bab4cd5a Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 1 Apr 2026 07:59:16 -0700 Subject: [PATCH 13/29] fix isfluidequal --- .../library/cap/item/FluidHandlerCapabilityStack.java | 4 ++-- .../java/com/lothrazar/library/render/FluidRenderMap.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/lothrazar/library/cap/item/FluidHandlerCapabilityStack.java b/src/main/java/com/lothrazar/library/cap/item/FluidHandlerCapabilityStack.java index f8e42f4..604aeb5 100644 --- a/src/main/java/com/lothrazar/library/cap/item/FluidHandlerCapabilityStack.java +++ b/src/main/java/com/lothrazar/library/cap/item/FluidHandlerCapabilityStack.java @@ -103,7 +103,7 @@ public int fill(FluidStack resource, FluidAction doFill) { } return fillAmount; } else { - if (contained.isFluidEqual(resource)) { + if (FluidStack.isSameFluidSameComponents(contained, resource)) { int fillAmount = Math.min(capacity - contained.getAmount(), resource.getAmount()); if (doFill.execute() && fillAmount > 0) { contained.grow(fillAmount); @@ -117,7 +117,7 @@ public int fill(FluidStack resource, FluidAction doFill) { @Override public FluidStack drain(FluidStack resource, FluidAction action) { - if (container.getCount() != 1 || resource.isEmpty() || !resource.isFluidEqual(getFluid())) { + if (container.getCount() != 1 || resource.isEmpty() || !FluidStack.isSameFluidSameComponents(resource, getFluid())) { return FluidStack.EMPTY; } return drain(resource.getAmount(), action); diff --git a/src/main/java/com/lothrazar/library/render/FluidRenderMap.java b/src/main/java/com/lothrazar/library/render/FluidRenderMap.java index 4529b24..afc96b5 100644 --- a/src/main/java/com/lothrazar/library/render/FluidRenderMap.java +++ b/src/main/java/com/lothrazar/library/render/FluidRenderMap.java @@ -67,7 +67,7 @@ public int hashCode(FluidStack stack) { @Override public boolean equals(FluidStack a, FluidStack b) { - return a == null ? b == null : b != null && a.isFluidEqual(b); + return a == null ? b == null : b != null && FluidStack.isSameFluidSameComponents(a, b); } } } From 811f6c7764900d0ce74d4728367c592a8de540bd Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 1 Apr 2026 09:11:33 -0700 Subject: [PATCH 14/29] partial rendering fixes --- .../library/render/RenderBlockOverlay.java | 6 +- .../render/RenderEntityToBlockLaser.java | 33 ++++--- .../library/render/RenderResizableCuboid.java | 2 +- .../render/type/FakeBlockRenderTypes.java | 30 ++++-- .../library/render/type/LaserRenderType.java | 6 +- .../com/lothrazar/library/util/BlockUtil.java | 2 +- .../library/util/BlockstatesUtil.java | 2 +- .../library/util/FakePlayerUtil.java | 12 +-- .../lothrazar/library/util/ItemStackUtil.java | 9 +- .../library/util/LevelWorldUtil.java | 2 +- .../lothrazar/library/util/PlayerUtil.java | 1 - .../library/util/RenderBlockUtils.java | 96 +++++++++---------- .../lothrazar/library/util/RenderUtil.java | 48 +++++----- .../resources/META-INF/accesstransformer.cfg | 3 + 14 files changed, 134 insertions(+), 118 deletions(-) diff --git a/src/main/java/com/lothrazar/library/render/RenderBlockOverlay.java b/src/main/java/com/lothrazar/library/render/RenderBlockOverlay.java index 6aa93fd..ba9284f 100644 --- a/src/main/java/com/lothrazar/library/render/RenderBlockOverlay.java +++ b/src/main/java/com/lothrazar/library/render/RenderBlockOverlay.java @@ -225,8 +225,8 @@ private void drawSide(VertexConsumer buffer, Matrix4f matrix, int c, int i, int } private void addVertex(VertexConsumer buffer, Matrix4f matrix, double u, double v, int i) { - buffer.vertex(matrix, (float) vs[i].x, (float) vs[i].y, (float) vs[i].z) - .color(1.0f, 1.0f, 1.0f, 0.375f) - .uv((float) u, (float) v).endVertex(); + buffer.addVertex(matrix, (float) vs[i].x, (float) vs[i].y, (float) vs[i].z) + .setColor(1.0f, 1.0f, 1.0f, 0.375f) + .setUv((float) u, (float) v); } } diff --git a/src/main/java/com/lothrazar/library/render/RenderEntityToBlockLaser.java b/src/main/java/com/lothrazar/library/render/RenderEntityToBlockLaser.java index 6de96ff..1f59a1f 100644 --- a/src/main/java/com/lothrazar/library/render/RenderEntityToBlockLaser.java +++ b/src/main/java/com/lothrazar/library/render/RenderEntityToBlockLaser.java @@ -11,7 +11,6 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.util.Mth; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.player.Player; @@ -118,26 +117,26 @@ private static void drawBeam(ItemStack stack, double xOffset, double yOffset, do Vector4f vec4 = new Vector4f(startXOffset, thickness + startYOffset, startZOffset, 1.0F); vec4.mul(positionMatrix); if (hand == InteractionHand.MAIN_HAND) { - builder.vertex(vec4.x(), vec4.y(), vec4.z(), r, g, b, alpha, 0, (float) v1, OverlayTexture.NO_OVERLAY, 15728880, vector3f.x(), vector3f.y(), vector3f.z()); - builder.vertex(vec3.x(), vec3.y(), vec3.z(), r, g, b, alpha, 0, (float) v2, OverlayTexture.NO_OVERLAY, 15728880, vector3f.x(), vector3f.y(), vector3f.z()); - builder.vertex(vec2.x(), vec2.y(), vec2.z(), r, g, b, alpha, 1, (float) v2, OverlayTexture.NO_OVERLAY, 15728880, vector3f.x(), vector3f.y(), vector3f.z()); - builder.vertex(vec1.x(), vec1.y(), vec1.z(), r, g, b, alpha, 1, (float) v1, OverlayTexture.NO_OVERLAY, 15728880, vector3f.x(), vector3f.y(), vector3f.z()); + builder.addVertex(vec4.x(), vec4.y(), vec4.z()).setColor(r, g, b, alpha).setUv(0, (float) v1); + builder.addVertex(vec3.x(), vec3.y(), vec3.z()).setColor(r, g, b, alpha).setUv(0, (float) v2); + builder.addVertex(vec2.x(), vec2.y(), vec2.z()).setColor(r, g, b, alpha).setUv(1, (float) v2); + builder.addVertex(vec1.x(), vec1.y(), vec1.z()).setColor(r, g, b, alpha).setUv(1, (float) v1); //Rendering a 2nd time to allow you to see both sides in multiplayer, shouldn't be necessary with culling disabled but here we are.... - builder.vertex(vec1.x(), vec1.y(), vec1.z(), r, g, b, alpha, 1, (float) v1, OverlayTexture.NO_OVERLAY, 15728880, vector3f.x(), vector3f.y(), vector3f.z()); - builder.vertex(vec2.x(), vec2.y(), vec2.z(), r, g, b, alpha, 1, (float) v2, OverlayTexture.NO_OVERLAY, 15728880, vector3f.x(), vector3f.y(), vector3f.z()); - builder.vertex(vec3.x(), vec3.y(), vec3.z(), r, g, b, alpha, 0, (float) v2, OverlayTexture.NO_OVERLAY, 15728880, vector3f.x(), vector3f.y(), vector3f.z()); - builder.vertex(vec4.x(), vec4.y(), vec4.z(), r, g, b, alpha, 0, (float) v1, OverlayTexture.NO_OVERLAY, 15728880, vector3f.x(), vector3f.y(), vector3f.z()); + builder.addVertex(vec1.x(), vec1.y(), vec1.z()).setColor(r, g, b, alpha).setUv(1, (float) v1); + builder.addVertex(vec2.x(), vec2.y(), vec2.z()).setColor(r, g, b, alpha).setUv(1, (float) v2); + builder.addVertex(vec3.x(), vec3.y(), vec3.z()).setColor(r, g, b, alpha).setUv(0, (float) v2); + builder.addVertex(vec4.x(), vec4.y(), vec4.z()).setColor(r, g, b, alpha).setUv(0, (float) v1); } else { - builder.vertex(vec1.x(), vec1.y(), vec1.z(), r, g, b, alpha, 1, (float) v1, OverlayTexture.NO_OVERLAY, 15728880, vector3f.x(), vector3f.y(), vector3f.z()); - builder.vertex(vec2.x(), vec2.y(), vec2.z(), r, g, b, alpha, 1, (float) v2, OverlayTexture.NO_OVERLAY, 15728880, vector3f.x(), vector3f.y(), vector3f.z()); - builder.vertex(vec3.x(), vec3.y(), vec3.z(), r, g, b, alpha, 0, (float) v2, OverlayTexture.NO_OVERLAY, 15728880, vector3f.x(), vector3f.y(), vector3f.z()); - builder.vertex(vec4.x(), vec4.y(), vec4.z(), r, g, b, alpha, 0, (float) v1, OverlayTexture.NO_OVERLAY, 15728880, vector3f.x(), vector3f.y(), vector3f.z()); + builder.addVertex(vec1.x(), vec1.y(), vec1.z()).setColor(r, g, b, alpha).setUv(1, (float) v1); + builder.addVertex(vec2.x(), vec2.y(), vec2.z()).setColor(r, g, b, alpha).setUv(1, (float) v2); + builder.addVertex(vec3.x(), vec3.y(), vec3.z()).setColor(r, g, b, alpha).setUv(0, (float) v2); + builder.addVertex(vec4.x(), vec4.y(), vec4.z()).setColor(r, g, b, alpha).setUv(0, (float) v1); //Rendering a 2nd time to allow you to see both sides in multiplayer, shouldn't be necessary with culling disabled but here we are.... - builder.vertex(vec4.x(), vec4.y(), vec4.z(), r, g, b, alpha, 0, (float) v1, OverlayTexture.NO_OVERLAY, 15728880, vector3f.x(), vector3f.y(), vector3f.z()); - builder.vertex(vec3.x(), vec3.y(), vec3.z(), r, g, b, alpha, 0, (float) v2, OverlayTexture.NO_OVERLAY, 15728880, vector3f.x(), vector3f.y(), vector3f.z()); - builder.vertex(vec2.x(), vec2.y(), vec2.z(), r, g, b, alpha, 1, (float) v2, OverlayTexture.NO_OVERLAY, 15728880, vector3f.x(), vector3f.y(), vector3f.z()); - builder.vertex(vec1.x(), vec1.y(), vec1.z(), r, g, b, alpha, 1, (float) v1, OverlayTexture.NO_OVERLAY, 15728880, vector3f.x(), vector3f.y(), vector3f.z()); + builder.addVertex(vec4.x(), vec4.y(), vec4.z()).setColor(r, g, b, alpha).setUv(0, (float) v1); + builder.addVertex(vec3.x(), vec3.y(), vec3.z()).setColor(r, g, b, alpha).setUv(0, (float) v2); + builder.addVertex(vec2.x(), vec2.y(), vec2.z()).setColor(r, g, b, alpha).setUv(1, (float) v2); + builder.addVertex(vec1.x(), vec1.y(), vec1.z()).setColor(r, g, b, alpha).setUv(1, (float) v1); } } } diff --git a/src/main/java/com/lothrazar/library/render/RenderResizableCuboid.java b/src/main/java/com/lothrazar/library/render/RenderResizableCuboid.java index 1a6efc6..dd8ccc2 100644 --- a/src/main/java/com/lothrazar/library/render/RenderResizableCuboid.java +++ b/src/main/java/com/lothrazar/library/render/RenderResizableCuboid.java @@ -129,6 +129,6 @@ private void renderPoint(Matrix4f matrix4f, VertexConsumer buffer, Direction fac Vector3f vertex = withValue(VEC_ZERO, u, xyz[uFinal]); vertex = withValue(vertex, v, xyz[vFinal]); vertex = withValue(vertex, face.getAxis(), other); - buffer.vertex(matrix4f, vertex.x(), vertex.y(), vertex.z()).color(red, green, blue, alpha).uv(uv[uFinal], uv[vFinal]).uv2(light).endVertex(); + buffer.addVertex(matrix4f, vertex.x(), vertex.y(), vertex.z()).setColor(red, green, blue, alpha).setUv(uv[uFinal], uv[vFinal]).setLight(light); } } diff --git a/src/main/java/com/lothrazar/library/render/type/FakeBlockRenderTypes.java b/src/main/java/com/lothrazar/library/render/type/FakeBlockRenderTypes.java index bd7c9d1..ea7a74c 100644 --- a/src/main/java/com/lothrazar/library/render/type/FakeBlockRenderTypes.java +++ b/src/main/java/com/lothrazar/library/render/type/FakeBlockRenderTypes.java @@ -2,8 +2,11 @@ import java.util.OptionalDouble; import com.lothrazar.library.FutureLibMod; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.VertexFormat; +import net.minecraft.client.renderer.RenderStateShard; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; @@ -22,11 +25,20 @@ public FakeBlockRenderTypes(String nameIn, VertexFormat formatIn, VertexFormat.M super(nameIn, formatIn, drawModeIn, bufferSizeIn, useDelegateIn, needsSortingIn, setupTaskIn, clearTaskIn); } + // ADDITIVE_TRANSPARENCY was removed from RenderStateShard in 1.21.1; define it locally + private static final TransparencyStateShard ADDITIVE_TRANSPARENCY_SHARD = new TransparencyStateShard( + "additive_transparency", + () -> { + RenderSystem.enableBlend(); + RenderSystem.blendFunc(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE); + }, + RenderSystem::disableBlend); + public final static ResourceLocation BEAM = ResourceLocation.fromNamespaceAndPath(FutureLibMod.MODID, "textures/effect/beam.png"); public static final RenderType LASER_MAIN_BEAM = create(FutureLibMod.MODID + ":mininglasermainbeam", - DefaultVertexFormat.POSITION_COLOR_TEX, VertexFormat.Mode.QUADS, BUFFERSIZE, CRUMBLING, SORT, + DefaultVertexFormat.POSITION_TEX_COLOR, VertexFormat.Mode.QUADS, BUFFERSIZE, CRUMBLING, SORT, RenderType.CompositeState.builder() - .setTextureState(new TextureStateShard(BEAM, BLUR, MIPMAP)).setShaderState(ShaderStateShard.POSITION_COLOR_TEX_SHADER) + .setTextureState(new TextureStateShard(BEAM, BLUR, MIPMAP)).setShaderState(POSITION_COLOR_SHADER) // was POSITION_COLOR_TEX_SHADER .setLayeringState(VIEW_OFFSET_Z_LAYERING) .setTransparencyState(TRANSLUCENT_TRANSPARENCY) .setDepthTestState(NO_DEPTH_TEST) @@ -36,16 +48,16 @@ public FakeBlockRenderTypes(String nameIn, VertexFormat formatIn, VertexFormat.M .createCompositeState(false)); /** * used by TESR that render blocks with textures Shape builder, ghostsoundmuffler, render light camo. - * + * */ public static final RenderType FAKE_BLOCK = create(FutureLibMod.MODID + ":fakeblock", DefaultVertexFormat.BLOCK, VertexFormat.Mode.QUADS, BUFFERSIZE, CRUMBLING, SORT, RenderType.CompositeState.builder() .setShaderState(RENDERTYPE_SOLID_SHADER) //1.17 was - BLOCK_SHADER - .setLayeringState(POLYGON_OFFSET_LAYERING) // VIEW_OFFSET_Z_LAYERING) // .setShadeModelState(SMOOTH_SHADE) + .setLayeringState(POLYGON_OFFSET_LAYERING) // VIEW_OFFSET_Z_LAYERING) .setLightmapState(NO_LIGHTMAP) .setTextureState(BLOCK_SHEET_MIPPED) - .setTransparencyState(ADDITIVE_TRANSPARENCY) + .setTransparencyState(ADDITIVE_TRANSPARENCY_SHARD) .setDepthTestState(NO_DEPTH_TEST) .setCullState(CULL) .setWriteMaskState(COLOR_DEPTH_WRITE) @@ -59,7 +71,7 @@ public FakeBlockRenderTypes(String nameIn, VertexFormat formatIn, VertexFormat.M .setShaderState(RENDERTYPE_LINES_SHADER) .setLayeringState(VIEW_OFFSET_Z_LAYERING) .setOutputState(ITEM_ENTITY_TARGET) - .setTransparencyState(ADDITIVE_TRANSPARENCY) + .setTransparencyState(ADDITIVE_TRANSPARENCY_SHARD) .setTextureState(NO_TEXTURE) .setDepthTestState(NO_DEPTH_TEST) .setCullState(CULL) @@ -68,8 +80,8 @@ public FakeBlockRenderTypes(String nameIn, VertexFormat formatIn, VertexFormat.M .createCompositeState(false)); /** * used by most blocks that select blocks such as cyclic:forester, cyclic:harvester, cyclic:miner in TESRs - * - * + * + * */ public static final RenderType SOLID_COLOUR = create(FutureLibMod.MODID + ":solidcolour", DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.QUADS, BUFFERSIZE, CRUMBLING, SORT, @@ -77,7 +89,7 @@ public FakeBlockRenderTypes(String nameIn, VertexFormat formatIn, VertexFormat.M .setShaderState(RENDERTYPE_LINES_SHADER) .setLayeringState(VIEW_OFFSET_Z_LAYERING) .setOutputState(ITEM_ENTITY_TARGET) - .setTransparencyState(ADDITIVE_TRANSPARENCY) + .setTransparencyState(ADDITIVE_TRANSPARENCY_SHARD) .setTextureState(NO_TEXTURE) .setDepthTestState(NO_DEPTH_TEST) .setCullState(CULL) diff --git a/src/main/java/com/lothrazar/library/render/type/LaserRenderType.java b/src/main/java/com/lothrazar/library/render/type/LaserRenderType.java index 14d7516..f805c06 100644 --- a/src/main/java/com/lothrazar/library/render/type/LaserRenderType.java +++ b/src/main/java/com/lothrazar/library/render/type/LaserRenderType.java @@ -25,7 +25,7 @@ public LaserRenderType(String nameIn, VertexFormat formatIn, VertexFormat.Mode d public static final RenderType LASER_MAIN_BEAM = create("MAIN_", DefaultVertexFormat.POSITION_COLOR_TEX, VertexFormat.Mode.QUADS, 256, false, false, RenderType.CompositeState.builder().setTextureState(new TextureStateShard(RL_BEAM, false, false)) - .setShaderState(ShaderStateShard.POSITION_COLOR_TEX_SHADER) + .setShaderState(POSITION_COLOR_TEX_SHADER) .setLayeringState(VIEW_OFFSET_Z_LAYERING) .setTransparencyState(TRANSLUCENT_TRANSPARENCY) .setDepthTestState(NO_DEPTH_TEST) @@ -36,7 +36,7 @@ public LaserRenderType(String nameIn, VertexFormat formatIn, VertexFormat.Mode d public static final RenderType LASER_MAIN_ADDITIVE = create("MiningLaserAdditiveBeam", DefaultVertexFormat.POSITION_COLOR_TEX, VertexFormat.Mode.QUADS, 256, false, false, RenderType.CompositeState.builder().setTextureState(new TextureStateShard(RL_GLOW, false, false)) - .setShaderState(ShaderStateShard.POSITION_COLOR_TEX_SHADER) + .setShaderState(POSITION_COLOR_TEX_SHADER) .setLayeringState(VIEW_OFFSET_Z_LAYERING) .setTransparencyState(TRANSLUCENT_TRANSPARENCY) .setDepthTestState(NO_DEPTH_TEST) @@ -47,7 +47,7 @@ public LaserRenderType(String nameIn, VertexFormat formatIn, VertexFormat.Mode d public static final RenderType LASER_MAIN_CORE = create("MiningLaserCoreBeam", DefaultVertexFormat.POSITION_COLOR_TEX, VertexFormat.Mode.QUADS, 256, false, false, RenderType.CompositeState.builder().setTextureState(new TextureStateShard(RL_LASER, false, false)) - .setShaderState(ShaderStateShard.POSITION_COLOR_TEX_SHADER) + .setShaderState(POSITION_COLOR_TEX_SHADER) .setLayeringState(VIEW_OFFSET_Z_LAYERING) .setTransparencyState(TRANSLUCENT_TRANSPARENCY) .setDepthTestState(NO_DEPTH_TEST) diff --git a/src/main/java/com/lothrazar/library/util/BlockUtil.java b/src/main/java/com/lothrazar/library/util/BlockUtil.java index e13b4f6..5b183ae 100644 --- a/src/main/java/com/lothrazar/library/util/BlockUtil.java +++ b/src/main/java/com/lothrazar/library/util/BlockUtil.java @@ -23,7 +23,7 @@ public class BlockUtil { @SuppressWarnings("deprecation") public static Block.Properties wrap(Block.Properties propIn, Block blockIn) { return propIn - .sound(blockIn.getSoundType(blockIn.defaultBlockState())) + .sound(blockIn.soundType) .strength(blockIn.defaultBlockState().destroySpeed); } diff --git a/src/main/java/com/lothrazar/library/util/BlockstatesUtil.java b/src/main/java/com/lothrazar/library/util/BlockstatesUtil.java index 8977553..3066538 100644 --- a/src/main/java/com/lothrazar/library/util/BlockstatesUtil.java +++ b/src/main/java/com/lothrazar/library/util/BlockstatesUtil.java @@ -14,7 +14,7 @@ public class BlockstatesUtil { public static boolean isGlass(BlockState blockIn) { - return blockIn.is(Tags.Blocks.GLASS) || blockIn.is(Tags.Blocks.GLASS_PANES); + return blockIn.is(Tags.Blocks.GLASS_BLOCKS) || blockIn.is(Tags.Blocks.GLASS_PANES); } public static Direction getFacingFromEntity(BlockPos clickedBlock, LivingEntity entity) { diff --git a/src/main/java/com/lothrazar/library/util/FakePlayerUtil.java b/src/main/java/com/lothrazar/library/util/FakePlayerUtil.java index 6945729..244a622 100644 --- a/src/main/java/com/lothrazar/library/util/FakePlayerUtil.java +++ b/src/main/java/com/lothrazar/library/util/FakePlayerUtil.java @@ -61,12 +61,12 @@ public static WeakReference initFakePlayer(ServerLevel ws, String bl return null; // trying to get around https://github.com/PrinceOfAmber/Cyclic/issues/113 } fakePlayer.get().setOnGround(true); - // fakePlayer.get().onGround = true; - fakePlayer.get().connection = new ServerGamePacketListenerImpl(ws.getServer(), new Connection(PacketFlow.SERVERBOUND), fakePlayer.get()) { - - @Override - public void send(Packet packetIn) {} - }; + // in neoforge 1.21.1 the connection should already be faked +// fakePlayer.get().connection = new ServerGamePacketListenerImpl(ws.getServer(), new Connection(PacketFlow.SERVERBOUND), fakePlayer.get()) { +// +// @Override +// public void send(Packet packetIn) {} +// }; fakePlayer.get().setSilent(true); return fakePlayer; } diff --git a/src/main/java/com/lothrazar/library/util/ItemStackUtil.java b/src/main/java/com/lothrazar/library/util/ItemStackUtil.java index 909a2b3..9b49992 100644 --- a/src/main/java/com/lothrazar/library/util/ItemStackUtil.java +++ b/src/main/java/com/lothrazar/library/util/ItemStackUtil.java @@ -10,6 +10,7 @@ import net.minecraft.util.RandomSource; import net.minecraft.world.Containers; import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; @@ -122,9 +123,11 @@ public static void damageItem(LivingEntity player, ItemStack stack, InteractionH stack.setDamageValue(stack.getDamageValue() + 1); } else { - stack.hurtAndBreak(1, player, (p) -> { - p.broadcastBreakEvent(InteractionHand.MAIN_HAND); - }); + final Item item = stack.getItem(); + stack.hurtAndBreak(1, player, EquipmentSlot.MAINHAND); +// (p) -> { +// p.broadcastBreakEvent(EquipmentSlot.MAINHAND); +// }); } if (stack.getDamageValue() >= stack.getMaxDamage()) { stack.shrink(1); diff --git a/src/main/java/com/lothrazar/library/util/LevelWorldUtil.java b/src/main/java/com/lothrazar/library/util/LevelWorldUtil.java index b352f67..f3ca298 100644 --- a/src/main/java/com/lothrazar/library/util/LevelWorldUtil.java +++ b/src/main/java/com/lothrazar/library/util/LevelWorldUtil.java @@ -42,7 +42,7 @@ public static boolean removeFlowingLiquid(Level world, BlockPos pos, boolean nuk if (blockHere.getBlock() instanceof BucketPickup) { BucketPickup block = (BucketPickup) blockHere.getBlock(); // - ItemStack res = block.pickupBlock(world, pos, blockHere); + ItemStack res = block.pickupBlock(null, world, pos, blockHere); if (!res.isEmpty()) { // flowing block return world.setBlock(pos, Blocks.AIR.defaultBlockState(), 18); diff --git a/src/main/java/com/lothrazar/library/util/PlayerUtil.java b/src/main/java/com/lothrazar/library/util/PlayerUtil.java index eeb5b02..ccbf03d 100644 --- a/src/main/java/com/lothrazar/library/util/PlayerUtil.java +++ b/src/main/java/com/lothrazar/library/util/PlayerUtil.java @@ -99,7 +99,6 @@ public static Optional getPlayerHome(ServerPlayer player) { if (respawnPos != null) { optional = Player.findRespawnPositionAndUseSpawnBlock((ServerLevel) player.level(), respawnPos, 0.0F, true, true); } - // optional = Player.findRespawnPositionAndUseSpawnBlock(player.getLevel(), respawnPos, 0.0F, true, true); return optional; } } diff --git a/src/main/java/com/lothrazar/library/util/RenderBlockUtils.java b/src/main/java/com/lothrazar/library/util/RenderBlockUtils.java index 566b6b8..1b2eafa 100644 --- a/src/main/java/com/lothrazar/library/util/RenderBlockUtils.java +++ b/src/main/java/com/lothrazar/library/util/RenderBlockUtils.java @@ -51,35 +51,35 @@ public static void renderCube(Matrix4f matrix, VertexConsumer builder, BlockPos float red = color.getRed() / 255f, green = color.getGreen() / 255f, blue = color.getBlue() / 255f; float startX = 0, startY = 0, startZ = -1, endX = 1, endY = 1, endZ = 0; //down - builder.vertex(matrix, startX, startY, startZ).color(red, green, blue, alpha).endVertex(); - builder.vertex(matrix, endX, startY, startZ).color(red, green, blue, alpha).endVertex(); - builder.vertex(matrix, endX, startY, endZ).color(red, green, blue, alpha).endVertex(); - builder.vertex(matrix, startX, startY, endZ).color(red, green, blue, alpha).endVertex(); + builder.addVertex(matrix,startX, startY, startZ).setColor(red, green, blue, alpha); + builder.addVertex(matrix,endX, startY, startZ).setColor(red, green, blue, alpha); + builder.addVertex(matrix,endX, startY, endZ).setColor(red, green, blue, alpha); + builder.addVertex(matrix,startX, startY, endZ).setColor(red, green, blue, alpha); //up - builder.vertex(matrix, startX, endY, startZ).color(red, green, blue, alpha).endVertex(); - builder.vertex(matrix, startX, endY, endZ).color(red, green, blue, alpha).endVertex(); - builder.vertex(matrix, endX, endY, endZ).color(red, green, blue, alpha).endVertex(); - builder.vertex(matrix, endX, endY, startZ).color(red, green, blue, alpha).endVertex(); + builder.addVertex(matrix,startX, endY, startZ).setColor(red, green, blue, alpha); + builder.addVertex(matrix,startX, endY, endZ).setColor(red, green, blue, alpha); + builder.addVertex(matrix,endX, endY, endZ).setColor(red, green, blue, alpha); + builder.addVertex(matrix,endX, endY, startZ).setColor(red, green, blue, alpha); //east - builder.vertex(matrix, startX, startY, startZ).color(red, green, blue, alpha).endVertex(); - builder.vertex(matrix, startX, endY, startZ).color(red, green, blue, alpha).endVertex(); - builder.vertex(matrix, endX, endY, startZ).color(red, green, blue, alpha).endVertex(); - builder.vertex(matrix, endX, startY, startZ).color(red, green, blue, alpha).endVertex(); + builder.addVertex(matrix,startX, startY, startZ).setColor(red, green, blue, alpha); + builder.addVertex(matrix,startX, endY, startZ).setColor(red, green, blue, alpha); + builder.addVertex(matrix,endX, endY, startZ).setColor(red, green, blue, alpha); + builder.addVertex(matrix,endX, startY, startZ).setColor(red, green, blue, alpha); //west - builder.vertex(matrix, startX, startY, endZ).color(red, green, blue, alpha).endVertex(); - builder.vertex(matrix, endX, startY, endZ).color(red, green, blue, alpha).endVertex(); - builder.vertex(matrix, endX, endY, endZ).color(red, green, blue, alpha).endVertex(); - builder.vertex(matrix, startX, endY, endZ).color(red, green, blue, alpha).endVertex(); + builder.addVertex(matrix,startX, startY, endZ).setColor(red, green, blue, alpha); + builder.addVertex(matrix,endX, startY, endZ).setColor(red, green, blue, alpha); + builder.addVertex(matrix,endX, endY, endZ).setColor(red, green, blue, alpha); + builder.addVertex(matrix,startX, endY, endZ).setColor(red, green, blue, alpha); //south - builder.vertex(matrix, endX, startY, startZ).color(red, green, blue, alpha).endVertex(); - builder.vertex(matrix, endX, endY, startZ).color(red, green, blue, alpha).endVertex(); - builder.vertex(matrix, endX, endY, endZ).color(red, green, blue, alpha).endVertex(); - builder.vertex(matrix, endX, startY, endZ).color(red, green, blue, alpha).endVertex(); + builder.addVertex(matrix,endX, startY, startZ).setColor(red, green, blue, alpha); + builder.addVertex(matrix,endX, endY, startZ).setColor(red, green, blue, alpha); + builder.addVertex(matrix,endX, endY, endZ).setColor(red, green, blue, alpha); + builder.addVertex(matrix,endX, startY, endZ).setColor(red, green, blue, alpha); //north - builder.vertex(matrix, startX, startY, startZ).color(red, green, blue, alpha).endVertex(); - builder.vertex(matrix, startX, startY, endZ).color(red, green, blue, alpha).endVertex(); - builder.vertex(matrix, startX, endY, endZ).color(red, green, blue, alpha).endVertex(); - builder.vertex(matrix, startX, endY, startZ).color(red, green, blue, alpha).endVertex(); + builder.addVertex(matrix,startX, startY, startZ).setColor(red, green, blue, alpha); + builder.addVertex(matrix,startX, startY, endZ).setColor(red, green, blue, alpha); + builder.addVertex(matrix,startX, endY, endZ).setColor(red, green, blue, alpha); + builder.addVertex(matrix,startX, endY, startZ).setColor(red, green, blue, alpha); } /** @@ -341,30 +341,30 @@ public static void createBox(MultiBufferSource.BufferSource bufferSource, Vec3 c VertexConsumer vertexConsumer = bufferSource.getBuffer(FakeBlockRenderTypes.TOMB_LINES); poseStack.translate(-cameraPosition.x, -cameraPosition.y, -cameraPosition.z); Matrix4f pose = poseStack.last().pose(); - vertexConsumer.vertex(pose, x, y, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y + offset, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y + offset, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y + offset, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y + offset, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y + offset, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y + offset, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y + offset, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y + offset, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y + offset, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y + offset, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y + offset, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y + offset, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); + vertexConsumer.addVertex(pose, x, y, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y + offset, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y + offset, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y + offset, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y + offset, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y + offset, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y + offset, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y + offset, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y + offset, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y + offset, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y + offset, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y + offset, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y + offset, z + offset).setColor(color[0], color[1], color[2], 1.0F); bufferSource.endBatch(FakeBlockRenderTypes.TOMB_LINES); RenderSystem.enableDepthTest(); } diff --git a/src/main/java/com/lothrazar/library/util/RenderUtil.java b/src/main/java/com/lothrazar/library/util/RenderUtil.java index 87d126d..e0c77c2 100644 --- a/src/main/java/com/lothrazar/library/util/RenderUtil.java +++ b/src/main/java/com/lothrazar/library/util/RenderUtil.java @@ -50,30 +50,30 @@ public static void createBox(MultiBufferSource.BufferSource bufferSource, PoseSt VertexConsumer vertexConsumer = bufferSource.getBuffer(renderType); poseStack.translate(-cameraPosition.x, -cameraPosition.y, -cameraPosition.z); Matrix4f pose = poseStack.last().pose(); - vertexConsumer.vertex(pose, x, y, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y + offset, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y + offset, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y + offset, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y + offset, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y + offset, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y + offset, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y + offset, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y + offset, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y + offset, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y + offset, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y + offset, z).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x + offset, y, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); - vertexConsumer.vertex(pose, x, y + offset, z + offset).color(color[0], color[1], color[2], 1.0F).endVertex(); + vertexConsumer.addVertex(pose, x, y, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y + offset, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y + offset, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y + offset, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y + offset, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y + offset, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y + offset, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y + offset, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y + offset, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y + offset, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y + offset, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y + offset, z).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x + offset, y, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y, z + offset).setColor(color[0], color[1], color[2], 1.0F); + vertexConsumer.addVertex(pose, x, y + offset, z + offset).setColor(color[0], color[1], color[2], 1.0F); bufferSource.endBatch(renderType); RenderSystem.enableDepthTest(); } diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 05e5c20..a5693c2 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -55,3 +55,6 @@ public net.minecraft.world.entity.animal.horse.AbstractHorse eating()V # m_30610 # net.minecraft.world.level.block.state.BlockBehaviour$BlockStateBase destroySpeed public net.minecraft.world.level.block.state.BlockBehaviour$BlockStateBase destroySpeed # f_60599_ + +public net.minecraft.world.level.block.state.BlockBehaviour soundType + From 14c144c35146e2c05380314b946d74dc16a13aac Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 1 Apr 2026 09:28:38 -0700 Subject: [PATCH 15/29] Better rendering fixes --- .../RandomizedOutputIngredient.java | 12 +++- .../render/type/FakeBlockRenderTypes.java | 4 +- .../library/render/type/LaserRenderType.java | 25 +++++--- .../render/type/OverlayRenderType.java | 5 +- .../render/type/ParticleRenderTypes.java | 61 ++++++++++--------- .../lothrazar/library/util/PlayerUtil.java | 3 +- 6 files changed, 67 insertions(+), 43 deletions(-) diff --git a/src/main/java/com/lothrazar/library/recipe/ingredient/RandomizedOutputIngredient.java b/src/main/java/com/lothrazar/library/recipe/ingredient/RandomizedOutputIngredient.java index d3d2d36..fe8ebb0 100644 --- a/src/main/java/com/lothrazar/library/recipe/ingredient/RandomizedOutputIngredient.java +++ b/src/main/java/com/lothrazar/library/recipe/ingredient/RandomizedOutputIngredient.java @@ -1,6 +1,8 @@ package com.lothrazar.library.recipe.ingredient; import com.google.gson.JsonObject; +import com.lothrazar.library.FutureLibMod; +import com.mojang.serialization.JsonOps; import net.minecraft.util.GsonHelper; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.ShapedRecipe; @@ -23,7 +25,15 @@ public RandomizedOutputIngredient(int readInt, ItemStack readItem) { private void parseData(JsonObject json) { if (json.has(KEY_BONUS) && json.has(KEY_PERCENT)) { - bonus = ShapedRecipe.itemStackFromJson(GsonHelper.getAsJsonObject(json, KEY_BONUS)); + + //bonus = ShapedRecipe.itemStackFromJson(GsonHelper.getAsJsonObject(json, KEY_BONUS)); + // replaced with codec parse + bonus = ItemStack.CODEC.parse(JsonOps.INSTANCE, json) + .resultOrPartial(errorMessage -> { + FutureLibMod.LOGGER.error("Failed to parse ItemStack: {}", errorMessage); + }) + .orElse(ItemStack.EMPTY); + percent = json.get(KEY_PERCENT).getAsInt(); percent = Math.max(0, percent); if (percent > 100) { diff --git a/src/main/java/com/lothrazar/library/render/type/FakeBlockRenderTypes.java b/src/main/java/com/lothrazar/library/render/type/FakeBlockRenderTypes.java index ea7a74c..eaa52bb 100644 --- a/src/main/java/com/lothrazar/library/render/type/FakeBlockRenderTypes.java +++ b/src/main/java/com/lothrazar/library/render/type/FakeBlockRenderTypes.java @@ -6,6 +6,7 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.VertexFormat; +import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.RenderStateShard; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; @@ -38,7 +39,8 @@ public FakeBlockRenderTypes(String nameIn, VertexFormat formatIn, VertexFormat.M public static final RenderType LASER_MAIN_BEAM = create(FutureLibMod.MODID + ":mininglasermainbeam", DefaultVertexFormat.POSITION_TEX_COLOR, VertexFormat.Mode.QUADS, BUFFERSIZE, CRUMBLING, SORT, RenderType.CompositeState.builder() - .setTextureState(new TextureStateShard(BEAM, BLUR, MIPMAP)).setShaderState(POSITION_COLOR_SHADER) // was POSITION_COLOR_TEX_SHADER + .setTextureState(new TextureStateShard(BEAM, BLUR, MIPMAP)) + .setShaderState(new RenderStateShard.ShaderStateShard(GameRenderer::getPositionTexColorShader)) // was POSITION_COLOR_TEX_SHADER .setLayeringState(VIEW_OFFSET_Z_LAYERING) .setTransparencyState(TRANSLUCENT_TRANSPARENCY) .setDepthTestState(NO_DEPTH_TEST) diff --git a/src/main/java/com/lothrazar/library/render/type/LaserRenderType.java b/src/main/java/com/lothrazar/library/render/type/LaserRenderType.java index f805c06..7d761bb 100644 --- a/src/main/java/com/lothrazar/library/render/type/LaserRenderType.java +++ b/src/main/java/com/lothrazar/library/render/type/LaserRenderType.java @@ -3,14 +3,19 @@ import com.lothrazar.library.FutureLibMod; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.VertexFormat; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.RenderStateShard; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; /** - * Citation/source/author - * - * - * https://github.com/Direwolf20-MC/MiningGadgets + * + * Old Forge 1.20 NeoForge 1.21 (GameRenderer Method or Constant) + * POSITION_COLOR_TEX_SHADER getPositionTexColorShader() + * POSITION_COLOR_SHADER getPositionColorShader() + * POSITION_TEX_SHADER getPositionTexShader() + * POSITION_SHADER getPositionShader() + * POSITION_COLOR_TEX POSITION_TEX_COLOR * */ public class LaserRenderType extends RenderType { @@ -23,9 +28,9 @@ public LaserRenderType(String nameIn, VertexFormat formatIn, VertexFormat.Mode d private final static ResourceLocation RL_BEAM = ResourceLocation.fromNamespaceAndPath(FutureLibMod.MODID, "textures/effect/beam.png"); private final static ResourceLocation RL_GLOW = ResourceLocation.fromNamespaceAndPath(FutureLibMod.MODID, "textures/effect/glow.png"); public static final RenderType LASER_MAIN_BEAM = create("MAIN_", - DefaultVertexFormat.POSITION_COLOR_TEX, VertexFormat.Mode.QUADS, 256, false, false, + DefaultVertexFormat.POSITION_TEX_COLOR, VertexFormat.Mode.QUADS, 256, false, false, RenderType.CompositeState.builder().setTextureState(new TextureStateShard(RL_BEAM, false, false)) - .setShaderState(POSITION_COLOR_TEX_SHADER) + .setShaderState(new RenderStateShard.ShaderStateShard(GameRenderer::getPositionTexColorShader)) // was POSITION_COLOR_TEX_SHADER .setLayeringState(VIEW_OFFSET_Z_LAYERING) .setTransparencyState(TRANSLUCENT_TRANSPARENCY) .setDepthTestState(NO_DEPTH_TEST) @@ -34,9 +39,9 @@ public LaserRenderType(String nameIn, VertexFormat formatIn, VertexFormat.Mode d .setWriteMaskState(COLOR_WRITE) .createCompositeState(false)); public static final RenderType LASER_MAIN_ADDITIVE = create("MiningLaserAdditiveBeam", - DefaultVertexFormat.POSITION_COLOR_TEX, VertexFormat.Mode.QUADS, 256, false, false, + DefaultVertexFormat.POSITION_TEX_COLOR, VertexFormat.Mode.QUADS, 256, false, false, RenderType.CompositeState.builder().setTextureState(new TextureStateShard(RL_GLOW, false, false)) - .setShaderState(POSITION_COLOR_TEX_SHADER) + .setShaderState(new RenderStateShard.ShaderStateShard(GameRenderer::getPositionTexColorShader)) // was POSITION_COLOR_TEX_SHADER .setLayeringState(VIEW_OFFSET_Z_LAYERING) .setTransparencyState(TRANSLUCENT_TRANSPARENCY) .setDepthTestState(NO_DEPTH_TEST) @@ -45,9 +50,9 @@ public LaserRenderType(String nameIn, VertexFormat formatIn, VertexFormat.Mode d .setWriteMaskState(COLOR_WRITE) .createCompositeState(false)); public static final RenderType LASER_MAIN_CORE = create("MiningLaserCoreBeam", - DefaultVertexFormat.POSITION_COLOR_TEX, VertexFormat.Mode.QUADS, 256, false, false, + DefaultVertexFormat.POSITION_TEX_COLOR, VertexFormat.Mode.QUADS, 256, false, false, RenderType.CompositeState.builder().setTextureState(new TextureStateShard(RL_LASER, false, false)) - .setShaderState(POSITION_COLOR_TEX_SHADER) + .setShaderState(new RenderStateShard.ShaderStateShard(GameRenderer::getPositionTexColorShader))// was POSITION_COLOR_TEX_SHADER .setLayeringState(VIEW_OFFSET_Z_LAYERING) .setTransparencyState(TRANSLUCENT_TRANSPARENCY) .setDepthTestState(NO_DEPTH_TEST) diff --git a/src/main/java/com/lothrazar/library/render/type/OverlayRenderType.java b/src/main/java/com/lothrazar/library/render/type/OverlayRenderType.java index 5bcf8bc..c40b05b 100644 --- a/src/main/java/com/lothrazar/library/render/type/OverlayRenderType.java +++ b/src/main/java/com/lothrazar/library/render/type/OverlayRenderType.java @@ -2,6 +2,7 @@ import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.VertexFormat; +import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.RenderStateShard; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; @@ -34,10 +35,10 @@ public static RenderType overlayRenderer(String id, ResourceLocation resourceLoc RenderType.CompositeState state = RenderType.CompositeState.builder() .setTextureState(new RenderStateShard.TextureStateShard(resourceLocation, false, false)) .setCullState(RenderStateShard.NO_CULL) - .setShaderState(RenderStateShard.POSITION_COLOR_TEX_SHADER) + .setShaderState(new RenderStateShard.ShaderStateShard(GameRenderer::getPositionTexColorShader))// was POSITION_COLOR_TEX_SHADER .setTransparencyState(TRANSLUCENT_TRANSPARENCY) .setOutputState(RenderStateShard.TRANSLUCENT_TARGET) .createCompositeState(true); - return create(id, DefaultVertexFormat.POSITION_COLOR_TEX, VertexFormat.Mode.QUADS, 256, true, false, state); + return create(id, DefaultVertexFormat.POSITION_TEX_COLOR, VertexFormat.Mode.QUADS, 256, true, false, state); } } diff --git a/src/main/java/com/lothrazar/library/render/type/ParticleRenderTypes.java b/src/main/java/com/lothrazar/library/render/type/ParticleRenderTypes.java index 87f5ad8..135c8e2 100644 --- a/src/main/java/com/lothrazar/library/render/type/ParticleRenderTypes.java +++ b/src/main/java/com/lothrazar/library/render/type/ParticleRenderTypes.java @@ -18,37 +18,42 @@ * calling type.begin(buffer, textureManager), so begin() only sets up GL state. * end() must call BufferUploader.drawWithShader(tessellator.end()) since * Tesselator.end() now returns MeshData instead of uploading directly. + * + * see other Render Types in this library or build your own */ +@Deprecated public class ParticleRenderTypes { - public static final ParticleRenderType MAGIC_RENDER = new ParticleRenderType() { - - @Override - public void begin(BufferBuilder buffer, TextureManager textureManager) { - RenderSystem.enableBlend(); - RenderSystem.enableCull(); - RenderSystem.setShaderTexture(0, TextureAtlas.LOCATION_PARTICLES); - RenderSystem.depthMask(false); - RenderSystem.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); - // Note: do NOT call buffer.begin() here - the ParticleEngine already started - // the buffer via Tesselator.begin(Mode, Format) before calling this method. - } - @Override - public void end(Tesselator tessellator) { - MeshData meshData = tessellator.end(); - if (meshData != null) { - BufferUploader.drawWithShader(meshData); - } - RenderSystem.enableDepthTest(); - RenderSystem.depthMask(true); - RenderSystem.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); - RenderSystem.disableCull(); - } - @Override - public String toString() { - return "rootsclassic:magic"; - } - }; +// public static final ParticleRenderType MAGIC_RENDER = new ParticleRenderType() { +// +// @Override +// public void begin(BufferBuilder buffer, TextureManager textureManager) { +// RenderSystem.enableBlend(); +// RenderSystem.enableCull(); +// RenderSystem.setShaderTexture(0, TextureAtlas.LOCATION_PARTICLES); +// RenderSystem.depthMask(false); +// RenderSystem.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); +// // Note: do NOT call buffer.begin() here - the ParticleEngine already started +// // the buffer via Tesselator.begin(Mode, Format) before calling this method. +// } +// +// @Override +// public void end(Tesselator tessellator) { +// MeshData meshData = tessellator.end(); +// if (meshData != null) { +// BufferUploader.drawWithShader(meshData); +// } +// RenderSystem.enableDepthTest(); +// RenderSystem.depthMask(true); +// RenderSystem.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); +// RenderSystem.disableCull(); +// } +// +// @Override +// public String toString() { +// return "rootsclassic:magic"; +// } +// }; } diff --git a/src/main/java/com/lothrazar/library/util/PlayerUtil.java b/src/main/java/com/lothrazar/library/util/PlayerUtil.java index ccbf03d..dcbb3ab 100644 --- a/src/main/java/com/lothrazar/library/util/PlayerUtil.java +++ b/src/main/java/com/lothrazar/library/util/PlayerUtil.java @@ -7,6 +7,7 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.player.Player; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Block; @@ -97,7 +98,7 @@ public static Optional getPlayerHome(ServerPlayer player) { BlockPos respawnPos = player.getRespawnPosition(); Optional optional = Optional.empty(); if (respawnPos != null) { - optional = Player.findRespawnPositionAndUseSpawnBlock((ServerLevel) player.level(), respawnPos, 0.0F, true, true); + optional = ServerPlayer.findRespawnPositionAndUseSpawnBlock((ServerLevel) player.level(), respawnPos, player.getRespawnAngle(), true, true); } return optional; } From f455c046ead8dbc73979c6c13b7469d9d254790c Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 1 Apr 2026 09:56:26 -0700 Subject: [PATCH 16/29] postpone find respawn position and fix another displayName --- .../com/lothrazar/library/gui/FluidBar.java | 2 +- .../lothrazar/library/util/PlayerUtil.java | 35 +++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/lothrazar/library/gui/FluidBar.java b/src/main/java/com/lothrazar/library/gui/FluidBar.java index ad38da2..98da02a 100644 --- a/src/main/java/com/lothrazar/library/gui/FluidBar.java +++ b/src/main/java/com/lothrazar/library/gui/FluidBar.java @@ -114,7 +114,7 @@ public int getCapacity() { public void renderTooltip(GuiGraphics gg, int mouseX, int mouseY, FluidStack current) { String tt = emtpyTooltip; if (current != null && !current.isEmpty()) { - tt = current.getAmount() + "/" + getCapacity() + " " + current.getDisplayName().getString(); + tt = current.getAmount() + "/" + getCapacity() + " " + current.getHoverName().getString(); // getDisplayName() -> getHoverName() } List list = new ArrayList<>(); list.add(Component.translatable(tt)); diff --git a/src/main/java/com/lothrazar/library/util/PlayerUtil.java b/src/main/java/com/lothrazar/library/util/PlayerUtil.java index dcbb3ab..8e4f719 100644 --- a/src/main/java/com/lothrazar/library/util/PlayerUtil.java +++ b/src/main/java/com/lothrazar/library/util/PlayerUtil.java @@ -7,10 +7,10 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.player.Player; -import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.RespawnAnchorBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; @@ -94,11 +94,42 @@ public static Item getItemArmorSlot(Player player, EquipmentSlot slot) { return item; } + /** + * // Teleport player to a specific location in a different dimension + * ServerLevel targetLevel = player.getServer().getLevel(Level.NETHER); // Get target dimension + * if (targetLevel != null) { + * player.teleportTo( + * targetLevel, + * x, y, z, // Target coordinates + * yaw, pitch // Rotation + * ); + * } + * + * Also see EndPortalBlock.java getPortalDestination + * and PlayerList.java respawn + * + * using serverplayer.findRespawnPositionAndUseSpawnBlock(false, DimensionTransition.DO_NOTHING); + * + * @param player + * @return + */ + @Deprecated public static Optional getPlayerHome(ServerPlayer player) { BlockPos respawnPos = player.getRespawnPosition(); Optional optional = Optional.empty(); if (respawnPos != null) { - optional = ServerPlayer.findRespawnPositionAndUseSpawnBlock((ServerLevel) player.level(), respawnPos, player.getRespawnAngle(), true, true); + // Find the safe spot near the bed +// RespawnAnchorBlock x; +// Optional safePos = Player.findRespawnPositionAndUseSpawnBlock( +// player.level(), +// respawnPos, +// player.getRespawnAngle(), +// player.isRespawnForced(), +// true // Consumes Respawn Anchor charges if applicable +// ); + // TODO: fix this later +// DimensionTransition trans = player.findRespawnPositionAndUseSpawnBlock(true, null); + // optional = player.findRespawnPositionAndUseSpawnBlock((ServerLevel) player.level(), respawnPos, player.getRespawnAngle(), true, true); } return optional; } From bfb90716c502f8cf5011dccc6708bf8d0233f9fe Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 1 Apr 2026 14:40:10 -0700 Subject: [PATCH 17/29] finally fixing gradle and template issues --- build.gradle | 39 +++++++++++++----- gradle.properties | 26 +++++------- .../META-INF/neoforge.mods.toml | 41 +++++++++++++------ 3 files changed, 67 insertions(+), 39 deletions(-) rename src/main/{resources => templates}/META-INF/neoforge.mods.toml (72%) diff --git a/build.gradle b/build.gradle index 41ac1b4..a4769f9 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,6 @@ tasks.named('wrapper', Wrapper).configure { // (Verify by checking gradle/wrapper/gradle-wrapper.properties to see if distributionUrl now points to `-all`) distributionType = Wrapper.DistributionType.BIN } - version = "${mc_version}-${mod_version}" group = mod_group_id @@ -44,6 +43,7 @@ base { } // Mojang ships Java 21 to end users in 1.21.1, so mods should target Java 21. +// for intellij make sure to set JVM Navigate to Build, Execution, Deployment > Build Tools > Gradle java.toolchain.languageVersion = JavaLanguageVersion.of(21) println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}" @@ -51,6 +51,14 @@ neoForge { // Specify the version of NeoForge to use. version = project.neo_version + + // This property allows configuring Gradle's ProcessResources task(s) to run on IDE output locations before launching the game. + // It is REQUIRED to be set to true for the 1.21.1 template to function correctly. + // ideConfigGenerated = true + + // Other optional settings + // validateAccessTransformers = true + parchment { mappingsVersion = project.parchment_mappings_version minecraftVersion = project.parchment_minecraft_version @@ -104,6 +112,7 @@ neoForge { // You can set various levels here. // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels logLevel = org.slf4j.event.Level.DEBUG + } } @@ -156,7 +165,6 @@ dependencies { var generateModMetadata = tasks.register("generateModMetadata", ProcessResources) { var replaceProperties = [ minecraft_version : minecraft_version, - minecraft_version_range: minecraft_version_range, neo_version : neo_version, loader_version_range : loader_version_range, mod_id : mod_id, @@ -169,11 +177,27 @@ var generateModMetadata = tasks.register("generateModMetadata", ProcessResources from "src/main/templates" into "build/generated/sources/modMetadata" } + +// ??? +//sourceSets.main.resources.srcDir 'src/main/templates' + // Include the output of "generateModMetadata" as an input directory for the build // this works with both building through Gradle and the IDE. sourceSets.main.resources.srcDir generateModMetadata // To avoid having to run "generateModMetadata" manually, make it run on every project reload neoForge.ideSyncTask generateModMetadata +// Ensure standard processResources doesn't try to double-process the same files + + +//processResources { +// //from("src/main/resources") +// // 1. Tell Gradle what to do if it finds a duplicate (usually take the first one) +// duplicatesStrategy = DuplicatesStrategy.INCLUDE +// +// // 2. Ensure we aren't accidentally pulling the raw templates folder +// // into the final build (the generateModMetadata task handles this instead) +// exclude 'templates' +//} // Example configuration to allow publishing using the maven-publish plugin publishing { @@ -184,7 +208,9 @@ publishing { } repositories { maven { - url "file://${project.projectDir}/repo" + // url "file://${project.projectDir}/repo" + // url uri("${project.projectDir}/repo") + url = uri("${project.projectDir}/repo") } } } @@ -200,10 +226,3 @@ idea { downloadJavadoc = true } } - - -// custom tasks -task cleanJar { - delete 'build/libs' -} - diff --git a/gradle.properties b/gradle.properties index 6ecf636..815e50d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,8 +1,8 @@ # Sets default memory used for gradle commands. Can be overridden by user or command line properties. # This is required to provide enough memory for the Minecraft decompilation process. org.gradle.jvmargs=-Xmx3G -org.gradle.daemon=false -org.gradle.debug=false +org.gradle.daemon=true +org.gradle.parallel=true org.gradle.caching=true org.gradle.configuration-cache=true @@ -15,29 +15,23 @@ parchment_mappings_version=2024.11.17 # https://www.curseforge.com/minecraft/mc-mods/flib mod_id=flib curse_id=661261 -mod_version=0.0.12 +mod_version=1.0.0 minecraft_version=1.21.1 mc_version=1.21.1 neo_version=21.1.222 +mod_name=FutureLibrary +mod_group_id=com.lothrazar.library -mod_name=flib -mod_group_id=com.lothrazar.flib - - -mod_license=SeeGithub +mod_license=MIT mod_authors=Lothrazar mod_description=mod -minecraft_version_range=[1.21,) -forge_version_range=[47,) -loader_version_range=[47,) -mapping_channel=official -mapping_version=1.21 +loader_version_range=[1,) -#patchouli_version=81 -jei_version=15.0.0.12 -curios_version=5.2.0-beta.3+1.20.1 +# patchouli_version=81 +# jei_version=15.0.0.12 +# curios_version=5.2.0-beta.3+1.20.1 diff --git a/src/main/resources/META-INF/neoforge.mods.toml b/src/main/templates/META-INF/neoforge.mods.toml similarity index 72% rename from src/main/resources/META-INF/neoforge.mods.toml rename to src/main/templates/META-INF/neoforge.mods.toml index 2f2954d..369a8a1 100644 --- a/src/main/resources/META-INF/neoforge.mods.toml +++ b/src/main/templates/META-INF/neoforge.mods.toml @@ -5,29 +5,31 @@ # 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 -license="MIT" -# A version range to match for said mod loader - for regular FML @Mod it will be the forge version -loaderVersion="[4,)" #mandatory (26 is current forge version) +license="${mod_license}" + +# A version range to match for said mod loader - for regular FML @Mod it will be the FML version. This is currently 2. +loaderVersion="${loader_version_range}" #mandatory + # A URL to refer people to when problems occur with this mod issueTrackerURL="https://github.com/Lothrazar/FLib/issues" #optional # A list of mods - how many allowed here is determined by the individual mod loader [[mods]] #mandatory # The modid of the mod -modId="flib" #mandatory +modId="${mod_id}" #mandatory # The version number of the mod - there's a few well known ${} variables useable here or just hardcode it version="${mod_version}" #mandatory # A display name for the mod - -displayName="flib" #mandatory + +displayName="${mod_name}" #mandatory # A URL to query for updates for this mod. See the JSON update specification #updateJSONURL="https://raw.githubusercontent.com/Lothrazar/FLib/trunk/1.20/update.json" #optional # A URL for the "homepage" for this mod, displayed in the mod UI # replace with your website displayURL="https://www.curseforge.com/minecraft/mc-mods/flib" # A file name (in the root of the mod JAR) containing a logo for display -logoFile="logoFile.png" #optional +logoFile="flib.png" #optional # A text field displayed in the mod UI -credits="Lothrazar" #optional +#="Lothrazar" #optional # A text field displayed in the mod UI authors="Lothrazar" #optional # The description text for the mod (multi line!) (#mandatory) @@ -35,14 +37,24 @@ authors="Lothrazar" #optional description=''' Future Library. Empowers many forge mods. by Lothrazar ''' +# The [[mixins]] block allows you to declare your mixin config to FML so that it gets loaded. +#[[mixins]] +#config="${mod_id}.mixins.json" + + +# The [[accessTransformers]] block allows you to declare where your AT file is. +# If this block is omitted, a fallback attempt will be made to load an AT from META-INF/accesstransformer.cfg +[[accessTransformers]] + file="META-INF/accesstransformer.cfg" + # A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional. [[dependencies.${mod_id}]] #optional # the modid of the dependency modId="neoforge" #mandatory # Does this dependency have to exist - if not, ordering below must be specified - mandatory=true #mandatory + type="required" # was mandatory=true # The version range of the dependency - versionRange="[47.1,)" #mandatory + versionRange="[${neo_version},)" #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 @@ -50,7 +62,10 @@ Future Library. Empowers many forge mods. by Lothrazar # Here's another dependency [[dependencies.${mod_id}]] modId="minecraft" - mandatory=true - versionRange="[1.21,)" + type="required" # was mandatory=true + versionRange="[${minecraft_version},)" ordering="NONE" - side="BOTH" \ No newline at end of file + side="BOTH" + +#[features.${mod_id}] +#openGLVersion="[3.2,)" \ No newline at end of file From 4bcf9eba75f16f6d5f44fded6f0aecb2074f7b1c Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 1 Apr 2026 22:48:43 -0700 Subject: [PATCH 18/29] improve modid use in toml, set snapshot version --- gradle.properties | 2 +- src/main/templates/META-INF/neoforge.mods.toml | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/gradle.properties b/gradle.properties index 815e50d..7639df2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,7 +15,7 @@ parchment_mappings_version=2024.11.17 # https://www.curseforge.com/minecraft/mc-mods/flib mod_id=flib curse_id=661261 -mod_version=1.0.0 +mod_version=1.0.0-SNAPSHOT minecraft_version=1.21.1 mc_version=1.21.1 neo_version=21.1.222 diff --git a/src/main/templates/META-INF/neoforge.mods.toml b/src/main/templates/META-INF/neoforge.mods.toml index 861d080..6ff22ac 100644 --- a/src/main/templates/META-INF/neoforge.mods.toml +++ b/src/main/templates/META-INF/neoforge.mods.toml @@ -11,7 +11,7 @@ license="${mod_license}" loaderVersion="${loader_version_range}" #mandatory # A URL to refer people to when problems occur with this mod -issueTrackerURL="https://github.com/Lothrazar/FLib/issues" #optional +issueTrackerURL="https://github.com/Lothrazar/${mod_id}/issues" #optional # A list of mods - how many allowed here is determined by the individual mod loader [[mods]] #mandatory # The modid of the mod @@ -22,14 +22,13 @@ version="${mod_version}" #mandatory displayName="${mod_name}" #mandatory # A URL to query for updates for this mod. See the JSON update specification -updateJSONURL="https://raw.githubusercontent.com/Lothrazar/FLib/trunk/${minecraft_version}/update.json" #optional +updateJSONURL="https://raw.githubusercontent.com/Lothrazar/${mod_id}/trunk/${minecraft_version}/update.json" #optional # A URL for the "homepage" for this mod, displayed in the mod UI # replace with your website -displayURL="https://www.curseforge.com/minecraft/mc-mods/flib" +displayURL="https://www.curseforge.com/minecraft/mc-mods/${mod_id}" # A file name (in the root of the mod JAR) containing a logo for display -logoFile="flib.png" #optional -# A text field displayed in the mod UI -#="Lothrazar" #optional +logoFile="logoFile.png" #optional + # A text field displayed in the mod UI authors="${mod_authors}" #optional # The description text for the mod (multi line!) (#mandatory) From 5f2a4309b4e1c324fff82d75c612e5d290a8e445 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 1 Apr 2026 23:16:34 -0700 Subject: [PATCH 19/29] fix player util gethome transition --- .gitignore | 1 + .../lothrazar/library/util/PlayerUtil.java | 38 ++++--------------- 2 files changed, 8 insertions(+), 31 deletions(-) diff --git a/.gitignore b/.gitignore index ff73fea..09d74be 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ build run logs libs +repo # Files from Forge MDK forge*changelog.txt diff --git a/src/main/java/com/lothrazar/library/util/PlayerUtil.java b/src/main/java/com/lothrazar/library/util/PlayerUtil.java index d2f28e0..d55d277 100644 --- a/src/main/java/com/lothrazar/library/util/PlayerUtil.java +++ b/src/main/java/com/lothrazar/library/util/PlayerUtil.java @@ -1,9 +1,8 @@ package com.lothrazar.library.util; import java.util.Optional; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.portal.DimensionTransition; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EquipmentSlot; @@ -14,7 +13,6 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.RespawnAnchorBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; @@ -122,42 +120,20 @@ public static Item getItemArmorSlot(Player player, EquipmentSlot slot) { } /** - * // Teleport player to a specific location in a different dimension - * ServerLevel targetLevel = player.getServer().getLevel(Level.NETHER); // Get target dimension - * if (targetLevel != null) { - * player.teleportTo( - * targetLevel, - * x, y, z, // Target coordinates - * yaw, pitch // Rotation - * ); - * } + * Teleport player to a specific location in a different dimension * * Also see EndPortalBlock.java getPortalDestination * and PlayerList.java respawn * - * using serverplayer.findRespawnPositionAndUseSpawnBlock(false, DimensionTransition.DO_NOTHING); * * @param player - * @return + * @return optional vec3 respawn position */ - @Deprecated public static Optional getPlayerHome(ServerPlayer player) { - BlockPos respawnPos = player.getRespawnPosition(); - Optional optional = Optional.empty(); - if (respawnPos != null) { - // Find the safe spot near the bed -// RespawnAnchorBlock x; -// Optional safePos = Player.findRespawnPositionAndUseSpawnBlock( -// player.level(), -// respawnPos, -// player.getRespawnAngle(), -// player.isRespawnForced(), -// true // Consumes Respawn Anchor charges if applicable -// ); - // TODO: fix this later -// DimensionTransition trans = player.findRespawnPositionAndUseSpawnBlock(true, null); - // optional = player.findRespawnPositionAndUseSpawnBlock((ServerLevel) player.level(), respawnPos, player.getRespawnAngle(), true, true); + if (player.getRespawnPosition() == null) { // TODO: is this redundant? player method has its own null check + return Optional.empty(); } - return optional; + DimensionTransition dt = player.findRespawnPositionAndUseSpawnBlock(false, DimensionTransition.DO_NOTHING); + return Optional.of(dt.pos()); } } From f375f3881e4d10790af50d80d2a52d578593891a Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 1 Apr 2026 23:49:39 -0700 Subject: [PATCH 20/29] add deployLocal gradle task --- .gitignore | 4 +--- build.gradle | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 09d74be..2b3d641 100644 --- a/.gitignore +++ b/.gitignore @@ -16,12 +16,10 @@ out # gradle build .gradle +deploy.properties # other run logs libs repo - -# Files from Forge MDK -forge*changelog.txt diff --git a/build.gradle b/build.gradle index 42cf4fe..83a2053 100644 --- a/build.gradle +++ b/build.gradle @@ -224,6 +224,10 @@ publishing { } } +tasks.named('publish') { + finalizedBy 'deployLocal' +} + tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation } @@ -235,3 +239,45 @@ idea { downloadJavadoc = true } } + + +// --------------------------------------------------------------------------- +// deployLocal +// this triggers after 'publish' task every time +// depends on only jar because all we need is the jar complete, so deployLocal can also run standalone if the jar exists. +// otherwise if this dependson publish, then running deployLocal would trigger a full publish cycle, which is not neeeded +// --------------------------------------------------------------------------- +def deployProps = new Properties() +def deployFile = rootProject.file('deploy.properties') +if (deployFile.exists()) { + deployFile.withInputStream { deployProps.load(it) } +} +tasks.register('deployLocal') { + description = 'Copies build jar to all destinations in deploy.properties' + group = 'distribution' + dependsOn 'jar' + + def jarFile = layout.buildDirectory.file("libs/${base.archivesName.get()}-${version}.jar") + + def destinations = deployProps.getProperty('destinations', '') + .split(',') + .collect { it.trim() } + .findAll { it } + + onlyIf { !destinations.isEmpty() } + + // important to use doLast to avoid errors like 'Caused by: org.gradle.api.InvalidUserCodeException: Invocation of 'copy' references a Gradle script object from a Groovy closure at execution time, which is unsupported with the configuration cache' + doLast { + def source = jarFile.get().asFile + destinations.each { dest -> + def destDir = new File(dest) + destDir.mkdirs() + java.nio.file.Files.copy( + source.toPath(), + new File(destDir, source.name).toPath(), + java.nio.file.StandardCopyOption.REPLACE_EXISTING + ) + logger.lifecycle("Deployed ${source.name} -> ${dest}") + } + } +} From ca73dba3e269327e29e91e7b0d802870f72af54c Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 2 Apr 2026 09:06:24 -0700 Subject: [PATCH 21/29] refactor deploylocal to standalone file --- build.gradle | 46 +------------------------------------------ gradle/deploy.gradle | 47 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 45 deletions(-) create mode 100644 gradle/deploy.gradle diff --git a/build.gradle b/build.gradle index 83a2053..63435a1 100644 --- a/build.gradle +++ b/build.gradle @@ -224,9 +224,7 @@ publishing { } } -tasks.named('publish') { - finalizedBy 'deployLocal' -} +apply from: 'gradle/deploy.gradle' tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation @@ -239,45 +237,3 @@ idea { downloadJavadoc = true } } - - -// --------------------------------------------------------------------------- -// deployLocal -// this triggers after 'publish' task every time -// depends on only jar because all we need is the jar complete, so deployLocal can also run standalone if the jar exists. -// otherwise if this dependson publish, then running deployLocal would trigger a full publish cycle, which is not neeeded -// --------------------------------------------------------------------------- -def deployProps = new Properties() -def deployFile = rootProject.file('deploy.properties') -if (deployFile.exists()) { - deployFile.withInputStream { deployProps.load(it) } -} -tasks.register('deployLocal') { - description = 'Copies build jar to all destinations in deploy.properties' - group = 'distribution' - dependsOn 'jar' - - def jarFile = layout.buildDirectory.file("libs/${base.archivesName.get()}-${version}.jar") - - def destinations = deployProps.getProperty('destinations', '') - .split(',') - .collect { it.trim() } - .findAll { it } - - onlyIf { !destinations.isEmpty() } - - // important to use doLast to avoid errors like 'Caused by: org.gradle.api.InvalidUserCodeException: Invocation of 'copy' references a Gradle script object from a Groovy closure at execution time, which is unsupported with the configuration cache' - doLast { - def source = jarFile.get().asFile - destinations.each { dest -> - def destDir = new File(dest) - destDir.mkdirs() - java.nio.file.Files.copy( - source.toPath(), - new File(destDir, source.name).toPath(), - java.nio.file.StandardCopyOption.REPLACE_EXISTING - ) - logger.lifecycle("Deployed ${source.name} -> ${dest}") - } - } -} diff --git a/gradle/deploy.gradle b/gradle/deploy.gradle new file mode 100644 index 0000000..1b17f2a --- /dev/null +++ b/gradle/deploy.gradle @@ -0,0 +1,47 @@ +// --------------------------------------------------------------------------- +// deployLocal — copies the built JAR to every folder listed in deploy.properties +// deploy.properties is gitignored; each developer maintains their own copy. +// +// Runs automatically after 'publish' via finalizedBy. +// Can also be run standalone with: gradlew deployLocal +// (depends only on 'jar' so it won't trigger a full publish cycle standalone) +// --------------------------------------------------------------------------- +def deployProps = new Properties() +def deployFile = rootProject.file('deploy.properties') +if (deployFile.exists()) { + deployFile.withInputStream { deployProps.load(it) } +} + +tasks.register('deployLocal') { + description = 'Copies build jar to all destinations in deploy.properties' + group = 'distribution' + dependsOn 'jar' + + def jarFile = layout.buildDirectory.file("libs/${base.archivesName.get()}-${version}.jar") + + def destinations = deployProps.getProperty('destinations', '') + .split(',') + .collect { it.trim() } + .findAll { it } + + onlyIf { !destinations.isEmpty() } + + // doLast avoids configuration cache errors from project.copy() references + doLast { + def source = jarFile.get().asFile + destinations.each { dest -> + def destDir = new File(dest) + destDir.mkdirs() + java.nio.file.Files.copy( + source.toPath(), + new File(destDir, source.name).toPath(), + java.nio.file.StandardCopyOption.REPLACE_EXISTING + ) + logger.lifecycle("Deployed ${source.name} -> ${dest}") + } + } +} + +tasks.named('publish') { + finalizedBy 'deployLocal' +} From 8f3bfbf850322023d2f12ae7b1cd1dee85e74ef1 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 2 Apr 2026 09:28:28 -0700 Subject: [PATCH 22/29] optional dependencies test --- .gitignore | 2 +- build.gradle | 41 ++++++++++++++++++++++------------------- gradle.properties | 9 ++++++--- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index 2b3d641..4b1853a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ bin *.launch .settings .metadata -.classpath +.cla* .project # idea diff --git a/build.gradle b/build.gradle index 63435a1..b321650 100644 --- a/build.gradle +++ b/build.gradle @@ -28,14 +28,14 @@ sourceSets.main.resources { repositories { // mavenLocal() -// flatDir { dir 'libs' } - - // maven { -// name = "curios" - // url = 'https://maven.theillusivec4.top/' - // } - // maven { url = 'https://maven.blamejared.com' } -// maven { url = 'https://www.cursemaven.com' } + flatDir { dir 'libs' } + + maven { + name = "curios" + url = 'https://maven.theillusivec4.top/' + } + maven { url = 'https://maven.blamejared.com' } + maven { url = 'https://www.cursemaven.com' } } base { @@ -137,20 +137,23 @@ configurations { dependencies { - // Example optional mod dependency with JEI - // The JEI API is declared for compile time use, while the full JEI artifact is used at runtime - // compileOnly "mezz.jei:jei-${mc_version}-common-api:${jei_version}" - // compileOnly "mezz.jei:jei-${mc_version}-neoforge-api:${jei_version}" - // We add the full version to localRuntime, not runtimeOnly, so that we do not publish a dependency on it - // localRuntime "mezz.jei:jei-${mc_version}-neoforge:${jei_version}" + // for other mods depending on THIS FLIB library, use + // implementation "local.mods:flib:${mc_version}-${flib_version}" - // runtimeOnly fg.deobf("top.theillusivec4.curios:curios-forge:${curios_version}+${mc_version}") - // compileOnly fg.deobf("top.theillusivec4.curios:curios-forge:${curios_version}+${mc_version}:api") - // implementation fg.deobf("com.blamejared.crafttweaker:CraftTweaker-forge-${mc_version}:${crafttweaker_version}") + //these mods have API jars for compile as well as the full mod for local + compileOnly "mezz.jei:jei-${mc_version}-neoforge-api:${jei_version}" + localRuntime "mezz.jei:jei-${mc_version}-neoforge:${jei_version}" + + compileOnly "top.theillusivec4.curios:curios-neoforge:${curios_version}+${mc_version}" + localRuntime "top.theillusivec4.curios:curios-neoforge:${curios_version}+${mc_version}" + + // no APIs + compileOnly "vazkii.patchouli:Patchouli:${mc_version}-${patchouli_version}-NEOFORGE" + + compileOnly "com.blamejared.crafttweaker:CraftTweaker-neoforge-${mc_version}:${crafttweaker_version}" + - - // Example mod dependency using a mod jar from ./libs with a flat dir repository // This maps to ./libs/coolmod-${mc_version}-${coolmod_version}.jar // The group id is ignored when searching -- in this case, it is "blank" diff --git a/gradle.properties b/gradle.properties index 7639df2..0019f31 100644 --- a/gradle.properties +++ b/gradle.properties @@ -32,6 +32,9 @@ mod_description=mod loader_version_range=[1,) -# patchouli_version=81 -# jei_version=15.0.0.12 -# curios_version=5.2.0-beta.3+1.20.1 +# flib_version=1.0.0 + +patchouli_version=93 +jei_version=19.27.0.340 +curios_version=9.5.1 +crafttweaker_version=21.0.38 From bf84d91d8b96e972715f2433566769083040e518 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 2 Apr 2026 14:16:53 -0700 Subject: [PATCH 23/29] refactor gradle to use mod.properties --- build.gradle | 5 +++++ gradle.properties | 13 +------------ mod.properties | 10 ++++++++++ 3 files changed, 16 insertions(+), 12 deletions(-) create mode 100644 mod.properties diff --git a/build.gradle b/build.gradle index b321650..244f622 100644 --- a/build.gradle +++ b/build.gradle @@ -4,6 +4,11 @@ plugins { id 'net.neoforged.moddev' version '2.0.141' id 'idea' } +def localProps = new Properties() +def localFile = file("mod.properties") +localFile.withInputStream { localProps.load(it) } +localProps.each { k, v -> project.ext.set(k, v) } + tasks.named('wrapper', Wrapper).configure { // Define wrapper values here so as to not have to always do so when updating gradlew.properties. // Switching this to Wrapper.DistributionType.ALL will download the full gradle sources that comes with diff --git a/gradle.properties b/gradle.properties index 0019f31..05923b3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,22 +13,11 @@ parchment_mappings_version=2024.11.17 # your properties # https://www.curseforge.com/minecraft/mc-mods/flib -mod_id=flib -curse_id=661261 -mod_version=1.0.0-SNAPSHOT + minecraft_version=1.21.1 mc_version=1.21.1 neo_version=21.1.222 - -mod_name=FutureLibrary -mod_group_id=com.lothrazar.library - - -mod_license=MIT -mod_authors=Lothrazar -mod_description=mod - loader_version_range=[1,) diff --git a/mod.properties b/mod.properties new file mode 100644 index 0000000..1795e9a --- /dev/null +++ b/mod.properties @@ -0,0 +1,10 @@ + +mod_version=1.0.0-SNAPSHOT + +mod_id=flib +mod_license=MIT +mod_authors=Lothrazar +mod_description=mod +mod_name=FutureLibrary +mod_group_id=com.lothrazar.library +curse_id=661261 \ No newline at end of file From bf7f6ed8a57819cf4af1c43dc2e3dcbb8dedf8c0 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 2 Apr 2026 14:20:25 -0700 Subject: [PATCH 24/29] refactor duplicate variable and cleanup readme --- .github/README.md | 6 +++--- build.gradle | 22 +++++++++++----------- gradle.properties | 1 - 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/.github/README.md b/.github/README.md index de70948..92de502 100644 --- a/.github/README.md +++ b/.github/README.md @@ -31,7 +31,7 @@ Use the libs folder in the repositories section of your build scripts as follows ``` And then use the blank keyword to add the version inside your dependencies block ``` - implementation fg.deobf("blank:flib-${mc_version}:${flib_version}") + implementation "local.mods:flib:${minecraft_version}-${flib_version}" ``` And then your gradle.properties file will get the version number set that you are using ``` @@ -54,8 +54,8 @@ And then add a dependency at the bottom of your META-INF/mods.toml page ``` [[dependencies.examplemod]] modId="flib" - mandatory=true - versionRange="[0.0.0,)" + type="required" # was mandatory=true + versionRange="[1.0.0,)" ordering="NONE" side="BOTH" ``` diff --git a/build.gradle b/build.gradle index 244f622..dcf0b2b 100644 --- a/build.gradle +++ b/build.gradle @@ -17,7 +17,7 @@ tasks.named('wrapper', Wrapper).configure { // (Verify by checking gradle/wrapper/gradle-wrapper.properties to see if distributionUrl now points to `-all`) distributionType = Wrapper.DistributionType.BIN } -version = "${mc_version}-${mod_version}" +version = "${minecraft_version}-${mod_version}" group = mod_group_id sourceSets.main.resources { @@ -143,29 +143,29 @@ configurations { dependencies { // for other mods depending on THIS FLIB library, use - // implementation "local.mods:flib:${mc_version}-${flib_version}" + // implementation "local.mods:flib:${minecraft_version}-${flib_version}" //these mods have API jars for compile as well as the full mod for local - compileOnly "mezz.jei:jei-${mc_version}-neoforge-api:${jei_version}" - localRuntime "mezz.jei:jei-${mc_version}-neoforge:${jei_version}" + compileOnly "mezz.jei:jei-${minecraft_version}-neoforge-api:${jei_version}" + localRuntime "mezz.jei:jei-${minecraft_version}-neoforge:${jei_version}" - compileOnly "top.theillusivec4.curios:curios-neoforge:${curios_version}+${mc_version}" - localRuntime "top.theillusivec4.curios:curios-neoforge:${curios_version}+${mc_version}" + compileOnly "top.theillusivec4.curios:curios-neoforge:${curios_version}+${minecraft_version}" + localRuntime "top.theillusivec4.curios:curios-neoforge:${curios_version}+${minecraft_version}" // no APIs - compileOnly "vazkii.patchouli:Patchouli:${mc_version}-${patchouli_version}-NEOFORGE" + compileOnly "vazkii.patchouli:Patchouli:${minecraft_version}-${patchouli_version}-NEOFORGE" - compileOnly "com.blamejared.crafttweaker:CraftTweaker-neoforge-${mc_version}:${crafttweaker_version}" + compileOnly "com.blamejared.crafttweaker:CraftTweaker-neoforge-${minecraft_version}:${crafttweaker_version}" // Example mod dependency using a mod jar from ./libs with a flat dir repository - // This maps to ./libs/coolmod-${mc_version}-${coolmod_version}.jar + // This maps to ./libs/coolmod-${minecraft_version}-${coolmod_version}.jar // The group id is ignored when searching -- in this case, it is "blank" - // implementation "blank:coolmod-${mc_version}:${coolmod_version}" + // implementation "blank:coolmod-${minecraft_version}:${coolmod_version}" // Example mod dependency using a file as dependency - // implementation files("libs/coolmod-${mc_version}-${coolmod_version}.jar") + // implementation files("libs/coolmod-${minecraft_version}-${coolmod_version}.jar") // Example project dependency using a sister or child project: // implementation project(":myproject") diff --git a/gradle.properties b/gradle.properties index 05923b3..e1a0e8c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,7 +15,6 @@ parchment_mappings_version=2024.11.17 # https://www.curseforge.com/minecraft/mc-mods/flib minecraft_version=1.21.1 -mc_version=1.21.1 neo_version=21.1.222 loader_version_range=[1,) From a45b759b7646eec087267312eed7f14d1af1af9c Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 2 Apr 2026 21:15:16 -0700 Subject: [PATCH 25/29] clone script for 1.21 repos --- build.gradle | 1 + mod.properties | 3 +- scripts/clone.sh | 95 +++++++++++++++++++ .../templates/META-INF/neoforge.mods.toml | 10 +- 4 files changed, 102 insertions(+), 7 deletions(-) create mode 100644 scripts/clone.sh diff --git a/build.gradle b/build.gradle index dcf0b2b..c96974d 100644 --- a/build.gradle +++ b/build.gradle @@ -182,6 +182,7 @@ var generateModMetadata = tasks.register("generateModMetadata", ProcessResources minecraft_version : minecraft_version, neo_version : neo_version, loader_version_range : loader_version_range, + curse_slug : curse_slug, mod_id : mod_id, mod_name : mod_name, mod_license : mod_license, diff --git a/mod.properties b/mod.properties index 1795e9a..e0fa07c 100644 --- a/mod.properties +++ b/mod.properties @@ -7,4 +7,5 @@ mod_authors=Lothrazar mod_description=mod mod_name=FutureLibrary mod_group_id=com.lothrazar.library -curse_id=661261 \ No newline at end of file +curse_slug=flib +curse_id=661261 diff --git a/scripts/clone.sh b/scripts/clone.sh new file mode 100644 index 0000000..9a9e3d5 --- /dev/null +++ b/scripts/clone.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env bash +# this set -e tells bash to exit if a command such as git clone fails (nonzero) +set -e + +GITHUB="Lothrazar" +TEMP_DIR="/c/temp" +SOURCE_DIR="/c/Users/USER/eclipse-workspace/mc121/FLib" + +REPONAME="$1" +if [ -z "$REPONAME" ]; then + echo "Usage: clone.sh " + exit 1 +fi + +MC="1.21.1" +TARGET_DIR="/c/Users/USER/MyFiles/mc121/$REPONAME" +GIT_URL="git@github.com:${GITHUB}/${REPONAME}.git" +MOD_PROPS="$TARGET_DIR/mod.properties" +FLIB_VERSION="1.0.0-SNAPSHOT" + +echo +git clone "$GIT_URL" "$TARGET_DIR" +echo + +echo "✓ Cloned '$REPONAME' repository" + + +cd "$TARGET_DIR" + + +if [ ! -f "$MOD_PROPS" ]; then + + cat > "$MOD_PROPS" << EOF + +flib_version=$FLIB_VERSION + +EOF + + echo "✓ mod.properties not found, template created" + + grep -E "^(mod_version|mod_id|mod_name|mod_license|mod_authors|mod_description|mod_group_id|curse_id|curse_slug)=" "$TARGET_DIR/gradle.properties" >> "$MOD_PROPS" || true + + echo "✓ Moved mod-specific properties into $MOD_PROPS" + +fi + +cp "$SOURCE_DIR/.gitignore" ./.gitignore +# gradle and other core shared files copied +cp -r "$SOURCE_DIR/gradle" ./ +cp "$SOURCE_DIR/gradle.properties" ./gradle.properties +cp "$SOURCE_DIR/settings.gradle" ./settings.gradle +cp "$SOURCE_DIR/build.gradle" ./build.gradle +cp "$SOURCE_DIR/gradlew" ./gradlew +cp "$SOURCE_DIR/gradlew.bat" ./gradlew.bat +echo "✓ Updated gradle" + +# rm legacy mods.toml if present (NeoForge uses templates -> neoforge.mods.toml) +rm -f ./src/main/resources/META-INF/mods.toml +echo "✓ Removed legacy mods.toml" + +# add the new template +cp -r "$SOURCE_DIR/src/main/templates" ./src/main/templates + +MODS_TOML="$TARGET_DIR/src/main/templates/META-INF/neoforge.mods.toml" +if [ -f "$MODS_TOML" ]; then + cat >> "$MODS_TOML" << 'EOF' + +[[dependencies.${mod_id}]] + modId="flib" + type="required" + versionRange="[0.1.0,)" + ordering="NONE" + side="BOTH" +EOF + + echo "✓ Appended flib dependency to neoforge.mods.toml" +fi + + + +mkdir "$TARGET_DIR/libs" +cp "/c/temp/flib-$MC-$FLIB_VERSION.jar" "$TARGET_DIR/libs/flib-$MC-$FLIB_VERSION.jar" + +echo "✓ Default library copied from temp" + +echo "✓ Source branch $(git rev-parse --abbrev-ref HEAD)" + +echo "! Verify mod.properties values and optional dependencies before building !" + +echo + +git checkout -b port + +echo +# read -rp "Press Enter to close..." diff --git a/src/main/templates/META-INF/neoforge.mods.toml b/src/main/templates/META-INF/neoforge.mods.toml index 6ff22ac..3cf5067 100644 --- a/src/main/templates/META-INF/neoforge.mods.toml +++ b/src/main/templates/META-INF/neoforge.mods.toml @@ -22,9 +22,9 @@ version="${mod_version}" #mandatory displayName="${mod_name}" #mandatory # A URL to query for updates for this mod. See the JSON update specification -updateJSONURL="https://raw.githubusercontent.com/Lothrazar/${mod_id}/trunk/${minecraft_version}/update.json" #optional +# updateJSONURL="https://raw.githubusercontent.com/Lothrazar/${mod_id}/trunk/${minecraft_version}/update.json" #optional # A URL for the "homepage" for this mod, displayed in the mod UI # replace with your website -displayURL="https://www.curseforge.com/minecraft/mc-mods/${mod_id}" +displayURL="https://www.curseforge.com/minecraft/mc-mods/${curse_slug}" # A file name (in the root of the mod JAR) containing a logo for display logoFile="logoFile.png" #optional @@ -40,6 +40,8 @@ ${mod_description} #[[mixins]] #config="${mod_id}.mixins.json" +#[features.${mod_id}] +#openGLVersion="[3.2,)" # The [[accessTransformers]] block allows you to declare where your AT file is. # If this block is omitted, a fallback attempt will be made to load an AT from META-INF/accesstransformer.cfg @@ -58,13 +60,9 @@ ${mod_description} ordering="NONE" # Side this dependency is applied on - BOTH, CLIENT or SERVER side="BOTH" -# Here's another dependency [[dependencies.${mod_id}]] modId="minecraft" type="required" # was mandatory=true versionRange="[${minecraft_version},)" ordering="NONE" side="BOTH" - -#[features.${mod_id}] -#openGLVersion="[3.2,)" \ No newline at end of file From 963c9612c12ce0dc23dae6e7f901828fb14b8884 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 10 Apr 2026 22:31:20 -0700 Subject: [PATCH 26/29] config template no longer needed with neoforge --- .../com/lothrazar/library/config/ConfigTemplate.java | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 src/main/java/com/lothrazar/library/config/ConfigTemplate.java diff --git a/src/main/java/com/lothrazar/library/config/ConfigTemplate.java b/src/main/java/com/lothrazar/library/config/ConfigTemplate.java deleted file mode 100644 index 93d267a..0000000 --- a/src/main/java/com/lothrazar/library/config/ConfigTemplate.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.lothrazar.library.config; - -import net.neoforged.neoforge.common.ModConfigSpec; -import net.neoforged.neoforge.common.ModConfigSpec.Builder; - -public abstract class ConfigTemplate { - - public static Builder builder() { - return new ModConfigSpec.Builder(); - } -} From 92b81120063ea881a26912dfce8eef59dc174f46 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 10 Apr 2026 22:32:17 -0700 Subject: [PATCH 27/29] rm outdated bashscripts --- scripts/dist.sh | 36 ------------------- scripts/release.sh | 5 --- scripts/setup.sh | 3 -- .../lothrazar/library/mod/ConfigModule.java | 5 ++- 4 files changed, 2 insertions(+), 47 deletions(-) delete mode 100644 scripts/dist.sh delete mode 100644 scripts/release.sh delete mode 100644 scripts/setup.sh diff --git a/scripts/dist.sh b/scripts/dist.sh deleted file mode 100644 index 96859c1..0000000 --- a/scripts/dist.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -#./gradlew copyJar -# TODO loop on list lol -# cp -R build/libs/. c:/temp - -cp -R build/libs/. ../Cyclic/libs -cp -R build/libs/. ../RootsClassic/libs -cp -R build/libs/. ../Similsax-Transtructors/libs -cp -R build/libs/. ../SimpleTomb/libs -cp -R build/libs/. ../Storage-Network/libs -cp -R build/libs/. ../VeinCreeper/libs - -# cp -R build/libs/. ../Cyclic/libs -# cp -R build/libs/. ../ElementaryOres/libs -# cp -R build/libs/. ../PotatoBread/libs -# cp -R build/libs/. ../TinyLightBulbs/libs -# cp -R build/libs/. ../CustomGameRules/libs -# cp -R build/libs/. ../ForgeCreeperHeal/libs -# cp -R build/libs/. ../EnchantingRunes/libs -# cp -R build/libs/. ../ForgeTemplate/libs -# cp -R build/libs/. ../Scraps/libs -# cp -R build/libs/. ../SaplingGrowthControl/libs -# cp -R build/libs/. ../cobblestoney/libs -# cp -R build/libs/. ../absentbydesign/libs -# cp -R build/libs/. ../antibonemeal/libs -# cp -R build/libs/. ../BlockLayers/libs -# cp -R build/libs/. ../AutoRun/libs -# cp -R build/libs/. ../FragileTorches/libs -# cp -R build/libs/. ../GardenTools/libs -# cp -R build/libs/. ../GlassCutter/libs -# cp -R build/libs/. ../FragileTorches/libs -# cp -R build/libs/. ../HeartBalance/libs -# cp -R build/libs/. ../NoLogPunch/libs -# cp -R build/libs/. ../NoLavaBuild/libs -# cp -R build/libs/. ../stupidHorseStandStill/libs diff --git a/scripts/release.sh b/scripts/release.sh deleted file mode 100644 index f9ae4f1..0000000 --- a/scripts/release.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -./gradlew cleanJar build signJar - -./scripts/dist.sh diff --git a/scripts/setup.sh b/scripts/setup.sh deleted file mode 100644 index e7289d6..0000000 --- a/scripts/setup.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -./gradlew genEclipseRuns diff --git a/src/main/java/com/lothrazar/library/mod/ConfigModule.java b/src/main/java/com/lothrazar/library/mod/ConfigModule.java index b8c10f4..dcf5d66 100644 --- a/src/main/java/com/lothrazar/library/mod/ConfigModule.java +++ b/src/main/java/com/lothrazar/library/mod/ConfigModule.java @@ -1,20 +1,19 @@ package com.lothrazar.library.mod; import com.lothrazar.library.FutureLibMod; -import com.lothrazar.library.config.ConfigTemplate; import net.neoforged.fml.ModContainer; import net.neoforged.fml.config.ModConfig; import net.neoforged.neoforge.common.ModConfigSpec; import net.neoforged.neoforge.common.ModConfigSpec.BooleanValue; import net.neoforged.neoforge.common.ModConfigSpec.Builder; -public class ConfigModule extends ConfigTemplate { +public class ConfigModule { private static final ModConfigSpec CONFIG; public static BooleanValue ENABLE_COMMANDS; static { - final Builder builder = builder(); + final Builder builder = new ModConfigSpec.Builder(); builder.comment("General settings").push(FutureLibMod.MODID); ENABLE_COMMANDS = builder.comment("If true, the /flib command will be registered").define("command.enabled", true); builder.pop(); From e85417aa9cd08b237f2ef5d3093ddb3876d8681f Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 10 Apr 2026 22:56:13 -0700 Subject: [PATCH 28/29] clone script deploy properties template --- scripts/clone.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/scripts/clone.sh b/scripts/clone.sh index 9a9e3d5..d89feb2 100644 --- a/scripts/clone.sh +++ b/scripts/clone.sh @@ -16,6 +16,7 @@ MC="1.21.1" TARGET_DIR="/c/Users/USER/MyFiles/mc121/$REPONAME" GIT_URL="git@github.com:${GITHUB}/${REPONAME}.git" MOD_PROPS="$TARGET_DIR/mod.properties" +DEPLOY_PROPS="$TARGET_DIR/deploy.properties" FLIB_VERSION="1.0.0-SNAPSHOT" echo @@ -36,6 +37,7 @@ flib_version=$FLIB_VERSION EOF + echo "✓ mod.properties not found, template created" grep -E "^(mod_version|mod_id|mod_name|mod_license|mod_authors|mod_description|mod_group_id|curse_id|curse_slug)=" "$TARGET_DIR/gradle.properties" >> "$MOD_PROPS" || true @@ -44,6 +46,19 @@ EOF fi +if [ ! -f "$DEPLOY_PROPS" ]; then + + cat > "$DEPLOY_PROPS" << EOF + +# CSV list of folders that will copy the release version to +# after the gradle publish task + +destinations=C:/temp + +EOF + echo "✓ deploy.properties not found, template created" +fi + cp "$SOURCE_DIR/.gitignore" ./.gitignore # gradle and other core shared files copied cp -r "$SOURCE_DIR/gradle" ./ @@ -87,6 +102,8 @@ echo "✓ Source branch $(git rev-parse --abbrev-ref HEAD)" echo "! Verify mod.properties values and optional dependencies before building !" +echo "! Update build.gradle dependencies as needed" + echo git checkout -b port From b9781a61f8428b59e79dce939c23ba166d291296 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 15 Apr 2026 07:54:19 -0700 Subject: [PATCH 29/29] silence mkdir clone errors. add isEdible to item util --- scripts/clone.sh | 2 +- .../java/com/lothrazar/library/util/ItemStackUtil.java | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/scripts/clone.sh b/scripts/clone.sh index d89feb2..2032bd3 100644 --- a/scripts/clone.sh +++ b/scripts/clone.sh @@ -93,7 +93,7 @@ fi -mkdir "$TARGET_DIR/libs" +mkdir -p "$TARGET_DIR/libs" cp "/c/temp/flib-$MC-$FLIB_VERSION.jar" "$TARGET_DIR/libs/flib-$MC-$FLIB_VERSION.jar" echo "✓ Default library copied from temp" diff --git a/src/main/java/com/lothrazar/library/util/ItemStackUtil.java b/src/main/java/com/lothrazar/library/util/ItemStackUtil.java index 9b49992..e6381b1 100644 --- a/src/main/java/com/lothrazar/library/util/ItemStackUtil.java +++ b/src/main/java/com/lothrazar/library/util/ItemStackUtil.java @@ -206,4 +206,12 @@ public static void randomlyRepair(RandomSource rnd, ItemStack stack, int factor) stack.setDamageValue(stack.getDamageValue() - 1); } } + + /** + * true if item is edible. replaces old item.isEdible(). based on FoodProperties + * @return + */ + public static boolean isEdible(ItemStack s) { + return (s.getItem().getFoodProperties(s,null) != null); + } }