From 13b981a916ed27288722e309a1b5f2ee9adf607a Mon Sep 17 00:00:00 2001 From: 1820982382 Date: Mon, 17 Aug 2026 15:15:04 +0800 Subject: [PATCH] =?UTF-8?q?[=E5=85=A8=E6=B5=81=E7=A8=8B=E5=AE=8C=E6=88=90]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + gradle.properties | 2 +- gradlew | 251 ++++++++++++++++++ gradlew.bat | 94 +++++++ .../ThaumicEnergistics.java | 11 +- .../common/blocks/OrientableEntityBlock.java | 30 ++- .../common/blocks/ThEBaseEntityBlock.java | 28 +- .../container/ContainerArcaneAssembler.java | 31 +-- .../ContainerArcaneCraftingTerminal.java | 80 ++++-- .../ContainerDistillationPatternEncoder.java | 15 +- .../ContainerEssentiaCellTerminal.java | 20 -- .../ContainerKnowledgeInscriber.java | 8 +- .../common/container/GuiArcaneAssembler.java | 4 +- .../container/GuiArcaneCraftingTerminal.java | 40 +-- .../container/GuiEssentiaCellTerminal.java | 15 -- .../slot/ArcaneCraftingResultSlot.java | 238 +++++++++++++---- .../common/features/RecipeRegistration.java | 48 ++-- .../common/grid/EssentiaGridService.java | 27 +- .../jade/VibrationChamberProvider.java | 8 +- .../items/WirelessEssentiaTerminalItem.java | 3 +- .../common/network/ThENetworking.java | 14 + .../common/parts/EssentiaExportBusPart.java | 11 +- .../common/parts/EssentiaImportBusPart.java | 10 +- .../common/parts/EssentiaTerminalPart.java | 3 +- .../common/parts/VisInterfacePart.java | 5 +- .../common/tiles/TileArcaneAssembler.java | 18 -- .../tiles/TileEssentiaVibrationChamber.java | 61 +++-- .../thaumicenergistics/init/ModMenuTypes.java | 23 +- .../integration/jei/ThEJeiPlugin.java | 4 +- .../jei/ThEUseArcaneRecipeTransfer.java | 51 +++- .../jei/ThEUseCraftingRecipeTransfer.java | 71 ++--- .../resources/META-INF/neoforge.mods.toml | 2 +- .../ae2/screens/arcane_crafting_terminal.json | 11 +- .../assets/thaumicenergistics/lang/en_us.json | 5 +- .../assets/thaumicenergistics/lang/zh_cn.json | 7 +- .../textures/gui/arcane_crafting.png | Bin 15048 -> 19382 bytes .../textures/model/golembackpack/clay.png | Bin 4252 -> 0 bytes .../textures/model/golembackpack/diamond.png | Bin 4208 -> 0 bytes .../textures/model/golembackpack/flesh.png | Bin 4410 -> 0 bytes .../textures/model/golembackpack/gold.png | Bin 4348 -> 0 bytes .../textures/model/golembackpack/iron.png | Bin 4234 -> 0 bytes .../textures/model/golembackpack/stone.png | Bin 4343 -> 0 bytes .../textures/model/golembackpack/straw.png | Bin 4405 -> 0 bytes .../textures/model/golembackpack/tallow.png | Bin 4242 -> 0 bytes .../textures/model/golembackpack/thaum.png | Bin 3836 -> 0 bytes .../textures/model/golembackpack/wood.png | Bin 4276 -> 0 bytes .../resources/thaumicenergistics.mixins.json | 2 + 47 files changed, 920 insertions(+), 333 deletions(-) create mode 100644 gradlew create mode 100644 gradlew.bat delete mode 100644 src/main/java/thaumicenergistics/common/container/ContainerEssentiaCellTerminal.java delete mode 100644 src/main/java/thaumicenergistics/common/container/GuiEssentiaCellTerminal.java delete mode 100644 src/main/resources/assets/thaumicenergistics/textures/model/golembackpack/clay.png delete mode 100644 src/main/resources/assets/thaumicenergistics/textures/model/golembackpack/diamond.png delete mode 100644 src/main/resources/assets/thaumicenergistics/textures/model/golembackpack/flesh.png delete mode 100644 src/main/resources/assets/thaumicenergistics/textures/model/golembackpack/gold.png delete mode 100644 src/main/resources/assets/thaumicenergistics/textures/model/golembackpack/iron.png delete mode 100644 src/main/resources/assets/thaumicenergistics/textures/model/golembackpack/stone.png delete mode 100644 src/main/resources/assets/thaumicenergistics/textures/model/golembackpack/straw.png delete mode 100644 src/main/resources/assets/thaumicenergistics/textures/model/golembackpack/tallow.png delete mode 100644 src/main/resources/assets/thaumicenergistics/textures/model/golembackpack/thaum.png delete mode 100644 src/main/resources/assets/thaumicenergistics/textures/model/golembackpack/wood.png diff --git a/.gitignore b/.gitignore index 6860eca..1b699c4 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,5 @@ progress.md /.reasonix/ /.tmp_*/ __pycache__/ +/Issue-改善物品方块扫描要素.md +/路径.md diff --git a/gradle.properties b/gradle.properties index 72f65ac..f6d74bf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Project -mod_version=2.0.1 +mod_version=2.1.1 mod_group=thaumicenergistics # Mod diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..f3b75f3 --- /dev/null +++ b/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/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/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -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 + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + 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. +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=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +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 + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +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 %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/main/java/thaumicenergistics/ThaumicEnergistics.java b/src/main/java/thaumicenergistics/ThaumicEnergistics.java index b8b1669..b20153e 100644 --- a/src/main/java/thaumicenergistics/ThaumicEnergistics.java +++ b/src/main/java/thaumicenergistics/ThaumicEnergistics.java @@ -63,6 +63,8 @@ public final class ThaumicEnergistics { thaumicenergistics.common.network.ThENetworking.init(modBus); + thaumicenergistics.common.blocks.ThEWrenchHandler.register(); + modBus.addListener(this::registerCapabilities); PartModels.registerModels( @@ -147,7 +149,14 @@ public final class ThaumicEnergistics { event.register(ModMenuTypes.ESSENTIA_CELL_WORKBENCH.get(), GuiEssentiaCellWorkbench::new); event.register(ModMenuTypes.EVC.get(), GuiEssentiaVibrationChamber::new); event.register(ModMenuTypes.ARCANE_ASSEMBLER.get(), GuiArcaneAssembler::new); - event.register(ModMenuTypes.ESSENTIA_TERMINAL.get(), GuiEssentiaCellTerminal::new); + event.register(ModMenuTypes.ESSENTIA_TERMINAL.get(), + (EssentiaTerminalMenu menu, Inventory inv, Component title) + -> new GuiEssentiaTerminal(menu, inv, title, + StyleManager.loadStyleDoc("/screens/terminals/terminal.json"))); + event.register(ModMenuTypes.WIRELESS_ESSENTIA_TERMINAL.get(), + (EssentiaTerminalMenu menu, Inventory inv, Component title) + -> new GuiEssentiaTerminal(menu, inv, title, + StyleManager.loadStyleDoc("/screens/terminals/wireless_terminal.json"))); event.register(ModMenuTypes.KNOWLEDGE_INSCRIBER.get(), GuiKnowledgeInscriber::new); event.register(ModMenuTypes.DISTILLATION_ENCODER.get(), GuiDistillationPatternEncoder::new); diff --git a/src/main/java/thaumicenergistics/common/blocks/OrientableEntityBlock.java b/src/main/java/thaumicenergistics/common/blocks/OrientableEntityBlock.java index bfde4af..c29f4fb 100644 --- a/src/main/java/thaumicenergistics/common/blocks/OrientableEntityBlock.java +++ b/src/main/java/thaumicenergistics/common/blocks/OrientableEntityBlock.java @@ -1,10 +1,12 @@ package thaumicenergistics.common.blocks; +import java.util.List; + import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.InteractionHand; import net.minecraft.world.ItemInteractionResult; +import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; @@ -14,10 +16,8 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.storage.loot.LootParams; import net.minecraft.world.phys.BlockHitResult; -import thaumcraft.api.aspects.Aspect; -import thaumcraft.api.aspects.AspectList; -import thaumcraft.api.aspects.IEssentiaContainerItem; import thaumicenergistics.common.tiles.ThETileBase; import thaumicenergistics.common.tiles.TileEssentiaVibrationChamber; @@ -43,20 +43,16 @@ public abstract class OrientableEntityBlock extends Block implements EntityBlock @Override public abstract BlockEntity newBlockEntity(BlockPos pos, BlockState state); + /** + * 谐振仓:通配吸力模式,不再需要安瓿瓶切换燃料类型。 + * 放行默认交互(若后续添加 GUI 则走 getMenuProvider)。 + */ @Override protected ItemInteractionResult useItemOn(ItemStack stack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { if (level.isClientSide()) return ItemInteractionResult.SUCCESS; BlockEntity be = level.getBlockEntity(pos); if (!(be instanceof TileEssentiaVibrationChamber chamber)) return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; - // 检查手持物品是否为源质安瓿瓶 - if (!(stack.getItem() instanceof IEssentiaContainerItem container)) return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; - AspectList aspects = container.getAspects(stack); - if (aspects == null || aspects.size() == 0) return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; - Aspect aspect = aspects.getAspects()[0]; - if (aspect == Aspect.FIRE || aspect == Aspect.ENERGY) { - chamber.setSuctionType(aspect); - return ItemInteractionResult.SUCCESS; - } + // 通配吸力:无需切换,直接放行 return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; } @@ -68,4 +64,12 @@ public abstract class OrientableEntityBlock extends Block implements EntityBlock } super.onRemove(state, level, pos, newState, moved); } + + /** + * 挖掘掉落方块自身(不导出方块实体 NBT)。 + */ + @Override + public List getDrops(BlockState state, LootParams.Builder builder) { + return List.of(new ItemStack(this)); + } } diff --git a/src/main/java/thaumicenergistics/common/blocks/ThEBaseEntityBlock.java b/src/main/java/thaumicenergistics/common/blocks/ThEBaseEntityBlock.java index 0c0bab4..b07e911 100644 --- a/src/main/java/thaumicenergistics/common/blocks/ThEBaseEntityBlock.java +++ b/src/main/java/thaumicenergistics/common/blocks/ThEBaseEntityBlock.java @@ -1,13 +1,21 @@ package thaumicenergistics.common.blocks; +import java.util.List; + import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.ItemInteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityTicker; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.Level; +import net.minecraft.world.level.storage.loot.LootParams; +import net.minecraft.world.phys.BlockHitResult; import thaumicenergistics.common.tiles.TileEssentiaProvider; import thaumicenergistics.common.tiles.TileEssentiaVibrationChamber; import thaumicenergistics.common.tiles.TileInfusionProvider; @@ -36,6 +44,24 @@ public abstract class ThEBaseEntityBlock extends Block implements EntityBlock { return (BlockEntityTicker) ticker; } + /** + * AE2 扳手拆卸。WrenchHook 只处理 AEBaseBlockEntity,ThE 方块 BE 不走该路径,故在此自行拆卸并掉落。 + */ + @Override + protected ItemInteractionResult useItemOn(ItemStack stack, BlockState state, Level level, BlockPos pos, + Player player, InteractionHand hand, BlockHitResult hit) { + // 扳手拆卸由 ThEWrenchHandler(RightClickBlock 事件)处理,这里不重复 + return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; + } + + /** + * 挖掘掉落方块自身(不导出方块实体 NBT)。 + */ + @Override + public List getDrops(BlockState state, LootParams.Builder builder) { + return List.of(new ItemStack(this)); + } + @Override public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean moved) { if (!state.is(newState.getBlock())) { diff --git a/src/main/java/thaumicenergistics/common/container/ContainerArcaneAssembler.java b/src/main/java/thaumicenergistics/common/container/ContainerArcaneAssembler.java index b03f961..002c651 100644 --- a/src/main/java/thaumicenergistics/common/container/ContainerArcaneAssembler.java +++ b/src/main/java/thaumicenergistics/common/container/ContainerArcaneAssembler.java @@ -13,7 +13,7 @@ import net.neoforged.neoforge.items.SlotItemHandler; import thaumcraft.api.IVisDiscountGear; import thaumcraft.api.IWarpingGear; import thaumcraft.api.aspects.Aspect; -import thaumicenergistics.ThaumicEnergistics; +import thaumicenergistics.common.container.slot.ReadOnlySlot; import thaumicenergistics.common.tiles.TileArcaneAssembler; import thaumicenergistics.init.ModMenuTypes; @@ -160,16 +160,12 @@ public class ContainerArcaneAssembler extends AbstractContainerMenu { } }); - // ===== 4. 3×7 配方槽(只读展示) ===== + // ===== 4. 3×7 配方槽(只读展示,AE2 式防整理) ===== for (int r = 0; r < PATTERN_ROWS; r++) for (int c = 0; c < PATTERN_COLS; c++) { int invIdx = TileArcaneAssembler.PATTERN_SLOT_START + r * PATTERN_COLS + c; - addSlot(new SlotItemHandler(machineHandler, invIdx, - PATTERN_X + c * 18, PATTERN_Y + r * 18) { - @Override public boolean mayPlace(ItemStack s) { return false; } - @Override public boolean mayPickup(Player p) { return false; } - @Override public int getMaxStackSize() { return 1; } - }); + addSlot(new ReadOnlySlot(machineHandler, invIdx, + PATTERN_X + c * 18, PATTERN_Y + r * 18)); } // ===== 5. 4张AE2速度卡 ===== @@ -182,11 +178,8 @@ public class ContainerArcaneAssembler extends AbstractContainerMenu { }); } - // ===== 6. 目标产物输出槽(只读展示) ===== - addSlot(new SlotItemHandler(machineHandler, TileArcaneAssembler.TARGET_SLOT, TARGET_X, TARGET_Y) { - @Override public boolean mayPlace(ItemStack s) { return false; } - @Override public boolean mayPickup(Player p) { return false; } - }); + // ===== 6. 目标产物输出槽(只读展示,AE2 式防整理) ===== + addSlot(new ReadOnlySlot(machineHandler, TileArcaneAssembler.TARGET_SLOT, TARGET_X, TARGET_Y)); // ===== 7. 4个护甲折扣槽 ===== for (int i = 0; i < ARMOR_COUNT; i++) { @@ -202,9 +195,9 @@ public class ContainerArcaneAssembler extends AbstractContainerMenu { @Override public boolean mayPlace(ItemStack s) { if (s.getItem() instanceof IVisDiscountGear) return true; if (s.getItem() instanceof IWarpingGear) return true; - if (s.getItem() instanceof net.minecraft.world.item.Equipable eqItem - && eqItem.getEquipmentSlot() == eq) return true; - return s.canEquip(eq, null); + if (s.getItem() instanceof net.minecraft.world.item.Equipable eqItem) + return eqItem.getEquipmentSlot() == eq; + return false; } @Override public void setChanged() { super.setChanged(); @@ -220,13 +213,9 @@ public class ContainerArcaneAssembler extends AbstractContainerMenu { this(id, inv, resolveTile(inv, buf)); } - /** 临时诊断:确认客户端能否拿到 tile(定位后删除) */ private static TileArcaneAssembler resolveTile(Inventory inv, RegistryFriendlyByteBuf buf) { var pos = buf.readBlockPos(); - var be = inv.player.level().getBlockEntity(pos); - ThaumicEnergistics.LOG.info("[AA-DEBUG] client ctor: pos={}, be={}", - pos, be == null ? "null" : be.getClass().getSimpleName()); - return (TileArcaneAssembler) be; + return (TileArcaneAssembler) inv.player.level().getBlockEntity(pos); } private ItemStackHandler wrapMachineInventory() { diff --git a/src/main/java/thaumicenergistics/common/container/ContainerArcaneCraftingTerminal.java b/src/main/java/thaumicenergistics/common/container/ContainerArcaneCraftingTerminal.java index fbffee4..59aaddd 100644 --- a/src/main/java/thaumicenergistics/common/container/ContainerArcaneCraftingTerminal.java +++ b/src/main/java/thaumicenergistics/common/container/ContainerArcaneCraftingTerminal.java @@ -33,9 +33,11 @@ import appeng.me.storage.LinkStatusRespectingInventory; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import thaumcraft.api.aspects.Aspect; import thaumcraft.api.aspects.AspectList; +import thaumcraft.api.wands.WandCap; import net.minecraft.world.item.crafting.Ingredient; import thaumcraft.common.items.TCFunctionalItems; import thaumcraft.common.lib.crafting.ThaumcraftCraftingManager; +import thaumcraft.common.vis.TCVisHelper; import thaumicenergistics.ThaumicEnergistics; import thaumicenergistics.common.container.slot.ArcaneCraftingResultSlot; import thaumicenergistics.common.parts.ArcaneCraftingTerminalPart; @@ -55,6 +57,34 @@ public class ContainerArcaneCraftingTerminal extends MEStorageMenu implements IC */ private boolean isCraftingResultBeingTaken = false; + /** vis 恢复检测节流:每 10 tick(0.5 秒)检查一次,避免持续遍历配方。 */ + private static final int VIS_RECOVERY_CHECK_INTERVAL = 10; + private int visRecoveryTickCounter = 0; + + @Override + public void broadcastChanges() { + super.broadcastChanges(); + // vis 充能恢复后自动重算结果槽:结果槽空 + 奥术配方有效 + vis 已足够 → 重新显示产物。 + // 节流:仅"待恢复"状态每 10 tick 检查一次(findMatchingArcaneRecipe 只在满足时执行) + var player = getPlayerInventory().player; + if (player.level().isClientSide() || !hasValidRecipe || !resultSlot.getItem().isEmpty()) { + return; + } + if (++visRecoveryTickCounter < VIS_RECOVERY_CHECK_INTERVAL) { + return; + } + visRecoveryTickCounter = 0; + var craftContainer = this.craftingInventoryHost.getSubInventory(ArcaneCraftingTerminalPart.INV_CRAFTING).toContainer(); + ItemStack arcaneResult = ThaumcraftCraftingManager.findMatchingArcaneRecipe(craftContainer, player); + if (!arcaneResult.isEmpty()) { + AspectList aspects = ThaumcraftCraftingManager.findMatchingArcaneRecipeAspects(craftContainer, player); + if (aspects != null && hasEnoughVis(aspects)) { + resultSlot.setRequiredAspects(aspects); + resultSlot.setDisplayedCraftingOutput(arcaneResult); + } + } + } + private final ISegmentedInventory craftingInventoryHost; private final CraftingMatrixSlot[] craftingSlots = new CraftingMatrixSlot[9]; private final ArcaneCraftingResultSlot resultSlot; @@ -76,9 +106,9 @@ public class ContainerArcaneCraftingTerminal extends MEStorageMenu implements IC } var linkStatusInventory = new LinkStatusRespectingInventory(host.getInventory(), this::getLinkStatus); - this.resultSlot = new ArcaneCraftingResultSlot(getPlayerInventory().player, craftingGridInv); - this.resultSlot.setRefreshCallback(() -> updateCurrentRecipeAndOutput(false)); - this.resultSlot.setContainer(this); + this.resultSlot = new ArcaneCraftingResultSlot( + getPlayerInventory().player, this, craftingGridInv, craftingGridInv, + linkStatusInventory, this.getEnergySource(), this.getActionSource()); this.addSlot(this.resultSlot, SlotSemantics.CRAFTING_RESULT); var wandInv = this.craftingInventoryHost.getSubInventory(ArcaneCraftingTerminalPart.INV_WAND); @@ -88,7 +118,6 @@ public class ContainerArcaneCraftingTerminal extends MEStorageMenu implements IC return 1; } - @Override public boolean mayPlace(ItemStack stack) { //只允许 TCFunctionalItems.WandCastingItem 类型的物品放入 @@ -145,6 +174,26 @@ public class ContainerArcaneCraftingTerminal extends MEStorageMenu implements IC private static final int CENTIVIS = 100; + /** + * 复刻 TC port {@code WandCastingItem.consumptionModifier}:法杖 cap 折扣 − 玩家装备/饰品折扣 − 法杖折扣。 + * 仅用于显示(GUI 所需 vis),实际扣费由 consumeVisCost 内部同公式处理。 + */ + private float getConsumptionModifier(Aspect aspect, boolean crafting) { + var wandInv = this.craftingInventoryHost.getSubInventory(ArcaneCraftingTerminalPart.INV_WAND); + var wandStack = wandInv.getStackInSlot(0); + if (wandStack.isEmpty() || !(wandStack.getItem() instanceof TCFunctionalItems.WandCastingItem wand)) { + return 1.0f; + } + float modifier = wand.consumptionModifier(wandStack, getPlayerInventory().player, aspect, crafting); + return modifier; + } + + /** 折扣后的 vis 成本(GUI 显示用)。 */ + private int getDiscountedVisCost(Aspect aspect, int rawCost) { + if (rawCost <= 0 || aspect == null) return 0; + return Math.max(0, Math.round(rawCost * getConsumptionModifier(aspect, true))); + } + private boolean hasEnoughVis(AspectList cost) { ThaumicEnergistics.LOG.debug("[V] hasEnoughVis: cost={}", cost); if (cost == null || cost.isEmpty()) { @@ -172,7 +221,6 @@ public class ContainerArcaneCraftingTerminal extends MEStorageMenu implements IC } private void updateCurrentRecipeAndOutput(boolean forceUpdate) { - ThaumicEnergistics.LOG.debug("[R] === updateCurrentRecipeAndOutput forceUpdate={} ===", forceUpdate); var player = getPlayerInventory().player; var level = player.level(); @@ -183,27 +231,20 @@ public class ContainerArcaneCraftingTerminal extends MEStorageMenu implements IC var craftContainer = this.craftingInventoryHost.getSubInventory(ArcaneCraftingTerminalPart.INV_CRAFTING).toContainer(); ItemStack arcaneResult = ThaumcraftCraftingManager.findMatchingArcaneRecipe(craftContainer, player); - ThaumicEnergistics.LOG.debug("[R] findMatchingArcaneRecipe result={}", arcaneResult); if (!arcaneResult.isEmpty()) { requiredAspects = ThaumcraftCraftingManager.findMatchingArcaneRecipeAspects(craftContainer, player); - ThaumicEnergistics.LOG.debug("[R] ARCANE MATCH! aspects={}, result={}", requiredAspects, arcaneResult); foundArcane = true; if (hasEnoughVis(requiredAspects)) { - ThaumicEnergistics.LOG.debug("[R] Vis OK → showing result"); resultSlot.setDisplayedCraftingOutput(arcaneResult); } else { - ThaumicEnergistics.LOG.debug("[R] Vis INSUFFICIENT → result empty, but recipe recognized"); resultSlot.setDisplayedCraftingOutput(ItemStack.EMPTY); } - } else { - ThaumicEnergistics.LOG.debug("[R] No arcane recipe match"); } } if (!foundArcane) { - ThaumicEnergistics.LOG.debug("[R] No arcane match, trying vanilla..."); var testItems = new ArrayList(this.craftingSlots.length); for (var craftingSlot : this.craftingSlots) { testItems.add(craftingSlot.getItem().copy()); @@ -212,10 +253,8 @@ public class ContainerArcaneCraftingTerminal extends MEStorageMenu implements IC var recipeHolder = level.getRecipeManager().getRecipeFor(RecipeType.CRAFTING, testInput, level); if (recipeHolder.isPresent()) { ItemStack result = recipeHolder.get().value().assemble(testInput, level.registryAccess()); - ThaumicEnergistics.LOG.debug("[R] Vanilla match: {}, setting result slot", result); resultSlot.setDisplayedCraftingOutput(result); } else { - ThaumicEnergistics.LOG.debug("[R] No vanilla match either, clearing result slot"); // 客户端不清空产物槽,@GuiSync 会同步服务端的正确状态 if (!level.isClientSide()) { resultSlot.setDisplayedCraftingOutput(ItemStack.EMPTY); @@ -225,9 +264,7 @@ public class ContainerArcaneCraftingTerminal extends MEStorageMenu implements IC if (foundArcane) { // 服务端设置 @GuiSync 字段;客户端不应覆盖来自服务端的同步值 - ThaumicEnergistics.LOG.debug("[R] foundArcane branch: isClientSide={}", level.isClientSide()); if (level.isClientSide()) { - ThaumicEnergistics.LOG.debug("[R] Client: keeping server-synced values, not overriding"); return; } this.hasValidRecipe = true; @@ -235,32 +272,27 @@ public class ContainerArcaneCraftingTerminal extends MEStorageMenu implements IC var wandInv = this.craftingInventoryHost.getSubInventory(ArcaneCraftingTerminalPart.INV_WAND); var ws = wandInv.getStackInSlot(0); resultSlot.setWandStack(ws); - ThaumicEnergistics.LOG.debug("[R] SET state: hasValidRecipe=true, wandStack={}", ws); if (requiredAspects != null && requiredAspects.size() > 0) { StringBuilder sb = new StringBuilder(); for (Map.Entry entry : requiredAspects.aspects.entrySet()) { if (!sb.isEmpty()) sb.append(","); - sb.append(entry.getKey().getTag()).append("=").append(entry.getValue()); + // 存折扣后数值(GUI 显示实际所需 vis,含法杖 + 装备 + 饰品减免) + sb.append(entry.getKey().getTag()).append("=") + .append(getDiscountedVisCost(entry.getKey(), entry.getValue())); } this.requiredAspectsData = sb.toString(); - ThaumicEnergistics.LOG.debug("[R] aspectsData={}", this.requiredAspectsData); } else { this.requiredAspectsData = ""; - ThaumicEnergistics.LOG.debug("[R] aspectsData=empty (no aspects)"); } } else { - ThaumicEnergistics.LOG.debug("[R] else branch: isClientSide={}, levelClass={}", - level.isClientSide(), level.getClass().getSimpleName()); if (level.isClientSide()) { - ThaumicEnergistics.LOG.debug("[R] Client: not overriding synced values (no arcane recipe on client)"); return; } this.requiredAspectsData = ""; this.hasValidRecipe = false; resultSlot.setRequiredAspects(null); resultSlot.setWandStack(ItemStack.EMPTY); - ThaumicEnergistics.LOG.debug("[R] SET state: hasValidRecipe=false (no arcane recipe)"); } } diff --git a/src/main/java/thaumicenergistics/common/container/ContainerDistillationPatternEncoder.java b/src/main/java/thaumicenergistics/common/container/ContainerDistillationPatternEncoder.java index d0c76ac..f61ffae 100644 --- a/src/main/java/thaumicenergistics/common/container/ContainerDistillationPatternEncoder.java +++ b/src/main/java/thaumicenergistics/common/container/ContainerDistillationPatternEncoder.java @@ -24,6 +24,7 @@ import thaumcraft.api.aspects.AspectList; import thaumcraft.common.research.TCResearchManager; import thaumcraft.common.research.ThaumometerScanManager; import thaumicenergistics.ThaumicEnergistics; +import thaumicenergistics.common.container.slot.ReadOnlySlot; import thaumicenergistics.common.integration.appeng.AEssentiaKey; import thaumicenergistics.common.integration.tc.TCReflection; import thaumicenergistics.common.network.DistillationEncoderSetSourceC2SPacket; @@ -98,20 +99,10 @@ public class ContainerDistillationPatternEncoder extends AbstractContainerMenu { for (int i = 0; i < SLOT_ASPECTS_COUNT; i++) { int y = SLOT_ASPECTS_Y + i * 18; - addSlot(new SlotItemHandler(aspectInventory, i, SLOT_ASPECTS_X, y) { - @Override - public boolean mayPlace(ItemStack s) { return false; } - @Override - public boolean mayPickup(Player p) { return false; } - }); + addSlot(new ReadOnlySlot(aspectInventory, i, SLOT_ASPECTS_X, y)); } - addSlot(new SlotItemHandler(aspectInventory, SLOT_ASPECTS_COUNT, SLOT_SELECTED_X, SLOT_SELECTED_Y) { - @Override - public boolean mayPlace(ItemStack s) { return false; } - @Override - public boolean mayPickup(Player p) { return false; } - }); + addSlot(new ReadOnlySlot(aspectInventory, SLOT_ASPECTS_COUNT, SLOT_SELECTED_X, SLOT_SELECTED_Y)); if (encoder != null) { // 源物品槽:ghost 模板(背包拖入不消耗——实际物品还在手里;空手点击清空;JEI 拖拽设置模板) diff --git a/src/main/java/thaumicenergistics/common/container/ContainerEssentiaCellTerminal.java b/src/main/java/thaumicenergistics/common/container/ContainerEssentiaCellTerminal.java deleted file mode 100644 index 9a326d0..0000000 --- a/src/main/java/thaumicenergistics/common/container/ContainerEssentiaCellTerminal.java +++ /dev/null @@ -1,20 +0,0 @@ -package thaumicenergistics.common.container; - -import net.minecraft.network.RegistryFriendlyByteBuf; -import net.minecraft.world.entity.player.Inventory; -import net.neoforged.neoforge.items.ItemStackHandler; -import net.neoforged.neoforge.items.SlotItemHandler; -import thaumicenergistics.init.ModMenuTypes; - -/** 源质元件终端的容器。基于网格的源质视图 + 元件槽。 */ -public class ContainerEssentiaCellTerminal extends ThEContainerBase { - final ItemStackHandler cellSlot = new ItemStackHandler(1); - final ItemStackHandler viewSlot = new ItemStackHandler(1); - - public ContainerEssentiaCellTerminal(int id, Inventory inv) { - super(ModMenuTypes.ESSENTIA_TERMINAL.get(), id, inv, 2); - addSlot(new SlotItemHandler(cellSlot, 0, 26, 16)); - addSlot(new SlotItemHandler(viewSlot, 0, 134, 16)); - } - public ContainerEssentiaCellTerminal(int id, Inventory inv, RegistryFriendlyByteBuf buf) { this(id, inv); } -} diff --git a/src/main/java/thaumicenergistics/common/container/ContainerKnowledgeInscriber.java b/src/main/java/thaumicenergistics/common/container/ContainerKnowledgeInscriber.java index eb19d33..02c97f4 100644 --- a/src/main/java/thaumicenergistics/common/container/ContainerKnowledgeInscriber.java +++ b/src/main/java/thaumicenergistics/common/container/ContainerKnowledgeInscriber.java @@ -25,6 +25,7 @@ import thaumcraft.api.crafting.ShapedArcaneRecipe; import thaumcraft.api.crafting.ShapelessArcaneRecipe; import thaumcraft.common.research.TCResearchManager; import thaumicenergistics.common.container.slot.GhostSlot; +import thaumicenergistics.common.container.slot.ReadOnlySlot; import thaumicenergistics.common.integration.tc.ArcaneCraftingPattern; import thaumicenergistics.common.inventory.HandlerKnowledgeCore; import thaumicenergistics.common.network.KnowledgeInscriberGhostSlotPacket; @@ -121,12 +122,7 @@ public class ContainerKnowledgeInscriber extends AbstractContainerMenu { initPatternSlots(); initCraftingSlots(); - addSlot(new SlotItemHandler(resultInventory, 0, RESULT_SLOT_X, RESULT_SLOT_Y) { - @Override - public boolean mayPlace(ItemStack s) { return false; } - @Override - public boolean mayPickup(Player p) { return false; } - }); + addSlot(new ReadOnlySlot(resultInventory, 0, RESULT_SLOT_X, RESULT_SLOT_Y)); saveStateSlot = addDataSlot(DataSlot.standalone()); saveStateSlot.set(0); diff --git a/src/main/java/thaumicenergistics/common/container/GuiArcaneAssembler.java b/src/main/java/thaumicenergistics/common/container/GuiArcaneAssembler.java index d9c0dbd..ee070cc 100644 --- a/src/main/java/thaumicenergistics/common/container/GuiArcaneAssembler.java +++ b/src/main/java/thaumicenergistics/common/container/GuiArcaneAssembler.java @@ -7,9 +7,10 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.inventory.ContainerData; import thaumicenergistics.ThaumicEnergistics; +import org.anti_ad.mc.ipn.api.IPNIgnore; /** - * 奥术装配器 GUI。 + * 奥术装配器 GUI。标 @IPNIgnore:IPN 一键整理完全跳过此界面(不渲染排序按钮、不执行整理)。 * * 贴图 arcane_assembler.png = 256×256 画布,包含4块不连续区域: * 第1块 主矩形:(0,0) → 176×197 @@ -20,6 +21,7 @@ import thaumicenergistics.ThaumicEnergistics; * 仿1.7.10纹理裁剪方式:GUI分块blit,bar区域不随纹理整体绘制, * 而是先画暗色背景,再从纹理Y=202处裁剪满bar按百分比叠加。 */ +@IPNIgnore public class GuiArcaneAssembler extends AbstractContainerScreen { static final ResourceLocation TEX = ResourceLocation.fromNamespaceAndPath( diff --git a/src/main/java/thaumicenergistics/common/container/GuiArcaneCraftingTerminal.java b/src/main/java/thaumicenergistics/common/container/GuiArcaneCraftingTerminal.java index b0c6310..fe8e4ef 100644 --- a/src/main/java/thaumicenergistics/common/container/GuiArcaneCraftingTerminal.java +++ b/src/main/java/thaumicenergistics/common/container/GuiArcaneCraftingTerminal.java @@ -11,17 +11,13 @@ import appeng.client.gui.style.ScreenStyle; import java.util.Map; -public class GuiArcaneCraftingTerminal extends MEStorageScreen { +import org.anti_ad.mc.ipn.api.IPNIgnore; - /** 6 个要素图标位置(左上角坐标) */ - private static final int[][] ASPECT_POSITIONS = { - {10, 95}, // 左列 第1行 - {10, 112}, // 左列 第2行 - {10, 128}, // 左列 第3行 - {80, 95}, // 右列 第1行 - {80, 112}, // 右列 第2行 - {80, 128}, // 右列 第3行 - }; +/** + * 奥术合成终端 GUI。标 @IPNIgnore:IPN 一键整理完全跳过此界面(不渲染排序按钮、不执行整理)。 + */ +@IPNIgnore +public class GuiArcaneCraftingTerminal extends MEStorageScreen { private static final int ICON_SIZE = 14; @@ -30,9 +26,6 @@ public class GuiArcaneCraftingTerminal extends MEStorageScreen aspectMap = this.menu.getParsedAspects(); if (aspectMap.isEmpty()) return; - // 获取合成结果槽的 Y 位置作为锚点(槽位置不变,首次计算后缓存,避免每帧遍历) - int anchorY; - if (cachedAnchorY < 0) { - for (var slot : this.menu.slots) { - // CRAFTING_RESULT 槽在 style JSON 中 bottom:140 - if (slot instanceof appeng.menu.slot.AppEngCraftingSlot) { - cachedAnchorY = slot.y; - break; - } + // 锚点取合成结果槽的 Y:圆环紧贴结果槽左侧,窗口缩放时随槽位一起移动 + int anchorY = -1; + for (var slot : this.menu.slots) { + if (slot instanceof appeng.menu.slot.AppEngCraftingSlot) { + anchorY = slot.y; + break; } - // 若找不到锚点则回退到硬编码值 - if (cachedAnchorY < 0) cachedAnchorY = 95; } - anchorY = cachedAnchorY; + if (anchorY < 0) anchorY = 95; - // 要素圆圈 Y = 锚点 + 偏移(-16/1/17,对应纹理 95/112/128) + // 两列三行:左列 x=10,右列 x=80;行偏移对应三行圆环 int[] aspectOffsets = { -16, 1, 17 }; int index = 0; diff --git a/src/main/java/thaumicenergistics/common/container/GuiEssentiaCellTerminal.java b/src/main/java/thaumicenergistics/common/container/GuiEssentiaCellTerminal.java deleted file mode 100644 index b9faf30..0000000 --- a/src/main/java/thaumicenergistics/common/container/GuiEssentiaCellTerminal.java +++ /dev/null @@ -1,15 +0,0 @@ -package thaumicenergistics.common.container; - -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.player.Inventory; -import thaumicenergistics.ThaumicEnergistics; - -public class GuiEssentiaCellTerminal extends AbstractContainerScreen { - static final ResourceLocation TEX = ResourceLocation.fromNamespaceAndPath(ThaumicEnergistics.MODID,"textures/gui/essentia_terminal.png"); - public GuiEssentiaCellTerminal(ContainerEssentiaCellTerminal m, Inventory inv, Component t) { super(m,inv,t); imageWidth=176; imageHeight=166; inventoryLabelY=imageHeight-94; } - @Override protected void renderBg(GuiGraphics g, float pt, int mx, int my) { int x=(width-imageWidth)/2,y=(height-imageHeight)/2; g.blit(TEX,x,y,0,0,imageWidth,imageHeight); } - @Override public void render(GuiGraphics g, int mx, int my, float pt) { super.render(g,mx,my,pt); renderTooltip(g,mx,my); } -} diff --git a/src/main/java/thaumicenergistics/common/container/slot/ArcaneCraftingResultSlot.java b/src/main/java/thaumicenergistics/common/container/slot/ArcaneCraftingResultSlot.java index 1f49da8..8d92a72 100644 --- a/src/main/java/thaumicenergistics/common/container/slot/ArcaneCraftingResultSlot.java +++ b/src/main/java/thaumicenergistics/common/container/slot/ArcaneCraftingResultSlot.java @@ -4,37 +4,44 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import appeng.api.inventories.InternalInventory; -import appeng.menu.slot.AppEngCraftingSlot; +import appeng.api.networking.energy.IEnergySource; +import appeng.api.networking.security.IActionSource; +import appeng.api.storage.MEStorage; +import appeng.helpers.ICraftingGridMenu; +import appeng.helpers.InventoryAction; +import appeng.menu.slot.CraftingTermSlot; +import appeng.util.inv.PlayerInternalInventory; import thaumcraft.api.aspects.Aspect; import thaumcraft.api.aspects.AspectList; import thaumcraft.common.items.TCFunctionalItems; -import thaumcraft.common.lib.crafting.ThaumcraftCraftingManager; import thaumicenergistics.common.container.ContainerArcaneCraftingTerminal; /** - * 奥术合成结果槽:在取走合成结果时消耗法杖要素。 - * 参考 TC4 1.21.1 ArcaneWorkbenchMenu.onResultTaken + consumeVis。 + * 奥术合成结果槽:继承 AE2 CraftingTermSlot 使客户端识别(shift/右键/space 合成自动生效), + * 并保留 vis 消耗检查(mayPickup)与取走时 vis 扣除 + 自动补货(onTake)。 */ -public class ArcaneCraftingResultSlot extends AppEngCraftingSlot { +public class ArcaneCraftingResultSlot extends CraftingTermSlot { /** TC4 内部使用 centivis,1 vis = 100 centivis */ private static final int CENTIVIS = 100; private AspectList requiredAspects = null; private ItemStack wandStack = ItemStack.EMPTY; - private Runnable refreshCallback = null; private ContainerArcaneCraftingTerminal container = null; + private final MEStorage storage; + private final IEnergySource energySrc; + private final IActionSource mySrc; + private final InternalInventory craftingGrid; - public ArcaneCraftingResultSlot(Player player, InternalInventory craftingGridInv) { - super(player, craftingGridInv); - } - - public void setContainer(ContainerArcaneCraftingTerminal container) { + public ArcaneCraftingResultSlot(Player player, ContainerArcaneCraftingTerminal container, + InternalInventory craftingGridInv, InternalInventory secondMatrix, + MEStorage storage, IEnergySource energySrc, IActionSource mySrc) { + super(player, mySrc, energySrc, storage, craftingGridInv, secondMatrix, (ICraftingGridMenu) container); this.container = container; - } - - public void setRefreshCallback(Runnable callback) { - this.refreshCallback = callback; + this.storage = storage; + this.energySrc = energySrc; + this.mySrc = mySrc; + this.craftingGrid = craftingGridInv; } public void setRequiredAspects(AspectList aspects) { @@ -47,40 +54,177 @@ public class ArcaneCraftingResultSlot extends AppEngCraftingSlot { @Override public boolean mayPickup(Player player) { - if (requiredAspects == null || requiredAspects.isEmpty()) { - return super.mayPickup(player); + // AE2 原版:结果槽不可 vanilla 点按取走,所有取走走 doClick(含 vis 检查) + return false; + } + + @Override + public void doClick(InventoryAction action, Player who) { + // vis 检查:奥术配方需法杖有足够 vis,否则不合成 + if (requiredAspects != null && !requiredAspects.isEmpty()) { + if (wandStack.isEmpty()) { + return; + } + if (!(wandStack.getItem() instanceof TCFunctionalItems.WandCastingItem wand)) { + return; + } + AspectList centivisCost = new AspectList(); + for (Aspect aspect : requiredAspects.aspects()) { + centivisCost.add(aspect, requiredAspects.amount(aspect) * CENTIVIS); + } + if (!wand.consumeVisCost(wandStack, who, centivisCost, false, true)) { + return; + } + } + + + // 奥术配方(非 vanilla CRAFTING)不走 AE2 craftItem(findRecipe 只认 vanilla) + // 走自定义合成:从合成格读配方 → 产物 + 消耗材料 + 从网络补货 + if (container != null && container.hasValidRecipe) { + doArcaneCraft(action, who); + return; } - if (wandStack.isEmpty()) return false; - if (!(wandStack.getItem() instanceof TCFunctionalItems.WandCastingItem wand)) { - return false; + // vanilla 配方:严格 AE2(从网络提取材料填合成格) + super.doClick(action, who); + // 消耗 vis(实际扣除) + if (requiredAspects != null && !requiredAspects.isEmpty() && !wandStack.isEmpty()) { + if (wandStack.getItem() instanceof TCFunctionalItems.WandCastingItem wand) { + AspectList centivisCost = new AspectList(); + for (Aspect aspect : requiredAspects.aspects()) { + centivisCost.add(aspect, requiredAspects.amount(aspect) * CENTIVIS); + } + wand.consumeVisCost(wandStack, who, centivisCost, true, true); + } + } + } + + /** 奥术配方合成:从合成格读 Thaumcraft 奥术配方 → 产物 + 消耗材料 + 从网络补货。 */ + private void doArcaneCraft(InventoryAction action, Player who) { + if (this.getItem().isEmpty() || isRemote()) { + return; + } + var grid = craftingGrid; + var level = who.level(); + if (level.isClientSide()) return; + + // 用 Thaumcraft 奥术配方匹配(取配方对象以支持 retainIngredient 保留原料) + var craftContainer = grid.toContainer(); + thaumcraft.api.crafting.IArcaneRecipe arcaneRecipe = thaumcraft.common.lib.crafting.ThaumcraftCraftingManager + .findMatchingArcaneRecipeEntry(craftContainer, who); + if (arcaneRecipe == null) { + return; + } + ItemStack arcaneResult = arcaneRecipe.getCraftingResult(craftContainer); + if (arcaneResult.isEmpty()) { + return; + } + // 保留原料(retainIngredient,如元始珍珠):getRemainingItems 返回非空栈的槽位不消耗。 + // 对应 TC 奥术工作台行为——珍珠作为"催化"留在合成格,仅消耗构材与虚空金属锭。 + net.minecraft.core.NonNullList remainders = + arcaneRecipe.getRemainingItems(craftContainer); + + + // shift=整组到背包、普通=1 个到手 + int maxTimesToCraft; + InternalInventory target; + if (action == InventoryAction.CRAFT_SHIFT || action == InventoryAction.CRAFT_ALL) { + target = new appeng.util.inv.PlayerInternalInventory(who.getInventory()); + maxTimesToCraft = (int) Math.floor((double) arcaneResult.getMaxStackSize() / (double) arcaneResult.getCount()); + if (action == InventoryAction.CRAFT_ALL) { + maxTimesToCraft *= net.minecraft.world.entity.player.Inventory.INVENTORY_SIZE; + } + } else { + target = new appeng.util.inv.CarriedItemInventory(getMenu()); + maxTimesToCraft = 1; } - AspectList centivisCost = new AspectList(); - for (Aspect aspect : requiredAspects.aspects()) { - centivisCost.add(aspect, requiredAspects.amount(aspect) * CENTIVIS); + int crafted = 0; + for (int x = 0; x < maxTimesToCraft; x++) { + // 每轮 vis 检查 + 实际扣减(consume=true):法杖 vis 不足则停 + if (requiredAspects != null && !requiredAspects.isEmpty()) { + if (wandStack.isEmpty()) break; + if (!(wandStack.getItem() instanceof TCFunctionalItems.WandCastingItem wand)) break; + AspectList centivisCost = new AspectList(); + for (Aspect aspect : requiredAspects.aspects()) { + centivisCost.add(aspect, requiredAspects.amount(aspect) * CENTIVIS); + } + boolean ok = wand.consumeVisCost(wandStack, who, centivisCost, true, true); + if (!ok) { + break; + } + } + // 目标满或配方失效则停 + if (!target.simulateAdd(arcaneResult).isEmpty()) { + break; + } + // 合成前检查奥术配方仍匹配 + ItemStack currentResult = thaumcraft.common.lib.crafting.ThaumcraftCraftingManager + .findMatchingArcaneRecipe(grid.toContainer(), who); + if (currentResult.isEmpty()) { + break; + } + + // 记录消耗前合成格(首次记录,后续每轮消耗后补货) + var beforeItems = new java.util.HashMap(); + for (int i = 0; i < grid.size(); i++) { + var s = grid.getStackInSlot(i); + if (!s.isEmpty()) beforeItems.put(i, s.copy()); + } + // 消耗合成格材料(每格 1 个);保留原料槽(remainders 非空,如元始珍珠)不消耗 + for (int i = 0; i < grid.size(); i++) { + if (!grid.getStackInSlot(i).isEmpty() && remainders.get(i).isEmpty()) { + grid.extractItem(i, 1, false); + } + } + // 从网络补货(对齐 AE2 终端) + if (storage != null && energySrc != null && mySrc != null) { + for (var entry : beforeItems.entrySet()) { + int slot = entry.getKey(); + var beforeItem = entry.getValue(); + var currentItem = grid.getStackInSlot(slot); + if (currentItem.getCount() < beforeItem.getCount()) { + long needed = beforeItem.getCount() - currentItem.getCount(); + var key = appeng.api.stacks.AEItemKey.of(beforeItem); + if (key != null) { + long extracted = appeng.api.storage.StorageHelper.poweredExtraction( + energySrc, storage, key, needed, mySrc); + if (extracted > 0) { + grid.setItemDirect(slot, beforeItem.copyWithCount( + (int) (currentItem.getCount() + extracted))); + } + } + } + } + } + + // 产物入目标 + var extra = target.addItems(arcaneResult.copy()); + if (!extra.isEmpty()) { + appeng.util.Platform.spawnDrops(who.level(), who.blockPosition(), java.util.List.of(extra)); + break; + } + crafted++; } - return wand.consumeVisCost(wandStack, player, centivisCost, false, true); + + // 触发容器刷新(重算结果槽) + container.slotsChanged(grid.toContainer()); } @Override public void onTake(Player player, ItemStack stack) { - // 记录消耗前各合成格中的物品类型,用于消耗后从 ME 网络补充 - java.util.Map beforeItems = new java.util.HashMap<>(); - if (container != null) { - var grid = container.getCraftingMatrix(); - for (int i = 0; i < grid.size(); i++) { - var s = grid.getStackInSlot(i); - if (!s.isEmpty()) { - beforeItems.put(i, s.copy()); - } - } - } - if (container != null) { container.setCraftingResultBeingTaken(true); } try { + // 记录消耗前各合成格物品,取走后从 ME 存储自动补回(AE2 终端行为) + java.util.Map beforeItems = new java.util.HashMap<>(); + var grid = craftingGrid; + for (int i = 0; i < grid.size(); i++) { + var s = grid.getStackInSlot(i); + if (!s.isEmpty()) beforeItems.put(i, s.copy()); + } + super.onTake(player, stack); if (requiredAspects != null && !requiredAspects.isEmpty() && !wandStack.isEmpty()) { @@ -93,28 +237,22 @@ public class ArcaneCraftingResultSlot extends AppEngCraftingSlot { } } - // 从 ME 网络自动补充消耗掉的合成材料 - if (container != null && !beforeItems.isEmpty()) { - var grid = container.getCraftingMatrix(); - var node = container.getGridNode(); - if (node != null && node.getGrid() != null) { - var storage = node.getGrid().getStorageService().getInventory(); - var energy = container.getEnergySource(); - var actionSource = container.getActionSource(); + // 自动补货:合成格材料被消耗后从 ME 存储补回 + if (!beforeItems.isEmpty()) { + if (storage != null && energySrc != null && mySrc != null) { for (var entry : beforeItems.entrySet()) { int slot = entry.getKey(); var beforeItem = entry.getValue(); var currentItem = grid.getStackInSlot(slot); - // 如果该格物品变少了(被消耗了),从网络提取补充 if (currentItem.getCount() < beforeItem.getCount()) { long needed = beforeItem.getCount() - currentItem.getCount(); var key = appeng.api.stacks.AEItemKey.of(beforeItem); if (key != null) { long extracted = appeng.api.storage.StorageHelper.poweredExtraction( - energy, storage, key, needed, actionSource); + energySrc, storage, key, needed, mySrc); if (extracted > 0) { - var toPlace = beforeItem.copyWithCount((int) (currentItem.getCount() + extracted)); - grid.setItemDirect(slot, toPlace); + grid.setItemDirect(slot, beforeItem.copyWithCount( + (int) (currentItem.getCount() + extracted))); } } } @@ -126,8 +264,6 @@ public class ArcaneCraftingResultSlot extends AppEngCraftingSlot { container.setCraftingResultBeingTaken(false); } } - if (refreshCallback != null) { - refreshCallback.run(); - } } + } diff --git a/src/main/java/thaumicenergistics/common/features/RecipeRegistration.java b/src/main/java/thaumicenergistics/common/features/RecipeRegistration.java index ddcd26f..57d0a20 100644 --- a/src/main/java/thaumicenergistics/common/features/RecipeRegistration.java +++ b/src/main/java/thaumicenergistics/common/features/RecipeRegistration.java @@ -128,7 +128,7 @@ public final class RecipeRegistration { "lBl", "QPQ", 'Q', ae("quartz_glass"), - 'l', new ItemStack(Items.LAPIS_LAZULI, 4), + 'l', new ItemStack(Items.LAPIS_LAZULI, 1), 'B', tc("zombie_brain"), 'P', ae("calculation_processor")); @@ -138,7 +138,7 @@ public final class RecipeRegistration { "qWq", "FqA", 'A', tc("air_shard"), - 'q', new ItemStack(Items.QUARTZ, 4), + 'q', new ItemStack(Items.QUARTZ, 1), 'F', tc("fire_shard"), 'W', ae("certus_quartz_wrench")); @@ -156,22 +156,23 @@ public final class RecipeRegistration { ESSENTIA_IMPORT_BUS = ThaumcraftApi.addArcaneCraftingRecipe("ESSENTIABUSES", stack(ModItems.ESSENTIA_IMPORT_BUS), new AspectList().add(Aspect.FIRE, 2).add(Aspect.EARTH, 2).add(Aspect.WATER, 1), - "JDJ", + // 注意:TC ShapedArcaneRecipe 要求模式为矩形(各行等长),删 J 后必须补空格占位 + "JD ", "IFI", " ", - 'J', tc("warded_jar"), + 'J', tc("jar_of_essentia"), 'D', stack(ModItems.DIFFUSION_CORE), - 'I', new ItemStack(Items.IRON_INGOT, 2), + 'I', new ItemStack(Items.IRON_INGOT, 1), 'F', tc("essentia_filter")); ESSENTIA_EXPORT_BUS = ThaumcraftApi.addArcaneCraftingRecipe("ESSENTIABUSES", stack(ModItems.ESSENTIA_EXPORT_BUS), new AspectList().add(Aspect.FIRE, 2).add(Aspect.EARTH, 2).add(Aspect.WATER, 1), - "JCJ", + "JC ", "IFI", " ", - 'J', tc("warded_jar"), + 'J', tc("jar_of_essentia"), 'C', stack(ModItems.COALESCENCE_CORE), - 'I', new ItemStack(Items.IRON_INGOT, 2), + 'I', new ItemStack(Items.IRON_INGOT, 1), 'F', tc("essentia_filter")); ESSENTIA_STORAGE_BUS = ThaumcraftApi.addArcaneCraftingRecipe("ESSENTIABUSES", stack(ModItems.ESSENTIA_STORAGE_BUS), @@ -182,7 +183,7 @@ public final class RecipeRegistration { 'D', stack(ModItems.DIFFUSION_CORE), 'C', stack(ModItems.COALESCENCE_CORE), 'F', tc("essentia_filter"), - 'I', new ItemStack(Items.IRON_INGOT, 2), + 'I', new ItemStack(Items.IRON_INGOT, 1), 'G', ae("quartz_glass")); KNOWLEDGE_INSCRIBER_BLOCK = ThaumcraftApi.addArcaneCraftingRecipe("KNOWLEDGEINSCRIBER", stack(ModBlocks.KNOWLEDGE_INSCRIBER), @@ -190,7 +191,7 @@ public final class RecipeRegistration { "ILI", " T ", "IPI", - 'I', new ItemStack(Items.IRON_INGOT, 4), + 'I', new ItemStack(Items.IRON_INGOT, 1), 'L', MONITORS, 'T', tc("thaumonomicon"), 'P', ae("logic_processor")); @@ -200,7 +201,7 @@ public final class RecipeRegistration { "ILI", " G ", "IPI", - 'I', new ItemStack(Items.IRON_INGOT, 4), + 'I', new ItemStack(Items.IRON_INGOT, 1), 'L', MONITORS, 'G', tc("thaumometer"), 'P', ae("engineering_processor")); @@ -252,7 +253,7 @@ public final class RecipeRegistration { // 6. 源流接口 VIS_INTERFACE = ThaumcraftApi.addShapelessArcaneCraftingRecipe("VISINTERFACE", stack(ModItems.VIS_INTERFACE), new AspectList().add(Aspect.AIR, 2).add(Aspect.EARTH, 2).add(Aspect.FIRE, 2).add(Aspect.WATER, 2).add(Aspect.ORDER, 2).add(Aspect.ENTROPY, 2), - tc("balance_shard"), + tc("balanced_shard"), ae("me_p2p_tunnel")); // 7. 原质振荡室 @@ -293,27 +294,38 @@ public final class RecipeRegistration { tc("salis_mundus")); // 3. 奥术装配器 + // 权杖要求:6 个原质要素值全满(满充能)。createFullVisScepter() 生成"满充能"预期栈, + // TC port 的 InfusionRecipe.hasExpectedComponents 会逐键比对 custom_data—— + // 预期键必须全部存在于实物且数值相等 → 未满充能的权杖无法匹配。 + // 组件数:8 个(1.7.10 原版一致)。实测 9 组件(含世界盐)注魔祭坛无法启动—— + // TC 自身所有注魔配方组件数上限就是 8。 ARCANE_ASSEMBLER = ThaumcraftApi.addInfusionCraftingRecipe("ARCANEASSEMBLER", stack(ModBlocks.ARCANE_ASSEMBLER), 5, new AspectList().add(Aspect.CRAFT, 64).add(Aspect.EXCHANGE, 32).add(Aspect.AURA, 16).add(Aspect.MAGIC, 16).add(Aspect.METAL, 8).add(Aspect.CRYSTAL, 8), ae("molecular_assembler"), tc("fire_shard"), tc("entropy_shard"), tc("order_shard"), - tc("balance_shard"), + tc("balanced_shard"), tc("water_shard"), tc("earth_shard"), tc("air_shard"), - tc("salis_mundus"), createFullVisScepter()); - - - } + /** + * 生成"满充能"银木神秘权杖作为注魔配方的预期组件。 + * + * ⚠ 关键:不要调用 TCVisHelper.setWandParts()!玩家实际合成的权杖(ArcaneSceptreRecipe → + * WandCastingItem.createWandFor)是纯物品,custom_data 只有充能时写入的 tc_vis_* 键, + * 没有 tc_wand_rod/tc_wand_cap。若在预期侧写入这些键,hasExpectedComponents 逐键比对时 + * 会因实物缺少而永不匹配——满充能权杖也放不进去。 + * + * getWandMaxVis 用 fallbackVariant "silverwood_thaumium_scepter" 解析即可得 15000 + * (银木杆 10000 × 权杖 1.5),无需依赖栈上的部件数据。 + */ private static ItemStack createFullVisScepter() { ItemStack scepter = tc("silverwood_thaumium_scepter"); if (scepter.isEmpty()) return scepter; - TCVisHelper.setWandParts(scepter, "silverwood", "thaumium", true); int max = TCVisHelper.getWandMaxVis(scepter, "silverwood_thaumium_scepter"); for (Aspect a : Aspect.getPrimalAspects()) { TCVisHelper.storeVis(scepter, a, max, max); diff --git a/src/main/java/thaumicenergistics/common/grid/EssentiaGridService.java b/src/main/java/thaumicenergistics/common/grid/EssentiaGridService.java index 60ca826..8a03b7d 100644 --- a/src/main/java/thaumicenergistics/common/grid/EssentiaGridService.java +++ b/src/main/java/thaumicenergistics/common/grid/EssentiaGridService.java @@ -7,13 +7,13 @@ import java.util.Map; import net.minecraft.resources.ResourceLocation; +import appeng.api.config.Actionable; import appeng.api.networking.IGrid; import appeng.api.networking.IGridServiceProvider; import appeng.api.networking.security.IActionSource; import appeng.api.networking.storage.IStorageService; import appeng.api.storage.MEStorage; import appeng.api.storage.StorageHelper; -import appeng.api.networking.security.IActionSource; import thaumicenergistics.api.grid.IEssentiaGrid; import thaumicenergistics.api.storage.AspectStack; import thaumicenergistics.api.storage.IAspectStack; @@ -101,11 +101,28 @@ public class EssentiaGridService implements IEssentiaGrid, IGridServiceProvider @Override public long injectEssentia(ResourceLocation aspectId, long amount, boolean simulate) { if (amount <= 0) return 0; - if (!simulate) { - long current = monitor.get(aspectId); - monitor.set(aspectId, current + amount); + // 写入 AE2 原生存储(源质存储元件/存储总线可见、持久化) + var nativeInjected = injectNative(aspectId, amount, simulate); + if (nativeInjected < amount) { + // 原生存储空间不足时剩余部分退回内存 monitor(供注魔供应器等内部读取) + long remaining = amount - nativeInjected; + if (!simulate) { + long current = monitor.get(aspectId); + monitor.set(aspectId, current + remaining); + } + return amount - nativeInjected - remaining; // 全部接受(monitor 兜底) } - return 0; + return 0; // 全部写入原生存储 + } + + private long injectNative(ResourceLocation aspectId, long amount, boolean simulate) { + var storage = getNativeStorage(); + if (storage == null) return 0; + var key = AEssentiaKey.of(aspectId); + if (key == null) return 0; + return StorageHelper.poweredInsert( + grid.getEnergyService(), storage, key, amount, + IActionSource.empty(), simulate ? Actionable.SIMULATE : Actionable.MODULATE); } @Override diff --git a/src/main/java/thaumicenergistics/common/integration/jade/VibrationChamberProvider.java b/src/main/java/thaumicenergistics/common/integration/jade/VibrationChamberProvider.java index 61636f3..5997cc5 100644 --- a/src/main/java/thaumicenergistics/common/integration/jade/VibrationChamberProvider.java +++ b/src/main/java/thaumicenergistics/common/integration/jade/VibrationChamberProvider.java @@ -34,11 +34,11 @@ public enum VibrationChamberProvider implements IBlockComponentProvider, IServer CompoundTag data = accessor.getServerData(); if (data == null || data.isEmpty()) return; - // 吸力类型 + // 当前仓内源质类型(通配吸力模式下显示仓内实际燃料) if (data.contains(TAG_ASPECT)) { String aspect = data.getString(TAG_ASPECT); String aspectKey = "thaumicenergistics.aspect." + aspect; - tooltip.add(Component.translatable("thaumicenergistics.jade.suction_type", + tooltip.add(Component.translatable("thaumicenergistics.jade.current_aspect", Component.translatable(aspectKey))); } @@ -93,8 +93,8 @@ public enum VibrationChamberProvider implements IBlockComponentProvider, IServer data.putDouble(TAG_ENERGY_MAX, chamber.getMaxEnergyStorage()); data.putDouble(TAG_ENERGY_OUTPUT, chamber.getMaxOutputPerTick()); data.putBoolean(TAG_GENERATING, chamber.isActive()); - if (chamber.getSuctionType(null) != null) { - data.putString(TAG_ASPECT, chamber.getSuctionType(null).getTag()); + if (chamber.getEssentiaType(null) != null) { + data.putString(TAG_ASPECT, chamber.getEssentiaType(null).getTag()); } } } diff --git a/src/main/java/thaumicenergistics/common/items/WirelessEssentiaTerminalItem.java b/src/main/java/thaumicenergistics/common/items/WirelessEssentiaTerminalItem.java index ca785b0..9b21f93 100644 --- a/src/main/java/thaumicenergistics/common/items/WirelessEssentiaTerminalItem.java +++ b/src/main/java/thaumicenergistics/common/items/WirelessEssentiaTerminalItem.java @@ -11,7 +11,6 @@ import net.minecraft.world.phys.BlockHitResult; import appeng.helpers.WirelessTerminalMenuHost; import appeng.items.tools.powered.WirelessTerminalItem; import appeng.menu.locator.ItemMenuHostLocator; -import appeng.menu.me.common.MEStorageMenu; /** * 无线源质终端物品。继承 AE2 的WirelessTerminalItem @@ -25,7 +24,7 @@ public class WirelessEssentiaTerminalItem extends WirelessTerminalItem { @Override public MenuType getMenuType() { - return MEStorageMenu.WIRELESS_TYPE; + return thaumicenergistics.init.ModMenuTypes.WIRELESS_ESSENTIA_TERMINAL.get(); } @Override diff --git a/src/main/java/thaumicenergistics/common/network/ThENetworking.java b/src/main/java/thaumicenergistics/common/network/ThENetworking.java index 346a1ea..22e17c7 100644 --- a/src/main/java/thaumicenergistics/common/network/ThENetworking.java +++ b/src/main/java/thaumicenergistics/common/network/ThENetworking.java @@ -50,6 +50,20 @@ public final class ThENetworking { (pkt, ctx) -> pkt.handleOnClient(ctx) ); + // EssentiaTerminalFillC2SPacket — C2S(客户端→服务端,源质终端右键装罐) + registrar.playToServer( + EssentiaTerminalFillC2SPacket.TYPE, + EssentiaTerminalFillC2SPacket.STREAM_CODEC, + (pkt, ctx) -> pkt.handleOnServer(ctx) + ); + + // EssentiaTerminalDepositC2SPacket — C2S(客户端→服务端,手持源质容器右键存入网络) + registrar.playToServer( + EssentiaTerminalDepositC2SPacket.TYPE, + EssentiaTerminalDepositC2SPacket.STREAM_CODEC, + (pkt, ctx) -> pkt.handleOnServer(ctx) + ); + // ResearchGateErrorPacket — S2C(服务端→客户端,研究未解锁拦截提示,携带研究键) registrar.playToClient( ResearchGateErrorPacket.TYPE, diff --git a/src/main/java/thaumicenergistics/common/parts/EssentiaExportBusPart.java b/src/main/java/thaumicenergistics/common/parts/EssentiaExportBusPart.java index 0692822..ae4573c 100644 --- a/src/main/java/thaumicenergistics/common/parts/EssentiaExportBusPart.java +++ b/src/main/java/thaumicenergistics/common/parts/EssentiaExportBusPart.java @@ -60,7 +60,6 @@ public class EssentiaExportBusPart extends IOBusPart private static final double IDLE_POWER = 0.5; private static final double TRANSFER_POWER = EssentiaConversionHelper.AE_PER_ESSENTIA; - private static final int TRANSFER_RATE = 8; private boolean isWorkingFlag = false; @@ -70,6 +69,14 @@ public class EssentiaExportBusPart extends IOBusPart private long storedEnergy = 0; + /** + * 单次导出量 = 基础速率 8 × 每 tick 操作次数(受加速卡影响)。 + * AE2 加速卡语义:0卡=1、1卡=8、2卡=32、3卡=64、4卡=96(getOperationsPerTick)。 + */ + private long getExportRate() { + return 8L * Math.max(1, getOperationsPerTick()); + } + public EssentiaExportBusPart(IPartItem partItem) { super(TickRates.ExportBus, Set.of(AEssentiaKeyType.INSTANCE), partItem); this.getMainNode().setIdlePowerUsage(IDLE_POWER); @@ -122,7 +129,7 @@ public class EssentiaExportBusPart extends IOBusPart if (key == null) return false; long extracted = grid.getStorageService().getInventory().extract( - key, TRANSFER_RATE, Actionable.MODULATE, IActionSource.ofMachine(this)); + key, getExportRate(), Actionable.MODULATE, IActionSource.ofMachine(this)); if (extracted <= 0) return false; // 尝试注入到相邻方块:先 IAspectContainer,再回退到 IEssentiaTransport diff --git a/src/main/java/thaumicenergistics/common/parts/EssentiaImportBusPart.java b/src/main/java/thaumicenergistics/common/parts/EssentiaImportBusPart.java index 6922281..71606d1 100644 --- a/src/main/java/thaumicenergistics/common/parts/EssentiaImportBusPart.java +++ b/src/main/java/thaumicenergistics/common/parts/EssentiaImportBusPart.java @@ -62,6 +62,14 @@ public class EssentiaImportBusPart extends IOBusPart private boolean isWorkingFlag = false; + /** + * 单次传输量 = 基础速率 × 每 tick 操作次数(受加速卡影响)。 + * AE2 加速卡语义:0卡=1、1卡=8、2卡=32、3卡=64、4卡=96(getOperationsPerTick)。 + */ + private int getTransferRate() { + return TRANSFER_RATE * Math.max(1, getOperationsPerTick()); + } + private final KeyTypeSelection keyTypeSelection = new KeyTypeSelection( selection -> { }, keyType -> keyType == AEssentiaKeyType.INSTANCE); @@ -104,7 +112,7 @@ public class EssentiaImportBusPart extends IOBusPart BlockEntity adjacentBE = level.getBlockEntity(adjacentPos); if (adjacentBE == null) return false; - AspectStack extracted = TCReflection.extractEssentia(adjacentBE, TRANSFER_RATE); + AspectStack extracted = TCReflection.extractEssentia(adjacentBE, getTransferRate()); if (extracted == null || extracted.isEmpty()) return false; long injected = this.injectToNetwork(grid, extracted); diff --git a/src/main/java/thaumicenergistics/common/parts/EssentiaTerminalPart.java b/src/main/java/thaumicenergistics/common/parts/EssentiaTerminalPart.java index 57f1e1c..0f340ac 100644 --- a/src/main/java/thaumicenergistics/common/parts/EssentiaTerminalPart.java +++ b/src/main/java/thaumicenergistics/common/parts/EssentiaTerminalPart.java @@ -10,7 +10,6 @@ import appeng.api.parts.IPartItem; import appeng.api.parts.IPartModel; import appeng.api.util.KeyTypeSelection; import appeng.items.parts.PartModels; -import appeng.menu.me.common.MEStorageMenu; import appeng.parts.PartModel; import appeng.parts.reporting.AbstractTerminalPart; import thaumicenergistics.ThaumicEnergistics; @@ -54,7 +53,7 @@ public class EssentiaTerminalPart extends AbstractTerminalPart { @Override public MenuType getMenuType(Player player) { - return MEStorageMenu.TYPE; + return thaumicenergistics.init.ModMenuTypes.ESSENTIA_TERMINAL.get(); } @Override diff --git a/src/main/java/thaumicenergistics/common/parts/VisInterfacePart.java b/src/main/java/thaumicenergistics/common/parts/VisInterfacePart.java index fb3b0e2..9d15c88 100644 --- a/src/main/java/thaumicenergistics/common/parts/VisInterfacePart.java +++ b/src/main/java/thaumicenergistics/common/parts/VisInterfacePart.java @@ -53,6 +53,9 @@ public class VisInterfacePart extends P2PTunnelPart implements /** 抽取颜色在没有新抽取后保持点亮的时间(ms),超时清除。 */ private static final long TIME_TO_CLEAR = 500L; + /** 懒 tick 周期:固定 30 tick(vis 传输为低频操作,无需实时轮询)。 */ + private static final int TICK_RATE = 30; + private static final String NBT_KEY_UID = "uid"; private static final String NBT_KEY_IS_PROVIDER = "isProvider"; @@ -290,7 +293,7 @@ public class VisInterfacePart extends P2PTunnelPart implements @Override public TickingRequest getTickingRequest(IGridNode node) { - return new TickingRequest(30, 30, false); + return new TickingRequest(TICK_RATE, TICK_RATE, false); } @Override diff --git a/src/main/java/thaumicenergistics/common/tiles/TileArcaneAssembler.java b/src/main/java/thaumicenergistics/common/tiles/TileArcaneAssembler.java index e46d2f4..a5a8416 100644 --- a/src/main/java/thaumicenergistics/common/tiles/TileArcaneAssembler.java +++ b/src/main/java/thaumicenergistics/common/tiles/TileArcaneAssembler.java @@ -51,7 +51,6 @@ import thaumcraft.api.aspects.AspectList; import thaumcraft.api.crafting.IArcaneRecipe; import thaumicenergistics.api.grid.IEssentiaGrid; -import thaumicenergistics.ThaumicEnergistics; import thaumicenergistics.common.integration.tc.ArcaneCraftingPattern; import thaumicenergistics.common.integration.tc.TCReflection; import thaumicenergistics.common.inventory.HandlerKnowledgeCore; @@ -314,7 +313,6 @@ public class TileArcaneAssembler extends ThETileBase boolean enoughVis = hasEnoughVisForCraft(); if (!enoughVis) { - ThaumicEnergistics.LOG.debug("[AA] craftingTick: vis 不足,等待补充 (storedVis cvis={})", storedVis.visSize()); return TickRateModulation.SAME; } @@ -331,7 +329,6 @@ public class TileArcaneAssembler extends ThETileBase long inserted = storage.getInventory().insert( outputKey, output.getCount(), Actionable.SIMULATE, actionSource); if (inserted < output.getCount()) { - ThaumicEnergistics.LOG.debug("[AA] craftingTick: 产物无法插入网络(模拟 inserted={}/{}),等待", inserted, output.getCount()); return TickRateModulation.SAME; } @@ -339,7 +336,6 @@ public class TileArcaneAssembler extends ThETileBase storage.getInventory().insert( outputKey, output.getCount(), Actionable.MODULATE, actionSource); - ThaumicEnergistics.LOG.debug("[AA] craftingTick: 完成!插入产物 {}x{} 到网络", outputKey, output.getCount()); isCrafting = false; currentRecipe = null; @@ -359,11 +355,8 @@ public class TileArcaneAssembler extends ThETileBase double extracted = energy.extractAEPower(need, Actionable.MODULATE, PowerMultiplier.CONFIG); if (extracted >= need * 0.9) { craftTickCounter += ticksSinceLast; - ThaumicEnergistics.LOG.debug("[AA] craftingTick: 推进 {}/{} (抽电 {}/{})", craftTickCounter, ticksPerCraft, extracted, need); // 节流同步合成进度到客户端(GUI 第7格进度条动画) maybeMarkVisDirty(); - } else { - ThaumicEnergistics.LOG.debug("[AA] craftingTick: 能量不足 (抽到 {}/{}),不推进", extracted, need); } } @@ -446,19 +439,13 @@ public class TileArcaneAssembler extends ThETileBase ArcaneAssemblerPattern ap = buildArcanePattern(acp); if (ap != null) { result.add(ap); - ThaumicEnergistics.LOG.debug("[AA] getAvailablePatterns: pattern primaryOutput={}, definition={}", - ap.getPrimaryOutput(), ap.getDefinition()); } } - ThaumicEnergistics.LOG.debug("[AA] getAvailablePatterns: kCore valid={}, handler patterns={}, returned={}", - !kCore.isEmpty(), patterns.size(), result.size()); return result; } @Override public boolean pushPattern(IPatternDetails patternDetails, KeyCounter[] inputHolder) { - ThaumicEnergistics.LOG.info("[AA] pushPattern(provider) called, pattern={}, isArcanePattern={}", - patternDetails, patternDetails instanceof ArcaneAssemblerPattern); if (patternDetails instanceof ArcaneAssemblerPattern arcanePattern) { return beginCrafting(arcanePattern); } @@ -490,9 +477,6 @@ public class TileArcaneAssembler extends ThETileBase private boolean beginCrafting(ArcaneAssemblerPattern arcanePattern) { AspectList aspects = arcanePattern.getAspects(); ItemStack result = arcanePattern.getResultStack(); - ThaumicEnergistics.LOG.info("[AA] beginCrafting: isCrafting={}, active={}, aspectsEmpty={}, resultEmpty={}", - isCrafting, mainNode.isActive(), - aspects == null || aspects.isEmpty(), result.isEmpty()); if (isCrafting || !mainNode.isActive()) return false; if (aspects == null || aspects.isEmpty() || result.isEmpty()) return false; @@ -504,7 +488,6 @@ public class TileArcaneAssembler extends ThETileBase this.internalInventory.setItem(TARGET_SLOT, result.copy()); setChanged(); markForUpdate(); - ThaumicEnergistics.LOG.info("[AA] beginCrafting: STARTED, result={}, aspects={}", result, aspects.visSize()); return true; } @@ -593,7 +576,6 @@ public class TileArcaneAssembler extends ThETileBase // 守卫 getGrid()!=null:装配器未连 ME 网络(无相邻 cable)时 getGrid() 为 null, // 此时 requestUpdate 内部 node.getGrid().getCraftingService() 会 NPE,导致 kCore 插入事务回滚 → "无法绑定"。 if (level != null && !level.isClientSide() && mainNode.getGrid() != null) { - ThaumicEnergistics.LOG.info("[AA] kCore slot changed → requestUpdate"); ICraftingProvider.requestUpdate(mainNode); } } diff --git a/src/main/java/thaumicenergistics/common/tiles/TileEssentiaVibrationChamber.java b/src/main/java/thaumicenergistics/common/tiles/TileEssentiaVibrationChamber.java index c5997e0..3d7875c 100644 --- a/src/main/java/thaumicenergistics/common/tiles/TileEssentiaVibrationChamber.java +++ b/src/main/java/thaumicenergistics/common/tiles/TileEssentiaVibrationChamber.java @@ -40,12 +40,16 @@ public class TileEssentiaVibrationChamber extends ThETileBase implements IInWorl private static final int MAX_ESSENTIA = 64; private static final int BASE_BURN_TICKS = 800; - private static final double BASE_AE_PER_TICK = 20.0; + private static final double BASE_AE_PER_TICK = 200.0; private static final int IDLE_POWER = 1; - // 能量槽配置:8KFE = 8000 AE,对外最大输出 400 AE/t - public static final double MAX_ENERGY_STORAGE = 8000.0; - public static final double MAX_OUTPUT_PER_TICK = 400.0; + // 能量槽配置:16KFE = 16000 AE,对外最大输出 1000 AE/t + public static final double MAX_ENERGY_STORAGE = 16000.0; + public static final double MAX_OUTPUT_PER_TICK = 2000.0; + + // 懒 tick 周期:燃烧中 10 tick、空闲 40 tick(能量生产无需实时响应,低频即可) + private static final int TICK_RATE_BURNING = 10; + private static final int TICK_RATE_IDLE = 40; protected final IManagedGridNode mainNode; private final IGridNodeListener nodeListener = new IGridNodeListener<>() { @@ -62,7 +66,6 @@ public class TileEssentiaVibrationChamber extends ThETileBase implements IInWorl private double aePerTick; private int storedEssentia; private Aspect currentAspect; - private Aspect suctionAspect = Aspect.ENERGY; private double storedEnergy; @@ -97,7 +100,7 @@ public class TileEssentiaVibrationChamber extends ThETileBase implements IInWorl @Override public TickingRequest getTickingRequest(IGridNode node) { - return new TickingRequest(10, 40, false); + return new TickingRequest(TICK_RATE_BURNING, TICK_RATE_IDLE, false); } @Override @@ -177,8 +180,7 @@ public class TileEssentiaVibrationChamber extends ThETileBase implements IInWorl int srcAmt = source.getEssentiaAmount(sourceSide); if (!canOut) continue; if (srcType == null) continue; - String srcTag = srcType.getTag(); - if (!srcTag.equals("ignis") && !srcTag.equals("potentia") && !srcTag.equals("energy")) continue; + // 所有要素均可作为燃料(火/能量效率更高,其他要素 1/2) if (space <= 0) return; @@ -187,7 +189,7 @@ public class TileEssentiaVibrationChamber extends ThETileBase implements IInWorl if (taken > 0) { storedEssentia += taken; currentAspect = srcType; - suctionAspect = srcType; + // suctionAspect 固定为 null(通配吸力),不锁定单一类型 setChanged(); return; } @@ -240,9 +242,25 @@ public class TileEssentiaVibrationChamber extends ThETileBase implements IInWorl private boolean startBurning() { if (currentAspect == null) currentAspect = Aspect.FIRE; - boolean isPotentia = currentAspect != null && (currentAspect == Aspect.ENERGY || currentAspect.getTag().equals("potentia") || currentAspect.getTag().equals("energy")); - int burnTime = isPotentia ? (int)(BASE_BURN_TICKS / 1.6f) : BASE_BURN_TICKS / 2; - double power = isPotentia ? BASE_AE_PER_TICK * 1.6 : BASE_AE_PER_TICK; + String tag = currentAspect.getTag(); + boolean isPotentia = currentAspect == Aspect.ENERGY || tag.equals("potentia") || tag.equals("energy"); + boolean isOther = !tag.equals("ignis") && !isPotentia; + + int burnTime; + double power; + if (isPotentia) { + // 能量:1.6 倍功率,燃烧更久 + burnTime = (int)(BASE_BURN_TICKS / 1.6f); + power = BASE_AE_PER_TICK * 1.6; + } else if (isOther) { + // 其他所有要素:基础效率的 1/2 + burnTime = BASE_BURN_TICKS / 2; + power = BASE_AE_PER_TICK / 2.0; + } else { + // 火:基础效率 + burnTime = BASE_BURN_TICKS / 2; + power = BASE_AE_PER_TICK; + } burnTicksRemaining = burnTime; totalBurnTicks = burnTime; @@ -254,17 +272,16 @@ public class TileEssentiaVibrationChamber extends ThETileBase implements IInWorl @Override public boolean canInputFrom(Direction side) { return true; } @Override public boolean canOutputTo(Direction side) { return true; } @Override public void setSuction(Aspect aspect, int amount) { - this.suctionAspect = aspect; + // 通配吸力:始终吸所有源质类型,忽略外部设置 } @Override public Aspect getSuctionType(Direction side) { - return suctionAspect; + return null; // null = 通配吸力:管道可输送任意类型源质 } @Override public int getSuctionAmount(Direction side) { return 128; } private boolean isFuelAspect(Aspect aspect) { - if (aspect == null) return false; - String tag = aspect.getTag(); - return tag.equals("ignis") || tag.equals("potentia") || tag.equals("energy"); + // 所有要素均可作为燃料(火/能量效率更高,其他要素 1/2) + return aspect != null; } @Override @@ -298,11 +315,7 @@ public class TileEssentiaVibrationChamber extends ThETileBase implements IInWorl @Override public boolean renderExtendedTube() { return false; } public void setSuctionType(Aspect aspect) { - if (aspect == Aspect.FIRE || aspect == Aspect.ENERGY) { - suctionAspect = aspect; - setChanged(); - markForUpdate(); - } + // 通配吸力模式下无需设置类型;保留方法避免编译错误 } public int getStoredEssentia() { return storedEssentia; } @@ -338,7 +351,7 @@ public class TileEssentiaVibrationChamber extends ThETileBase implements IInWorl storedEnergy = tag.getDouble("StoredEnergy"); if (storedEnergy > MAX_ENERGY_STORAGE) storedEnergy = MAX_ENERGY_STORAGE; if (tag.contains("AspectTag")) currentAspect = Aspect.getAspect(tag.getString("AspectTag")); - if (tag.contains("SuctionTag")) suctionAspect = Aspect.getAspect(tag.getString("SuctionTag")); + // suctionAspect 固定为 null(通配吸力),不读取 SuctionTag } @Override @@ -352,6 +365,6 @@ public class TileEssentiaVibrationChamber extends ThETileBase implements IInWorl tag.putInt("StoredEssentia", storedEssentia); tag.putDouble("StoredEnergy", storedEnergy); if (currentAspect != null) tag.putString("AspectTag", currentAspect.getTag()); - if (suctionAspect != null) tag.putString("SuctionTag", suctionAspect.getTag()); + // suctionAspect 固定为 null(通配吸力),不写入 SuctionTag } } \ No newline at end of file diff --git a/src/main/java/thaumicenergistics/init/ModMenuTypes.java b/src/main/java/thaumicenergistics/init/ModMenuTypes.java index 7f12ac1..bfdd7da 100644 --- a/src/main/java/thaumicenergistics/init/ModMenuTypes.java +++ b/src/main/java/thaumicenergistics/init/ModMenuTypes.java @@ -1,5 +1,6 @@ package thaumicenergistics.init; +import appeng.api.implementations.menuobjects.IPortableTerminal; import appeng.api.storage.ITerminalHost; import appeng.menu.implementations.MenuTypeBuilder; import net.minecraft.core.registries.Registries; @@ -27,8 +28,16 @@ public final class ModMenuTypes { REGISTRY.register("essentia_vibration_chamber", () -> IMenuTypeExtension.create(ContainerEssentiaVibrationChamber::new)); public static final Supplier> ARCANE_ASSEMBLER = REGISTRY.register("arcane_assembler", () -> IMenuTypeExtension.create(ContainerArcaneAssembler::new)); - public static final Supplier> ESSENTIA_TERMINAL = - REGISTRY.register("essentia_terminal", () -> IMenuTypeExtension.create(ContainerEssentiaCellTerminal::new)); + /** 源质终端菜单:有线段(挂在线缆上的终端部件)。 */ + public static final Supplier> ESSENTIA_TERMINAL = + REGISTRY.register("essentia_terminal", () -> + MenuTypeBuilder.create(EssentiaTerminalMenu::new, ITerminalHost.class) + .buildUnregistered(ThaumicEnergistics.id("essentia_terminal"))); + /** 源质终端菜单:无线段(手持无线源质终端)。 */ + public static final Supplier> WIRELESS_ESSENTIA_TERMINAL = + REGISTRY.register("wireless_essentia_terminal", () -> + MenuTypeBuilder.create(EssentiaTerminalMenu::new, IPortableTerminal.class) + .buildUnregistered(ThaumicEnergistics.id("wireless_essentia_terminal"))); public static final Supplier> KNOWLEDGE_INSCRIBER = REGISTRY.register("knowledge_inscriber", () -> IMenuTypeExtension.create(ContainerKnowledgeInscriber::new)); public static final Supplier> DISTILLATION_ENCODER = @@ -38,28 +47,28 @@ public final class ModMenuTypes { REGISTRY.register("essentia_import_bus", () -> MenuTypeBuilder.create(ContainerEssentiaImportBus::new, EssentiaImportBusPart.class) .withMenuTitle(host -> host.getName() != null ? host.getName() : Component.empty()) - .build("essentia_import_bus")); + .buildUnregistered(ThaumicEnergistics.id("essentia_import_bus"))); public static final Supplier> ESSENTIA_EXPORT_BUS = REGISTRY.register("essentia_export_bus", () -> MenuTypeBuilder.create(ContainerEssentiaExportBus::new, EssentiaExportBusPart.class) .withMenuTitle(host -> host.getName() != null ? host.getName() : Component.empty()) - .build("essentia_export_bus")); + .buildUnregistered(ThaumicEnergistics.id("essentia_export_bus"))); public static final Supplier> ESSENTIA_STORAGE_BUS = REGISTRY.register("essentia_storage_bus", () -> MenuTypeBuilder.create(ContainerEssentiaStorageBus::new, EssentiaStorageBusPart.class) .withMenuTitle(host -> host.getName() != null ? host.getName() : Component.empty()) - .build("essentia_storage_bus")); + .buildUnregistered(ThaumicEnergistics.id("essentia_storage_bus"))); public static final Supplier> ARCANE_CRAFTING_TERMINAL = REGISTRY.register("arcane_crafting_terminal", () -> MenuTypeBuilder.create(ContainerArcaneCraftingTerminal::new, ITerminalHost.class) - .build("arcane_crafting_terminal")); + .buildUnregistered(ThaumicEnergistics.id("arcane_crafting_terminal"))); public static final Supplier> ESSENTIA_LEVEL_EMITTER = REGISTRY.register("essentia_level_emitter", () -> MenuTypeBuilder.create(ContainerEssentiaLevelEmitter::new, EssentiaLevelEmitterPart.class) .withMenuTitle(host -> host.getName() != null ? host.getName() : Component.empty()) - .build("essentia_level_emitter")); + .buildUnregistered(ThaumicEnergistics.id("essentia_level_emitter"))); } diff --git a/src/main/java/thaumicenergistics/integration/jei/ThEJeiPlugin.java b/src/main/java/thaumicenergistics/integration/jei/ThEJeiPlugin.java index ccb549e..6d7647c 100644 --- a/src/main/java/thaumicenergistics/integration/jei/ThEJeiPlugin.java +++ b/src/main/java/thaumicenergistics/integration/jei/ThEJeiPlugin.java @@ -49,9 +49,8 @@ public class ThEJeiPlugin implements IModPlugin { Class.forName("tamaized.ae2jeiintegration.api.integrations.jei.IngredientConverters"); Class.forName("thaumicenergistics.integration.jei.Ae2JeiCompat") .getMethod("register").invoke(null); - ThaumicEnergistics.LOG.info("[JEI] AE2-JEI-Integration detected, essentia drag-conversion registered"); } catch (ClassNotFoundException e) { - ThaumicEnergistics.LOG.info("[JEI] AE2-JEI-Integration not present, essentia drag-conversion unavailable (optional)"); + // AE2-JEI-Integration 未安装:跳过源质拖拽转换(可选功能,不影响其他 JEI 功能) } catch (ReflectiveOperationException e) { ThaumicEnergistics.LOG.warn("[JEI] AE2-JEI-Integration registration failed: {}", e.toString()); } @@ -83,7 +82,6 @@ public class ThEJeiPlugin implements IModPlugin { @Override public void registerRecipeTransferHandlers(IRecipeTransferRegistration registration) { - ThaumicEnergistics.LOG.info("[JEI] Registering ThEUseCraftingRecipeTransfer for ArcaneCraftingTerminal"); // 注册 IRecipeTransferInfo 让 JEI 显示 "+" 按钮 registration.addRecipeTransferHandler(new ArcaneCraftingTransferInfo()); registration.addRecipeTransferHandler(new ArcaneRecipeTransferInfo()); diff --git a/src/main/java/thaumicenergistics/integration/jei/ThEUseArcaneRecipeTransfer.java b/src/main/java/thaumicenergistics/integration/jei/ThEUseArcaneRecipeTransfer.java index 4ff0318..9450a27 100644 --- a/src/main/java/thaumicenergistics/integration/jei/ThEUseArcaneRecipeTransfer.java +++ b/src/main/java/thaumicenergistics/integration/jei/ThEUseArcaneRecipeTransfer.java @@ -1,5 +1,7 @@ package thaumicenergistics.integration.jei; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -24,10 +26,14 @@ import net.neoforged.neoforge.network.PacketDistributor; import thaumcraft.integration.jei.JeiArcaneRecipe; import thaumcraft.integration.jei.ThaumcraftJeiPlugin; -import thaumicenergistics.ThaumicEnergistics; import thaumicenergistics.common.container.ContainerArcaneCraftingTerminal; import thaumicenergistics.init.ModMenuTypes; +import static appeng.integration.modules.itemlists.TransferHelper.BLUE_PLUS_BUTTON_COLOR; +import static appeng.integration.modules.itemlists.TransferHelper.BLUE_SLOT_HIGHLIGHT_COLOR; +import static appeng.integration.modules.itemlists.TransferHelper.ORANGE_PLUS_BUTTON_COLOR; +import static appeng.integration.modules.itemlists.TransferHelper.RED_SLOT_HIGHLIGHT_COLOR; + /** * 奥术合成终端专用的 JEI 奥术配方转移处理器。 * 点击 "+" 时发送 FillCraftingGridFromRecipePacket 从 ME 网络填充材料。 @@ -65,13 +71,31 @@ public class ThEUseArcaneRecipeTransfer boolean maxTransfer, boolean doTransfer) { - ThaumicEnergistics.LOG.info("[JEI-Arcane] transferRecipe called, recipeId={}, doTransfer={}", - recipe.id(), doTransfer); - boolean craftMissing = AbstractContainerScreen.hasControlDown(); - // 预览:始终 null(绿色按钮),由服务端处理实际缺失 + // 构建 3x3 合成格 slot→ingredient 映射,检测材料缺失(与普通配方一致) + var slotToIngredientMap = buildSlotToIngredientMap(recipe); + var missingSlots = menu.findMissingIngredients(slotToIngredientMap); + + // 全部缺失 → 红色,无法点击 + if (missingSlots.missingSlots().size() == slotToIngredientMap.size()) { + var inputSlots = display.getSlotViews(RecipeIngredientRole.INPUT); + var missingSlotViews = missingSlots.missingSlots().stream() + .map(idx -> idx < inputSlots.size() ? inputSlots.get(idx) : null) + .filter(Objects::nonNull) + .toList(); + return helper.createUserErrorForMissingSlots( + appeng.core.localization.ItemModText.NO_ITEMS.text(), missingSlotViews); + } + + // 预览:检查缺失情况,返回对应的错误渲染 if (!doTransfer) { + if (missingSlots.totalSize() != 0) { + int color = missingSlots.anyMissing() ? ORANGE_PLUS_BUTTON_COLOR : BLUE_PLUS_BUTTON_COLOR; + // 有缺料 → Type.ERROR 阻止转移(按钮不可点),有料也不允许部分填充 + return new ThEUseCraftingRecipeTransfer.MissingSlotsError( + missingSlots, craftMissing, color, missingSlots.anyMissing(), menu); + } return null; } @@ -88,10 +112,23 @@ public class ThEUseArcaneRecipeTransfer // 奥术配方不在 vanilla 配方管理器中,recipeId 传 null // 服务端会用 Ingredient.of(templateItems) 重建,然后从 ME 网络提取 var packet = new FillCraftingGridFromRecipePacket(null, templateItems, craftMissing); - ThaumicEnergistics.LOG.info("[JEI-Arcane] Sending FillCraftingGridFromRecipePacket, templateCount={}", - templateItems.stream().filter(s -> !s.isEmpty()).count()); PacketDistributor.sendToServer(packet); return null; } + + /** + * 根据奥术配方 inputs(9 槽 List>)构建 3x3 合成格 slot → ingredient 映射。 + */ + private static Map buildSlotToIngredientMap(JeiArcaneRecipe recipe) { + Map map = new HashMap<>(); + var inputs = recipe.inputs(); + for (int i = 0; i < inputs.size() && i < 9; i++) { + var variants = inputs.get(i); + if (variants != null && !variants.isEmpty()) { + map.put(i, Ingredient.of(variants.stream())); + } + } + return map; + } } diff --git a/src/main/java/thaumicenergistics/integration/jei/ThEUseCraftingRecipeTransfer.java b/src/main/java/thaumicenergistics/integration/jei/ThEUseCraftingRecipeTransfer.java index 1554211..55d0be8 100644 --- a/src/main/java/thaumicenergistics/integration/jei/ThEUseCraftingRecipeTransfer.java +++ b/src/main/java/thaumicenergistics/integration/jei/ThEUseCraftingRecipeTransfer.java @@ -82,8 +82,6 @@ public class ThEUseCraftingRecipeTransfer boolean doTransfer) { var recipe = recipeHolder.value(); - ThaumicEnergistics.LOG.info("[JEI] transferRecipe called, recipeId={}, doTransfer={}, player={}", - recipeHolder.id(), doTransfer, player.getName().getString()); if (recipe.getType() != RecipeType.CRAFTING) { ThaumicEnergistics.LOG.warn("[JEI] Not a crafting recipe, type={}", recipe.getType()); return helper.createInternalError(); @@ -96,16 +94,14 @@ public class ThEUseCraftingRecipeTransfer } boolean craftMissing = AbstractContainerScreen.hasControlDown(); - // 自行构建 slot→ingredient 映射(0-8 对应 3x3 合成格), - // 不依赖 helper.getGuiSlotIndexToIngredientMap(需要 IRecipeTransferInfo 才能正确工作) - var slotToIngredientMap = buildSlotToIngredientMap(recipe); + // 用 JEI 官方映射 helper.getGuiSlotIndexToIngredientMap:配方居中摆入 3x3 网格, + // 键空间与 JEI 输入槽视图完全一致。之前用 ensure3by3CraftingMatrix(左上对齐填充), + // 对非 3x3 配方(如 2x2 笔与墨)索引错位,导致缺失高亮画到错误的格子上。 + var slotToIngredientMap = helper.getGuiSlotIndexToIngredientMap(recipeHolder); var missingSlots = menu.findMissingIngredients(slotToIngredientMap); - ThaumicEnergistics.LOG.info("[JEI] missingSlots: missing={}, craftable={}, total={}", - missingSlots.missingSlots().size(), missingSlots.craftableSlots().size(), missingSlots.totalSize()); // 全部缺失 → 红色,无法点击 if (missingSlots.missingSlots().size() == slotToIngredientMap.size()) { - ThaumicEnergistics.LOG.info("[JEI] All items missing, returning NO_ITEMS error"); var inputSlots = display.getSlotViews(RecipeIngredientRole.INPUT); var missingSlotViews = missingSlots.missingSlots().stream() .map(idx -> idx < inputSlots.size() ? inputSlots.get(idx) : null) @@ -119,7 +115,8 @@ public class ThEUseCraftingRecipeTransfer if (!doTransfer) { if (missingSlots.totalSize() != 0) { int color = missingSlots.anyMissing() ? ORANGE_PLUS_BUTTON_COLOR : BLUE_PLUS_BUTTON_COLOR; - return new MissingSlotsError(missingSlots, craftMissing, color); + // 有缺料 → USER_FACING 阻止转移(按钮不可点);仅可合成(craftable)不阻止(可触发自动合成) + return new MissingSlotsError(missingSlots, craftMissing, color, missingSlots.anyMissing(), menu); } // 全部物品都有 → null = 绿色按钮 return null; @@ -145,42 +142,28 @@ public class ThEUseCraftingRecipeTransfer } var packet = new FillCraftingGridFromRecipePacket(recipeId, templateItems, craftMissing); - ThaumicEnergistics.LOG.info("[JEI] Sending FillCraftingGridFromRecipePacket, recipeId={}, templateCount={}, craftMissing={}", - recipeId, templateItems.stream().filter(s -> !s.isEmpty()).count(), craftMissing); PacketDistributor.sendToServer(packet); return null; } - /** - * 根据配方构建 3x3 合成格的 slot index → ingredient 映射。 - * 使用 CraftingRecipeUtil.ensure3by3CraftingMatrix 确保 9 格对齐, - * 与实际转移时的索引体系完全一致。 - */ - private static Map buildSlotToIngredientMap(CraftingRecipe recipe) { - var ingredients = CraftingRecipeUtil.ensure3by3CraftingMatrix(recipe); - Map map = new HashMap<>(); - for (int i = 0; i < ingredients.size() && i < 9; i++) { - var ing = ingredients.get(i); - if (!ing.isEmpty()) { - map.put(i, ing); - } - } - return map; - } - /** * 缺失/可合成物品的预览错误渲染器。 * 参考 AE2-JEI-Integration.UseCraftingRecipeTransfer.ErrorRenderer。 + * 供奥术配方转移(ThEUseArcaneRecipeTransfer)复用。 + * blockTransfer=true 时返回 ERROR(阻止转移,按钮灰/橙不可点)。 */ - private record MissingSlotsError( + public record MissingSlotsError( ContainerArcaneCraftingTerminal.MissingIngredientSlots indices, boolean craftMissing, - int color) implements IRecipeTransferError { + int color, + boolean blockTransfer, + ContainerArcaneCraftingTerminal menu) implements IRecipeTransferError { @Override public Type getType() { - return Type.COSMETIC; + // USER_FACING 阻止转移(allowsTransfer=false)且显示错误;COSMETIC 仅预览 + return blockTransfer ? Type.USER_FACING : Type.COSMETIC; } @Override @@ -195,16 +178,20 @@ public class ThEUseCraftingRecipeTransfer poseStack.pushPose(); poseStack.translate(recipeX, recipeY, 0); - var slotViews = slots.getSlotViews(RecipeIngredientRole.INPUT); - for (int i = 0; i < slotViews.size(); i++) { - var slotView = slotViews.get(i); + // 用 JEI 槽视图 drawHighlight 画高亮(AE2-JEI-Integration 官方做法)。 + // 不能用 menu.slots 的容器坐标:奥术终端槽位顺序与配方格不对应, + // 且 translate(recipeX,recipeY) 后再用相对坐标会双重偏移 → 红框画到屏幕外。 + var inputSlots = slots.getSlotViews(RecipeIngredientRole.INPUT); + for (int i = 0; i < 9; i++) { boolean missing = indices.missingSlots().contains(i); boolean craftable = indices.craftableSlots().contains(i); - if (missing || craftable) { - slotView.drawHighlight( - guiGraphics, - missing ? RED_SLOT_HIGHLIGHT_COLOR : BLUE_SLOT_HIGHLIGHT_COLOR); - } + if (!missing && !craftable) continue; + if (i >= inputSlots.size()) continue; + var slotView = inputSlots.get(i); + slotView.drawHighlight(guiGraphics, + missing ? RED_SLOT_HIGHLIGHT_COLOR : BLUE_SLOT_HIGHLIGHT_COLOR); + ThaumicEnergistics.LOG.info("[JEI-Transfer] showError slot={} missing={} craftable={}", + i, missing, craftable); } poseStack.popPose(); @@ -221,15 +208,15 @@ public class ThEUseCraftingRecipeTransfer int craftable = indices.craftableSlots().size(); if (missing > 0) { tooltip.add(net.minecraft.network.chat.Component.translatable( - "jei.tooltip.transfer.missing", missing)); + "thaumicenergistics.jei.transfer.missing", missing)); } if (craftable > 0) { tooltip.add(net.minecraft.network.chat.Component.translatable( - "jei.tooltip.transfer.craftable", craftable)); + "thaumicenergistics.jei.transfer.craftable", craftable)); } if (craftMissing) { tooltip.add(net.minecraft.network.chat.Component.translatable( - "jei.tooltip.transfer.ctrl.click")); + "thaumicenergistics.jei.transfer.ctrl_click")); } } } diff --git a/src/main/resources/META-INF/neoforge.mods.toml b/src/main/resources/META-INF/neoforge.mods.toml index a5020aa..e76744f 100644 --- a/src/main/resources/META-INF/neoforge.mods.toml +++ b/src/main/resources/META-INF/neoforge.mods.toml @@ -35,7 +35,7 @@ side="BOTH" [[dependencies.thaumicenergistics]] modId="thaumcraft" type="required" -versionRange="[0,)" +versionRange="[0.2.2.95,)" ordering="AFTER" side="BOTH" diff --git a/src/main/resources/assets/ae2/screens/arcane_crafting_terminal.json b/src/main/resources/assets/ae2/screens/arcane_crafting_terminal.json index 1978d9c..795756d 100644 --- a/src/main/resources/assets/ae2/screens/arcane_crafting_terminal.json +++ b/src/main/resources/assets/ae2/screens/arcane_crafting_terminal.json @@ -32,7 +32,16 @@ }, "position": { "left": 8, - "bottom": 177 + "bottom": 179 + } + }, + "player_inventory_title": { + "text": { + "translate": "container.inventory" + }, + "position": { + "left": 8, + "bottom": 94 } } }, diff --git a/src/main/resources/assets/thaumicenergistics/lang/en_us.json b/src/main/resources/assets/thaumicenergistics/lang/en_us.json index 9e03af2..7f4b1eb 100644 --- a/src/main/resources/assets/thaumicenergistics/lang/en_us.json +++ b/src/main/resources/assets/thaumicenergistics/lang/en_us.json @@ -111,5 +111,8 @@ "thaumicenergistics.jade.energy_stored": "Stored: %s / %s", "thaumicenergistics.jade.energy_output": "Output Limit: %s AE/tick", "thaumicenergistics.jade.tank_full": "Tank full, generation stopped", - "thaumicenergistics.gui.distillation_encoder.not_scanned": "Not scanned" + "thaumicenergistics.gui.distillation_encoder.not_scanned": "Not scanned", + "thaumicenergistics.jei.transfer.missing": "Missing: %d", + "thaumicenergistics.jei.transfer.craftable": "Craftable: %d", + "thaumicenergistics.jei.transfer.ctrl_click": "Use Ctrl to craft missing items" } \ No newline at end of file diff --git a/src/main/resources/assets/thaumicenergistics/lang/zh_cn.json b/src/main/resources/assets/thaumicenergistics/lang/zh_cn.json index 674cd61..261440e 100644 --- a/src/main/resources/assets/thaumicenergistics/lang/zh_cn.json +++ b/src/main/resources/assets/thaumicenergistics/lang/zh_cn.json @@ -121,7 +121,7 @@ "tc.research_name.PSEUDO_SCEPTRE": "工艺权杖", "tc.research_name.PSEUDO_COREGATHER": "傀儡核心:聚集", - "thaumicenergistics.jade.suction_type": "吸力: %s", + "thaumicenergistics.jade.current_aspect": "燃料: %s", "thaumicenergistics.jade.essentia_stored": "源质: %d / %d", "thaumicenergistics.jade.burning": "燃烧 %d%%, %.1f AE/tick", "thaumicenergistics.aspect.ignis": "火", @@ -130,5 +130,8 @@ "thaumicenergistics.jade.energy_stored": "已存储: %s / %s", "thaumicenergistics.jade.energy_output": "输出上限: %s AE/tick", "thaumicenergistics.jade.tank_full": "能量槽已满,停止发电", - "thaumicenergistics.gui.distillation_encoder.not_scanned": "未扫描" + "thaumicenergistics.gui.distillation_encoder.not_scanned": "未扫描", + "thaumicenergistics.jei.transfer.missing": "缺少: %d", + "thaumicenergistics.jei.transfer.craftable": "可合成: %d", + "thaumicenergistics.jei.transfer.ctrl_click": "按住 Ctrl 合成缺失物品" } \ No newline at end of file diff --git a/src/main/resources/assets/thaumicenergistics/textures/gui/arcane_crafting.png b/src/main/resources/assets/thaumicenergistics/textures/gui/arcane_crafting.png index 82ea9628757728810fd1bdaef7456541f86f5204..a1c868835e7fe5ad32131da92e3365c605396ed8 100644 GIT binary patch literal 19382 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 diff --git a/src/main/resources/assets/thaumicenergistics/textures/model/golembackpack/clay.png b/src/main/resources/assets/thaumicenergistics/textures/model/golembackpack/clay.png deleted file mode 100644 index 3e8f4b7387ef2fd20ce7cbdd4c9803e771f31773..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4252 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 A0RR91 diff --git a/src/main/resources/assets/thaumicenergistics/textures/model/golembackpack/gold.png b/src/main/resources/assets/thaumicenergistics/textures/model/golembackpack/gold.png deleted file mode 100644 index 6c98730ec65364c9d1cfc5c8863adfe6b166afa9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4348 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 diff --git a/src/main/resources/assets/thaumicenergistics/textures/model/golembackpack/stone.png b/src/main/resources/assets/thaumicenergistics/textures/model/golembackpack/stone.png deleted file mode 100644 index ea52fceec4b2b257988899c00372e4a275cadae9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4343 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 diff --git a/src/main/resources/assets/thaumicenergistics/textures/model/golembackpack/thaum.png b/src/main/resources/assets/thaumicenergistics/textures/model/golembackpack/thaum.png deleted file mode 100644 index effad48564cac485be6da2fdb78231014a807f62..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3836 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