diff --git a/build.gradle b/build.gradle deleted file mode 100644 index ece3b21..0000000 --- a/build.gradle +++ /dev/null @@ -1,195 +0,0 @@ -plugins { - id 'java' - id 'idea' - id 'net.minecraftforge.gradle' version '[6.0,6.2)' - id 'org.parchmentmc.librarian.forgegradle' version '1.+' - id 'com.matthewprenger.cursegradle' version '1.4.0' - id 'maven-publish' -} - -apply plugin: 'net.minecraftforge.gradle' -apply plugin: 'org.parchmentmc.librarian.forgegradle' -apply plugin: 'maven-publish' - -version = "$minecraft_version-$mod_version" -group = 'com.smashingmods' - -java { - archivesBaseName = 'alchemylib' - toolchain.languageVersion = JavaLanguageVersion.of(17) - withSourcesJar() - withJavadocJar() -} - -minecraft { - mappings channel: "$mapping_channel", version: "$mapping_version-1.20.1" - copyIdeResources = true - accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') - runs { - client { - workingDirectory project.file('run') - property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' - property 'forge.logging.console.level', 'debug' - property 'mixin.env.remapRefMap', 'true' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" - jvmArgs '-XX:+AllowEnhancedClassRedefinition' - - mods { - alchemylib { - source sourceSets.main - } - } - } - - server { - workingDirectory project.file('run') - property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' - property 'forge.logging.console.level', 'debug' - property 'mixin.env.remapRefMap', 'true' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" - jvmArgs '-XX:+AllowEnhancedClassRedefinition' - args 'nogui' - - mods { - alchemylib { - source sourceSets.main - } - } - } - - gameTestServer { - workingDirectory project.file('run') - property 'forge.logging.markers', 'REGISTRIES' - property 'forge.logging.console.level', 'debug' - property 'forge.enabledGameTestNamespaces', 'alchemylib' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" - jvmArgs '-XX:+AllowEnhancedClassRedefinition' - - mods { - alchemylib { - source sourceSets.main - } - } - } - - data { - workingDirectory project.file('run') - property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' - property 'forge.logging.console.level', 'debug' - property 'mixin.env.remapRefMap', 'true' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" - jvmArgs '-XX:+AllowEnhancedClassRedefinition' - - args '--mod', "$archivesBaseName", '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources') - - mods { - alchemylib { - source sourceSets.main - } - } - } - } -} - -repositories { - maven { url "https://maven.tamaized.com/releases" } -} - -dependencies { - minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" - implementation fg.deobf("smashingmods:chemlib:${minecraft_version}-${chemlib_version}") -} - -def resourceTargets = ['META-INF/mods.toml', 'pack.mcmeta'] -def replaceProperties = [ - minecraft_version: minecraft_version, minecraft_version_range: minecraft_version_range, - forge_version: forge_version, forge_version_range: forge_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, - chemlib_version: chemlib_version -] -processResources { - inputs.properties replaceProperties - replaceProperties.put 'project', project - - filesMatching(resourceTargets) { - expand replaceProperties - } -} - -jar { - manifest { - attributes([ - "Specification-Title" : "$archiveBaseName", - "Specification-Vendor" : "SmashingMods", - "Specification-Version" : "1", - "Implementation-Title" : project.name, - "Implementation-Version" : project.jar.archiveVersion, - "Implementation-Vendor" : "SmashingMods", - "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") - ]) - } -} - -def secrets = new Properties() -file('secrets.properties').withInputStream { - stream -> secrets.load(stream) -} - -fileTree("secrets").matching { - include "**/*.properties" -}.each { - File file -> - file.withInputStream { - stream -> secrets.load(stream) - } -} - -publishing { - publications { - mavenJava(MavenPublication) { - afterEvaluate { - artifact project.jar - artifact project.sourcesJar - artifact project.javadocJar - } - setGroupId 'smashingmods' - setArtifactId 'alchemylib' - } - } - repositories { - maven { - url "https://maven.tamaized.com/releases" - credentials { - username secrets.getProperty("maven_username") - password secrets.getProperty("maven_password") - } - } - } -} - -curseforge { - apiKey = secrets.getProperty("apiKey") - project { - id = '293426' - releaseType = 'release' - changelogType = 'markdown' - changelog = file("changelog.md") - addGameVersion 'Java 17' - mainArtifact(jar) { - displayName = "AlchemyLib - $project.version" - relations { - requiredDependency 'chemlib' - } - } - } -} - -sourceSets.main.resources { srcDir 'src/generated/resources' } - -jar.finalizedBy('reobfJar') - -tasks.withType(JavaCompile).configureEach { - options.encoding = 'UTF-8' -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..3fc5e94 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,146 @@ +plugins { + id("java-library") + id("maven-publish") + id("net.neoforged.moddev") version "2.0.140" + id("idea") +} + +val minecraftVersion: String by extra +val modVersion: String by extra +val neoVersion: String by extra +val parchmentMappingsVersion: String by extra +val parchmentMinecraftVersion: String by extra +val neoforgeVersionRange: String by extra +val chemlibVersionRange: String by extra +val chemlibVersion: String by extra + +val localRuntime: Configuration by configurations.creating + +tasks.wrapper { + distributionType = Wrapper.DistributionType.BIN +} + +version = "$minecraftVersion-$modVersion" +group = "com.smashingmods.alchemylib" + +repositories { + exclusiveContent { + forRepository { + maven("https://api.modrinth.com/maven") + } + + filter { + includeGroup("maven.modrinth") + } + } +} + +base { + archivesName = "alchemylib" +} + +java.toolchain.languageVersion = JavaLanguageVersion.of(21) + +neoForge { + version = neoVersion + + parchment { + mappingsVersion = parchmentMappingsVersion + minecraftVersion = parchmentMinecraftVersion + } + + accessTransformers.from("src/main/resources/META-INF/accesstransformer.cfg") + + runs { + create("client") { + client() + systemProperty("neoforge.enabledGameTestNamespaces", "alchemylib") + } + + create("server") { + server() + programArgument("--nogui") + systemProperty("neoforge.enabledGameTestNamespaces", "alchemylib") + } + + create("gameTestServer") { + type = "gameTestServer" + systemProperty("neoforge.enabledGameTestNamespaces", "alchemylib") + } + + create("data") { + data() + programArguments.addAll("--mod", "alchemylib", "--all", "--output", file("src/generated/resources/").absolutePath, "--existing", file("src/main/resources/").absolutePath) + } + + configureEach { + systemProperty("forge.logging.markers", "REGISTRIES") + jvmArguments.add("-XX:+AllowEnhancedClassRedefinition") + logLevel = org.slf4j.event.Level.INFO + } + } + + mods { + create("alchemylib") { + sourceSet(sourceSets.main.get()) + } + } +} + +sourceSets.main.get().resources { srcDir("src/generated/resources") } + +configurations { + runtimeClasspath.get().extendsFrom(localRuntime) +} + +dependencies { + implementation(files("../ChemLib-1211/build/libs/chemlib-${chemlibVersion}.jar")) +} + +tasks.processResources { + var replaceProperties = mapOf("minecraftVersion" to minecraftVersion, "neoVersion" to neoVersion, + "neoforgeVersionRange" to neoforgeVersionRange, "modVersion" to modVersion, "chemlibVersionRange" to chemlibVersionRange + ) + + inputs.properties(replaceProperties) + + filesMatching(listOf("META-INF/neoforge.mods.toml")) { + expand(replaceProperties) + } +} + +tasks.withType().configureEach { + options.encoding = "UTF-8" +} + +idea { + module { + isDownloadSources = true + isDownloadJavadoc = true + } +} + +/* +publishing { + publications { + mavenJava(MavenPublication) { + afterEvaluate { + artifact project.jar + artifact project.sourcesJar + artifact project.javadocJar + } + setGroupId "smashingmods" + setArtifactId "alchemylib" + } + } + repositories { + maven { + url "https://maven.tamaized.com/releases" + credentials { + username secrets.getProperty("maven_username") + password secrets.getProperty("maven_password") + } + } + } +} + */ \ No newline at end of file diff --git a/changelog.md b/changelog.md deleted file mode 100644 index 4671e76..0000000 --- a/changelog.md +++ /dev/null @@ -1,4 +0,0 @@ -# AlchemyLib 1.20.1-1.0.30 RELEASE - -Changes: -- Includes PR #7 which should fix machines that stop working after a recipe change. Thanks to contributor cyb0124. \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 5813f7f..9074d28 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,20 +1,20 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false -minecraft_version=1.20.1 -minecraft_version_range=[1.20.1,1.21) -forge_version=47.1.0 -forge_version_range=[47,) -loader_version_range=[47,) -mapping_channel=parchment -mapping_version=2023.07.09 +# Minecraft +minecraftVersion=1.21.1 -mod_id=alchemylib -mod_name=AlchemyLib -mod_license=LGPLv2.1 -mod_version=1.0.30 -mod_group_id=com.smashingmods.alchemylib -mod_authors=DarkArcana -mod_description=AlchemyLib is a library mod for ChemLib addon mods such as Alchemistry and Techemistry. Anyone can use AlchemyLib to help bootstrap their mod development. Everything you need is in the api package. +# NeoForge +neoVersion=21.1.219 +neoforgeVersionRange=[21,22) -chemlib_version=2.0.17 \ No newline at end of file +# Parchment +parchmentMinecraftVersion=1.21.1 +parchmentMappingsVersion=2024.11.17 + +# Mod +modVersion=1.0.30 + +# Dependencies +chemlibVersion=2.0.19 +chemlibVersionRange=[2.0,2.1) \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 943f0cb..61285a6 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37aef8d..37f78a6 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-9.3.1-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 index 65dcd68..adff685 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -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/. @@ -83,10 +85,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 -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 @@ -114,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -133,10 +132,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 +146,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 +154,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 @@ -169,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -197,16 +198,19 @@ 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, 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" \ - -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 93e3f59..c4bdd3a 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 ########################################################################## @@ -43,11 +45,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,22 +59,21 @@ 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 :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/secrets.properties b/secrets.properties deleted file mode 100644 index 4ac9c16..0000000 --- a/secrets.properties +++ /dev/null @@ -1,2 +0,0 @@ -maven_username= -maven_password= \ No newline at end of file diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index dc82978..0000000 --- a/settings.gradle +++ /dev/null @@ -1,11 +0,0 @@ -pluginManagement { - repositories { - gradlePluginPortal() - maven { url = 'https://maven.minecraftforge.net/' } - maven { url = 'https://maven.parchmentmc.org' } - } -} - -plugins { - id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0' -} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..56ecd5c --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,9 @@ +pluginManagement { + repositories { + gradlePluginPortal() + } +} + +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" +} \ No newline at end of file diff --git a/src/main/java/com/smashingmods/alchemylib/AlchemyLib.java b/src/main/java/com/smashingmods/alchemylib/AlchemyLib.java index 80a500a..15d04fe 100644 --- a/src/main/java/com/smashingmods/alchemylib/AlchemyLib.java +++ b/src/main/java/com/smashingmods/alchemylib/AlchemyLib.java @@ -2,9 +2,9 @@ import com.smashingmods.alchemylib.common.network.PacketHandler; import com.smashingmods.alchemylib.datagen.DataGenerators; -import net.minecraftforge.eventbus.api.IEventBus; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraft.resources.ResourceLocation; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.fml.common.Mod; /** @@ -17,15 +17,13 @@ public class AlchemyLib { public static final String MODID = "alchemylib"; public static AlchemyLib instance; - private final PacketHandler packetHandler = new PacketHandler().register(); - public AlchemyLib() { + public AlchemyLib(IEventBus modEventBus) { instance = this; - IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); modEventBus.addListener(DataGenerators::gatherData); } - public static PacketHandler getPacketHandler() { - return instance.packetHandler; + public static ResourceLocation modLoc(String path) { + return ResourceLocation.fromNamespaceAndPath(MODID, path); } } diff --git a/src/main/java/com/smashingmods/alchemylib/api/block/AbstractProcessingBlock.java b/src/main/java/com/smashingmods/alchemylib/api/block/AbstractProcessingBlock.java index ff5933e..c160f23 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/block/AbstractProcessingBlock.java +++ b/src/main/java/com/smashingmods/alchemylib/api/block/AbstractProcessingBlock.java @@ -24,7 +24,7 @@ * @see BaseEntityBlock */ @SuppressWarnings("unused") -public class AbstractProcessingBlock extends BaseEntityBlock { +public abstract class AbstractProcessingBlock extends BaseEntityBlock { private final BiFunction blockEntityFunction; public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; diff --git a/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/AbstractProcessingMenu.java b/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/AbstractProcessingMenu.java index 468b28e..1faf53e 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/AbstractProcessingMenu.java +++ b/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/AbstractProcessingMenu.java @@ -1,17 +1,20 @@ package com.smashingmods.alchemylib.api.blockentity.container; -import com.smashingmods.alchemylib.AlchemyLib; import com.smashingmods.alchemylib.api.blockentity.processing.AbstractProcessingBlockEntity; -import com.smashingmods.alchemylib.common.network.BlockEntityPacket; +import com.smashingmods.alchemylib.api.blockentity.processing.AbstractFluidBlockEntity; import net.minecraft.world.Container; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.inventory.Slot; +import net.minecraft.world.inventory.ContainerData; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.server.level.ServerPlayer; /** * This abstract class extends {@link AbstractContainerMenu} by adding overrides for mod support. It also provides @@ -25,6 +28,7 @@ public abstract class AbstractProcessingMenu extends AbstractContainerMenu { private final Level level; private final int inputSlots; private final int outputSlots; + private final Player menuPlayer; protected AbstractProcessingMenu(MenuType pMenuType, int pContainerId, Inventory pInventory, BlockEntity pBlockEntity, int pInputSlots, int pOutputSlots) { super(pMenuType, pContainerId); @@ -33,8 +37,66 @@ protected AbstractProcessingMenu(MenuType pMenuType, int pContainerId, Invent this.outputSlots = pOutputSlots; this.blockEntity = ((AbstractProcessingBlockEntity) pBlockEntity); this.level = pInventory.player.level(); + this.menuPlayer = pInventory.player; addPlayerInventorySlots(pInventory); + + // Agregar sincronización de progreso desde el BlockEntity al cliente + addDataSlots(createProgressData()); + } + + /** + * Crea los DataSlots para sincronizar el estado del progreso desde el BlockEntity al cliente. + * @return ContainerData con [progress, maxProgress, canProcess, recipeLocked, paused] + */ + private ContainerData createProgressData() { + final boolean isFluidMachine = blockEntity instanceof AbstractFluidBlockEntity; + return new ContainerData() { + @Override + public int get(int pIndex) { + if (pIndex <= 4) { + int[] data = blockEntity.createIntArray(); + return pIndex < data.length ? data[pIndex] : 0; + } + + if (isFluidMachine) { + AbstractFluidBlockEntity fluidBlockEntity = (AbstractFluidBlockEntity) blockEntity; + return switch (pIndex) { + case 5 -> fluidBlockEntity.getFluidStorage().getFluidAmount(); + case 6 -> fluidBlockEntity.getFluidStorage().getCapacity(); + default -> 0; + }; + } + + return 0; + } + + @Override + public void set(int pIndex, int pValue) { + if (pIndex <= 4) { + int[] data = blockEntity.createIntArray(); + if (pIndex < data.length) { + switch (pIndex) { + case 0 -> blockEntity.setProgress(pValue); + case 1 -> blockEntity.setMaxProgress(pValue); + case 2 -> blockEntity.setCanProcess(pValue == 1); + case 3 -> blockEntity.setRecipeLocked(pValue == 1); + case 4 -> blockEntity.setPaused(pValue == 1); + } + } + return; + } + + if (isFluidMachine && pIndex == 5) { + ((AbstractFluidBlockEntity) blockEntity).getFluidStorage().setAmount(pValue); + } + } + + @Override + public int getCount() { + return isFluidMachine ? 7 : 5; + } + }; } /** @@ -49,8 +111,11 @@ protected AbstractProcessingMenu(MenuType pMenuType, int pContainerId, Invent @Override public void broadcastChanges() { super.broadcastChanges(); - if (level != null && !level.isClientSide()) { - AlchemyLib.getPacketHandler().sendToTrackingChunk(new BlockEntityPacket(getBlockEntity().getBlockPos(), getBlockEntity().getUpdateTag()), getLevel(), getBlockEntity().getBlockPos()); + if (level != null && !level.isClientSide() && menuPlayer instanceof ServerPlayer serverPlayer) { + Packet updatePacket = getBlockEntity().getUpdatePacket(); + if (updatePacket != null) { + serverPlayer.connection.send(updatePacket); + } } } diff --git a/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/AbstractProcessingScreen.java b/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/AbstractProcessingScreen.java index e7f8504..0e50461 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/AbstractProcessingScreen.java +++ b/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/AbstractProcessingScreen.java @@ -19,8 +19,8 @@ import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.inventory.InventoryMenu; import net.minecraft.world.item.ItemStack; -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; import java.util.LinkedList; import java.util.List; @@ -62,7 +62,7 @@ protected void init() { */ @Override public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) { - renderBackground(pGuiGraphics); + renderBackground(pGuiGraphics, pMouseX, pMouseY, pPartialTick); renderBg(pGuiGraphics, pPartialTick, pMouseX, pMouseY); super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick); @@ -129,15 +129,18 @@ public void drawTexture(AbstractDisplayData pData, TextureAtlasSprite pSprite, i float blitOffset = 0; + /* TODO Tesselator tesselator = Tesselator.getInstance(); BufferBuilder bufferBuilder = tesselator.getBuilder(); - + bufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX); bufferBuilder.vertex(x1, y2, blitOffset).uv(minU, scaleV).endVertex(); bufferBuilder.vertex(x2, y2, blitOffset).uv(scaleU, scaleV).endVertex(); bufferBuilder.vertex(x2, y1, blitOffset).uv(scaleU, minV).endVertex(); bufferBuilder.vertex(x1, y1, blitOffset).uv(minU, minV).endVertex(); tesselator.end(); + + */ height += 15; } @@ -250,7 +253,7 @@ private void directionalBlit(GuiGraphics pGuiGraphics, int pX, int pY, int pUOff } case DOWN -> vHeight = pVScaled; } - pGuiGraphics.blit(new ResourceLocation(AlchemyLib.MODID, "textures/gui/widgets.png"), x, y, uOffset, vOffset, uWidth, vHeight); + pGuiGraphics.blit(AlchemyLib.modLoc("textures/gui/widgets.png"), x, y, uOffset, vOffset, uWidth, vHeight); } /** diff --git a/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/RecipeDisplayUtil.java b/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/RecipeDisplayUtil.java index 6c6f67e..85c2029 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/RecipeDisplayUtil.java +++ b/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/RecipeDisplayUtil.java @@ -6,11 +6,11 @@ import com.smashingmods.chemlib.common.items.CompoundItem; import com.smashingmods.chemlib.common.items.ElementItem; import net.minecraft.ChatFormatting; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; -import net.minecraft.network.chat.contents.LiteralContents; +import net.minecraft.network.chat.contents.PlainTextContents; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.registries.ForgeRegistries; import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; @@ -21,27 +21,27 @@ public class RecipeDisplayUtil { public static List getItemTooltipComponent(ItemStack pItemStack, MutableComponent pComponent) { List components = new ArrayList<>(); - String namespace = StringUtils.capitalize(Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(pItemStack.getItem())).getNamespace()); + String namespace = StringUtils.capitalize(Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(pItemStack.getItem())).getNamespace()); components.add(pComponent.withStyle(ChatFormatting.UNDERLINE, ChatFormatting.YELLOW)); - components.add(MutableComponent.create(new LiteralContents(String.format("%dx %s", pItemStack.getCount(), pItemStack.getItem().getDescription().getString())))); + components.add(MutableComponent.create(new PlainTextContents.LiteralContents(String.format("%dx %s", pItemStack.getCount(), pItemStack.getItem().getDescription().getString())))); if (pItemStack.getItem() instanceof Chemical chemical) { String abbreviation = chemical.getAbbreviation(); if (chemical instanceof ElementItem element) { - components.add(MutableComponent.create(new LiteralContents(String.format("%s (%d)", abbreviation, element.getAtomicNumber()))).withStyle(ChatFormatting.DARK_AQUA)); - components.add(MutableComponent.create(new LiteralContents(element.getGroupName())).withStyle(ChatFormatting.GRAY)); + components.add(MutableComponent.create(new PlainTextContents.LiteralContents(String.format("%s (%d)", abbreviation, element.getAtomicNumber()))).withStyle(ChatFormatting.DARK_AQUA)); + components.add(MutableComponent.create(new PlainTextContents.LiteralContents(element.getGroupName())).withStyle(ChatFormatting.GRAY)); } else if (chemical instanceof ChemicalItem chemicalItem && !chemicalItem.getItemType().equals(ChemicalItemType.COMPOUND)) { ElementItem element = (ElementItem) chemicalItem.getChemical(); - components.add(MutableComponent.create(new LiteralContents(String.format("%s (%d)", chemicalItem.getAbbreviation(), element.getAtomicNumber()))).withStyle(ChatFormatting.DARK_AQUA)); - components.add(MutableComponent.create(new LiteralContents(element.getGroupName())).withStyle(ChatFormatting.GRAY)); + components.add(MutableComponent.create(new PlainTextContents.LiteralContents(String.format("%s (%d)", chemicalItem.getAbbreviation(), element.getAtomicNumber()))).withStyle(ChatFormatting.DARK_AQUA)); + components.add(MutableComponent.create(new PlainTextContents.LiteralContents(element.getGroupName())).withStyle(ChatFormatting.GRAY)); } else if (chemical instanceof CompoundItem) { - components.add(MutableComponent.create(new LiteralContents(abbreviation)).withStyle(ChatFormatting.DARK_AQUA)); + components.add(MutableComponent.create(new PlainTextContents.LiteralContents(abbreviation)).withStyle(ChatFormatting.DARK_AQUA)); } } - components.add(MutableComponent.create(new LiteralContents(namespace)).withStyle(ChatFormatting.BLUE)); + components.add(MutableComponent.create(new PlainTextContents.LiteralContents(namespace)).withStyle(ChatFormatting.BLUE)); return components; } } diff --git a/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/button/AbstractAlchemyButton.java b/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/button/AbstractAlchemyButton.java index dda78ea..d3c36d7 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/button/AbstractAlchemyButton.java +++ b/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/button/AbstractAlchemyButton.java @@ -6,7 +6,7 @@ import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Button; import net.minecraft.network.chat.MutableComponent; -import net.minecraft.network.chat.contents.LiteralContents; +import net.minecraft.network.chat.contents.PlainTextContents; import javax.annotation.Nonnull; import java.util.List; @@ -28,7 +28,7 @@ public abstract class AbstractAlchemyButton extends Button { * @param pOnPress {@link Button#onPress} */ public AbstractAlchemyButton(AbstractProcessingScreen pParent, Button.OnPress pOnPress) { - this(0, 0, 20, 20, MutableComponent.create(new LiteralContents("")), pParent, pOnPress); + this(0, 0, 20, 20, MutableComponent.create(new PlainTextContents.LiteralContents("")), pParent, pOnPress); } /** diff --git a/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/data/AbstractDisplayData.java b/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/data/AbstractDisplayData.java index 6365172..8d90361 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/data/AbstractDisplayData.java +++ b/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/data/AbstractDisplayData.java @@ -1,7 +1,7 @@ package com.smashingmods.alchemylib.api.blockentity.container.data; import net.minecraft.network.chat.MutableComponent; -import net.minecraft.network.chat.contents.LiteralContents; +import net.minecraft.network.chat.contents.PlainTextContents; /** * This abstract class defines getters and setters for shared fields for all {@link DisplayData} implementers. @@ -61,6 +61,6 @@ public MutableComponent toTextComponent() { if (this.toString() != null) { temp = this.toString(); } - return MutableComponent.create(new LiteralContents(temp)); + return MutableComponent.create(new PlainTextContents.LiteralContents(temp)); } } diff --git a/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/data/FluidDisplayData.java b/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/data/FluidDisplayData.java index 260853c..c3239d8 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/data/FluidDisplayData.java +++ b/src/main/java/com/smashingmods/alchemylib/api/blockentity/container/data/FluidDisplayData.java @@ -4,8 +4,7 @@ import com.smashingmods.alchemylib.api.blockentity.processing.AbstractProcessingBlockEntity; import com.smashingmods.alchemylib.api.storage.FluidStorageHandler; import net.minecraft.client.resources.language.I18n; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.FluidStack; import java.text.NumberFormat; import java.util.Locale; @@ -35,7 +34,7 @@ public int getMaxValue() { } public FluidStorageHandler getFluidHandler() { - return (FluidStorageHandler) blockEntity.getCapability(ForgeCapabilities.FLUID_HANDLER).orElseGet(() -> new FluidStorageHandler(0, FluidStack.EMPTY)); + return blockEntity.getFluidStorage(); } @Override diff --git a/src/main/java/com/smashingmods/alchemylib/api/blockentity/processing/AbstractFluidBlockEntity.java b/src/main/java/com/smashingmods/alchemylib/api/blockentity/processing/AbstractFluidBlockEntity.java index 071baed..1b2fc27 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/blockentity/processing/AbstractFluidBlockEntity.java +++ b/src/main/java/com/smashingmods/alchemylib/api/blockentity/processing/AbstractFluidBlockEntity.java @@ -3,20 +3,18 @@ import com.smashingmods.alchemylib.api.storage.FluidStorageHandler; import com.smashingmods.alchemylib.api.storage.ProcessingSlotHandler; import com.smashingmods.alchemylib.api.storage.SidedProcessingSlotWrapper; - import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fluids.FluidUtil; -import net.minecraftforge.fluids.capability.IFluidHandler; +import net.neoforged.neoforge.common.util.Lazy; +import net.neoforged.neoforge.fluids.FluidUtil; +import net.neoforged.neoforge.fluids.capability.IFluidHandler; import org.jetbrains.annotations.Nullable; import javax.annotation.Nonnull; @@ -25,7 +23,7 @@ public abstract class AbstractFluidBlockEntity extends AbstractProcessingBlockEntity implements FluidBlockEntity, InventoryBlockEntity { private final FluidStorageHandler fluidStorage = initializeFluidStorage(); - private final LazyOptional lazyFluidHandler = LazyOptional.of(() -> fluidStorage); + private final Lazy lazyFluidHandler = Lazy.of(() -> fluidStorage); private final ProcessingSlotHandler inputHandler = initializeInputHandler(); private final ProcessingSlotHandler outputHandler = initializeOutputHandler(); @@ -63,6 +61,7 @@ public SidedProcessingSlotWrapper getCombinedSlotHandler() { return combinedHandler; } + /* TODO @Nonnull @Override public LazyOptional getCapability(Capability pCapability, @Nullable Direction pDirection) { @@ -73,12 +72,12 @@ public LazyOptional getCapability(Capability pCapability, @Nullable Di } return super.getCapability(pCapability, pDirection); } - + */ @Override - public void invalidateCaps() { + public void invalidateCapabilities() { combinedHandler.invalidate(); lazyFluidHandler.invalidate(); - super.invalidateCaps(); + super.invalidateCapabilities(); } @Override @@ -87,22 +86,22 @@ public boolean isRecipeLocked() { } @Override - protected void saveAdditional(CompoundTag pTag) { - pTag.put("input", inputHandler.serializeNBT()); - pTag.put("output", outputHandler.serializeNBT()); - pTag.put("fluid", fluidStorage.writeToNBT(new CompoundTag())); - pTag.putShort("sides", combinedHandler.sideModesToShort()); - super.saveAdditional(pTag); + protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) { + tag.put("input", inputHandler.serializeNBT(registries)); + tag.put("output", outputHandler.serializeNBT(registries)); + tag.put("fluid", fluidStorage.writeToNBT(registries, new CompoundTag())); + tag.putShort("sides", combinedHandler.sideModesToShort()); + super.saveAdditional(tag, registries); } @Override - public void load(CompoundTag pTag) { - super.load(pTag); - inputHandler.deserializeNBT(pTag.getCompound("input")); - outputHandler.deserializeNBT(pTag.getCompound("output")); - fluidStorage.readFromNBT(pTag.getCompound("fluid")); - if (pTag.contains("sides")) { - combinedHandler.setSideModesFromShort(pTag.getShort("sides")); + protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) { + super.loadAdditional(tag, registries); + inputHandler.deserializeNBT(registries, tag.getCompound("input")); + outputHandler.deserializeNBT(registries, tag.getCompound("output")); + fluidStorage.readFromNBT(registries, tag.getCompound("fluid")); + if (tag.contains("sides")) { + combinedHandler.setSideModesFromShort(tag.getShort("sides")); } else { combinedHandler.setSideModesFromShort(SidedProcessingSlotWrapper.LEGACY_SIDES_CONFIGURATION); } diff --git a/src/main/java/com/smashingmods/alchemylib/api/blockentity/processing/AbstractInventoryBlockEntity.java b/src/main/java/com/smashingmods/alchemylib/api/blockentity/processing/AbstractInventoryBlockEntity.java index 838d56e..0b53e8a 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/blockentity/processing/AbstractInventoryBlockEntity.java +++ b/src/main/java/com/smashingmods/alchemylib/api/blockentity/processing/AbstractInventoryBlockEntity.java @@ -2,18 +2,11 @@ import com.smashingmods.alchemylib.api.storage.ProcessingSlotHandler; import com.smashingmods.alchemylib.api.storage.SidedProcessingSlotWrapper; - import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; +import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.common.util.LazyOptional; -import org.jetbrains.annotations.Nullable; - -import javax.annotation.Nonnull; @SuppressWarnings("unused") public abstract class AbstractInventoryBlockEntity extends AbstractProcessingBlockEntity implements InventoryBlockEntity { @@ -49,6 +42,7 @@ public SidedProcessingSlotWrapper getCombinedSlotHandler() { return combinedHandler; } + /* TODO @Nonnull @Override public LazyOptional getCapability(Capability pCapability, @Nullable Direction pDirection) { @@ -57,28 +51,29 @@ public LazyOptional getCapability(Capability pCapability, @Nullable Di } return super.getCapability(pCapability, pDirection); } - + */ + @Override - public void invalidateCaps() { + public void invalidateCapabilities() { combinedHandler.invalidate(); - super.invalidateCaps(); + super.invalidateCapabilities(); } @Override - protected void saveAdditional(CompoundTag pTag) { - pTag.put("input", inputHandler.serializeNBT()); - pTag.put("output", outputHandler.serializeNBT()); - pTag.putShort("sides", combinedHandler.sideModesToShort()); - super.saveAdditional(pTag); + protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) { + tag.put("input", inputHandler.serializeNBT(registries)); + tag.put("output", outputHandler.serializeNBT(registries)); + tag.putShort("sides", combinedHandler.sideModesToShort()); + super.saveAdditional(tag, registries); } @Override - public void load(CompoundTag pTag) { - super.load(pTag); - inputHandler.deserializeNBT(pTag.getCompound("input")); - outputHandler.deserializeNBT(pTag.getCompound("output")); - if (pTag.contains("sides")) { - combinedHandler.setSideModesFromShort(pTag.getShort("sides")); + protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) { + super.loadAdditional(tag, registries); + inputHandler.deserializeNBT(registries, tag.getCompound("input")); + outputHandler.deserializeNBT(registries, tag.getCompound("output")); + if (tag.contains("sides")) { + combinedHandler.setSideModesFromShort(tag.getShort("sides")); } else { combinedHandler.setSideModesFromShort(SidedProcessingSlotWrapper.LEGACY_SIDES_CONFIGURATION); } diff --git a/src/main/java/com/smashingmods/alchemylib/api/blockentity/processing/AbstractProcessingBlockEntity.java b/src/main/java/com/smashingmods/alchemylib/api/blockentity/processing/AbstractProcessingBlockEntity.java index bd49c6c..93c4f69 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/blockentity/processing/AbstractProcessingBlockEntity.java +++ b/src/main/java/com/smashingmods/alchemylib/api/blockentity/processing/AbstractProcessingBlockEntity.java @@ -2,7 +2,8 @@ import com.smashingmods.alchemylib.api.storage.EnergyStorageHandler; import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.Connection; import net.minecraft.network.chat.Component; @@ -12,17 +13,14 @@ import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.world.MenuProvider; +import net.minecraft.world.level.block.Block; 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.capabilities.Capability; -import net.minecraftforge.common.capabilities.ForgeCapabilities; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.energy.IEnergyStorage; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.neoforge.common.util.Lazy; +import net.neoforged.neoforge.energy.IEnergyStorage; import org.jetbrains.annotations.Nullable; -import javax.annotation.Nonnull; import java.util.Objects; @SuppressWarnings("unused") @@ -39,11 +37,11 @@ public abstract class AbstractProcessingBlockEntity extends BlockEntity implemen private boolean ioScreenOpen = false; private final EnergyStorageHandler energyHandler = initializeEnergyStorage(); - private final LazyOptional lazyEnergyHandler = LazyOptional.of(() -> energyHandler); + private final Lazy lazyEnergyHandler = Lazy.of(() -> energyHandler); public AbstractProcessingBlockEntity(String pModId, BlockEntityType pBlockEntityType, BlockPos pWorldPosition, BlockState pBlockState) { super(pBlockEntityType, pWorldPosition, pBlockState); - this.name = MutableComponent.create(new TranslatableContents(String.format("%s.container.%s", pModId, ForgeRegistries.BLOCK_ENTITY_TYPES.getKey(getType())), null, TranslatableContents.NO_ARGS)); + this.name = MutableComponent.create(new TranslatableContents(String.format("%s.container.%s", pModId, BuiltInRegistries.BLOCK_ENTITY_TYPE.getKey(getType())), null, TranslatableContents.NO_ARGS)); } @Override @@ -52,17 +50,17 @@ public Component getDisplayName() { } @Override - public CompoundTag getUpdateTag() { - CompoundTag tag = super.getUpdateTag(); - saveAdditional(tag); + public CompoundTag getUpdateTag(HolderLookup.Provider registries) { + CompoundTag tag = super.getUpdateTag(registries); + saveAdditional(tag, registries); return tag; } @Override - public void onDataPacket(Connection pConnection, ClientboundBlockEntityDataPacket pPacket) { - Objects.requireNonNull(pPacket.getTag()); - this.load(pPacket.getTag()); - super.onDataPacket(pConnection, pPacket); + public void onDataPacket(Connection net, ClientboundBlockEntityDataPacket pkt, HolderLookup.Provider lookupProvider) { + Objects.requireNonNull(pkt.getTag()); + this.loadAdditional(pkt.getTag(), lookupProvider); + super.onDataPacket(net, pkt, lookupProvider); } @Nullable @@ -71,6 +69,14 @@ public Packet getUpdatePacket() { return ClientboundBlockEntityDataPacket.create(this); } + @Override + public void setChanged() { + super.setChanged(); + if (level != null && !level.isClientSide()) { + level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), Block.UPDATE_ALL); + } + } + @Override public void tick() { if (level != null && !level.isClientSide()) { @@ -163,6 +169,7 @@ public void setEnergyPerTick(int pEnergyPerTick) { energyPerTick = pEnergyPerTick; } + /* TODO @Override @Nonnull public LazyOptional getCapability(@Nonnull Capability pCapability, @Nullable Direction pDirection) { @@ -171,28 +178,44 @@ public LazyOptional getCapability(@Nonnull Capability pCapability, @Nu } return super.getCapability(pCapability, pDirection); } - + */ + @Override - public void invalidateCaps() { + public void invalidateCapabilities() { lazyEnergyHandler.invalidate(); - super.invalidateCaps(); + super.invalidateCapabilities(); } @Override - protected void saveAdditional(CompoundTag pTag) { - pTag.putInt("progress", progress); - pTag.putBoolean("locked", isRecipeLocked()); - pTag.putBoolean("paused", isProcessingPaused()); - pTag.put("energy", energyHandler.serializeNBT()); - super.saveAdditional(pTag); + protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) { + tag.putInt("progress", progress); + tag.putBoolean("locked", isRecipeLocked()); + tag.putBoolean("paused", isProcessingPaused()); + tag.put("energy", energyHandler.serializeNBT(registries)); + super.saveAdditional(tag, registries); } @Override - public void load(CompoundTag pTag) { - super.load(pTag); - setProgress(pTag.getInt("progress")); - setRecipeLocked(pTag.getBoolean("locked")); - setPaused(pTag.getBoolean("paused")); - energyHandler.deserializeNBT(pTag.get("energy")); + protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) { + super.loadAdditional(tag, registries); + setProgress(tag.getInt("progress")); + setRecipeLocked(tag.getBoolean("locked")); + setPaused(tag.getBoolean("paused")); + energyHandler.deserializeNBT(registries, tag.get("energy")); + } + + /** + * Create an int array for synchronizing progress state to the client. + * Used by AbstractProcessingMenu via addDataSlots(). + * @return int array with [progress, maxProgress, canProcess (0/1), recipeLocked (0/1), paused (0/1)] + */ + public int[] createIntArray() { + return new int[]{ + progress, + maxProgress, + canProcess ? 1 : 0, + recipeLocked ? 1 : 0, + paused ? 1 : 0 + }; } } diff --git a/src/main/java/com/smashingmods/alchemylib/api/blockentity/processing/AbstractSearchableBlockEntity.java b/src/main/java/com/smashingmods/alchemylib/api/blockentity/processing/AbstractSearchableBlockEntity.java index 014c008..4938203 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/blockentity/processing/AbstractSearchableBlockEntity.java +++ b/src/main/java/com/smashingmods/alchemylib/api/blockentity/processing/AbstractSearchableBlockEntity.java @@ -1,11 +1,12 @@ package com.smashingmods.alchemylib.api.blockentity.processing; -import com.smashingmods.alchemylib.AlchemyLib; import com.smashingmods.alchemylib.common.network.SearchPacket; import net.minecraft.core.BlockPos; +import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.neoforged.neoforge.network.PacketDistributor; import org.jetbrains.annotations.Nullable; public abstract class AbstractSearchableBlockEntity extends AbstractInventoryBlockEntity implements SearchableBlockEntity { @@ -37,20 +38,20 @@ public void setSearchText(@Nullable String pText) { if (pText != null && !pText.isEmpty()) { searchText = pText; if (level != null && level.isClientSide()) { - AlchemyLib.getPacketHandler().sendToServer(new SearchPacket(getBlockPos(), searchText)); + PacketDistributor.sendToServer(new SearchPacket(getBlockPos(), searchText)); } } } @Override - protected void saveAdditional(CompoundTag pTag) { - pTag.putString("searchText", searchText); - super.saveAdditional(pTag); + protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) { + tag.putString("searchText", searchText); + super.saveAdditional(tag, registries); } @Override - public void load(CompoundTag pTag) { - super.load(pTag); - setSearchText(pTag.getString("searchText")); + protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) { + super.loadAdditional(tag, registries); + setSearchText(tag.getString("searchText")); } } diff --git a/src/main/java/com/smashingmods/alchemylib/api/blockentity/processing/InventoryBlockEntity.java b/src/main/java/com/smashingmods/alchemylib/api/blockentity/processing/InventoryBlockEntity.java index 09adc56..80dafdd 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/blockentity/processing/InventoryBlockEntity.java +++ b/src/main/java/com/smashingmods/alchemylib/api/blockentity/processing/InventoryBlockEntity.java @@ -8,8 +8,7 @@ import net.minecraft.world.Containers; import net.minecraft.world.SimpleContainer; import net.minecraft.world.level.Level; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.items.IItemHandler; +import net.neoforged.neoforge.items.IItemHandler; /** * Attach optional input and output handler inventories to a {@link AbstractProcessingBlockEntity}. diff --git a/src/main/java/com/smashingmods/alchemylib/api/capability/AlchemyCapabilities.java b/src/main/java/com/smashingmods/alchemylib/api/capability/AlchemyCapabilities.java index f762688..5e59a05 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/capability/AlchemyCapabilities.java +++ b/src/main/java/com/smashingmods/alchemylib/api/capability/AlchemyCapabilities.java @@ -1,12 +1,14 @@ package com.smashingmods.alchemylib.api.capability; +import com.smashingmods.alchemylib.AlchemyLib; import io.netty.util.internal.UnstableApi; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.CapabilityManager; -import net.minecraftforge.common.capabilities.CapabilityToken; +import net.minecraft.core.Direction; +import net.neoforged.neoforge.capabilities.BlockCapability; +import org.jetbrains.annotations.Nullable; @SuppressWarnings("unused") @UnstableApi public class AlchemyCapabilities { - public static Capability HEAT_HANDLER = CapabilityManager.get(new CapabilityToken<>() {}); + // TODO + public static final BlockCapability HEAT_HANDLER = BlockCapability.createSided(AlchemyLib.modLoc("heat"), HeatCapability.class); } diff --git a/src/main/java/com/smashingmods/alchemylib/api/capability/HeatCapability.java b/src/main/java/com/smashingmods/alchemylib/api/capability/HeatCapability.java index 64e6d00..fdf01c3 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/capability/HeatCapability.java +++ b/src/main/java/com/smashingmods/alchemylib/api/capability/HeatCapability.java @@ -3,11 +3,10 @@ import io.netty.util.internal.UnstableApi; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; -import net.minecraftforge.common.capabilities.AutoRegisterCapability; -import net.minecraftforge.common.util.INBTSerializable; +import net.neoforged.neoforge.common.util.INBTSerializable; @SuppressWarnings("unused") -@AutoRegisterCapability +//@AutoRegisterCapability TODO @UnstableApi public interface HeatCapability extends INBTSerializable { diff --git a/src/main/java/com/smashingmods/alchemylib/api/capability/HeatHandler.java b/src/main/java/com/smashingmods/alchemylib/api/capability/HeatHandler.java index 02f18e8..0644da1 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/capability/HeatHandler.java +++ b/src/main/java/com/smashingmods/alchemylib/api/capability/HeatHandler.java @@ -1,10 +1,11 @@ package com.smashingmods.alchemylib.api.capability; import io.netty.util.internal.UnstableApi; +import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; -import net.minecraft.network.chat.contents.LiteralContents; +import net.minecraft.network.chat.contents.PlainTextContents; @SuppressWarnings("unused") @UnstableApi @@ -51,20 +52,20 @@ public int getMaxHeat() { } @Override - public CompoundTag serializeNBT() { + public CompoundTag serializeNBT(HolderLookup.Provider provider) { final CompoundTag tag = new CompoundTag(); tag.putInt("heat", heat); return tag; } @Override - public void deserializeNBT(CompoundTag pTag) { - setHeat(pTag.getInt("heat")); + public void deserializeNBT(HolderLookup.Provider provider, CompoundTag compoundTag) { + setHeat(compoundTag.getInt("heat")); } @Override public Component getComponent() { - return MutableComponent.create(new LiteralContents(String.format("%s H", heat))); + return MutableComponent.create(new PlainTextContents.LiteralContents(String.format("%s H", heat))); } @Override diff --git a/src/main/java/com/smashingmods/alchemylib/api/item/IngredientStack.java b/src/main/java/com/smashingmods/alchemylib/api/item/IngredientStack.java index 8131599..0eb68d3 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/item/IngredientStack.java +++ b/src/main/java/com/smashingmods/alchemylib/api/item/IngredientStack.java @@ -1,13 +1,23 @@ package com.smashingmods.alchemylib.api.item; import com.google.gson.JsonObject; +import com.google.gson.JsonElement; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Codec; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.JsonOps; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; import net.minecraft.util.GsonHelper; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.ItemLike; +import org.apache.commons.lang3.NotImplementedException; import java.util.Arrays; import java.util.List; @@ -24,6 +34,28 @@ @SuppressWarnings("unused") public class IngredientStack { + public static final Codec CODEC = Codec.PASSTHROUGH.comapFlatMap(dynamic -> { + JsonElement element = dynamic.convert(JsonOps.INSTANCE).getValue(); + if (!element.isJsonObject()) { + return DataResult.error(() -> "IngredientStack must be a JSON object"); + } + try { + return DataResult.success(fromJson(element.getAsJsonObject())); + } catch (RuntimeException exception) { + return DataResult.error(exception::getMessage); + } + }, ingredientStack -> new Dynamic<>(JsonOps.INSTANCE, ingredientStack.toJson())); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + Ingredient.CONTENTS_STREAM_CODEC, + IngredientStack::getIngredient, + + ByteBufCodecs.INT, + IngredientStack::getCount, + + IngredientStack::new + ); + private final Ingredient ingredient; private final int count; private final ResourceLocation registryName; @@ -41,9 +73,7 @@ public class IngredientStack { public IngredientStack(Ingredient pIngredient, int pCount) { this.ingredient = pIngredient; this.count = Math.min(pCount, 64); - this.registryName = new ResourceLocation(pIngredient.values[0].serialize().has("item") ? - pIngredient.values[0].serialize().get("item").getAsString() - : pIngredient.values[0].serialize().get("tag").getAsString()); + this.registryName = resolveRegistryName(pIngredient); } public IngredientStack(Ingredient pIngredient) { @@ -72,8 +102,10 @@ public IngredientStack(ItemLike pItemLike) { * @param pBuffer {@link FriendlyByteBuf} */ public void toNetwork(FriendlyByteBuf pBuffer) { - ingredient.toNetwork(pBuffer); - pBuffer.writeInt(count); + if (!(pBuffer instanceof RegistryFriendlyByteBuf registryFriendlyByteBuf)) { + throw new NotImplementedException("IngredientStack network serialization requires RegistryFriendlyByteBuf"); + } + STREAM_CODEC.encode(registryFriendlyByteBuf, this); } /** @@ -84,9 +116,10 @@ public void toNetwork(FriendlyByteBuf pBuffer) { * @return IngredientStack */ public static IngredientStack fromNetwork(FriendlyByteBuf pBuffer) { - Ingredient ingredient = Ingredient.fromNetwork(pBuffer); - int count = pBuffer.readInt(); - return new IngredientStack(ingredient, count); + if (!(pBuffer instanceof RegistryFriendlyByteBuf registryFriendlyByteBuf)) { + throw new NotImplementedException("IngredientStack network deserialization requires RegistryFriendlyByteBuf"); + } + return STREAM_CODEC.decode(registryFriendlyByteBuf); } /** @@ -95,8 +128,11 @@ public static IngredientStack fromNetwork(FriendlyByteBuf pBuffer) { * @return {@link JsonObject} */ public JsonObject toJson() { - JsonObject json = new JsonObject(); - json.add("ingredient", ingredient.toJson()); + JsonElement ingredientJson = Ingredient.CODEC.encodeStart(JsonOps.INSTANCE, ingredient).result().orElseThrow(); + if (!ingredientJson.isJsonObject()) { + throw new IllegalStateException("IngredientStack ingredient must encode to a JSON object"); + } + JsonObject json = ingredientJson.getAsJsonObject().deepCopy(); json.addProperty("count", count); return json; } @@ -108,8 +144,17 @@ public JsonObject toJson() { * @return IngredientStack */ public static IngredientStack fromJson(JsonObject pJson) { - Ingredient ingredient = Ingredient.fromJson(pJson.getAsJsonObject("ingredient")); int count = GsonHelper.getAsInt(pJson, "count", 1); + // Support both nested {"ingredient": {"item":"..."}, "count": N} + // and flat {"item":"...", "count": N} formats + JsonObject ingredientJson; + if (pJson.has("ingredient") && pJson.get("ingredient").isJsonObject()) { + ingredientJson = pJson.getAsJsonObject("ingredient"); + } else { + ingredientJson = pJson.deepCopy(); + ingredientJson.remove("count"); + } + Ingredient ingredient = Ingredient.CODEC.parse(JsonOps.INSTANCE, ingredientJson).result().orElseThrow(); return new IngredientStack(ingredient, count); } @@ -152,6 +197,32 @@ public boolean isEmpty() { return ingredient.isEmpty(); } + private static ResourceLocation resolveRegistryName(Ingredient ingredient) { + JsonElement ingredientJson = Ingredient.CODEC.encodeStart(JsonOps.INSTANCE, ingredient).result().orElseThrow(); + JsonObject ingredientObject = firstIngredientObject(ingredientJson); + if (ingredientObject.has("item")) { + return ResourceLocation.parse(ingredientObject.get("item").getAsString()); + } + if (ingredientObject.has("tag")) { + return ResourceLocation.parse(ingredientObject.get("tag").getAsString()); + } + ItemStack[] items = ingredient.getItems(); + if (items.length == 0) { + return BuiltInRegistries.ITEM.getKey(net.minecraft.world.item.Items.AIR); + } + return BuiltInRegistries.ITEM.getKey(items[0].getItem()); + } + + private static JsonObject firstIngredientObject(JsonElement ingredientJson) { + if (ingredientJson.isJsonObject()) { + return ingredientJson.getAsJsonObject(); + } + if (ingredientJson.isJsonArray() && !ingredientJson.getAsJsonArray().isEmpty() && ingredientJson.getAsJsonArray().get(0).isJsonObject()) { + return ingredientJson.getAsJsonArray().get(0).getAsJsonObject(); + } + throw new IllegalStateException("Unsupported ingredient JSON format"); + } + /** * Determines object equality of this IngredientStack against another object based on {@link ResourceLocation#equals(Object)}. * diff --git a/src/main/java/com/smashingmods/alchemylib/api/network/AbstractPacketHandler.java b/src/main/java/com/smashingmods/alchemylib/api/network/AbstractPacketHandler.java deleted file mode 100644 index d06b46e..0000000 --- a/src/main/java/com/smashingmods/alchemylib/api/network/AbstractPacketHandler.java +++ /dev/null @@ -1,168 +0,0 @@ -package com.smashingmods.alchemylib.api.network; - -import com.smashingmods.alchemylib.api.blockentity.container.AbstractProcessingMenu; -import com.smashingmods.alchemylib.common.network.*; -import net.minecraft.core.BlockPos; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraftforge.network.NetworkRegistry; -import net.minecraftforge.network.PacketDistributor; -import net.minecraftforge.network.simple.SimpleChannel; - -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.function.Supplier; - -/** - * AbstractPacketHandler is meant to be extended by other mods. It provides - * some basic helper methods so that you don't need to build your own from - * scratch for each mod. - * - *

Extend AlchemyPacket to easily create your own. Use the builtin packets - * as an example for how they should work.

- * - * @see AlchemyPacket - * @see BlockEntityPacket - * @see SearchPacket - * @see ToggleLockButtonPacket - * @see TogglePauseButtonPacket - */ -@SuppressWarnings({"unused", "SameParameterValue"}) -public abstract class AbstractPacketHandler { - - /** - * All packets need to have a valid unique discriminator. AbstractPacketHandler - * sets a private int PACKET_ID that implementing classes will need to increment. - */ - private int PACKET_ID; - - /** - * To send packets, you have to have a SimpleChannel registered in the NetworkRegistry. - * - * @param pChannelName ResourceLocation for your {@link SimpleChannel}. - * @param pProtocolVersion String representation of your protocol version (for example "1.0.0"). - * @return a new SimpleChannel registered in the {@link NetworkRegistry}. - * - * @see NetworkRegistry#newSimpleChannel(ResourceLocation, Supplier, Predicate, Predicate) - */ - protected static SimpleChannel createChannel(ResourceLocation pChannelName, String pProtocolVersion) { - return NetworkRegistry.newSimpleChannel(pChannelName, () -> pProtocolVersion, pProtocolVersion::equals, pProtocolVersion::equals); - } - - /** - * This method should be used to register all of your packets. After registering, return - * the instance of your PacketHandler so that it can be used to send packets. - * - * @return an implementation of AbstractPacketHandler. - * - * @see PacketHandler#register() - */ - public abstract AbstractPacketHandler register(); - - /** - * Implement this getter to return your own instance of {@link SimpleChannel} on your - * PacketHandler class. This is used to get the channel for sending packets - * by other parts of your mod. - * - * @return {@link SimpleChannel} - * - * @see AbstractProcessingMenu#broadcastChanges() - */ - protected abstract SimpleChannel getChannel(); - - /** - * All packets must be registered on your SimpleChannel. Call this method in your - * implementation class's register method. - * - * @param pMessageType Class of your packet. (for example BlockEntityPacket.class) - * @param pDecoder A function that takes a {@link FriendlyByteBuf} and returns a packet. - * Typically, you want this to be a constructor on your packet, - * but it can also be a static method that returns a new object. - * @param AlchemyPacket - * - * @see PacketHandler#register() - * @see BlockEntityPacket#BlockEntityPacket(FriendlyByteBuf) BlockEntityPacket - */ - protected void registerMessage(Class pMessageType, Function pDecoder) { - getChannel().registerMessage(PACKET_ID++, pMessageType, AlchemyPacket::encode, pDecoder, AlchemyPacket::handle); - } - - /** - * Sends the packet passed as a parameter to the server via your {@link SimpleChannel}. - * - * @param pMessage Your packet to send to the server. - * @param extends AlchemyPacket - * - * @see AlchemyPacket - */ - public void sendToServer(MSG pMessage) { - getChannel().sendToServer(pMessage); - } - - /** - * Sends a packet to the specific player specified in parameters via your {@link SimpleChannel}. - * - * @param pMessage Your packet to send to the player. - * @param pPlayer And instance of ServerPlayer. - * @param AlchemyPacket - * - * @see AlchemyPacket - */ - public void sendToPlayer(MSG pMessage, ServerPlayer pPlayer) { - getChannel().send(PacketDistributor.PLAYER.with(() -> pPlayer), pMessage); - } - - /** - * Sends the packet passed as a parameter to all players connected to the server via - * your {@link SimpleChannel}. Note: this will work if you are in a single player instance, - * LAN, or a dedicated server. - * - * @param pMessage Your packet to send to all players. - * @param AlchemyPacket - */ - public void sendToAll(MSG pMessage) { - getChannel().send(PacketDistributor.ALL.noArg(), pMessage); - } - - /** - * Sends the packet passed as a parameter to all players within a radius of the passed {@link BlockPos} - * in the {@link Level} parameter. - * - * @param pMessage Your packet to send. - * @param pLevel An instance of the Level (overworld, nether, end, etc) used to determine the context - * of the BlockPos parameter. - * @param pBlockPos BlockPos that is the center location for where to send the packet. - * @param pRadius Distance in blocks from the center BlockPos, the packet is sent to everyone in this radius. - * @param AlchemyPacket - * - */ - public void sendToNear(MSG pMessage, Level pLevel, BlockPos pBlockPos, double pRadius) { - ResourceKey dimension = pLevel.dimension(); - double posX = pBlockPos.getX(); - double posY = pBlockPos.getY(); - double posZ = pBlockPos.getZ(); - getChannel().send(PacketDistributor.NEAR.with(PacketDistributor.TargetPoint.p(posX, posY, posZ, pRadius, dimension)), pMessage); - } - - /** - * Sends the packet to all players that are tracking a specific chunk based on the passed {@link Level} and {@link BlockPos}. - * All players that are tracking the chunk of the BlockPos will receive the packet. - * - * @param pMessage Your packet to send. - * @param pLevel An instance of the Level (overworld, nether, end, etc) used to determine the context - * of the BlockPos parameter. - * @param pBlockPos BlockPos used to find the chunk being tracked. - * @param AlchemyPacket - * - * @see Level - * @see BlockPos - */ - public void sendToTrackingChunk(MSG pMessage, Level pLevel, BlockPos pBlockPos) { - LevelChunk levelChunk = pLevel.getChunkAt(pBlockPos); - getChannel().send(PacketDistributor.TRACKING_CHUNK.with(() -> levelChunk), pMessage); - } -} diff --git a/src/main/java/com/smashingmods/alchemylib/api/network/AlchemyPacket.java b/src/main/java/com/smashingmods/alchemylib/api/network/AlchemyPacket.java deleted file mode 100644 index 82c54ea..0000000 --- a/src/main/java/com/smashingmods/alchemylib/api/network/AlchemyPacket.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.smashingmods.alchemylib.api.network; - -import com.smashingmods.alchemylib.common.network.BlockEntityPacket; -import com.smashingmods.alchemylib.common.network.PacketHandler; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.network.NetworkEvent; - -import java.util.function.Function; -import java.util.function.Supplier; - -/** - * Implement AlchemyPacket to create your own packets to send across the network. - * - *

Implementing classes will need two constructors. The first is to create the packet elsewhere in your code. - * The second constructor is used as a decoder to create a new packet object on the receiving side.

- * - *

The packet must be registered in your implementation of {@link AbstractPacketHandler#register} using - * {@link AbstractPacketHandler#registerMessage(Class, Function)}

- * - * @see BlockEntityPacket - * @see PacketHandler - */ -public interface AlchemyPacket { - - /** - * Implement this method to encode your packet's data to a FriendlyByteBuf that will - * be sent across the network. - * - * @param pBuffer {@link FriendlyByteBuf} - * - * @see BlockEntityPacket#encode(FriendlyByteBuf) - */ - void encode(FriendlyByteBuf pBuffer); - - /** - * This method is called on the receiving end to handle the enqueued work. Whatever your packet does, - * this is where you do it. - * - * @param pContext NetworkEvent.Context - * - * @see BlockEntityPacket#handle(NetworkEvent.Context) - */ - void handle(NetworkEvent.Context pContext); - - /** - * Wrapper method for all packets implementing AlchemyPacket. This method enqueues work for {@link AlchemyPacket#handle(NetworkEvent.Context)} - * and sets the packet as handled when done. - * - * @param pMessage The implementing packet. - * @param pContext Supplier of {@link net.minecraftforge.network.NetworkEvent.Context} - * @param AlchemyPacket - */ - static void handle(final MSG pMessage, Supplier pContext) { - NetworkEvent.Context context = pContext.get(); - context.enqueueWork(() -> pMessage.handle(context)); - context.setPacketHandled(true); - } -} diff --git a/src/main/java/com/smashingmods/alchemylib/api/network/package-info.java b/src/main/java/com/smashingmods/alchemylib/api/network/package-info.java deleted file mode 100644 index 6b62335..0000000 --- a/src/main/java/com/smashingmods/alchemylib/api/network/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -package com.smashingmods.alchemylib.api.network; - -import net.minecraft.MethodsReturnNonnullByDefault; - -import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/com/smashingmods/alchemylib/api/recipe/AbstractProcessingRecipe.java b/src/main/java/com/smashingmods/alchemylib/api/recipe/AbstractProcessingRecipe.java index c311b9a..d4951cc 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/recipe/AbstractProcessingRecipe.java +++ b/src/main/java/com/smashingmods/alchemylib/api/recipe/AbstractProcessingRecipe.java @@ -1,28 +1,37 @@ package com.smashingmods.alchemylib.api.recipe; -import net.minecraft.core.RegistryAccess; +import net.minecraft.core.HolderLookup; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.RecipeInput; import net.minecraft.world.level.Level; +import org.jetbrains.annotations.Nullable; /** * This abstract implementation of {@link ProcessingRecipe} implements default methods that should * be ignored by extending classes. */ public abstract class AbstractProcessingRecipe implements ProcessingRecipe, Comparable { - - private final ResourceLocation recipeId; + @Nullable + private ResourceLocation id; private final String group; - public AbstractProcessingRecipe(ResourceLocation pRecipeId, String pGroup) { - this.recipeId = pRecipeId; + public AbstractProcessingRecipe(String pGroup) { + this(null, pGroup); + } + + public AbstractProcessingRecipe(@Nullable ResourceLocation pId, String pGroup) { + this.id = pId; this.group = pGroup; } - @Override + @Nullable public ResourceLocation getId() { - return recipeId; + return id; + } + + public void setId(@Nullable ResourceLocation pId) { + this.id = pId; } @Override @@ -36,7 +45,7 @@ public String getGroup() { * class if another return is necessary. */ @Override - public boolean matches(Inventory pContainer, Level pLevel) { + public boolean matches(RecipeInput recipeInput, Level level) { return false; } @@ -45,7 +54,7 @@ public boolean matches(Inventory pContainer, Level pLevel) { * crafting ignores this in favor of handling this logic within block entities. */ @Override - public ItemStack assemble(Inventory pContainer, RegistryAccess pRegistryAccess) { + public ItemStack assemble(RecipeInput recipeInput, HolderLookup.Provider provider) { return ItemStack.EMPTY; } @@ -54,7 +63,7 @@ public ItemStack assemble(Inventory pContainer, RegistryAccess pRegistryAccess) * an empty ItemStack. If your implementing class does return an ItemStack, override this. */ @Override - public ItemStack getResultItem(RegistryAccess pRegistryAccess) { + public ItemStack getResultItem(HolderLookup.Provider provider) { return ItemStack.EMPTY; } @@ -67,6 +76,20 @@ public boolean canCraftInDimensions(int pWidth, int pHeight) { return false; } + /** + * Null-safe ID comparison for use in compareTo implementations. + * Guards against the case where setId() has not yet been called (e.g. during onLoad + * if RecipeManager hasn't populated recipe holders yet). + */ + protected final int safeCompareIds(AbstractProcessingRecipe pOther) { + ResourceLocation mine = getId(); + ResourceLocation theirs = pOther.getId(); + if (mine == null && theirs == null) return 0; + if (mine == null) return -1; + if (theirs == null) return 1; + return mine.compareNamespaced(theirs); + } + @Override public boolean equals(Object pOther) { return pOther instanceof AbstractProcessingRecipe recipe && compareTo(recipe) == 0; diff --git a/src/main/java/com/smashingmods/alchemylib/api/recipe/ProcessingRecipe.java b/src/main/java/com/smashingmods/alchemylib/api/recipe/ProcessingRecipe.java index 7e8024c..627d0f3 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/recipe/ProcessingRecipe.java +++ b/src/main/java/com/smashingmods/alchemylib/api/recipe/ProcessingRecipe.java @@ -1,7 +1,7 @@ package com.smashingmods.alchemylib.api.recipe; -import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeInput; /** * The input and output of ProcessingRecipe can be of any type without defined class inheritance. @@ -10,7 +10,7 @@ *

Consumers of this recipe need to handle type casting when getting the input and output.

*/ @SuppressWarnings("unused") -public interface ProcessingRecipe extends Recipe { +public interface ProcessingRecipe extends Recipe { /** * Create a copy of this ProcessingRecipe that can be modified without altering diff --git a/src/main/java/com/smashingmods/alchemylib/api/storage/EnergyStorageHandler.java b/src/main/java/com/smashingmods/alchemylib/api/storage/EnergyStorageHandler.java index b74f535..39a3756 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/storage/EnergyStorageHandler.java +++ b/src/main/java/com/smashingmods/alchemylib/api/storage/EnergyStorageHandler.java @@ -1,6 +1,6 @@ package com.smashingmods.alchemylib.api.storage; -import net.minecraftforge.energy.EnergyStorage; +import net.neoforged.neoforge.energy.EnergyStorage; /** * This class is a wrapper around {@link EnergyStorage} which adds a call to {@link EnergyStorageHandler#onEnergyChanged()} diff --git a/src/main/java/com/smashingmods/alchemylib/api/storage/FluidStorageHandler.java b/src/main/java/com/smashingmods/alchemylib/api/storage/FluidStorageHandler.java index fbdba09..6170be6 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/storage/FluidStorageHandler.java +++ b/src/main/java/com/smashingmods/alchemylib/api/storage/FluidStorageHandler.java @@ -1,8 +1,8 @@ package com.smashingmods.alchemylib.api.storage; import net.minecraft.world.level.material.Fluid; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.fluids.capability.templates.FluidTank; +import net.neoforged.neoforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.capability.templates.FluidTank; /** * This class is a wrapper around {@link FluidTank} that adds some helper methods. @@ -41,6 +41,7 @@ public void setFluid(Fluid pFluid) { */ public void setAmount(int pValue) { fluid.setAmount(Math.max(Math.min(pValue, capacity), 0)); + onContentsChanged(); } /** @@ -48,6 +49,7 @@ public void setAmount(int pValue) { */ public void fillAmount(int pValue) { fluid.setAmount(Math.min(getFluidAmount() + pValue, capacity)); + onContentsChanged(); } /** @@ -55,6 +57,7 @@ public void fillAmount(int pValue) { */ public void drainAmount(int pValue) { fluid.setAmount(Math.max(getFluidAmount() - pValue, 0)); + onContentsChanged(); } public FluidStack getFluidStack() { diff --git a/src/main/java/com/smashingmods/alchemylib/api/storage/ProcessingSlotHandler.java b/src/main/java/com/smashingmods/alchemylib/api/storage/ProcessingSlotHandler.java index cc94bd9..24c459d 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/storage/ProcessingSlotHandler.java +++ b/src/main/java/com/smashingmods/alchemylib/api/storage/ProcessingSlotHandler.java @@ -3,9 +3,9 @@ import net.minecraft.core.NonNullList; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.items.ItemHandlerHelper; -import net.minecraftforge.items.ItemStackHandler; -import net.minecraftforge.items.wrapper.PlayerInvWrapper; +import net.neoforged.neoforge.items.ItemHandlerHelper; +import net.neoforged.neoforge.items.ItemStackHandler; +import net.neoforged.neoforge.items.wrapper.PlayerInvWrapper; /** * This class is a wrapper for {@link ItemStackHandler} that provides helper methods for diff --git a/src/main/java/com/smashingmods/alchemylib/api/storage/SidedProcessingSlotWrapper.java b/src/main/java/com/smashingmods/alchemylib/api/storage/SidedProcessingSlotWrapper.java index efe78a0..c0c429c 100644 --- a/src/main/java/com/smashingmods/alchemylib/api/storage/SidedProcessingSlotWrapper.java +++ b/src/main/java/com/smashingmods/alchemylib/api/storage/SidedProcessingSlotWrapper.java @@ -3,11 +3,11 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.neoforged.neoforge.common.util.Lazy; import net.minecraft.core.Direction; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.items.IItemHandler; -import net.minecraftforge.items.IItemHandlerModifiable; +import net.neoforged.neoforge.items.IItemHandler; +import net.neoforged.neoforge.items.IItemHandlerModifiable; /** * A wrapper around two {@link ProcessingSlotHandler} instances that can be used for @@ -33,7 +33,7 @@ public class SidedProcessingSlotWrapper { private final ProcessingSlotHandler outputHandler; private final SideMode[] sideModes = new SideMode[7]; // 4 cardinal directions + up/down + unspecified side = 7 sides total @SuppressWarnings("unchecked") // Java does not allow creating arrays with generics for some ungodly reason - private final LazyOptional[] views = new LazyOptional[7]; + private final Lazy[] views = new Lazy[7]; private class SidedItemHandlerView implements IItemHandlerModifiable { private final Direction side; @@ -112,13 +112,13 @@ public SidedProcessingSlotWrapper(ProcessingSlotHandler input, ProcessingSlotHan } public IItemHandler getView(@Nullable Direction side) { - return getViewLazily(side).orElse(null); + return getViewLazily(side).get(); } - public LazyOptional getViewLazily(@Nullable Direction side) { - LazyOptional view = views[side == null ? 6 : side.ordinal()]; + public Lazy getViewLazily(@Nullable Direction side) { + Lazy view = views[side == null ? 6 : side.ordinal()]; if (view == null) { - view = LazyOptional.of(() -> new SidedItemHandlerView(side)); + view = Lazy.of(() -> new SidedItemHandlerView(side)); views[side == null ? 6 : side.ordinal()] = view; } return view; @@ -141,7 +141,7 @@ public ProcessingSlotHandler getOutputHandler() { } public void invalidate() { - for (LazyOptional view : views) { + for (Lazy view : views) { if (view != null) { view.invalidate(); } diff --git a/src/main/java/com/smashingmods/alchemylib/client/button/LockButton.java b/src/main/java/com/smashingmods/alchemylib/client/button/LockButton.java index dbcb530..0419441 100644 --- a/src/main/java/com/smashingmods/alchemylib/client/button/LockButton.java +++ b/src/main/java/com/smashingmods/alchemylib/client/button/LockButton.java @@ -7,9 +7,7 @@ import net.minecraft.client.gui.GuiGraphics; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.contents.TranslatableContents; -import net.minecraft.resources.ResourceLocation; - -import javax.annotation.Nonnull; +import net.neoforged.neoforge.network.PacketDistributor; @SuppressWarnings("unused") public class LockButton extends AbstractAlchemyButton { @@ -19,13 +17,13 @@ public LockButton(AbstractProcessingScreen pParent) { boolean toggleLock = !pParent.getBlockEntity().isRecipeLocked(); pParent.getBlockEntity().setRecipeLocked(toggleLock); pParent.getBlockEntity().setChanged(); - AlchemyLib.getPacketHandler().sendToServer(new ToggleLockButtonPacket(pParent.getBlockEntity().getBlockPos(), toggleLock)); + PacketDistributor.sendToServer(new ToggleLockButtonPacket(pParent.getBlockEntity().getBlockPos(), toggleLock)); }); } @Override - public void renderWidget(@Nonnull GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) { - pGuiGraphics.blit(new ResourceLocation(AlchemyLib.MODID, "textures/gui/widgets.png"), getX(), getY(), 25 + ((blockEntity.isRecipeLocked() ? 0 : 1) * 20), 0, width, height); + public void renderWidget(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + pGuiGraphics.blit(AlchemyLib.modLoc("textures/gui/widgets.png"), getX(), getY(), 25 + ((blockEntity.isRecipeLocked() ? 0 : 1) * 20), 0, width, height); renderButtonTooltip(pGuiGraphics, pMouseX, pMouseY); } diff --git a/src/main/java/com/smashingmods/alchemylib/client/button/PauseButton.java b/src/main/java/com/smashingmods/alchemylib/client/button/PauseButton.java index b08be66..d810990 100644 --- a/src/main/java/com/smashingmods/alchemylib/client/button/PauseButton.java +++ b/src/main/java/com/smashingmods/alchemylib/client/button/PauseButton.java @@ -7,7 +7,7 @@ import net.minecraft.client.gui.GuiGraphics; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.contents.TranslatableContents; -import net.minecraft.resources.ResourceLocation; +import net.neoforged.neoforge.network.PacketDistributor; import javax.annotation.Nonnull; @@ -19,13 +19,13 @@ public PauseButton(AbstractProcessingScreen pParent) { boolean togglePause = !pParent.getBlockEntity().isProcessingPaused(); pParent.getBlockEntity().setPaused(!togglePause); pParent.getBlockEntity().setChanged(); - AlchemyLib.getPacketHandler().sendToServer(new TogglePauseButtonPacket(pParent.getBlockEntity().getBlockPos(), togglePause)); + PacketDistributor.sendToServer(new TogglePauseButtonPacket(pParent.getBlockEntity().getBlockPos(), togglePause)); }); } @Override public void renderWidget(@Nonnull GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) { - pGuiGraphics.blit(new ResourceLocation(AlchemyLib.MODID, "textures/gui/widgets.png"), getX(), getY(), 25 + ((blockEntity.isProcessingPaused() ? 1 : 0) * 20), 20, width, height); + pGuiGraphics.blit(AlchemyLib.modLoc("textures/gui/widgets.png"), getX(), getY(), 25 + ((blockEntity.isProcessingPaused() ? 1 : 0) * 20), 20, width, height); renderButtonTooltip(pGuiGraphics, pMouseX, pMouseY); } diff --git a/src/main/java/com/smashingmods/alchemylib/client/button/RecipeSelectorButton.java b/src/main/java/com/smashingmods/alchemylib/client/button/RecipeSelectorButton.java index 910b04d..2f2cb1e 100644 --- a/src/main/java/com/smashingmods/alchemylib/client/button/RecipeSelectorButton.java +++ b/src/main/java/com/smashingmods/alchemylib/client/button/RecipeSelectorButton.java @@ -10,7 +10,6 @@ import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.contents.TranslatableContents; -import net.minecraft.resources.ResourceLocation; @SuppressWarnings("unused") public class RecipeSelectorButton extends AbstractAlchemyButton { @@ -37,7 +36,7 @@ public void renderWidget(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, flo int u = open ? 25 : 45; int v = open ? 80 : 60; - pGuiGraphics.blit(new ResourceLocation(AlchemyLib.MODID, "textures/gui/widgets.png"), getX(), getY(), u, v, width, height); + pGuiGraphics.blit(AlchemyLib.modLoc("textures/gui/widgets.png"), getX(), getY(), u, v, width, height); renderButtonTooltip(pGuiGraphics, pMouseX, pMouseY); } diff --git a/src/main/java/com/smashingmods/alchemylib/client/button/SideModeButton.java b/src/main/java/com/smashingmods/alchemylib/client/button/SideModeButton.java index 8c096c0..ca4fc0a 100644 --- a/src/main/java/com/smashingmods/alchemylib/client/button/SideModeButton.java +++ b/src/main/java/com/smashingmods/alchemylib/client/button/SideModeButton.java @@ -10,7 +10,6 @@ import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.contents.TranslatableContents; -import net.minecraft.resources.ResourceLocation; @SuppressWarnings("unused") public class SideModeButton extends AbstractAlchemyButton { @@ -32,11 +31,11 @@ public SideModeButton(AbstractProcessingScreen pParent, Screen pNewScreen) { @Override public void renderWidget(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) { - boolean open = ((ProcessingBlockEntity) parent.getBlockEntity()).isSideConfigScreenOpen(); + boolean open = parent.getBlockEntity().isSideConfigScreenOpen(); int u = open ? 25 : 85; int v = open ? 80 : 0; - pGuiGraphics.blit(new ResourceLocation(AlchemyLib.MODID, "textures/gui/widgets.png"), getX(), getY(), u, v, width, height); + pGuiGraphics.blit(AlchemyLib.modLoc("textures/gui/widgets.png"), getX(), getY(), u, v, width, height); renderButtonTooltip(pGuiGraphics, pMouseX, pMouseY); } diff --git a/src/main/java/com/smashingmods/alchemylib/common/network/BlockEntityPacket.java b/src/main/java/com/smashingmods/alchemylib/common/network/BlockEntityPacket.java index c14ded5..0b3e57b 100644 --- a/src/main/java/com/smashingmods/alchemylib/common/network/BlockEntityPacket.java +++ b/src/main/java/com/smashingmods/alchemylib/common/network/BlockEntityPacket.java @@ -1,39 +1,42 @@ package com.smashingmods.alchemylib.common.network; -import com.smashingmods.alchemylib.api.network.AlchemyPacket; +import com.smashingmods.alchemylib.AlchemyLib; +import io.netty.buffer.ByteBuf; import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -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.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.network.NetworkEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; import java.util.Objects; -public class BlockEntityPacket implements AlchemyPacket { +public record BlockEntityPacket(BlockPos blockPos, CompoundTag tag) implements CustomPacketPayload { + public static final Type TYPE = new Type<>(AlchemyLib.modLoc("block_entity")); - private final BlockPos blockPos; - private final CompoundTag tag; + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + BlockPos.STREAM_CODEC, + BlockEntityPacket::blockPos, - public BlockEntityPacket(BlockPos pBlockPos, CompoundTag pTag) { - this.blockPos = pBlockPos; - this.tag = pTag; - } + ByteBufCodecs.COMPOUND_TAG, + BlockEntityPacket::tag, - public BlockEntityPacket(FriendlyByteBuf pBuffer) { - this.blockPos = pBuffer.readBlockPos(); - this.tag = pBuffer.readNbt(); - } + BlockEntityPacket::new + ); - public void encode(FriendlyByteBuf pBuffer) { - pBuffer.writeBlockPos(blockPos); - pBuffer.writeNbt(tag); + public static void handle(BlockEntityPacket packet, IPayloadContext pContext) { + pContext.enqueueWork(() -> { + Level level = Minecraft.getInstance().level; + BlockEntity blockEntity = Objects.requireNonNull(level).getBlockEntity(packet.blockPos); + //Objects.requireNonNull(blockEntity).load(packet.tag); TODO + }); } - public void handle(NetworkEvent.Context pContext) { - Level level = Minecraft.getInstance().level; - BlockEntity blockEntity = Objects.requireNonNull(level).getBlockEntity(blockPos); - Objects.requireNonNull(blockEntity).load(tag); + @Override + public Type type() { + return TYPE; } } diff --git a/src/main/java/com/smashingmods/alchemylib/common/network/PacketHandler.java b/src/main/java/com/smashingmods/alchemylib/common/network/PacketHandler.java index 869c66f..653f0c2 100644 --- a/src/main/java/com/smashingmods/alchemylib/common/network/PacketHandler.java +++ b/src/main/java/com/smashingmods/alchemylib/common/network/PacketHandler.java @@ -1,29 +1,20 @@ package com.smashingmods.alchemylib.common.network; import com.smashingmods.alchemylib.AlchemyLib; -import com.smashingmods.alchemylib.api.network.AbstractPacketHandler; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.network.simple.SimpleChannel; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; +import net.neoforged.neoforge.network.registration.HandlerThread; +import net.neoforged.neoforge.network.registration.PayloadRegistrar; -public class PacketHandler extends AbstractPacketHandler { - - private final SimpleChannel simpleChannel; - - public PacketHandler() { - this.simpleChannel = createChannel(new ResourceLocation(String.format("%s:main", AlchemyLib.MODID)), "1.0.0"); - } - - @Override - protected SimpleChannel getChannel() { - return simpleChannel; - } - - @Override - public PacketHandler register() { - registerMessage(ToggleLockButtonPacket.class, ToggleLockButtonPacket::new); - registerMessage(TogglePauseButtonPacket.class, TogglePauseButtonPacket::new); - registerMessage(SearchPacket.class, SearchPacket::new); - registerMessage(BlockEntityPacket.class, BlockEntityPacket::new); - return this; +@EventBusSubscriber(modid = AlchemyLib.MODID) +public class PacketHandler { + @SubscribeEvent + public static void registerPayloads(RegisterPayloadHandlersEvent event) { + final PayloadRegistrar registrar = event.registrar("1").executesOn(HandlerThread.MAIN); + registrar.playToServer(ToggleLockButtonPacket.TYPE, ToggleLockButtonPacket.STREAM_CODEC, ToggleLockButtonPacket::handle); + registrar.playToServer(TogglePauseButtonPacket.TYPE, TogglePauseButtonPacket.STREAM_CODEC, TogglePauseButtonPacket::handle); + registrar.playToServer(SearchPacket.TYPE, SearchPacket.STREAM_CODEC, SearchPacket::handle); + registrar.playToClient(BlockEntityPacket.TYPE, BlockEntityPacket.STREAM_CODEC, BlockEntityPacket::handle); } } diff --git a/src/main/java/com/smashingmods/alchemylib/common/network/SearchPacket.java b/src/main/java/com/smashingmods/alchemylib/common/network/SearchPacket.java index 74ac778..d834be3 100644 --- a/src/main/java/com/smashingmods/alchemylib/common/network/SearchPacket.java +++ b/src/main/java/com/smashingmods/alchemylib/common/network/SearchPacket.java @@ -1,42 +1,43 @@ package com.smashingmods.alchemylib.common.network; +import com.smashingmods.alchemylib.AlchemyLib; import com.smashingmods.alchemylib.api.blockentity.processing.AbstractSearchableBlockEntity; -import com.smashingmods.alchemylib.api.network.AlchemyPacket; +import io.netty.buffer.ByteBuf; 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.world.entity.player.Player; -import net.minecraftforge.network.NetworkEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; -public class SearchPacket implements AlchemyPacket { +public record SearchPacket(BlockPos blockPos, String searchText) implements CustomPacketPayload { + public static final Type TYPE = new Type<>(AlchemyLib.modLoc("search")); - private final BlockPos blockPos; - private final String searchText; + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + BlockPos.STREAM_CODEC, + SearchPacket::blockPos, - public SearchPacket(BlockPos pBlockPos, String pSearchText) { - this.blockPos = pBlockPos; - this.searchText = pSearchText; - } - - public SearchPacket(FriendlyByteBuf pBuffer) { - this.blockPos = pBuffer.readBlockPos(); - this.searchText = pBuffer.readUtf(); - } + ByteBufCodecs.STRING_UTF8, + SearchPacket::searchText, - public void encode(FriendlyByteBuf pBuffer) { - pBuffer.writeBlockPos(blockPos); - pBuffer.writeUtf(searchText); - } + SearchPacket::new + ); + + public static void handle(SearchPacket packet, IPayloadContext pContext) { + pContext.enqueueWork(() -> { + Player player = pContext.player(); - @Override - public void handle(NetworkEvent.Context pContext) { - Player player = pContext.getSender(); - if (player != null) { - AbstractSearchableBlockEntity blockEntity = (AbstractSearchableBlockEntity) player.level().getBlockEntity(blockPos); + AbstractSearchableBlockEntity blockEntity = (AbstractSearchableBlockEntity) player.level().getBlockEntity(packet.blockPos); if (blockEntity != null) { - blockEntity.setSearchText(searchText); + blockEntity.setSearchText(packet.searchText); blockEntity.setChanged(); } - } + }); + } + + @Override + public Type type() { + return TYPE; } } diff --git a/src/main/java/com/smashingmods/alchemylib/common/network/ToggleLockButtonPacket.java b/src/main/java/com/smashingmods/alchemylib/common/network/ToggleLockButtonPacket.java index ea86fc5..361c007 100644 --- a/src/main/java/com/smashingmods/alchemylib/common/network/ToggleLockButtonPacket.java +++ b/src/main/java/com/smashingmods/alchemylib/common/network/ToggleLockButtonPacket.java @@ -1,41 +1,42 @@ package com.smashingmods.alchemylib.common.network; +import com.smashingmods.alchemylib.AlchemyLib; import com.smashingmods.alchemylib.api.blockentity.processing.AbstractProcessingBlockEntity; -import com.smashingmods.alchemylib.api.network.AlchemyPacket; +import io.netty.buffer.ByteBuf; 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.world.entity.player.Player; -import net.minecraftforge.network.NetworkEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; -public class ToggleLockButtonPacket implements AlchemyPacket { +public record ToggleLockButtonPacket(BlockPos blockPos, boolean locked) implements CustomPacketPayload { + public static final Type TYPE = new Type<>(AlchemyLib.modLoc("toggle_lock_button")); - private final BlockPos blockPos; - private final boolean locked; + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + BlockPos.STREAM_CODEC, + ToggleLockButtonPacket::blockPos, - public ToggleLockButtonPacket(BlockPos pBlockPos, boolean pLock) { - this.blockPos = pBlockPos; - this.locked = pLock; - } - - public ToggleLockButtonPacket(FriendlyByteBuf pBuffer) { - this.blockPos = pBuffer.readBlockPos(); - this.locked = pBuffer.readBoolean(); - } + ByteBufCodecs.BOOL, + ToggleLockButtonPacket::locked, - public void encode(FriendlyByteBuf pBuffer) { - pBuffer.writeBlockPos(blockPos); - pBuffer.writeBoolean(locked); - } - - public void handle(NetworkEvent.Context pContext) { - Player player = pContext.getSender(); - if (player != null) { - AbstractProcessingBlockEntity blockEntity = (AbstractProcessingBlockEntity) player.level().getBlockEntity(blockPos); + ToggleLockButtonPacket::new + ); + + public static void handle(ToggleLockButtonPacket packet, IPayloadContext pContext) { + pContext.enqueueWork(() -> { + Player player = pContext.player(); + AbstractProcessingBlockEntity blockEntity = (AbstractProcessingBlockEntity) player.level().getBlockEntity(packet.blockPos); if (blockEntity != null) { - blockEntity.setRecipeLocked(locked); + blockEntity.setRecipeLocked(packet.locked); blockEntity.setChanged(); } - } + }); + } + + @Override + public Type type() { + return TYPE; } } diff --git a/src/main/java/com/smashingmods/alchemylib/common/network/TogglePauseButtonPacket.java b/src/main/java/com/smashingmods/alchemylib/common/network/TogglePauseButtonPacket.java index f3876aa..4bf5f43 100644 --- a/src/main/java/com/smashingmods/alchemylib/common/network/TogglePauseButtonPacket.java +++ b/src/main/java/com/smashingmods/alchemylib/common/network/TogglePauseButtonPacket.java @@ -1,41 +1,43 @@ package com.smashingmods.alchemylib.common.network; +import com.smashingmods.alchemylib.AlchemyLib; import com.smashingmods.alchemylib.api.blockentity.processing.AbstractProcessingBlockEntity; -import com.smashingmods.alchemylib.api.network.AlchemyPacket; +import io.netty.buffer.ByteBuf; 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.world.entity.player.Player; -import net.minecraftforge.network.NetworkEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; -public class TogglePauseButtonPacket implements AlchemyPacket { +public record TogglePauseButtonPacket(BlockPos blockPos, boolean paused) implements CustomPacketPayload { + public static final Type TYPE = new Type<>(AlchemyLib.modLoc("toggle_pause_button")); - private final BlockPos blockPos; - private final boolean paused; + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + BlockPos.STREAM_CODEC, + TogglePauseButtonPacket::blockPos, - public TogglePauseButtonPacket(BlockPos pBlockPos, boolean pPause) { - this.blockPos = pBlockPos; - this.paused = pPause; - } + ByteBufCodecs.BOOL, + TogglePauseButtonPacket::paused, - public TogglePauseButtonPacket(FriendlyByteBuf pBuffer) { - this.blockPos = pBuffer.readBlockPos(); - this.paused = pBuffer.readBoolean(); - } + TogglePauseButtonPacket::new + ); - public void encode(FriendlyByteBuf pBuffer) { - pBuffer.writeBlockPos(blockPos); - pBuffer.writeBoolean(paused); - } + public static void handle(TogglePauseButtonPacket packet, IPayloadContext pContext) { + pContext.enqueueWork(() -> { + Player player = pContext.player(); - public void handle(NetworkEvent.Context pContext) { - Player player = pContext.getSender(); - if (player != null) { - AbstractProcessingBlockEntity blockEntity = (AbstractProcessingBlockEntity) player.level().getBlockEntity(blockPos); + AbstractProcessingBlockEntity blockEntity = (AbstractProcessingBlockEntity) player.level().getBlockEntity(packet.blockPos); if (blockEntity != null) { - blockEntity.setPaused(paused); + blockEntity.setPaused(packet.paused); blockEntity.setChanged(); } - } + }); + } + + @Override + public Type type() { + return TYPE; } } diff --git a/src/main/java/com/smashingmods/alchemylib/datagen/DataGenerators.java b/src/main/java/com/smashingmods/alchemylib/datagen/DataGenerators.java index 940898d..234bceb 100644 --- a/src/main/java/com/smashingmods/alchemylib/datagen/DataGenerators.java +++ b/src/main/java/com/smashingmods/alchemylib/datagen/DataGenerators.java @@ -1,10 +1,14 @@ package com.smashingmods.alchemylib.datagen; +import com.smashingmods.alchemylib.AlchemyLib; import net.minecraft.data.DataGenerator; -import net.minecraftforge.data.event.GatherDataEvent; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.data.event.GatherDataEvent; +@EventBusSubscriber(modid = AlchemyLib.MODID) public class DataGenerators { - + @SubscribeEvent public static void gatherData(GatherDataEvent pEvent) { DataGenerator generator = pEvent.getGenerator(); diff --git a/src/main/java/com/smashingmods/alchemylib/datagen/DatagenHelpers.java b/src/main/java/com/smashingmods/alchemylib/datagen/DatagenHelpers.java index 5b8d0b2..805a4bd 100644 --- a/src/main/java/com/smashingmods/alchemylib/datagen/DatagenHelpers.java +++ b/src/main/java/com/smashingmods/alchemylib/datagen/DatagenHelpers.java @@ -6,6 +6,7 @@ import com.smashingmods.chemlib.common.items.CompoundItem; import com.smashingmods.chemlib.common.items.ElementItem; import com.smashingmods.chemlib.registry.ItemRegistry; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -13,9 +14,8 @@ import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; -import net.minecraftforge.common.crafting.conditions.*; -import net.minecraftforge.fluids.FluidStack; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.neoforge.common.conditions.*; +import net.neoforged.neoforge.fluids.FluidStack; import java.util.*; @@ -30,7 +30,7 @@ public static void itemStackToJson(JsonObject pJson, String pKey, ItemStack pIte if (!pItemStack.isEmpty()) { JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("item", Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(pItemStack.getItem())).toString()); + jsonObject.addProperty("item", Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(pItemStack.getItem())).toString()); if (pItemStack.getCount() > 1) { jsonObject.addProperty("count", pItemStack.getCount()); @@ -48,12 +48,12 @@ public static void itemStackListToJson(JsonObject pJson, String pKey, List 1) { jsonObject.addProperty("count", itemStack.getCount()); } } else { - jsonObject.addProperty("item", Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(ItemStack.EMPTY.getItem())).toString()); + jsonObject.addProperty("item", Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(ItemStack.EMPTY.getItem())).toString()); } jsonArray.add(jsonObject); } @@ -75,7 +75,7 @@ public static void fluidStacktoJson(JsonObject pJson, String pKey, FluidStack pF if (!pFluidStack.isEmpty()) { JsonObject jsonObject = new JsonObject(); - ResourceLocation fluidLocation = ForgeRegistries.FLUIDS.getKey(pFluidStack.getFluid()); + ResourceLocation fluidLocation = BuiltInRegistries.FLUID.getKey(pFluidStack.getFluid()); String amount = String.valueOf(pFluidStack.getAmount()); jsonObject.addProperty("fluid", Objects.requireNonNull(fluidLocation).toString()); @@ -102,13 +102,13 @@ public static IngredientStack toIngredientStack(String pString, int pCount) { private static ItemLike getChemicalItem(String pString) { - ResourceLocation resourceLocation = new ResourceLocation(pString); + ResourceLocation resourceLocation = ResourceLocation.tryParse(pString); Optional optionalElement = ItemRegistry.getElementByName(pString); Optional optionalCompound = ItemRegistry.getCompoundByName(pString.replace(" ", "_")); - Item outputItem = ForgeRegistries.ITEMS.getValue(resourceLocation); - Block outputBlock = ForgeRegistries.BLOCKS.getValue(resourceLocation); + Item outputItem = BuiltInRegistries.ITEM.get(resourceLocation); + Block outputBlock = BuiltInRegistries.BLOCK.get(resourceLocation); if (optionalElement.isPresent()) { return optionalElement.get(); @@ -124,15 +124,15 @@ private static ItemLike getChemicalItem(String pString) { } public static ResourceLocation getLocation(ItemStack pItemStack, String pType, String pModId) { - return new ResourceLocation(pModId, String.format("%s/%s", pType, Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(pItemStack.getItem())).getPath())); + return ResourceLocation.fromNamespaceAndPath(pModId, String.format("%s/%s", pType, Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(pItemStack.getItem())).getPath())); } public static ResourceLocation getLocation(Item pItem, String pType, String pModId) { - return new ResourceLocation(pModId, String.format("%s/%s", pType, Objects.requireNonNull(ForgeRegistries.ITEMS.getKey(pItem)).getPath())); + return ResourceLocation.fromNamespaceAndPath(pModId, String.format("%s/%s", pType, Objects.requireNonNull(BuiltInRegistries.ITEM.getKey(pItem)).getPath())); } public static ResourceLocation getLocation(FluidStack pFluidStack, String pType, String pModId) { - return new ResourceLocation(pModId, String.format("%s/%s", pType, Objects.requireNonNull(ForgeRegistries.FLUIDS.getKey(pFluidStack.getFluid())).getPath())); + return ResourceLocation.fromNamespaceAndPath(pModId, String.format("%s/%s", pType, Objects.requireNonNull(BuiltInRegistries.FLUID.getKey(pFluidStack.getFluid())).getPath())); } @SuppressWarnings("unused") @@ -146,12 +146,12 @@ public static NotCondition notCondition(ICondition pCondition) { @SuppressWarnings("unused") public static AndCondition andCondition(ICondition pCondition1, ICondition pCondition2) { - return new AndCondition(pCondition1, pCondition2); + return new AndCondition(List.of(pCondition1, pCondition2)); } @SuppressWarnings("unused") public static OrCondition orCondition(ICondition pCondition1, ICondition pCondition2) { - return new OrCondition(pCondition1, pCondition2); + return new OrCondition(List.of(pCondition1, pCondition2)); } public static TagEmptyCondition tagEmptyCondition(String pTag) { diff --git a/src/main/java/com/smashingmods/alchemylib/datagen/LocalizationGenerator.java b/src/main/java/com/smashingmods/alchemylib/datagen/LocalizationGenerator.java index e632e83..6383ce2 100644 --- a/src/main/java/com/smashingmods/alchemylib/datagen/LocalizationGenerator.java +++ b/src/main/java/com/smashingmods/alchemylib/datagen/LocalizationGenerator.java @@ -2,7 +2,7 @@ import com.smashingmods.alchemylib.AlchemyLib; import net.minecraft.data.PackOutput; -import net.minecraftforge.common.data.LanguageProvider; +import net.neoforged.neoforge.common.data.LanguageProvider; public class LocalizationGenerator extends LanguageProvider { diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml deleted file mode 100644 index 89e03da..0000000 --- a/src/main/resources/META-INF/mods.toml +++ /dev/null @@ -1,33 +0,0 @@ -modLoader="javafml" -loaderVersion="${loader_version_range}" -license="${mod_license}" -issueTrackerURL="https://github.com/smashingmods/alchemylib/issues" - -[[mods]] -modId="${mod_id}" -version="${mod_version}" -displayName="${mod_name}" -logoFile="alchemylib-logo.png" -authors="${mod_authors}" -description='''${mod_description}''' - -[[dependencies.${mod_id}]] -modId="forge" -mandatory=true -versionRange="${forge_version_range}" -ordering="NONE" -side="BOTH" - -[[dependencies.${mod_id}]] -modId="minecraft" -mandatory=true -versionRange="${minecraft_version_range}" -ordering="NONE" -side="BOTH" - -[[dependencies.${mod_id}]] -modId="chemlib" -mandatory=true -versionRange="[${minecraft_version}-${chemlib_version},)" -ordering="NONE" -side="BOTH" \ No newline at end of file diff --git a/src/main/resources/META-INF/neoforge.mods.toml b/src/main/resources/META-INF/neoforge.mods.toml new file mode 100644 index 0000000..9ab5f68 --- /dev/null +++ b/src/main/resources/META-INF/neoforge.mods.toml @@ -0,0 +1,38 @@ +modLoader="javafml" +loaderVersion="[0,)" +license="LGPLv2.1" +issueTrackerURL="https://github.com/TonimatasDEV/AlchemyLib/issues" + +[[mods]] +modId="alchemylib" +version="${modVersion}" +displayName="AlchemyLib" +logoFile="alchemylib-logo.png" +authors="DarkArcana - Creator | TonimatasDEV - Port" +description=''' +AlchemyLib is a library mod for ChemLib addon mods such as Alchemistry and Techemistry. Anyone can use AlchemyLib to help bootstrap their mod development. Everything you need is in the api package. +''' + +[[accessTransformers]] +file="META-INF/accesstransformer.cfg" + +[[dependencies.alchemylib]] +modId="neoforge" +required=true +versionRange="${neoforgeVersionRange}" +ordering="NONE" +side="BOTH" + +[[dependencies.alchemylib]] +modId="minecraft" +required=true +versionRange="[${minecraftVersion}]" +ordering="NONE" +side="BOTH" + +[[dependencies.alchemylib]] +modId="chemlib" +required=true +versionRange="${chemlibVersionRange}" +ordering="NONE" +side="BOTH" \ No newline at end of file diff --git a/alchemylib-logo.png b/src/main/resources/alchemylib-logo.png similarity index 100% rename from alchemylib-logo.png rename to src/main/resources/alchemylib-logo.png