From f0ef9f9a5e684c49ceb6f246bd8af31e096f4f85 Mon Sep 17 00:00:00 2001 From: TBPig <147127248+TBPig@users.noreply.github.com> Date: Thu, 12 Feb 2026 13:02:31 +0800 Subject: [PATCH 1/9] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=B1=BC=E7=BC=B8?= =?UTF-8?q?=E5=8F=8A=E5=85=B6=E9=83=A8=E5=88=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../assets/anvilcraft/lang/en_ud.json | 2 + .../assets/anvilcraft/lang/en_us.json | 2 + .../anvilcraft/models/item/fish_tank.json | 3 + .../advancement/recipes/misc/fish_tank.json | 32 +++++++ .../loot_table/blocks/fish_tank.json | 21 ++++ .../data/anvilcraft/recipe/fish_tank.json | 21 ++++ .../data/minecraft/tags/block/cauldrons.json | 1 + .../tags/block/mineable/pickaxe.json | 1 + .../api/tooltip/ItemTooltipManager.java | 5 + .../dubhe/anvilcraft/block/FishTankBlock.java | 95 +++++++++++++++++++ .../anvilcraft/init/block/ModBlocks.java | 27 +++++- .../anvilcraft/item/FishTankBlockItem.java | 40 ++++++++ .../anvilcraft/blockstates/fish_tank.json | 60 ++++++++++++ .../anvilcraft/models/block/fish_tank.json | 11 +++ 14 files changed, 320 insertions(+), 1 deletion(-) create mode 100644 src/generated/resources/assets/anvilcraft/models/item/fish_tank.json create mode 100644 src/generated/resources/data/anvilcraft/advancement/recipes/misc/fish_tank.json create mode 100644 src/generated/resources/data/anvilcraft/loot_table/blocks/fish_tank.json create mode 100644 src/generated/resources/data/anvilcraft/recipe/fish_tank.json create mode 100644 src/main/java/dev/dubhe/anvilcraft/block/FishTankBlock.java create mode 100644 src/main/java/dev/dubhe/anvilcraft/item/FishTankBlockItem.java create mode 100644 src/main/resources/assets/anvilcraft/blockstates/fish_tank.json diff --git a/src/generated/resources/assets/anvilcraft/lang/en_ud.json b/src/generated/resources/assets/anvilcraft/lang/en_ud.json index 9f083e793..a3e0f5017 100644 --- a/src/generated/resources/assets/anvilcraft/lang/en_ud.json +++ b/src/generated/resources/assets/anvilcraft/lang/en_ud.json @@ -313,6 +313,7 @@ "block.anvilcraft.exposed_copper_pressure_plate": "ǝʇɐןԀ ǝɹnssǝɹԀ ɹǝddoƆ pǝsodxƎ", "block.anvilcraft.ferrite_core_magnet_block": "ʇǝubɐW ɟo ʞɔoןᗺ pǝɹoƆ-ǝʇıɹɹǝℲ", "block.anvilcraft.fire_cauldron": "uoɹpןnɐƆ ǝɹıℲ", + "block.anvilcraft.fish_tank": "ʞuɐ⟘ ɥsıℲ", "block.anvilcraft.flint_block": "ʞɔoןᗺ ʇuıןℲ", "block.anvilcraft.frost_anvil": "ןıʌuⱯ ʇsoɹℲ", "block.anvilcraft.frost_glass": "ssɐן⅁ ʇsoɹℲ", @@ -1238,6 +1239,7 @@ "tooltip.anvilcraft.item.feather_amulet": "ǝbɐɯɐp ןןɐɟ oʇ ʎʇıunɯɯı sʇuɐɹ⅁", "tooltip.anvilcraft.item.ferrite_core_magnet_block": "sǝbɹɐɥɔ ǝʇɐɹǝuǝb oʇ sʞɔoןq ɹǝddoɔ ʇuǝɔɐظpɐ sǝsnɐɔ 'uoʇsıd ǝɥʇ ʎq pǝןןnd puɐ pǝɥsnd uǝɥʍ 'ʍoןǝq ןıʌuɐ ǝɥʇ buıʇɔɐɹʇʇⱯ", "tooltip.anvilcraft.item.filter": "ʇoןs ɹǝʇןıɟ ʎuɐ uı ǝןqɐs∩ ˙sɹǝʇןıɟ ɹo bıɟuoɔ uo pǝsɐq sɯǝʇı sǝɥɔʇɐW", + "tooltip.anvilcraft.item.fish_tank": "˙ɥsıɟ ןɐɔıdoɹʇ ǝɥʇ ǝsɐǝןǝɹ oʇ puɐɥ uı ʇǝʞɔnq ɥsıɟ ןɐɔıdoɹʇ ɐ ɥʇıʍ ʞuɐʇ ɥsıɟ ǝɥʇ ɟo ʇɹɐd ɹǝʍoן ǝɥʇ ʞɔıןɔ-ʇɥbıᴚ\n˙ǝpısuı ɯǝʇı ǝɥʇ ǝɔɐןd oʇ puɐɥ uı ɯǝʇı uɐ ɥʇıʍ doʇ ǝɥʇ ʞɔıןɔ-ʇɥbıᴚ\n˙ʇɔǝɟɟǝ buıɥʇɐǝɹq ɹǝʇɐʍɹǝpun ʎɹɐɹodɯǝʇ ɐ sǝpıʌoɹd pɐǝɥ ɹnoʎ uo ʇı buıɹɐǝM\n˙sısǝɥʇuʎs ןıʌuɐ pǝʇɐןǝɹ ɯɹoɟɹǝd oʇ ʇod ʎɯǝɥɔןɐ ǝɥʇ ɹoɟ ǝʇnʇıʇsqns ɐ sɐ pǝsn ǝq uɐɔ puɐ sʞooן ʇı uɐɥʇ ɹǝıpɹnʇs sı ʇI", "tooltip.anvilcraft.item.frost_anvil": "ɟooɹd ɹǝɥʇıM", "tooltip.anvilcraft.item.frost_grindstone": "ɟooɹd ɹǝɥʇıM", "tooltip.anvilcraft.item.frost_smithing_table": "ɟooɹd ɹǝɥʇıM", diff --git a/src/generated/resources/assets/anvilcraft/lang/en_us.json b/src/generated/resources/assets/anvilcraft/lang/en_us.json index 37047d82b..3a0341566 100644 --- a/src/generated/resources/assets/anvilcraft/lang/en_us.json +++ b/src/generated/resources/assets/anvilcraft/lang/en_us.json @@ -313,6 +313,7 @@ "block.anvilcraft.exposed_copper_pressure_plate": "Exposed Copper Pressure Plate", "block.anvilcraft.ferrite_core_magnet_block": "Ferrite-Cored Block of Magnet", "block.anvilcraft.fire_cauldron": "Fire Cauldron", + "block.anvilcraft.fish_tank": "Fish Tank", "block.anvilcraft.flint_block": "Flint Block", "block.anvilcraft.frost_anvil": "Frost Anvil", "block.anvilcraft.frost_glass": "Frost Glass", @@ -1238,6 +1239,7 @@ "tooltip.anvilcraft.item.feather_amulet": "Grants immunity to fall damage", "tooltip.anvilcraft.item.ferrite_core_magnet_block": "Attracting the anvil below, when pushed and pulled by the piston, causes adjacent copper blocks to generate charges", "tooltip.anvilcraft.item.filter": "Matches items based on config or filters. Usable in any filter slot", + "tooltip.anvilcraft.item.fish_tank": "It is sturdier than it looks and can be used as a substitute for the alchemy pot to perform related anvil synthesis.\nWearing it on your head provides a temporary underwater breathing effect.\nRight-click the top with an item in hand to place the item inside.\nRight-click the lower part of the fish tank with a tropical fish bucket in hand to release the tropical fish.", "tooltip.anvilcraft.item.frost_anvil": "Wither proof", "tooltip.anvilcraft.item.frost_grindstone": "Wither proof", "tooltip.anvilcraft.item.frost_smithing_table": "Wither proof", diff --git a/src/generated/resources/assets/anvilcraft/models/item/fish_tank.json b/src/generated/resources/assets/anvilcraft/models/item/fish_tank.json new file mode 100644 index 000000000..6037e3829 --- /dev/null +++ b/src/generated/resources/assets/anvilcraft/models/item/fish_tank.json @@ -0,0 +1,3 @@ +{ + "parent": "anvilcraft:block/fish_tank" +} \ No newline at end of file diff --git a/src/generated/resources/data/anvilcraft/advancement/recipes/misc/fish_tank.json b/src/generated/resources/data/anvilcraft/advancement/recipes/misc/fish_tank.json new file mode 100644 index 000000000..00d23c071 --- /dev/null +++ b/src/generated/resources/data/anvilcraft/advancement/recipes/misc/fish_tank.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_iron_ingot": { + "conditions": { + "items": [ + { + "items": "minecraft:iron_ingot" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "anvilcraft:fish_tank" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_iron_ingot" + ] + ], + "rewards": { + "recipes": [ + "anvilcraft:fish_tank" + ] + } +} \ No newline at end of file diff --git a/src/generated/resources/data/anvilcraft/loot_table/blocks/fish_tank.json b/src/generated/resources/data/anvilcraft/loot_table/blocks/fish_tank.json new file mode 100644 index 000000000..b2adb3301 --- /dev/null +++ b/src/generated/resources/data/anvilcraft/loot_table/blocks/fish_tank.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "anvilcraft:fish_tank" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "anvilcraft:blocks/fish_tank" +} \ No newline at end of file diff --git a/src/generated/resources/data/anvilcraft/recipe/fish_tank.json b/src/generated/resources/data/anvilcraft/recipe/fish_tank.json new file mode 100644 index 000000000..b34385b01 --- /dev/null +++ b/src/generated/resources/data/anvilcraft/recipe/fish_tank.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "misc", + "key": { + "A": { + "item": "minecraft:iron_ingot" + }, + "B": { + "tag": "c:glass_panes" + } + }, + "pattern": [ + "A A", + "B B", + "BBB" + ], + "result": { + "count": 1, + "id": "anvilcraft:fish_tank" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/block/cauldrons.json b/src/generated/resources/data/minecraft/tags/block/cauldrons.json index 82d13a849..6c7c95acf 100644 --- a/src/generated/resources/data/minecraft/tags/block/cauldrons.json +++ b/src/generated/resources/data/minecraft/tags/block/cauldrons.json @@ -1,5 +1,6 @@ { "values": [ + "anvilcraft:fish_tank", "anvilcraft:lava_cauldron", "anvilcraft:melt_gem_cauldron", "anvilcraft:honey_cauldron", diff --git a/src/generated/resources/data/minecraft/tags/block/mineable/pickaxe.json b/src/generated/resources/data/minecraft/tags/block/mineable/pickaxe.json index 3c1e0d18b..0d9a9417c 100644 --- a/src/generated/resources/data/minecraft/tags/block/mineable/pickaxe.json +++ b/src/generated/resources/data/minecraft/tags/block/mineable/pickaxe.json @@ -5,6 +5,7 @@ "anvilcraft:ferrite_core_magnet_block", "anvilcraft:stamping_platform", "anvilcraft:crushing_table", + "anvilcraft:fish_tank", "anvilcraft:corrupted_beacon", "anvilcraft:giant_anvil", "anvilcraft:spectral_anvil", diff --git a/src/main/java/dev/dubhe/anvilcraft/api/tooltip/ItemTooltipManager.java b/src/main/java/dev/dubhe/anvilcraft/api/tooltip/ItemTooltipManager.java index b88e7ccb8..a4a2a8755 100644 --- a/src/main/java/dev/dubhe/anvilcraft/api/tooltip/ItemTooltipManager.java +++ b/src/main/java/dev/dubhe/anvilcraft/api/tooltip/ItemTooltipManager.java @@ -63,6 +63,11 @@ public class ItemTooltipManager { "Attracting the anvil below, when pushed and pulled by the piston, causes adjacent copper blocks to generate charges"); map.put(ModBlocks.BATCH_CRAFTER.asItem(), "Received a redstone signal and synthesized all internal items at once, with a power consumption of 4 kW"); + map.put(ModBlocks.FISH_TANK.asItem(),""" + It is sturdier than it looks and can be used as a substitute for the alchemy pot to perform related anvil synthesis. + Wearing it on your head provides a temporary underwater breathing effect. + Right-click the top with an item in hand to place the item inside. + Right-click the lower part of the fish tank with a tropical fish bucket in hand to release the tropical fish."""); map.put(ModBlocks.ROYAL_STEEL_BLOCK.asItem(), "Explosion proof"); map.put(ModBlocks.SMOOTH_ROYAL_STEEL_BLOCK.asItem(), "Explosion proof"); map.put(ModBlocks.CUT_ROYAL_STEEL_BLOCK.asItem(), "Explosion proof"); diff --git a/src/main/java/dev/dubhe/anvilcraft/block/FishTankBlock.java b/src/main/java/dev/dubhe/anvilcraft/block/FishTankBlock.java new file mode 100644 index 000000000..0c6938f14 --- /dev/null +++ b/src/main/java/dev/dubhe/anvilcraft/block/FishTankBlock.java @@ -0,0 +1,95 @@ +package dev.dubhe.anvilcraft.block; + +import com.mojang.serialization.MapCodec; +import dev.dubhe.anvilcraft.api.hammer.HammerRotateBehavior; +import dev.dubhe.anvilcraft.api.hammer.IHammerRemovable; +import dev.dubhe.anvilcraft.init.item.ModItemTags; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +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.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.BooleanOp; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; + +public class FishTankBlock extends Block implements HammerRotateBehavior, IHammerRemovable { + public static final BooleanProperty TROPICAL = BooleanProperty.create("tropical"); + public static final BooleanProperty OUTLET = BooleanProperty.create("outlet"); + public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; + + public static final VoxelShape INPUT = box(2.0, 14.0, 2.0, 14.0, 16.0, 14.0); + public static final VoxelShape INSIDE = box(1.0, 1.0, 1.0, 15.0, 14.0, 15.0); + public static final VoxelShape SHAPE = Shapes.join(Shapes.block(), Shapes.join(INSIDE, INPUT, BooleanOp.OR), BooleanOp.ONLY_FIRST); + + public FishTankBlock(Properties properties) { + super(properties); + this.registerDefaultState(this.stateDefinition.any() + .setValue(TROPICAL, false) + .setValue(OUTLET, false) + .setValue(FACING, Direction.NORTH)); + } + + @Override + protected MapCodec codec() { + return simpleCodec(FishTankBlock::new); + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(TROPICAL, OUTLET, FACING); + } + + @Override + protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { + return SHAPE; + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + Direction facing = context.getHorizontalDirection().getOpposite(); + return this.defaultBlockState().setValue(FACING, facing); + } + + @Override + protected ItemInteractionResult useItemOn( + ItemStack stack, + BlockState state, + Level level, + BlockPos pos, + Player player, + InteractionHand hand, + BlockHitResult hitResult + ) { + if (!stack.is(ModItemTags.ANVIL_HAMMER)) { + return super.useItemOn(stack, state, level, pos, player, hand, hitResult); + } + // 切换 OUTLET 状态 + if (!level.isClientSide()) { + // 水平的四个方向根据被右键的方向转换 + Direction newOutletDirection = Direction.from2DDataValue((hitResult.getDirection().get2DDataValue())); + boolean newOutletValue = !state.getValue(OUTLET); + BlockState newState = state.setValue(OUTLET, newOutletValue).setValue(FACING, newOutletDirection); + + level.setBlock(pos, newState, 3); + level.playSound(null, pos, SoundEvents.ITEM_FRAME_ADD_ITEM, SoundSource.BLOCKS, 1.0f, 1.0f); + } + + return ItemInteractionResult.SUCCESS; + + } +} \ No newline at end of file diff --git a/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlocks.java b/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlocks.java index cc74adb80..fffd89a22 100644 --- a/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlocks.java +++ b/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlocks.java @@ -46,6 +46,7 @@ import dev.dubhe.anvilcraft.block.ExpFluidCauldronBlock; import dev.dubhe.anvilcraft.block.FerriteCoreMagnetBlock; import dev.dubhe.anvilcraft.block.FireCauldronBlock; +import dev.dubhe.anvilcraft.block.FishTankBlock; import dev.dubhe.anvilcraft.block.FlintBlock; import dev.dubhe.anvilcraft.block.FrostAnvilBlock; import dev.dubhe.anvilcraft.block.FrostGrindstoneBlock; @@ -176,6 +177,7 @@ import dev.dubhe.anvilcraft.init.item.ModItemGroups; import dev.dubhe.anvilcraft.init.item.ModItemTags; import dev.dubhe.anvilcraft.init.item.ModItems; +import dev.dubhe.anvilcraft.item.FishTankBlockItem; import dev.dubhe.anvilcraft.item.TeslaTowerItem; import dev.dubhe.anvilcraft.recipe.anvil.wrap.ItemInjectRecipe; import dev.dubhe.anvilcraft.recipe.multiblock.MultiblockRecipe; @@ -242,7 +244,12 @@ import static dev.dubhe.anvilcraft.api.power.IPowerComponent.OVERLOAD; import static dev.dubhe.anvilcraft.api.power.IPowerComponent.SWITCH; -@SuppressWarnings({"unused", "CodeBlock2Expr"}) +@SuppressWarnings( + { + "unused", + "CodeBlock2Expr" + } +) public class ModBlocks { static { REGISTRATE.defaultCreativeTab(ModItemGroups.ANVILCRAFT_FUNCTION_BLOCK.getKey()); @@ -358,6 +365,24 @@ public class ModBlocks { }) .register(); + public static final BlockEntry FISH_TANK = REGISTRATE.block("fish_tank", FishTankBlock::new) + .initialProperties(() -> Blocks.CAULDRON) + .blockstate(DataGenUtil::noExtraModelOrState) + .item(FishTankBlockItem::new) + .build() + .tag(BlockTags.MINEABLE_WITH_PICKAXE, BlockTags.CAULDRONS) + .recipe((ctx, provider) -> { + ShapedRecipeBuilder.shaped(RecipeCategory.MISC, ctx.get()) + .pattern("A A") + .pattern("B B") + .pattern("BBB") + .define('A', Items.IRON_INGOT) + .define('B', Tags.Items.GLASS_PANES) + .unlockedBy(AnvilCraftDatagen.hasItem(Items.IRON_INGOT), AnvilCraftDatagen.has(Items.IRON_INGOT)) + .save(provider); + }) + .register(); + public static final BlockEntry CORRUPTED_BEACON = REGISTRATE.block("corrupted_beacon", CorruptedBeaconBlock::new) .initialProperties(() -> Blocks.BEACON) .properties(p -> p.isValidSpawn(Blocks::never)) diff --git a/src/main/java/dev/dubhe/anvilcraft/item/FishTankBlockItem.java b/src/main/java/dev/dubhe/anvilcraft/item/FishTankBlockItem.java new file mode 100644 index 000000000..1e094c393 --- /dev/null +++ b/src/main/java/dev/dubhe/anvilcraft/item/FishTankBlockItem.java @@ -0,0 +1,40 @@ +package dev.dubhe.anvilcraft.item; + +import dev.dubhe.anvilcraft.init.block.ModBlocks; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Equipable; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; + +public class FishTankBlockItem extends BlockItem implements Equipable { + public FishTankBlockItem(Block block, Properties properties) { + super(block, properties); + } + + @Override + public EquipmentSlot getEquipmentSlot() { + return EquipmentSlot.HEAD; + } + + @Override + public boolean canEquip(ItemStack stack, EquipmentSlot armorType, LivingEntity entity) { + return armorType == EquipmentSlot.HEAD; + } + + @Override + public void inventoryTick(ItemStack stack, Level level, Entity entity, int slotId, boolean isSelected) { + super.inventoryTick(stack, level, entity, slotId, isSelected); + if (level.isClientSide()) return; + if (!(entity instanceof Player player)) return; + ItemStack headSlot = player.getItemBySlot(EquipmentSlot.HEAD); + if (!headSlot.getItem().equals(ModBlocks.FISH_TANK.asItem()) || player.isInWater()) return; + player.addEffect(new MobEffectInstance(MobEffects.WATER_BREATHING, 601, 0, false, false)); + } +} \ No newline at end of file diff --git a/src/main/resources/assets/anvilcraft/blockstates/fish_tank.json b/src/main/resources/assets/anvilcraft/blockstates/fish_tank.json new file mode 100644 index 000000000..888cfb531 --- /dev/null +++ b/src/main/resources/assets/anvilcraft/blockstates/fish_tank.json @@ -0,0 +1,60 @@ +{ + "multipart": [ + { + "when": { + "tropical": "false" + }, + "apply": { + "model": "anvilcraft:block/fish_tank" + } + }, + { + "when": { + "tropical": "true" + }, + "apply": { + "model": "anvilcraft:block/tropical_fish_tank" + } + }, + { + "when": { + "outlet": "true", + "facing": "north" + }, + "apply": { + "model": "anvilcraft:block/fish_tank_outlet", + "y": 0 + } + }, + { + "when": { + "outlet": "true", + "facing": "east" + }, + "apply": { + "model": "anvilcraft:block/fish_tank_outlet", + "y": 90 + } + }, + { + "when": { + "outlet": "true", + "facing": "south" + }, + "apply": { + "model": "anvilcraft:block/fish_tank_outlet", + "y": 180 + } + }, + { + "when": { + "outlet": "true", + "facing": "west" + }, + "apply": { + "model": "anvilcraft:block/fish_tank_outlet", + "y": 270 + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/anvilcraft/models/block/fish_tank.json b/src/main/resources/assets/anvilcraft/models/block/fish_tank.json index cb2edf3f0..4b1530267 100644 --- a/src/main/resources/assets/anvilcraft/models/block/fish_tank.json +++ b/src/main/resources/assets/anvilcraft/models/block/fish_tank.json @@ -54,6 +54,17 @@ } ], "display": { + "thirdperson_righthand": { + "rotation": [30, 45, 0], + "scale": [0.6, 0.6, 0.6] + }, + "ground": { + "scale": [0.5, 0.5, 0.5] + }, + "gui": { + "rotation": [30, 45, 0], + "scale": [0.6, 0.6, 0.6] + }, "head": { "rotation": [-180, 0, 0], "scale": [1.125, 1.125, 1.125] From f93946950825933a046cd60c6c8f337ec0c49383 Mon Sep 17 00:00:00 2001 From: TBPig <147127248+TBPig@users.noreply.github.com> Date: Thu, 12 Feb 2026 13:05:11 +0800 Subject: [PATCH 2/9] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=B1=BC=E7=BC=B8?= =?UTF-8?q?=E5=8F=8A=E5=85=B6=E9=83=A8=E5=88=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dubhe/anvilcraft/api/tooltip/ItemTooltipManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/dev/dubhe/anvilcraft/api/tooltip/ItemTooltipManager.java b/src/main/java/dev/dubhe/anvilcraft/api/tooltip/ItemTooltipManager.java index a4a2a8755..5f3846f05 100644 --- a/src/main/java/dev/dubhe/anvilcraft/api/tooltip/ItemTooltipManager.java +++ b/src/main/java/dev/dubhe/anvilcraft/api/tooltip/ItemTooltipManager.java @@ -64,9 +64,9 @@ public class ItemTooltipManager { map.put(ModBlocks.BATCH_CRAFTER.asItem(), "Received a redstone signal and synthesized all internal items at once, with a power consumption of 4 kW"); map.put(ModBlocks.FISH_TANK.asItem(),""" - It is sturdier than it looks and can be used as a substitute for the alchemy pot to perform related anvil synthesis. - Wearing it on your head provides a temporary underwater breathing effect. - Right-click the top with an item in hand to place the item inside. + It is sturdier than it looks and can be used as a substitute for the alchemy pot to perform related anvil synthesis. + Wearing it on your head provides a temporary underwater breathing effect. + Right-click the top with an item in hand to place the item inside. Right-click the lower part of the fish tank with a tropical fish bucket in hand to release the tropical fish."""); map.put(ModBlocks.ROYAL_STEEL_BLOCK.asItem(), "Explosion proof"); map.put(ModBlocks.SMOOTH_ROYAL_STEEL_BLOCK.asItem(), "Explosion proof"); From 492062dba35501f5bfaf5befc7b0d17c31e68ccd Mon Sep 17 00:00:00 2001 From: TBPig <147127248+TBPig@users.noreply.github.com> Date: Thu, 12 Feb 2026 22:53:45 +0800 Subject: [PATCH 3/9] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B5=81=E4=BD=93?= =?UTF-8?q?=E5=82=A8=E7=BD=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../assets/anvilcraft/lang/en_ud.json | 1 + .../assets/anvilcraft/lang/en_us.json | 1 + .../anvilcraft/models/item/fluid_tank.json | 3 + .../advancement/recipes/misc/fluid_tank.json | 32 ++++ .../loot_table/blocks/fluid_tank.json | 21 +++ .../data/anvilcraft/recipe/fluid_tank.json | 16 ++ .../tags/block/mineable/pickaxe.json | 1 + .../api/fluid/IFluidHandlerHolder.java | 10 ++ .../anvilcraft/api/fluid/package-info.java | 7 + .../anvilcraft/block/FluidTankBlock.java | 77 +++++++++ .../block/entity/FluidTankBlockEntity.java | 90 +++++++++++ .../FluidTankBlockEntityRenderer.java | 151 ++++++++++++++++++ .../event/CapabilitiesEventListener.java | 16 +- .../init/block/ModBlockEntities.java | 8 + .../anvilcraft/init/block/ModBlocks.java | 16 ++ .../dev/dubhe/anvilcraft/util/FluidUtil.java | 4 + .../dev/dubhe/anvilcraft/util/TankUtil.java | 12 ++ .../anvilcraft/blockstates/fluid_tank.json | 7 + 18 files changed, 469 insertions(+), 4 deletions(-) create mode 100644 src/generated/resources/assets/anvilcraft/models/item/fluid_tank.json create mode 100644 src/generated/resources/data/anvilcraft/advancement/recipes/misc/fluid_tank.json create mode 100644 src/generated/resources/data/anvilcraft/loot_table/blocks/fluid_tank.json create mode 100644 src/generated/resources/data/anvilcraft/recipe/fluid_tank.json create mode 100644 src/main/java/dev/dubhe/anvilcraft/api/fluid/IFluidHandlerHolder.java create mode 100644 src/main/java/dev/dubhe/anvilcraft/api/fluid/package-info.java create mode 100644 src/main/java/dev/dubhe/anvilcraft/block/FluidTankBlock.java create mode 100644 src/main/java/dev/dubhe/anvilcraft/block/entity/FluidTankBlockEntity.java create mode 100644 src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/FluidTankBlockEntityRenderer.java create mode 100644 src/main/java/dev/dubhe/anvilcraft/util/FluidUtil.java create mode 100644 src/main/java/dev/dubhe/anvilcraft/util/TankUtil.java create mode 100644 src/main/resources/assets/anvilcraft/blockstates/fluid_tank.json diff --git a/src/generated/resources/assets/anvilcraft/lang/en_ud.json b/src/generated/resources/assets/anvilcraft/lang/en_ud.json index a3e0f5017..8282c38f7 100644 --- a/src/generated/resources/assets/anvilcraft/lang/en_ud.json +++ b/src/generated/resources/assets/anvilcraft/lang/en_ud.json @@ -315,6 +315,7 @@ "block.anvilcraft.fire_cauldron": "uoɹpןnɐƆ ǝɹıℲ", "block.anvilcraft.fish_tank": "ʞuɐ⟘ ɥsıℲ", "block.anvilcraft.flint_block": "ʞɔoןᗺ ʇuıןℲ", + "block.anvilcraft.fluid_tank": "ʞuɐ⟘ pınןℲ", "block.anvilcraft.frost_anvil": "ןıʌuⱯ ʇsoɹℲ", "block.anvilcraft.frost_glass": "ssɐן⅁ ʇsoɹℲ", "block.anvilcraft.frost_grindstone": "ǝuoʇspuıɹ⅁ ʇsoɹℲ", diff --git a/src/generated/resources/assets/anvilcraft/lang/en_us.json b/src/generated/resources/assets/anvilcraft/lang/en_us.json index 3a0341566..aac9d1691 100644 --- a/src/generated/resources/assets/anvilcraft/lang/en_us.json +++ b/src/generated/resources/assets/anvilcraft/lang/en_us.json @@ -315,6 +315,7 @@ "block.anvilcraft.fire_cauldron": "Fire Cauldron", "block.anvilcraft.fish_tank": "Fish Tank", "block.anvilcraft.flint_block": "Flint Block", + "block.anvilcraft.fluid_tank": "Fluid Tank", "block.anvilcraft.frost_anvil": "Frost Anvil", "block.anvilcraft.frost_glass": "Frost Glass", "block.anvilcraft.frost_grindstone": "Frost Grindstone", diff --git a/src/generated/resources/assets/anvilcraft/models/item/fluid_tank.json b/src/generated/resources/assets/anvilcraft/models/item/fluid_tank.json new file mode 100644 index 000000000..0164d6041 --- /dev/null +++ b/src/generated/resources/assets/anvilcraft/models/item/fluid_tank.json @@ -0,0 +1,3 @@ +{ + "parent": "anvilcraft:block/fluid_tank" +} \ No newline at end of file diff --git a/src/generated/resources/data/anvilcraft/advancement/recipes/misc/fluid_tank.json b/src/generated/resources/data/anvilcraft/advancement/recipes/misc/fluid_tank.json new file mode 100644 index 000000000..66fb8f476 --- /dev/null +++ b/src/generated/resources/data/anvilcraft/advancement/recipes/misc/fluid_tank.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_fish_tank": { + "conditions": { + "items": [ + { + "items": "anvilcraft:fish_tank" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "anvilcraft:fluid_tank" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_fish_tank" + ] + ], + "rewards": { + "recipes": [ + "anvilcraft:fluid_tank" + ] + } +} \ No newline at end of file diff --git a/src/generated/resources/data/anvilcraft/loot_table/blocks/fluid_tank.json b/src/generated/resources/data/anvilcraft/loot_table/blocks/fluid_tank.json new file mode 100644 index 000000000..719dec20e --- /dev/null +++ b/src/generated/resources/data/anvilcraft/loot_table/blocks/fluid_tank.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "anvilcraft:fluid_tank" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "anvilcraft:blocks/fluid_tank" +} \ No newline at end of file diff --git a/src/generated/resources/data/anvilcraft/recipe/fluid_tank.json b/src/generated/resources/data/anvilcraft/recipe/fluid_tank.json new file mode 100644 index 000000000..90e211040 --- /dev/null +++ b/src/generated/resources/data/anvilcraft/recipe/fluid_tank.json @@ -0,0 +1,16 @@ +{ + "type": "minecraft:crafting_shapeless", + "category": "misc", + "ingredients": [ + { + "tag": "c:plates/brass" + }, + { + "item": "anvilcraft:fish_tank" + } + ], + "result": { + "count": 2, + "id": "anvilcraft:fluid_tank" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/block/mineable/pickaxe.json b/src/generated/resources/data/minecraft/tags/block/mineable/pickaxe.json index 0d9a9417c..d974c8159 100644 --- a/src/generated/resources/data/minecraft/tags/block/mineable/pickaxe.json +++ b/src/generated/resources/data/minecraft/tags/block/mineable/pickaxe.json @@ -6,6 +6,7 @@ "anvilcraft:stamping_platform", "anvilcraft:crushing_table", "anvilcraft:fish_tank", + "anvilcraft:fluid_tank", "anvilcraft:corrupted_beacon", "anvilcraft:giant_anvil", "anvilcraft:spectral_anvil", diff --git a/src/main/java/dev/dubhe/anvilcraft/api/fluid/IFluidHandlerHolder.java b/src/main/java/dev/dubhe/anvilcraft/api/fluid/IFluidHandlerHolder.java new file mode 100644 index 000000000..ea6b1264e --- /dev/null +++ b/src/main/java/dev/dubhe/anvilcraft/api/fluid/IFluidHandlerHolder.java @@ -0,0 +1,10 @@ +package dev.dubhe.anvilcraft.api.fluid; + +import net.neoforged.neoforge.fluids.capability.IFluidHandler; + +/** + * 持有FluidTank的 + */ +public interface IFluidHandlerHolder { + IFluidHandler getFluidHandler(); +} diff --git a/src/main/java/dev/dubhe/anvilcraft/api/fluid/package-info.java b/src/main/java/dev/dubhe/anvilcraft/api/fluid/package-info.java new file mode 100644 index 000000000..b994f6ec8 --- /dev/null +++ b/src/main/java/dev/dubhe/anvilcraft/api/fluid/package-info.java @@ -0,0 +1,7 @@ +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +package dev.dubhe.anvilcraft.api.fluid; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/dev/dubhe/anvilcraft/block/FluidTankBlock.java b/src/main/java/dev/dubhe/anvilcraft/block/FluidTankBlock.java new file mode 100644 index 000000000..e7af4e1e5 --- /dev/null +++ b/src/main/java/dev/dubhe/anvilcraft/block/FluidTankBlock.java @@ -0,0 +1,77 @@ +package dev.dubhe.anvilcraft.block; + +import com.mojang.serialization.MapCodec; +import dev.dubhe.anvilcraft.api.hammer.HammerRotateBehavior; +import dev.dubhe.anvilcraft.api.hammer.IHammerRemovable; +import dev.dubhe.anvilcraft.block.entity.FluidTankBlockEntity; +import dev.dubhe.anvilcraft.init.block.ModBlockEntities; +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +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.BaseEntityBlock; +import net.minecraft.world.level.block.RenderShape; +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.phys.BlockHitResult; +import org.jetbrains.annotations.Nullable; + +public class FluidTankBlock extends BaseEntityBlock implements HammerRotateBehavior, IHammerRemovable { + + public FluidTankBlock(Properties properties) { + super(properties); + } + + @Override + protected MapCodec codec() { + return simpleCodec(FluidTankBlock::new); + } + + @Nullable + @Override + public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { + return ModBlockEntities.FLUID_TANK.create(pos, state); + } + + @Override + protected RenderShape getRenderShape(BlockState state) { + return RenderShape.MODEL; + } + + @Nullable + @Override + public BlockEntityTicker getTicker(Level level, BlockState state, BlockEntityType type) { + return level.isClientSide + ? null + : createTickerHelper( + type, + ModBlockEntities.FLUID_TANK.get(), + (level1, blockPos, blockState, blockEntity) -> blockEntity.serverTick() + ); + } + + @Override + protected ItemInteractionResult useItemOn( + ItemStack stack, + BlockState state, + Level level, + BlockPos pos, + Player player, + InteractionHand hand, + BlockHitResult hitResult + ) { + InteractionResult result = super.useItemOn(stack, state, level, pos, player, hand, hitResult).result(); + if (result == InteractionResult.PASS) { + if (level.getBlockEntity(pos) instanceof FluidTankBlockEntity tank && tank.onPlayerUse(player, hand)) { + return ItemInteractionResult.sidedSuccess(level.isClientSide()); + } + + } + return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; + } +} \ No newline at end of file diff --git a/src/main/java/dev/dubhe/anvilcraft/block/entity/FluidTankBlockEntity.java b/src/main/java/dev/dubhe/anvilcraft/block/entity/FluidTankBlockEntity.java new file mode 100644 index 000000000..b63eded72 --- /dev/null +++ b/src/main/java/dev/dubhe/anvilcraft/block/entity/FluidTankBlockEntity.java @@ -0,0 +1,90 @@ +package dev.dubhe.anvilcraft.block.entity; + +import dev.dubhe.anvilcraft.api.fluid.IFluidHandlerHolder; +import dev.dubhe.anvilcraft.util.TankUtil; +import net.minecraft.core.BlockPos; +import net.minecraft.core.HolderLookup; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.neoforged.neoforge.fluids.FluidType; +import net.neoforged.neoforge.fluids.FluidUtil; +import net.neoforged.neoforge.fluids.IFluidTank; +import net.neoforged.neoforge.fluids.capability.IFluidHandler; +import net.neoforged.neoforge.fluids.capability.templates.FluidTank; + +public class FluidTankBlockEntity extends BlockEntity implements IFluidHandlerHolder { + public static final int CAPACITY = 16; + public static final int BIG_CAPACITY = 640; + public static final int COOLDOWN = 200; + protected FluidTank tank = new FluidTank(CAPACITY * FluidType.BUCKET_VOLUME); + protected int cooldown = 0; + + + public FluidTankBlockEntity(BlockEntityType type, BlockPos pos, BlockState blockState) { + super(type, pos, blockState); + } + + public void serverTick() { + if (--cooldown <= 0) { + checkStructure(); + cooldown = COOLDOWN; + } + setChanged(); + } + + protected void checkStructure() { +// int targetCapacity = TankUtil.isMengerStructure(this.getBlockPos(), 3) ? BIG_CAPACITY : CAPACITY; +// if (tank.getCapacity() != targetCapacity) { +// tank.setCapacity(targetCapacity); +// } + } + + @Override + protected void saveAdditional(CompoundTag tag, HolderLookup.Provider provider) { + super.saveAdditional(tag, provider); + CompoundTag tankNbt = tank.writeToNBT(provider, new CompoundTag()); + if (!tankNbt.isEmpty()) { + tag.put("tank", tankNbt); + } + } + + @Override + public void loadAdditional(CompoundTag tag, HolderLookup.Provider provider) { + super.loadAdditional(tag, provider); + tank.readFromNBT(provider, tag.getCompound("tank")); + } + + @Override + public CompoundTag getUpdateTag(HolderLookup.Provider registries) { + CompoundTag tag = super.getUpdateTag(registries); + CompoundTag fluidTag = new CompoundTag(); + tank.writeToNBT(registries, fluidTag); + tag.put("tank", fluidTag); + return tag; + } + + @Override + public Packet getUpdatePacket() { + return ClientboundBlockEntityDataPacket.create(this); + } + + public boolean onPlayerUse(Player player, InteractionHand hand) { + checkStructure(); + return FluidUtil.interactWithFluidHandler(player, hand, tank); + } + + public IFluidTank getTank() { + return tank; + } + + public IFluidHandler getFluidHandler() { + return tank; + } +} \ No newline at end of file diff --git a/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/FluidTankBlockEntityRenderer.java b/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/FluidTankBlockEntityRenderer.java new file mode 100644 index 000000000..185f9ae8c --- /dev/null +++ b/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/FluidTankBlockEntityRenderer.java @@ -0,0 +1,151 @@ +/* + * Original Code Copyright (C) 2013 - 2020 AlgorithmX2 et al + * Source: https://github.com/AppliedEnergistics/Applied-Energistics-2 + * + * This file is part of "Applied Energistics 2" project, which is licensed under + * the GNU Lesser General Public License Version 3 (LGPLv3). + * + * --- MODIFICATIONS --- + * This file has been modified for use in AnvilCraft. + * Modifications made by: TB_pig + * Modification date: 2026/2/12 + * These modifications continue to be licensed under LGPLv3. + * ------------------------------------------------------------- + */ +package dev.dubhe.anvilcraft.client.renderer.blockentity; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import dev.dubhe.anvilcraft.block.entity.FluidTankBlockEntity; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions; +import net.neoforged.neoforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.FluidType; +import org.joml.Matrix4f; + +public class FluidTankBlockEntityRenderer implements BlockEntityRenderer { + public FluidTankBlockEntityRenderer(BlockEntityRendererProvider.Context context) { + } + + + @Override + public void render( + FluidTankBlockEntity tank, float tickDelta, PoseStack ms, MultiBufferSource vertexConsumers, int light, int overlay) { + if (!tank.getTank().getFluid().isEmpty()) { + + /* + * + * // Uncomment to allow the liquid to rotate with the tank ms.pushPose(); ms.translate(0.5, 0.5, 0.5); + * FacingToRotation.get(tank.getForward(), tank.getUp()).push(ms); ms.translate(-0.5, -0.5, -0.5); + */ + + drawFluidInTank( + tank, ms, vertexConsumers, light, tank.getTank().getFluid(), + (float) tank.getTank().getFluid().getAmount() / tank.getTank().getCapacity() + ); + + // ms.popPose(); + } + } + + private static final float TANK_W = 1 / 16f + 0.001f; // avoiding Z-fighting + + public static void drawFluidInTank( + BlockEntity be, PoseStack ms, MultiBufferSource vcp, int light, FluidStack fluid, + float fill + ) { + drawFluidInTank(be.getLevel(), be.getBlockPos(), ms, vcp, light, fluid, fill); + } + + public static void drawFluidInTank( + Level level, BlockPos pos, PoseStack ps, MultiBufferSource mbs, int light, + FluidStack fluid, float fill + ) { + // From Modern Industrialization + var renderProps = IClientFluidTypeExtensions.of(fluid.getFluid()); + TextureAtlasSprite sprite = Minecraft.getInstance().getTextureAtlas(InventoryMenu.BLOCK_ATLAS) + .apply(renderProps.getStillTexture(fluid)); + + int color = renderProps.getTintColor(fluid); + float fillY = Mth.lerp(Mth.clamp(fill, 0, 1), TANK_W, 1 - TANK_W); + + // Top and bottom positions of the fluid inside the tank + float topHeight = fillY; + float bottomHeight = TANK_W; + + // Render gas from top to bottom + FluidType attributes = fluid.getFluid().getFluidType(); + if (attributes.isLighterThanAir()) { + topHeight = 1 - TANK_W; + bottomHeight = 1 - fillY; + } + + float minX = TANK_W; + float minZ = TANK_W; + float maxX = (1 - TANK_W); + float maxZ = (1 - TANK_W); + float minY = bottomHeight; + float maxY = topHeight; + + // 在 render 方法中 + ps.pushPose(); + + // 获取顶点构建器 + VertexConsumer consumer = mbs.getBuffer(RenderType.translucent()); + + // 纹理映射:简单将整个 sprite 映射到每个面,不进行平铺 + float u0 = sprite.getU0(); + float u1 = sprite.getU1(); + float v0 = sprite.getV0(); + float v1 = sprite.getV1(); + + Matrix4f pose = ps.last().pose(); + + consumer.addVertex(pose, maxX, maxY, maxZ).setColor(color).setUv(u0, v0).setLight(light).setNormal(0, 1, 0); + consumer.addVertex(pose, maxX, maxY, minZ).setColor(color).setUv(u1, v0).setLight(light).setNormal(0, 1, 0); + consumer.addVertex(pose, minX, maxY, minZ).setColor(color).setUv(u1, v1).setLight(light).setNormal(0, 1, 0); + consumer.addVertex(pose, minX, maxY, maxZ).setColor(color).setUv(u0, v1).setLight(light).setNormal(0, 1, 0); + + // 北面 (Z-) + consumer.addVertex(pose, maxX, maxY, minZ).setColor(color).setUv(u0, v0).setLight(light).setNormal(0, 0, -1); + consumer.addVertex(pose, maxX, minY, minZ).setColor(color).setUv(u1, v0).setLight(light).setNormal(0, 0, -1); + consumer.addVertex(pose, minX, minY, minZ).setColor(color).setUv(u1, v1).setLight(light).setNormal(0, 0, -1); + consumer.addVertex(pose, minX, maxY, minZ).setColor(color).setUv(u0, v1).setLight(light).setNormal(0, 0, -1); + + // 南面 (Z+) + consumer.addVertex(pose, maxX, minY, maxZ).setColor(color).setUv(u0, v0).setLight(light).setNormal(0, 0, 1); + consumer.addVertex(pose, maxX, maxY, maxZ).setColor(color).setUv(u1, v0).setLight(light).setNormal(0, 0, 1); + consumer.addVertex(pose, minX, maxY, maxZ).setColor(color).setUv(u1, v1).setLight(light).setNormal(0, 0, 1); + consumer.addVertex(pose, minX, minY, maxZ).setColor(color).setUv(u0, v1).setLight(light).setNormal(0, 0, 1); + + // 西面 (X-) + consumer.addVertex(pose, minX, maxY, maxZ).setColor(color).setUv(u0, v0).setLight(light).setNormal(-1, 0, 0); + consumer.addVertex(pose, minX, maxY, minZ).setColor(color).setUv(u1, v0).setLight(light).setNormal(-1, 0, 0); + consumer.addVertex(pose, minX, minY, minZ).setColor(color).setUv(u1, v1).setLight(light).setNormal(-1, 0, 0); + consumer.addVertex(pose, minX, minY, maxZ).setColor(color).setUv(u0, v1).setLight(light).setNormal(-1, 0, 0); + + // 东面 (X+) + consumer.addVertex(pose, maxX, minY, maxZ).setColor(color).setUv(u0, v0).setLight(light).setNormal(1, 0, 0); + consumer.addVertex(pose, maxX, minY, minZ).setColor(color).setUv(u1, v0).setLight(light).setNormal(1, 0, 0); + consumer.addVertex(pose, maxX, maxY, minZ).setColor(color).setUv(u1, v1).setLight(light).setNormal(1, 0, 0); + consumer.addVertex(pose, maxX, maxY, maxZ).setColor(color).setUv(u0, v1).setLight(light).setNormal(1, 0, 0); + + // 底面 (Y-) + consumer.addVertex(pose, maxX, minY, maxZ).setColor(color).setUv(u0, v0).setLight(light).setNormal(0, -1, 0); + consumer.addVertex(pose, minX, minY, maxZ).setColor(color).setUv(u1, v0).setLight(light).setNormal(0, -1, 0); + consumer.addVertex(pose, minX, minY, minZ).setColor(color).setUv(u1, v1).setLight(light).setNormal(0, -1, 0); + consumer.addVertex(pose, maxX, minY, minZ).setColor(color).setUv(u0, v1).setLight(light).setNormal(0, -1, 0); + ps.popPose(); + } + +} diff --git a/src/main/java/dev/dubhe/anvilcraft/event/CapabilitiesEventListener.java b/src/main/java/dev/dubhe/anvilcraft/event/CapabilitiesEventListener.java index 4e2ce32c4..83f9a6f35 100644 --- a/src/main/java/dev/dubhe/anvilcraft/event/CapabilitiesEventListener.java +++ b/src/main/java/dev/dubhe/anvilcraft/event/CapabilitiesEventListener.java @@ -15,7 +15,8 @@ public class CapabilitiesEventListener { @SubscribeEvent public static void registerCapabilities(final RegisterCapabilitiesEvent event) { - List.of(ModBlockEntities.BATCH_CRAFTER.get(), + List.of( + ModBlockEntities.BATCH_CRAFTER.get(), ModBlockEntities.CHARGER.get(), ModBlockEntities.CHUTE.get(), ModBlockEntities.SIMPLE_CHUTE.get(), @@ -23,9 +24,10 @@ public static void registerCapabilities(final RegisterCapabilitiesEvent event) { ModBlockEntities.MAGNETIC_CHUTE.get(), ModBlockEntities.CONFINEMENT_CHAMBER.get() ).forEach(type -> event.registerBlockEntity( - Capabilities.ItemHandler.BLOCK, - type, - (be, side) -> be.getItemHandler()) + Capabilities.ItemHandler.BLOCK, + type, + (be, side) -> be.getItemHandler() + ) ); event.registerBlock( @@ -33,5 +35,11 @@ public static void registerCapabilities(final RegisterCapabilitiesEvent event) { ((level, pos, state, blockEntity, side) -> new HoneyCauldronWrapper(level, pos)), ModBlocks.HONEY_CAULDRON.get() ); + + event.registerBlockEntity( + Capabilities.FluidHandler.BLOCK, + ModBlockEntities.FLUID_TANK.get(), + (be, side) -> be.getFluidHandler() + ); } } diff --git a/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlockEntities.java b/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlockEntities.java index 7a20581f8..a183d430a 100644 --- a/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlockEntities.java +++ b/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlockEntities.java @@ -16,6 +16,7 @@ import dev.dubhe.anvilcraft.block.entity.CreativeGeneratorBlockEntity; import dev.dubhe.anvilcraft.block.entity.DeflectionRingBlockEntity; import dev.dubhe.anvilcraft.block.entity.DetectorSlidingRailBlockEntity; +import dev.dubhe.anvilcraft.block.entity.FluidTankBlockEntity; import dev.dubhe.anvilcraft.block.entity.HeatCollectorBlockEntity; import dev.dubhe.anvilcraft.block.entity.HeaterBlockEntity; import dev.dubhe.anvilcraft.block.entity.HeliostatsBlockEntity; @@ -56,6 +57,7 @@ import dev.dubhe.anvilcraft.client.renderer.blockentity.ConfinementChamberRenderer; import dev.dubhe.anvilcraft.client.renderer.blockentity.CorruptedBeaconRenderer; import dev.dubhe.anvilcraft.client.renderer.blockentity.CreativeGeneratorRenderer; +import dev.dubhe.anvilcraft.client.renderer.blockentity.FluidTankBlockEntityRenderer; import dev.dubhe.anvilcraft.client.renderer.blockentity.HasMobBlockRenderer; import dev.dubhe.anvilcraft.client.renderer.blockentity.HeatCollectorRenderer; import dev.dubhe.anvilcraft.client.renderer.blockentity.HeliostatsRenderer; @@ -304,6 +306,12 @@ public class ModBlockEntities { .validBlocks(ModBlocks.NEUTRON_IRRADIATOR) .register(); + public static final BlockEntityEntry FLUID_TANK = REGISTRATE + .blockEntity("fluid_tank", FluidTankBlockEntity::new) + .validBlocks(ModBlocks.FLUID_TANK) + .renderer(() -> FluidTankBlockEntityRenderer::new) + .register(); + public static void register() { } } diff --git a/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlocks.java b/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlocks.java index fffd89a22..f841b7748 100644 --- a/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlocks.java +++ b/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlocks.java @@ -48,6 +48,7 @@ import dev.dubhe.anvilcraft.block.FireCauldronBlock; import dev.dubhe.anvilcraft.block.FishTankBlock; import dev.dubhe.anvilcraft.block.FlintBlock; +import dev.dubhe.anvilcraft.block.FluidTankBlock; import dev.dubhe.anvilcraft.block.FrostAnvilBlock; import dev.dubhe.anvilcraft.block.FrostGrindstoneBlock; import dev.dubhe.anvilcraft.block.FrostMetalBlock; @@ -383,6 +384,21 @@ public class ModBlocks { }) .register(); + public static final BlockEntry FLUID_TANK = REGISTRATE.block("fluid_tank", FluidTankBlock::new) + .initialProperties(() -> Blocks.IRON_BLOCK) + .properties(p -> p.noOcclusion().isValidSpawn(Blocks::never)) + .blockstate(DataGenUtil::noExtraModelOrState) + .simpleItem() + .tag(BlockTags.MINEABLE_WITH_PICKAXE) + .recipe((ctx, provider) -> { + ShapelessRecipeBuilder.shapeless(RecipeCategory.MISC, ctx.get(), 2) + .requires(ModItemTags.BRASS_PLATES) + .requires(ModBlocks.FISH_TANK) + .unlockedBy(AnvilCraftDatagen.hasItem(ModBlocks.FISH_TANK.asItem()), AnvilCraftDatagen.has(ModBlocks.FISH_TANK)) + .save(provider); + }) + .register(); + public static final BlockEntry CORRUPTED_BEACON = REGISTRATE.block("corrupted_beacon", CorruptedBeaconBlock::new) .initialProperties(() -> Blocks.BEACON) .properties(p -> p.isValidSpawn(Blocks::never)) diff --git a/src/main/java/dev/dubhe/anvilcraft/util/FluidUtil.java b/src/main/java/dev/dubhe/anvilcraft/util/FluidUtil.java new file mode 100644 index 000000000..8712a42b1 --- /dev/null +++ b/src/main/java/dev/dubhe/anvilcraft/util/FluidUtil.java @@ -0,0 +1,4 @@ +package dev.dubhe.anvilcraft.util; + +public class FluidUtil { +} diff --git a/src/main/java/dev/dubhe/anvilcraft/util/TankUtil.java b/src/main/java/dev/dubhe/anvilcraft/util/TankUtil.java new file mode 100644 index 000000000..48998d00a --- /dev/null +++ b/src/main/java/dev/dubhe/anvilcraft/util/TankUtil.java @@ -0,0 +1,12 @@ +package dev.dubhe.anvilcraft.util; + +import net.minecraft.core.BlockPos; + +public class TankUtil { + public static boolean isMengerStructure(BlockPos pos, int size) { + if (size <= 0) return false; + if (size != 1 && size%3 != 0) return false; + + return false; + } +} diff --git a/src/main/resources/assets/anvilcraft/blockstates/fluid_tank.json b/src/main/resources/assets/anvilcraft/blockstates/fluid_tank.json new file mode 100644 index 000000000..ca11bd270 --- /dev/null +++ b/src/main/resources/assets/anvilcraft/blockstates/fluid_tank.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "anvilcraft:block/fluid_tank" + } + } +} \ No newline at end of file From f56a355031b91cc9705d08aa9c530651769aa15c Mon Sep 17 00:00:00 2001 From: TBPig <147127248+TBPig@users.noreply.github.com> Date: Fri, 13 Feb 2026 10:40:19 +0800 Subject: [PATCH 4/9] =?UTF-8?q?=E6=B5=81=E4=BD=93=E5=82=A8=E7=BD=90?= =?UTF-8?q?=E5=A4=A7=E8=83=83=E8=A2=8B=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tags/fluid/menger_sponge_can_absorb.json | 1 + .../anvilcraft/block/FluidTankBlock.java | 12 ++- .../block/entity/FluidTankBlockEntity.java | 14 +-- .../anvilcraft/data/tags/FluidTagLoader.java | 1 + .../dev/dubhe/anvilcraft/util/FluidUtil.java | 4 - .../dev/dubhe/anvilcraft/util/TankUtil.java | 86 ++++++++++++++++++- 6 files changed, 97 insertions(+), 21 deletions(-) delete mode 100644 src/main/java/dev/dubhe/anvilcraft/util/FluidUtil.java diff --git a/src/generated/resources/data/anvilcraft/tags/fluid/menger_sponge_can_absorb.json b/src/generated/resources/data/anvilcraft/tags/fluid/menger_sponge_can_absorb.json index c96324e57..e277b984e 100644 --- a/src/generated/resources/data/anvilcraft/tags/fluid/menger_sponge_can_absorb.json +++ b/src/generated/resources/data/anvilcraft/tags/fluid/menger_sponge_can_absorb.json @@ -8,6 +8,7 @@ "anvilcraft:flowing_oil", "anvilcraft:melt_gem", "anvilcraft:flowing_melt_gem", + "anvilcraft:exp_fluid", "#c:cement" ] } \ No newline at end of file diff --git a/src/main/java/dev/dubhe/anvilcraft/block/FluidTankBlock.java b/src/main/java/dev/dubhe/anvilcraft/block/FluidTankBlock.java index e7af4e1e5..4ebf5eafc 100644 --- a/src/main/java/dev/dubhe/anvilcraft/block/FluidTankBlock.java +++ b/src/main/java/dev/dubhe/anvilcraft/block/FluidTankBlock.java @@ -46,13 +46,11 @@ protected RenderShape getRenderShape(BlockState state) { @Nullable @Override public BlockEntityTicker getTicker(Level level, BlockState state, BlockEntityType type) { - return level.isClientSide - ? null - : createTickerHelper( - type, - ModBlockEntities.FLUID_TANK.get(), - (level1, blockPos, blockState, blockEntity) -> blockEntity.serverTick() - ); + return createTickerHelper( + type, + ModBlockEntities.FLUID_TANK.get(), + (level1, blockPos, blockState, blockEntity) -> blockEntity.tick() + ); } @Override diff --git a/src/main/java/dev/dubhe/anvilcraft/block/entity/FluidTankBlockEntity.java b/src/main/java/dev/dubhe/anvilcraft/block/entity/FluidTankBlockEntity.java index b63eded72..1680fd83d 100644 --- a/src/main/java/dev/dubhe/anvilcraft/block/entity/FluidTankBlockEntity.java +++ b/src/main/java/dev/dubhe/anvilcraft/block/entity/FluidTankBlockEntity.java @@ -22,7 +22,7 @@ public class FluidTankBlockEntity extends BlockEntity implements IFluidHandlerHolder { public static final int CAPACITY = 16; public static final int BIG_CAPACITY = 640; - public static final int COOLDOWN = 200; + public static final int COOLDOWN = 100; protected FluidTank tank = new FluidTank(CAPACITY * FluidType.BUCKET_VOLUME); protected int cooldown = 0; @@ -31,7 +31,7 @@ public FluidTankBlockEntity(BlockEntityType type, BlockPos pos, BlockState bl super(type, pos, blockState); } - public void serverTick() { + public void tick() { if (--cooldown <= 0) { checkStructure(); cooldown = COOLDOWN; @@ -40,10 +40,12 @@ public void serverTick() { } protected void checkStructure() { -// int targetCapacity = TankUtil.isMengerStructure(this.getBlockPos(), 3) ? BIG_CAPACITY : CAPACITY; -// if (tank.getCapacity() != targetCapacity) { -// tank.setCapacity(targetCapacity); -// } + if (this.getLevel() == null) return; + + int targetCapacity = TankUtil.isMengerStructure(this.getLevel(), this.getBlockPos(), 3) ? BIG_CAPACITY : CAPACITY; + if (tank.getCapacity() != targetCapacity) { + tank.setCapacity(targetCapacity * FluidType.BUCKET_VOLUME); + } } @Override diff --git a/src/main/java/dev/dubhe/anvilcraft/data/tags/FluidTagLoader.java b/src/main/java/dev/dubhe/anvilcraft/data/tags/FluidTagLoader.java index 11a644c65..788dd7c3d 100644 --- a/src/main/java/dev/dubhe/anvilcraft/data/tags/FluidTagLoader.java +++ b/src/main/java/dev/dubhe/anvilcraft/data/tags/FluidTagLoader.java @@ -31,6 +31,7 @@ public static void init(RegistrateTagsProvider provider) { .add(ModFluids.FLOWING_OIL.getKey()) .add(ModFluids.MELT_GEM.getKey()) .add(ModFluids.FLOWING_MELT_GEM.getKey()) + .add(ModFluids.EXP_FLUID.getKey()) .addTag(ModFluidTags.CEMENT); provider.addTag(ModFluidTags.OIL) .add(findResourceKey(ModFluids.OIL.get())) diff --git a/src/main/java/dev/dubhe/anvilcraft/util/FluidUtil.java b/src/main/java/dev/dubhe/anvilcraft/util/FluidUtil.java deleted file mode 100644 index 8712a42b1..000000000 --- a/src/main/java/dev/dubhe/anvilcraft/util/FluidUtil.java +++ /dev/null @@ -1,4 +0,0 @@ -package dev.dubhe.anvilcraft.util; - -public class FluidUtil { -} diff --git a/src/main/java/dev/dubhe/anvilcraft/util/TankUtil.java b/src/main/java/dev/dubhe/anvilcraft/util/TankUtil.java index 48998d00a..7fb266594 100644 --- a/src/main/java/dev/dubhe/anvilcraft/util/TankUtil.java +++ b/src/main/java/dev/dubhe/anvilcraft/util/TankUtil.java @@ -1,12 +1,90 @@ package dev.dubhe.anvilcraft.util; +import dev.dubhe.anvilcraft.init.block.ModBlocks; import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; + +import java.util.List; public class TankUtil { - public static boolean isMengerStructure(BlockPos pos, int size) { + /** + * 递归检测当前位置的结构是否符合门格海绵结构 + * 门格海绵结构规则:将结构分为3x3x3的块后, + * 角块和边块应该是门格海绵方块,面块和中心块应该是空气 + * + * @param level 世界对象 + * @param centerPos 检测起始位置 + * @param size 结构大小(必须是3的倍数) + * @return 是否符合门格海绵结构 + */ + public static boolean isMengerStructure(Level level, BlockPos centerPos, int size) { if (size <= 0) return false; - if (size != 1 && size%3 != 0) return false; - return false; + // 基础情况:如果size为1,则直接检查是否为门格海绵 + if (size == 1) { + return level.getBlockState(centerPos).is(ModBlocks.MENGER_SPONGE.get()); + } + + if (size % 3 != 0) return false; + // 递归情况:将大结构分解为27个小结构进行检查 + int subSize = size / 3; + + for (int x = -1; x < 2; x++) { + for (int y = -1; y < 2; y++) { + for (int z = -1; z < 2; z++) { + BlockPos subPos = centerPos.offset(x * subSize, y * subSize, z * subSize); + + if (isMengerPos(x, y, z)) { + // 角块和边块应该符合门格海绵结构 + if (!isMengerStructure(level, subPos, subSize)) { + return false; + } + } else { + // 面块和中心块应该是空气 + if (!isNoMengerSponge(level, subPos, subSize)) { + return false; + } + } + } + } + } + + return true; + } + + public static boolean isNoMengerSponge(Level level, BlockPos centerPos, int size) { + if (size <= 0) return false; + if (size % 2 == 0) return false; + int delta = size / 2; + List blockPosList = BlockPos.betweenClosedStream( + centerPos.getX() - delta, + centerPos.getY() - delta, + centerPos.getZ() - delta, + centerPos.getX() + delta, + centerPos.getY() + delta, + centerPos.getZ() + delta + ) + .map(BlockPos::immutable) + .toList(); + for (BlockPos subPos : blockPosList) { + if (level.getBlockState(subPos).is(ModBlocks.MENGER_SPONGE.get())) { + return false; + } + } + return true; + } + + /** + * 判断在3x3x3结构中的位置是否为角块或边块 + */ + public static boolean isMengerPos(int x, int y, int z) { + int sideCount = 0; + if (x != 0) sideCount++; + if (y != 0) sideCount++; + if (z != 0) sideCount++; + + // 角块:至少两个坐标是-1或1 + // 边块:恰好一个坐标是-1或1 + return sideCount >= 2; } -} +} \ No newline at end of file From e36e2d039b34d642a31e5a9475757fd1968d4bb0 Mon Sep 17 00:00:00 2001 From: TBPig <147127248+TBPig@users.noreply.github.com> Date: Fri, 13 Feb 2026 21:55:47 +0800 Subject: [PATCH 5/9] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=B7=A8=E5=9E=8B?= =?UTF-8?q?=E6=B5=81=E4=BD=93=E5=82=A8=E7=BD=90=EF=BC=8C=E4=BD=86=E6=98=AF?= =?UTF-8?q?=E4=B8=8D=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../assets/anvilcraft/lang/en_ud.json | 1 + .../assets/anvilcraft/lang/en_us.json | 1 + .../models/item/large_fluid_tank.json | 3 + .../multiblock/large_fluid_tank_1.json | 21 ++ .../multiblock/large_fluid_tank_2.json | 21 ++ .../large_fluid_tank_1.json | 21 ++ .../large_fluid_tank_2.json | 21 ++ .../loot_table/blocks/large_fluid_tank.json | 30 +++ .../recipe/multiblock/large_fluid_tank_1.json | 31 +++ .../recipe/multiblock/large_fluid_tank_2.json | 31 +++ .../large_fluid_tank_1.json | 210 ++++++++++++++++ .../large_fluid_tank_2.json | 210 ++++++++++++++++ .../tags/block/mineable/pickaxe.json | 1 + .../anvilcraft/block/FluidTankBlock.java | 6 +- .../anvilcraft/block/LargeFluidTankBlock.java | 100 ++++++++ .../entity/LargeFluidTankBlockEntity.java | 98 ++++++++ .../LargeFluidTankBlockEntityRenderer.java | 152 +++++++++++ .../MultiBlockConversionRecipeLoader.java | 238 ++++++++++++++++++ .../data/recipe/MultiBlockRecipeLoader.java | 14 ++ .../event/CapabilitiesEventListener.java | 11 +- .../init/block/ModBlockEntities.java | 8 + .../anvilcraft/init/block/ModBlocks.java | 15 ++ .../blockstates/large_fluid_tank.json | 85 +++++++ .../anvilcraft/models/block/fluid_tank.json | 40 +-- .../models/block/large_fluid_tank_part.json | 6 + 25 files changed, 1331 insertions(+), 44 deletions(-) create mode 100644 src/generated/resources/assets/anvilcraft/models/item/large_fluid_tank.json create mode 100644 src/generated/resources/data/anvilcraft/advancement/recipes/multiblock/large_fluid_tank_1.json create mode 100644 src/generated/resources/data/anvilcraft/advancement/recipes/multiblock/large_fluid_tank_2.json create mode 100644 src/generated/resources/data/anvilcraft/advancement/recipes/multiblock_conversion/large_fluid_tank_1.json create mode 100644 src/generated/resources/data/anvilcraft/advancement/recipes/multiblock_conversion/large_fluid_tank_2.json create mode 100644 src/generated/resources/data/anvilcraft/loot_table/blocks/large_fluid_tank.json create mode 100644 src/generated/resources/data/anvilcraft/recipe/multiblock/large_fluid_tank_1.json create mode 100644 src/generated/resources/data/anvilcraft/recipe/multiblock/large_fluid_tank_2.json create mode 100644 src/generated/resources/data/anvilcraft/recipe/multiblock_conversion/large_fluid_tank_1.json create mode 100644 src/generated/resources/data/anvilcraft/recipe/multiblock_conversion/large_fluid_tank_2.json create mode 100644 src/main/java/dev/dubhe/anvilcraft/block/LargeFluidTankBlock.java create mode 100644 src/main/java/dev/dubhe/anvilcraft/block/entity/LargeFluidTankBlockEntity.java create mode 100644 src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/LargeFluidTankBlockEntityRenderer.java create mode 100644 src/main/resources/assets/anvilcraft/blockstates/large_fluid_tank.json create mode 100644 src/main/resources/assets/anvilcraft/models/block/large_fluid_tank_part.json diff --git a/src/generated/resources/assets/anvilcraft/lang/en_ud.json b/src/generated/resources/assets/anvilcraft/lang/en_ud.json index 8282c38f7..53c9f239a 100644 --- a/src/generated/resources/assets/anvilcraft/lang/en_ud.json +++ b/src/generated/resources/assets/anvilcraft/lang/en_ud.json @@ -354,6 +354,7 @@ "block.anvilcraft.item_detector": "ɹoʇɔǝʇǝᗡ ɯǝʇI", "block.anvilcraft.jewelcrafting_table": "ǝןqɐ⟘ buıʇɟɐɹƆ ןǝʍǝſ", "block.anvilcraft.large_cake": "ǝʞɐƆ ǝbɹɐꞀ", + "block.anvilcraft.large_fluid_tank": "ʞuɐ⟘ pınןℲ ǝbɹɐꞀ", "block.anvilcraft.laser_receiver": "ɹǝʌıǝɔǝᴚ ɹǝsɐꞀ", "block.anvilcraft.lava_cauldron": "uoɹpןnɐƆ ɐʌɐꞀ", "block.anvilcraft.lead_block": "pɐǝꞀ ɟo ʞɔoןᗺ", diff --git a/src/generated/resources/assets/anvilcraft/lang/en_us.json b/src/generated/resources/assets/anvilcraft/lang/en_us.json index aac9d1691..828db1a62 100644 --- a/src/generated/resources/assets/anvilcraft/lang/en_us.json +++ b/src/generated/resources/assets/anvilcraft/lang/en_us.json @@ -354,6 +354,7 @@ "block.anvilcraft.item_detector": "Item Detector", "block.anvilcraft.jewelcrafting_table": "Jewel Crafting Table", "block.anvilcraft.large_cake": "Large Cake", + "block.anvilcraft.large_fluid_tank": "Large Fluid Tank", "block.anvilcraft.laser_receiver": "Laser Receiver", "block.anvilcraft.lava_cauldron": "Lava Cauldron", "block.anvilcraft.lead_block": "Block of Lead", diff --git a/src/generated/resources/assets/anvilcraft/models/item/large_fluid_tank.json b/src/generated/resources/assets/anvilcraft/models/item/large_fluid_tank.json new file mode 100644 index 000000000..8b327a33a --- /dev/null +++ b/src/generated/resources/assets/anvilcraft/models/item/large_fluid_tank.json @@ -0,0 +1,3 @@ +{ + "parent": "anvilcraft:block/large_fluid_tank" +} \ No newline at end of file diff --git a/src/generated/resources/data/anvilcraft/advancement/recipes/multiblock/large_fluid_tank_1.json b/src/generated/resources/data/anvilcraft/advancement/recipes/multiblock/large_fluid_tank_1.json new file mode 100644 index 000000000..069370784 --- /dev/null +++ b/src/generated/resources/data/anvilcraft/advancement/recipes/multiblock/large_fluid_tank_1.json @@ -0,0 +1,21 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_the_recipe": { + "conditions": { + "recipe": "anvilcraft:multiblock/large_fluid_tank_1" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe" + ] + ], + "rewards": { + "recipes": [ + "anvilcraft:multiblock/large_fluid_tank_1" + ] + } +} \ No newline at end of file diff --git a/src/generated/resources/data/anvilcraft/advancement/recipes/multiblock/large_fluid_tank_2.json b/src/generated/resources/data/anvilcraft/advancement/recipes/multiblock/large_fluid_tank_2.json new file mode 100644 index 000000000..feadc6a2f --- /dev/null +++ b/src/generated/resources/data/anvilcraft/advancement/recipes/multiblock/large_fluid_tank_2.json @@ -0,0 +1,21 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_the_recipe": { + "conditions": { + "recipe": "anvilcraft:multiblock/large_fluid_tank_2" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe" + ] + ], + "rewards": { + "recipes": [ + "anvilcraft:multiblock/large_fluid_tank_2" + ] + } +} \ No newline at end of file diff --git a/src/generated/resources/data/anvilcraft/advancement/recipes/multiblock_conversion/large_fluid_tank_1.json b/src/generated/resources/data/anvilcraft/advancement/recipes/multiblock_conversion/large_fluid_tank_1.json new file mode 100644 index 000000000..e32b6c4e1 --- /dev/null +++ b/src/generated/resources/data/anvilcraft/advancement/recipes/multiblock_conversion/large_fluid_tank_1.json @@ -0,0 +1,21 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_the_recipe": { + "conditions": { + "recipe": "anvilcraft:multiblock_conversion/large_fluid_tank_1" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe" + ] + ], + "rewards": { + "recipes": [ + "anvilcraft:multiblock_conversion/large_fluid_tank_1" + ] + } +} \ No newline at end of file diff --git a/src/generated/resources/data/anvilcraft/advancement/recipes/multiblock_conversion/large_fluid_tank_2.json b/src/generated/resources/data/anvilcraft/advancement/recipes/multiblock_conversion/large_fluid_tank_2.json new file mode 100644 index 000000000..ae462dae6 --- /dev/null +++ b/src/generated/resources/data/anvilcraft/advancement/recipes/multiblock_conversion/large_fluid_tank_2.json @@ -0,0 +1,21 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_the_recipe": { + "conditions": { + "recipe": "anvilcraft:multiblock_conversion/large_fluid_tank_2" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe" + ] + ], + "rewards": { + "recipes": [ + "anvilcraft:multiblock_conversion/large_fluid_tank_2" + ] + } +} \ No newline at end of file diff --git a/src/generated/resources/data/anvilcraft/loot_table/blocks/large_fluid_tank.json b/src/generated/resources/data/anvilcraft/loot_table/blocks/large_fluid_tank.json new file mode 100644 index 000000000..a70719bb2 --- /dev/null +++ b/src/generated/resources/data/anvilcraft/loot_table/blocks/large_fluid_tank.json @@ -0,0 +1,30 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "conditions": [ + { + "block": "anvilcraft:large_fluid_tank", + "condition": "minecraft:block_state_property", + "properties": { + "half": "bottom_center" + } + } + ], + "name": "anvilcraft:large_fluid_tank" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "anvilcraft:blocks/large_fluid_tank" +} \ No newline at end of file diff --git a/src/generated/resources/data/anvilcraft/recipe/multiblock/large_fluid_tank_1.json b/src/generated/resources/data/anvilcraft/recipe/multiblock/large_fluid_tank_1.json new file mode 100644 index 000000000..4671e049e --- /dev/null +++ b/src/generated/resources/data/anvilcraft/recipe/multiblock/large_fluid_tank_1.json @@ -0,0 +1,31 @@ +{ + "type": "anvilcraft:multiblock", + "pattern": { + "layers": [ + [ + "AAA", + "AAA", + "AAA" + ], + [ + "AAA", + "AAA", + "AAA" + ], + [ + "AAA", + "AAA", + "AAA" + ] + ], + "symbols": { + "A": { + "block": "anvilcraft:fluid_tank" + } + } + }, + "result": { + "count": 1, + "id": "anvilcraft:large_fluid_tank" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/anvilcraft/recipe/multiblock/large_fluid_tank_2.json b/src/generated/resources/data/anvilcraft/recipe/multiblock/large_fluid_tank_2.json new file mode 100644 index 000000000..0895607fb --- /dev/null +++ b/src/generated/resources/data/anvilcraft/recipe/multiblock/large_fluid_tank_2.json @@ -0,0 +1,31 @@ +{ + "type": "anvilcraft:multiblock", + "pattern": { + "layers": [ + [ + "AAA", + "AAA", + "AAA" + ], + [ + "AAA", + "A A", + "AAA" + ], + [ + "AAA", + "AAA", + "AAA" + ] + ], + "symbols": { + "A": { + "block": "anvilcraft:fluid_tank" + } + } + }, + "result": { + "count": 1, + "id": "anvilcraft:large_fluid_tank" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/anvilcraft/recipe/multiblock_conversion/large_fluid_tank_1.json b/src/generated/resources/data/anvilcraft/recipe/multiblock_conversion/large_fluid_tank_1.json new file mode 100644 index 000000000..4cc342bd3 --- /dev/null +++ b/src/generated/resources/data/anvilcraft/recipe/multiblock_conversion/large_fluid_tank_1.json @@ -0,0 +1,210 @@ +{ + "type": "anvilcraft:multiblock_conversion", + "inputPattern": { + "layers": [ + [ + "AAA", + "AAA", + "AAA" + ], + [ + "AAA", + "AAA", + "AAA" + ], + [ + "AAA", + "AAA", + "AAA" + ] + ], + "symbols": { + "A": { + "block": "anvilcraft:fluid_tank" + } + } + }, + "outputPattern": { + "layers": [ + [ + "ABC", + "DEF", + "GHI" + ], + [ + "JKL", + "MNO", + "PQR" + ], + [ + "STU", + "VWX", + "YZ[" + ] + ], + "symbols": { + "A": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "bottom_wn" + } + }, + "B": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "bottom_n" + } + }, + "C": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "bottom_en" + } + }, + "D": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "bottom_w" + } + }, + "E": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "bottom_center" + } + }, + "F": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "bottom_e" + } + }, + "G": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "bottom_ws" + } + }, + "H": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "bottom_s" + } + }, + "I": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "bottom_es" + } + }, + "J": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "mid_wn" + } + }, + "K": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "mid_n" + } + }, + "L": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "mid_en" + } + }, + "M": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "mid_w" + } + }, + "N": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "mid_center" + } + }, + "O": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "mid_e" + } + }, + "P": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "mid_ws" + } + }, + "Q": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "mid_s" + } + }, + "R": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "mid_es" + } + }, + "S": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "top_wn" + } + }, + "T": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "top_n" + } + }, + "U": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "top_en" + } + }, + "V": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "top_w" + } + }, + "W": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "top_center" + } + }, + "X": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "top_e" + } + }, + "Y": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "top_ws" + } + }, + "Z": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "top_s" + } + }, + "[": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "top_es" + } + } + } + } +} \ No newline at end of file diff --git a/src/generated/resources/data/anvilcraft/recipe/multiblock_conversion/large_fluid_tank_2.json b/src/generated/resources/data/anvilcraft/recipe/multiblock_conversion/large_fluid_tank_2.json new file mode 100644 index 000000000..a02a4f1a9 --- /dev/null +++ b/src/generated/resources/data/anvilcraft/recipe/multiblock_conversion/large_fluid_tank_2.json @@ -0,0 +1,210 @@ +{ + "type": "anvilcraft:multiblock_conversion", + "inputPattern": { + "layers": [ + [ + "AAA", + "AAA", + "AAA" + ], + [ + "AAA", + "A A", + "AAA" + ], + [ + "AAA", + "AAA", + "AAA" + ] + ], + "symbols": { + "A": { + "block": "anvilcraft:fluid_tank" + } + } + }, + "outputPattern": { + "layers": [ + [ + "ABC", + "DEF", + "GHI" + ], + [ + "JKL", + "MNO", + "PQR" + ], + [ + "STU", + "VWX", + "YZ[" + ] + ], + "symbols": { + "A": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "bottom_wn" + } + }, + "B": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "bottom_n" + } + }, + "C": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "bottom_en" + } + }, + "D": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "bottom_w" + } + }, + "E": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "bottom_center" + } + }, + "F": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "bottom_e" + } + }, + "G": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "bottom_ws" + } + }, + "H": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "bottom_s" + } + }, + "I": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "bottom_es" + } + }, + "J": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "mid_wn" + } + }, + "K": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "mid_n" + } + }, + "L": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "mid_en" + } + }, + "M": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "mid_w" + } + }, + "N": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "mid_center" + } + }, + "O": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "mid_e" + } + }, + "P": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "mid_ws" + } + }, + "Q": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "mid_s" + } + }, + "R": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "mid_es" + } + }, + "S": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "top_wn" + } + }, + "T": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "top_n" + } + }, + "U": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "top_en" + } + }, + "V": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "top_w" + } + }, + "W": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "top_center" + } + }, + "X": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "top_e" + } + }, + "Y": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "top_ws" + } + }, + "Z": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "top_s" + } + }, + "[": { + "block": "anvilcraft:large_fluid_tank", + "properties": { + "half": "top_es" + } + } + } + } +} \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/block/mineable/pickaxe.json b/src/generated/resources/data/minecraft/tags/block/mineable/pickaxe.json index d974c8159..c74b7f0c5 100644 --- a/src/generated/resources/data/minecraft/tags/block/mineable/pickaxe.json +++ b/src/generated/resources/data/minecraft/tags/block/mineable/pickaxe.json @@ -58,6 +58,7 @@ "anvilcraft:activator_sliding_rail", "anvilcraft:detector_sliding_rail", "anvilcraft:sliding_rail_stop", + "anvilcraft:large_fluid_tank", "anvilcraft:acceleration_ring", "anvilcraft:deflection_ring", "anvilcraft:void_energy_collector", diff --git a/src/main/java/dev/dubhe/anvilcraft/block/FluidTankBlock.java b/src/main/java/dev/dubhe/anvilcraft/block/FluidTankBlock.java index 4ebf5eafc..22c87c3fa 100644 --- a/src/main/java/dev/dubhe/anvilcraft/block/FluidTankBlock.java +++ b/src/main/java/dev/dubhe/anvilcraft/block/FluidTankBlock.java @@ -65,8 +65,10 @@ protected ItemInteractionResult useItemOn( ) { InteractionResult result = super.useItemOn(stack, state, level, pos, player, hand, hitResult).result(); if (result == InteractionResult.PASS) { - if (level.getBlockEntity(pos) instanceof FluidTankBlockEntity tank && tank.onPlayerUse(player, hand)) { - return ItemInteractionResult.sidedSuccess(level.isClientSide()); + if (level.getBlockEntity(pos) instanceof FluidTankBlockEntity tank) { + if (tank.onPlayerUse(player, hand)) { + return ItemInteractionResult.sidedSuccess(level.isClientSide()); + } } } diff --git a/src/main/java/dev/dubhe/anvilcraft/block/LargeFluidTankBlock.java b/src/main/java/dev/dubhe/anvilcraft/block/LargeFluidTankBlock.java new file mode 100644 index 000000000..a557590bf --- /dev/null +++ b/src/main/java/dev/dubhe/anvilcraft/block/LargeFluidTankBlock.java @@ -0,0 +1,100 @@ +package dev.dubhe.anvilcraft.block; + +import dev.dubhe.anvilcraft.api.hammer.IHammerRemovable; +import dev.dubhe.anvilcraft.block.entity.LargeFluidTankBlockEntity; +import dev.dubhe.anvilcraft.block.multipart.SimpleMultiPartBlock; +import dev.dubhe.anvilcraft.block.state.Cube3x3PartHalf; +import dev.dubhe.anvilcraft.init.block.ModBlockEntities; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Vec3i; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +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.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.block.state.properties.Property; +import net.minecraft.world.phys.BlockHitResult; +import org.jetbrains.annotations.Nullable; + +import static dev.dubhe.anvilcraft.block.PropelPiston.createTickerHelper; + +public class LargeFluidTankBlock extends SimpleMultiPartBlock implements EntityBlock, IHammerRemovable { + public static final EnumProperty HALF = EnumProperty.create("half", Cube3x3PartHalf.class); + + public LargeFluidTankBlock(Properties properties) { + super(properties); + this.registerDefaultState(this.stateDefinition + .any() + .setValue(HALF, Cube3x3PartHalf.BOTTOM_CENTER)); + } + + @Override + public Vec3i getMainPartOffset() { + return new Vec3i(0, 1, 0); + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(HALF); + } + + @Override + public Property getPart() { + return HALF; + } + + @Override + public Cube3x3PartHalf[] getParts() { + return Cube3x3PartHalf.values(); + } + + @Override + public @Nullable BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) { + return ModBlockEntities.LARGE_FLUID_TANK.create(blockPos, blockState); + } + + @Override + public @Nullable BlockEntityTicker getTicker(Level level, BlockState state, BlockEntityType type) { + return createTickerHelper( + type, + ModBlockEntities.LARGE_FLUID_TANK.get(), + (level1, blockPos, blockState, blockEntity) -> blockEntity.tick() + ); + } + + @Override + protected ItemInteractionResult useItemOn( + ItemStack stack, + BlockState state, + Level level, + BlockPos pos, + Player player, + InteractionHand hand, + BlockHitResult hitResult + ) { + InteractionResult result = super.useItemOn(stack, state, level, pos, player, hand, hitResult).result(); + if (result != InteractionResult.PASS) return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; + if (!(level.getBlockEntity(pos) instanceof LargeFluidTankBlockEntity)) { + return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; + } + + BlockPos centerPos = this.getMainPartPos(pos, state); + if (!(level.getBlockEntity(centerPos) instanceof LargeFluidTankBlockEntity tank)) { + return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; + } + if (tank.onPlayerUse(player, hand)) { + return ItemInteractionResult.sidedSuccess(level.isClientSide()); + } + + return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; + } +} diff --git a/src/main/java/dev/dubhe/anvilcraft/block/entity/LargeFluidTankBlockEntity.java b/src/main/java/dev/dubhe/anvilcraft/block/entity/LargeFluidTankBlockEntity.java new file mode 100644 index 000000000..9be8e82d5 --- /dev/null +++ b/src/main/java/dev/dubhe/anvilcraft/block/entity/LargeFluidTankBlockEntity.java @@ -0,0 +1,98 @@ +package dev.dubhe.anvilcraft.block.entity; + +import dev.dubhe.anvilcraft.api.fluid.IFluidHandlerHolder; +import dev.dubhe.anvilcraft.block.AccelerationRingBlock; +import dev.dubhe.anvilcraft.block.LargeFluidTankBlock; +import dev.dubhe.anvilcraft.block.state.Cube3x3PartHalf; +import dev.dubhe.anvilcraft.block.state.DirectionCube3x3PartHalf; +import dev.dubhe.anvilcraft.util.TankUtil; +import net.minecraft.core.BlockPos; +import net.minecraft.core.HolderLookup; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.neoforged.neoforge.fluids.FluidType; +import net.neoforged.neoforge.fluids.FluidUtil; +import net.neoforged.neoforge.fluids.IFluidTank; +import net.neoforged.neoforge.fluids.capability.IFluidHandler; +import net.neoforged.neoforge.fluids.capability.templates.FluidTank; + +public class LargeFluidTankBlockEntity extends BlockEntity implements IFluidHandlerHolder { + public static final int CAPACITY = 320; + public static final int BIG_CAPACITY = 12800; + public static final int COOLDOWN = 100; + protected FluidTank tank = new FluidTank(CAPACITY * FluidType.BUCKET_VOLUME); + protected int cooldown = 0; + + + public LargeFluidTankBlockEntity(BlockEntityType type, BlockPos pos, BlockState blockState) { + super(type, pos, blockState); + } + + public void tick() { + BlockState state = getBlockState(); + if (!state.getValue(LargeFluidTankBlock.HALF).equals(Cube3x3PartHalf.MID_CENTER)) return; + if (--cooldown <= 0) { + checkStructure(); + cooldown = COOLDOWN; + } + setChanged(); + } + + protected void checkStructure() { + if (this.getLevel() == null) return; + + int targetCapacity = TankUtil.isMengerStructure(this.getLevel(), this.getBlockPos(), 9) ? BIG_CAPACITY : CAPACITY; + if (tank.getCapacity() != targetCapacity) { + tank.setCapacity(targetCapacity * FluidType.BUCKET_VOLUME); + } + } + + @Override + protected void saveAdditional(CompoundTag tag, HolderLookup.Provider provider) { + super.saveAdditional(tag, provider); + CompoundTag tankNbt = tank.writeToNBT(provider, new CompoundTag()); + if (!tankNbt.isEmpty()) { + tag.put("tank", tankNbt); + } + } + + @Override + public void loadAdditional(CompoundTag tag, HolderLookup.Provider provider) { + super.loadAdditional(tag, provider); + tank.readFromNBT(provider, tag.getCompound("tank")); + } + + @Override + public CompoundTag getUpdateTag(HolderLookup.Provider registries) { + CompoundTag tag = super.getUpdateTag(registries); + CompoundTag fluidTag = new CompoundTag(); + tank.writeToNBT(registries, fluidTag); + tag.put("tank", fluidTag); + return tag; + } + + @Override + public Packet getUpdatePacket() { + return ClientboundBlockEntityDataPacket.create(this); + } + + public boolean onPlayerUse(Player player, InteractionHand hand) { + checkStructure(); + return FluidUtil.interactWithFluidHandler(player, hand, tank); + } + + public IFluidTank getTank() { + return tank; + } + + public IFluidHandler getFluidHandler() { + return tank; + } +} \ No newline at end of file diff --git a/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/LargeFluidTankBlockEntityRenderer.java b/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/LargeFluidTankBlockEntityRenderer.java new file mode 100644 index 000000000..a8ded33fd --- /dev/null +++ b/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/LargeFluidTankBlockEntityRenderer.java @@ -0,0 +1,152 @@ +/* + * Original Code Copyright (C) 2013 - 2020 AlgorithmX2 et al + * Source: https://github.com/AppliedEnergistics/Applied-Energistics-2 + * + * This file is part of "Applied Energistics 2" project, which is licensed under + * the GNU Lesser General Public License Version 3 (LGPLv3). + * + * --- MODIFICATIONS --- + * This file has been modified for use in AnvilCraft. + * Modifications made by: TB_pig + * Modification date: 2026/2/12 + * These modifications continue to be licensed under LGPLv3. + * ------------------------------------------------------------- + */ +package dev.dubhe.anvilcraft.client.renderer.blockentity; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import dev.dubhe.anvilcraft.block.entity.FluidTankBlockEntity; +import dev.dubhe.anvilcraft.block.entity.LargeFluidTankBlockEntity; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions; +import net.neoforged.neoforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.FluidType; +import org.joml.Matrix4f; + +public class LargeFluidTankBlockEntityRenderer implements BlockEntityRenderer { + public LargeFluidTankBlockEntityRenderer(BlockEntityRendererProvider.Context context) { + } + + + @Override + public void render( + LargeFluidTankBlockEntity tank, float tickDelta, PoseStack ms, MultiBufferSource vertexConsumers, int light, int overlay) { + if (!tank.getTank().getFluid().isEmpty()) { + + /* + * + * // Uncomment to allow the liquid to rotate with the tank ms.pushPose(); ms.translate(0.5, 0.5, 0.5); + * FacingToRotation.get(tank.getForward(), tank.getUp()).push(ms); ms.translate(-0.5, -0.5, -0.5); + */ + + drawFluidInTank( + tank, ms, vertexConsumers, light, tank.getTank().getFluid(), + (float) tank.getTank().getFluid().getAmount() / tank.getTank().getCapacity() + ); + + // ms.popPose(); + } + } + + private static final float TANK_W = 1 / 16f + 0.001f; // avoiding Z-fighting + + public static void drawFluidInTank( + BlockEntity be, PoseStack ms, MultiBufferSource vcp, int light, FluidStack fluid, + float fill + ) { + drawFluidInTank(be.getLevel(), be.getBlockPos(), ms, vcp, light, fluid, fill); + } + + public static void drawFluidInTank( + Level level, BlockPos pos, PoseStack ps, MultiBufferSource mbs, int light, + FluidStack fluid, float fill + ) { + // From Modern Industrialization + var renderProps = IClientFluidTypeExtensions.of(fluid.getFluid()); + TextureAtlasSprite sprite = Minecraft.getInstance().getTextureAtlas(InventoryMenu.BLOCK_ATLAS) + .apply(renderProps.getStillTexture(fluid)); + + int color = renderProps.getTintColor(fluid); + float fillY = Mth.lerp(Mth.clamp(fill, 0, 1), TANK_W, 1 - TANK_W); + + // Top and bottom positions of the fluid inside the tank + float topHeight = fillY; + float bottomHeight = TANK_W; + + // Render gas from top to bottom + FluidType attributes = fluid.getFluid().getFluidType(); + if (attributes.isLighterThanAir()) { + topHeight = 1 - TANK_W; + bottomHeight = 1 - fillY; + } + + float minX = TANK_W * 3 - 1; + float minZ = TANK_W * 3 - 1; + float maxX = (1 - TANK_W) * 3 - 1; + float maxZ = (1 - TANK_W) * 3 - 1; + float minY = bottomHeight * 3 - 1; + float maxY = topHeight * 3 - 1; + + // 在 render 方法中 + ps.pushPose(); + + // 获取顶点构建器 + VertexConsumer consumer = mbs.getBuffer(RenderType.translucent()); + + // 纹理映射:简单将整个 sprite 映射到每个面,不进行平铺 + float u0 = sprite.getU0(); + float u1 = sprite.getU1(); + float v0 = sprite.getV0(); + float v1 = sprite.getV1(); + + Matrix4f pose = ps.last().pose(); + + consumer.addVertex(pose, maxX, maxY, maxZ).setColor(color).setUv(u0, v0).setLight(light).setNormal(0, 1, 0); + consumer.addVertex(pose, maxX, maxY, minZ).setColor(color).setUv(u1, v0).setLight(light).setNormal(0, 1, 0); + consumer.addVertex(pose, minX, maxY, minZ).setColor(color).setUv(u1, v1).setLight(light).setNormal(0, 1, 0); + consumer.addVertex(pose, minX, maxY, maxZ).setColor(color).setUv(u0, v1).setLight(light).setNormal(0, 1, 0); + + // 北面 (Z-) + consumer.addVertex(pose, maxX, maxY, minZ).setColor(color).setUv(u0, v0).setLight(light).setNormal(0, 0, -1); + consumer.addVertex(pose, maxX, minY, minZ).setColor(color).setUv(u1, v0).setLight(light).setNormal(0, 0, -1); + consumer.addVertex(pose, minX, minY, minZ).setColor(color).setUv(u1, v1).setLight(light).setNormal(0, 0, -1); + consumer.addVertex(pose, minX, maxY, minZ).setColor(color).setUv(u0, v1).setLight(light).setNormal(0, 0, -1); + + // 南面 (Z+) + consumer.addVertex(pose, maxX, minY, maxZ).setColor(color).setUv(u0, v0).setLight(light).setNormal(0, 0, 1); + consumer.addVertex(pose, maxX, maxY, maxZ).setColor(color).setUv(u1, v0).setLight(light).setNormal(0, 0, 1); + consumer.addVertex(pose, minX, maxY, maxZ).setColor(color).setUv(u1, v1).setLight(light).setNormal(0, 0, 1); + consumer.addVertex(pose, minX, minY, maxZ).setColor(color).setUv(u0, v1).setLight(light).setNormal(0, 0, 1); + + // 西面 (X-) + consumer.addVertex(pose, minX, maxY, maxZ).setColor(color).setUv(u0, v0).setLight(light).setNormal(-1, 0, 0); + consumer.addVertex(pose, minX, maxY, minZ).setColor(color).setUv(u1, v0).setLight(light).setNormal(-1, 0, 0); + consumer.addVertex(pose, minX, minY, minZ).setColor(color).setUv(u1, v1).setLight(light).setNormal(-1, 0, 0); + consumer.addVertex(pose, minX, minY, maxZ).setColor(color).setUv(u0, v1).setLight(light).setNormal(-1, 0, 0); + + // 东面 (X+) + consumer.addVertex(pose, maxX, minY, maxZ).setColor(color).setUv(u0, v0).setLight(light).setNormal(1, 0, 0); + consumer.addVertex(pose, maxX, minY, minZ).setColor(color).setUv(u1, v0).setLight(light).setNormal(1, 0, 0); + consumer.addVertex(pose, maxX, maxY, minZ).setColor(color).setUv(u1, v1).setLight(light).setNormal(1, 0, 0); + consumer.addVertex(pose, maxX, maxY, maxZ).setColor(color).setUv(u0, v1).setLight(light).setNormal(1, 0, 0); + + // 底面 (Y-) + consumer.addVertex(pose, maxX, minY, maxZ).setColor(color).setUv(u0, v0).setLight(light).setNormal(0, -1, 0); + consumer.addVertex(pose, minX, minY, maxZ).setColor(color).setUv(u1, v0).setLight(light).setNormal(0, -1, 0); + consumer.addVertex(pose, minX, minY, minZ).setColor(color).setUv(u1, v1).setLight(light).setNormal(0, -1, 0); + consumer.addVertex(pose, maxX, minY, minZ).setColor(color).setUv(u0, v1).setLight(light).setNormal(0, -1, 0); + ps.popPose(); + } + +} diff --git a/src/main/java/dev/dubhe/anvilcraft/data/recipe/MultiBlockConversionRecipeLoader.java b/src/main/java/dev/dubhe/anvilcraft/data/recipe/MultiBlockConversionRecipeLoader.java index f70e78596..f7b6e0c22 100644 --- a/src/main/java/dev/dubhe/anvilcraft/data/recipe/MultiBlockConversionRecipeLoader.java +++ b/src/main/java/dev/dubhe/anvilcraft/data/recipe/MultiBlockConversionRecipeLoader.java @@ -422,6 +422,244 @@ public static void init(RegistrateRecipeProvider provider) { ) .save(provider, AnvilCraft.of("multiblock_conversion/giant_anvil_2")); + + MultiblockConversionRecipe.builder() + .inputLayer("AAA", "AAA", "AAA") + .inputLayer("AAA", "AAA", "AAA") + .inputLayer("AAA", "AAA", "AAA") + .inputSymbol('A', ModBlocks.FLUID_TANK) + .outputLayer("ABC", "DEF", "GHI") + .outputLayer("JKL", "MNO", "PQR") + .outputLayer("STU", "VWX", "YZ[") + .outputSymbol( + 'A', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.BOTTOM_WN) + ) + .outputSymbol( + 'B', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.BOTTOM_N) + ) + .outputSymbol( + 'C', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.BOTTOM_EN) + ) + .outputSymbol( + 'D', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.BOTTOM_W) + ) + .outputSymbol( + 'E', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.BOTTOM_CENTER) + ) + .outputSymbol( + 'F', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.BOTTOM_E) + ) + .outputSymbol( + 'G', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.BOTTOM_WS) + ) + .outputSymbol( + 'H', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.BOTTOM_S) + ) + .outputSymbol( + 'I', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.BOTTOM_ES) + ) + .outputSymbol( + 'J', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.MID_WN) + ) + .outputSymbol( + 'K', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.MID_N) + ) + .outputSymbol( + 'L', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.MID_EN) + ) + .outputSymbol( + 'M', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.MID_W) + ) + .outputSymbol( + 'N', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.MID_CENTER) + ) + .outputSymbol( + 'O', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.MID_E) + ) + .outputSymbol( + 'P', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.MID_WS) + ) + .outputSymbol( + 'Q', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.MID_S) + ) + .outputSymbol( + 'R', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.MID_ES) + ) + .outputSymbol( + 'S', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.TOP_WN) + ) + .outputSymbol( + 'T', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.TOP_N) + ) + .outputSymbol( + 'U', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.TOP_EN) + ) + .outputSymbol( + 'V', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.TOP_W) + ) + .outputSymbol( + 'W', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.TOP_CENTER) + ) + .outputSymbol( + 'X', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.TOP_E) + ) + .outputSymbol( + 'Y', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.TOP_WS) + ) + .outputSymbol( + 'Z', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.TOP_S) + ) + .outputSymbol( + '[', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.TOP_ES) + ) + .save(provider, AnvilCraft.of("multiblock_conversion/large_fluid_tank_1")); + + MultiblockConversionRecipe.builder() + .inputLayer("AAA", "AAA", "AAA") + .inputLayer("AAA", "A A", "AAA") + .inputLayer("AAA", "AAA", "AAA") + .inputSymbol('A', ModBlocks.FLUID_TANK) + .outputLayer("ABC", "DEF", "GHI") + .outputLayer("JKL", "MNO", "PQR") + .outputLayer("STU", "VWX", "YZ[") + .outputSymbol( + 'A', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.BOTTOM_WN) + ) + .outputSymbol( + 'B', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.BOTTOM_N) + ) + .outputSymbol( + 'C', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.BOTTOM_EN) + ) + .outputSymbol( + 'D', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.BOTTOM_W) + ) + .outputSymbol( + 'E', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.BOTTOM_CENTER) + ) + .outputSymbol( + 'F', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.BOTTOM_E) + ) + .outputSymbol( + 'G', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.BOTTOM_WS) + ) + .outputSymbol( + 'H', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.BOTTOM_S) + ) + .outputSymbol( + 'I', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.BOTTOM_ES) + ) + .outputSymbol( + 'J', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.MID_WN) + ) + .outputSymbol( + 'K', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.MID_N) + ) + .outputSymbol( + 'L', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.MID_EN) + ) + .outputSymbol( + 'M', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.MID_W) + ) + .outputSymbol( + 'N', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.MID_CENTER) + ) + .outputSymbol( + 'O', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.MID_E) + ) + .outputSymbol( + 'P', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.MID_WS) + ) + .outputSymbol( + 'Q', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.MID_S) + ) + .outputSymbol( + 'R', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.MID_ES) + ) + .outputSymbol( + 'S', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.TOP_WN) + ) + .outputSymbol( + 'T', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.TOP_N) + ) + .outputSymbol( + 'U', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.TOP_EN) + ) + .outputSymbol( + 'V', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.TOP_W) + ) + .outputSymbol( + 'W', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.TOP_CENTER) + ) + .outputSymbol( + 'X', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.TOP_E) + ) + .outputSymbol( + 'Y', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.TOP_WS) + ) + .outputSymbol( + 'Z', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.TOP_S) + ) + .outputSymbol( + '[', BlockPredicateWithState.of(ModBlocks.LARGE_FLUID_TANK) + .hasState(GiantAnvilBlock.HALF, Cube3x3PartHalf.TOP_ES) + ) + .save(provider, AnvilCraft.of("multiblock_conversion/large_fluid_tank_2")); + + MultiblockConversionRecipe.builder() .inputLayer("ABA", "B B", "ABA") .inputLayer("CDC", "D D", "CDC") diff --git a/src/main/java/dev/dubhe/anvilcraft/data/recipe/MultiBlockRecipeLoader.java b/src/main/java/dev/dubhe/anvilcraft/data/recipe/MultiBlockRecipeLoader.java index 5bd77defc..6764ebede 100644 --- a/src/main/java/dev/dubhe/anvilcraft/data/recipe/MultiBlockRecipeLoader.java +++ b/src/main/java/dev/dubhe/anvilcraft/data/recipe/MultiBlockRecipeLoader.java @@ -69,6 +69,20 @@ public static void init(RegistrateRecipeProvider provider) { .symbol('C', ModBlocks.POLISHED_HEAVY_IRON_BLOCK) .save(provider, AnvilCraft.of("multiblock/giant_anvil_2")); + MultiblockRecipe.builder(ModBlocks.LARGE_FLUID_TANK) + .layer("AAA", "AAA", "AAA") + .layer("AAA", "AAA", "AAA") + .layer("AAA", "AAA", "AAA") + .symbol('A', ModBlocks.FLUID_TANK) + .save(provider, AnvilCraft.of("multiblock/large_fluid_tank_1")); + + MultiblockRecipe.builder(ModBlocks.LARGE_FLUID_TANK) + .layer("AAA", "AAA", "AAA") + .layer("AAA", "A A", "AAA") + .layer("AAA", "AAA", "AAA") + .symbol('A', ModBlocks.FLUID_TANK) + .save(provider, AnvilCraft.of("multiblock/large_fluid_tank_2")); + MultiblockRecipe.builder(ModBlocks.MENGER_SPONGE) .layer("AAA", "A A", "AAA") .layer("A A", " B ", "A A") diff --git a/src/main/java/dev/dubhe/anvilcraft/event/CapabilitiesEventListener.java b/src/main/java/dev/dubhe/anvilcraft/event/CapabilitiesEventListener.java index 83f9a6f35..6718f8620 100644 --- a/src/main/java/dev/dubhe/anvilcraft/event/CapabilitiesEventListener.java +++ b/src/main/java/dev/dubhe/anvilcraft/event/CapabilitiesEventListener.java @@ -36,10 +36,15 @@ public static void registerCapabilities(final RegisterCapabilitiesEvent event) { ModBlocks.HONEY_CAULDRON.get() ); - event.registerBlockEntity( - Capabilities.FluidHandler.BLOCK, + List.of( ModBlockEntities.FLUID_TANK.get(), + ModBlockEntities.LARGE_FLUID_TANK.get() + ).forEach(type -> event.registerBlockEntity( + Capabilities.FluidHandler.BLOCK, + type, (be, side) -> be.getFluidHandler() - ); + )); + + } } diff --git a/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlockEntities.java b/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlockEntities.java index a183d430a..ffbd39040 100644 --- a/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlockEntities.java +++ b/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlockEntities.java @@ -23,6 +23,7 @@ import dev.dubhe.anvilcraft.block.entity.InductionLightBlockEntity; import dev.dubhe.anvilcraft.block.entity.ItemCollectorBlockEntity; import dev.dubhe.anvilcraft.block.entity.ItemDetectorBlockEntity; +import dev.dubhe.anvilcraft.block.entity.LargeFluidTankBlockEntity; import dev.dubhe.anvilcraft.block.entity.LaserReceiverBlockEntity; import dev.dubhe.anvilcraft.block.entity.LoadMonitorBlockEntity; import dev.dubhe.anvilcraft.block.entity.MagneticChuteBlockEntity; @@ -61,6 +62,7 @@ import dev.dubhe.anvilcraft.client.renderer.blockentity.HasMobBlockRenderer; import dev.dubhe.anvilcraft.client.renderer.blockentity.HeatCollectorRenderer; import dev.dubhe.anvilcraft.client.renderer.blockentity.HeliostatsRenderer; +import dev.dubhe.anvilcraft.client.renderer.blockentity.LargeFluidTankBlockEntityRenderer; import dev.dubhe.anvilcraft.client.renderer.blockentity.LaserBlockRenderer; import dev.dubhe.anvilcraft.client.renderer.blockentity.PlasmaJetsRenderer; import dev.dubhe.anvilcraft.client.renderer.blockentity.VoidEnergyCollectorRenderer; @@ -312,6 +314,12 @@ public class ModBlockEntities { .renderer(() -> FluidTankBlockEntityRenderer::new) .register(); + public static final BlockEntityEntry LARGE_FLUID_TANK = REGISTRATE + .blockEntity("large_fluid_tank", LargeFluidTankBlockEntity::new) + .validBlocks(ModBlocks.LARGE_FLUID_TANK) + .renderer(() -> LargeFluidTankBlockEntityRenderer::new) + .register(); + public static void register() { } } diff --git a/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlocks.java b/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlocks.java index f841b7748..add71e251 100644 --- a/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlocks.java +++ b/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlocks.java @@ -74,6 +74,7 @@ import dev.dubhe.anvilcraft.block.ItemDetectorBlock; import dev.dubhe.anvilcraft.block.JewelCraftingTable; import dev.dubhe.anvilcraft.block.LargeCakeBlock; +import dev.dubhe.anvilcraft.block.LargeFluidTankBlock; import dev.dubhe.anvilcraft.block.LaserReceiverBlock; import dev.dubhe.anvilcraft.block.LavaCauldronBlock; import dev.dubhe.anvilcraft.block.LevitationPowderBlock; @@ -1753,6 +1754,20 @@ public class ModBlocks { }) .register(); + public static final BlockEntry LARGE_FLUID_TANK = REGISTRATE.block( + "large_fluid_tank", + LargeFluidTankBlock::new + ) + .initialProperties(() -> Blocks.IRON_BLOCK) + .properties(p -> p.isSuffocating(ModBlocks::never).noOcclusion().isValidSpawn(Blocks::never)) + .loot(SimpleMultiPartBlock::loot) + .item(SimpleMultiPartBlockItem::new) + .properties((properties) -> properties.stacksTo(16)) + .build() + .blockstate(DataGenUtil::noExtraModelOrState) + .tag(BlockTags.MINEABLE_WITH_PICKAXE) + .register(); + public static final BlockEntry ACCELERATION_RING = REGISTRATE.block( "acceleration_ring", AccelerationRingBlock::new diff --git a/src/main/resources/assets/anvilcraft/blockstates/large_fluid_tank.json b/src/main/resources/assets/anvilcraft/blockstates/large_fluid_tank.json new file mode 100644 index 000000000..c8f34e710 --- /dev/null +++ b/src/main/resources/assets/anvilcraft/blockstates/large_fluid_tank.json @@ -0,0 +1,85 @@ +{ + "variants": { + "half=mid_center": { + "model": "anvilcraft:block/large_fluid_tank" + }, + "half=bottom_center": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=bottom_w": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=bottom_e": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=bottom_n": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=bottom_s": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=bottom_wn": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=bottom_ws": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=bottom_en": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=bottom_es": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=mid_w": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=mid_e": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=mid_n": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=mid_s": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=mid_wn": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=mid_ws": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=mid_en": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=mid_es": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=top_center": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=top_w": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=top_e": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=top_n": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=top_s": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=top_wn": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=top_ws": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=top_en": { + "model": "anvilcraft:block/large_fluid_tank_part" + }, + "half=top_es": { + "model": "anvilcraft:block/large_fluid_tank_part" + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/anvilcraft/models/block/fluid_tank.json b/src/main/resources/assets/anvilcraft/models/block/fluid_tank.json index 16d15a495..70ec2a91d 100644 --- a/src/main/resources/assets/anvilcraft/models/block/fluid_tank.json +++ b/src/main/resources/assets/anvilcraft/models/block/fluid_tank.json @@ -34,43 +34,5 @@ "down": {"uv": [15, 1, 1, 15], "texture": "#top"} } } - ], - "display": { - "thirdperson_righthand": { - "rotation": [75, 45, 0], - "translation": [0, 2.5, 0], - "scale": [0.2, 0.2, 0.2] - }, - "thirdperson_lefthand": { - "rotation": [75, 45, 0], - "translation": [0, 2.5, 0], - "scale": [0.2, 0.2, 0.2] - }, - "firstperson_righthand": { - "rotation": [0, -135, 0], - "translation": [3.75, 0, 0], - "scale": [0.2, 0.2, 0.2] - }, - "firstperson_lefthand": { - "rotation": [0, -135, 0], - "translation": [3.75, 0, 0], - "scale": [0.2, 0.2, 0.2] - }, - "ground": { - "translation": [0, 4, 0], - "scale": [0.2, 0.2, 0.2] - }, - "gui": { - "rotation": [30, -135, 0], - "translation": [0, -0.25, 0], - "scale": [0.24, 0.24, 0.24] - }, - "head": { - "translation": [0, 1, 0], - "scale": [0.6, 0.6, 0.6] - }, - "fixed": { - "scale": [0.66, 0.66, 0.66] - } - } + ] } \ No newline at end of file diff --git a/src/main/resources/assets/anvilcraft/models/block/large_fluid_tank_part.json b/src/main/resources/assets/anvilcraft/models/block/large_fluid_tank_part.json new file mode 100644 index 000000000..4b6d2c61a --- /dev/null +++ b/src/main/resources/assets/anvilcraft/models/block/large_fluid_tank_part.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/block", + "textures": { + "particle": "anvilcraft:block/large_fluid_tank_side" + } +} \ No newline at end of file From 8efb5a0a74e7c43584ec7935261fe83404aa4b17 Mon Sep 17 00:00:00 2001 From: TBPig <147127248+TBPig@users.noreply.github.com> Date: Fri, 13 Feb 2026 21:56:35 +0800 Subject: [PATCH 6/9] fix style --- .../anvilcraft/block/entity/LargeFluidTankBlockEntity.java | 2 -- .../renderer/blockentity/LargeFluidTankBlockEntityRenderer.java | 1 - 2 files changed, 3 deletions(-) diff --git a/src/main/java/dev/dubhe/anvilcraft/block/entity/LargeFluidTankBlockEntity.java b/src/main/java/dev/dubhe/anvilcraft/block/entity/LargeFluidTankBlockEntity.java index 9be8e82d5..0c5352d16 100644 --- a/src/main/java/dev/dubhe/anvilcraft/block/entity/LargeFluidTankBlockEntity.java +++ b/src/main/java/dev/dubhe/anvilcraft/block/entity/LargeFluidTankBlockEntity.java @@ -1,10 +1,8 @@ package dev.dubhe.anvilcraft.block.entity; import dev.dubhe.anvilcraft.api.fluid.IFluidHandlerHolder; -import dev.dubhe.anvilcraft.block.AccelerationRingBlock; import dev.dubhe.anvilcraft.block.LargeFluidTankBlock; import dev.dubhe.anvilcraft.block.state.Cube3x3PartHalf; -import dev.dubhe.anvilcraft.block.state.DirectionCube3x3PartHalf; import dev.dubhe.anvilcraft.util.TankUtil; import net.minecraft.core.BlockPos; import net.minecraft.core.HolderLookup; diff --git a/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/LargeFluidTankBlockEntityRenderer.java b/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/LargeFluidTankBlockEntityRenderer.java index a8ded33fd..d93a8821f 100644 --- a/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/LargeFluidTankBlockEntityRenderer.java +++ b/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/LargeFluidTankBlockEntityRenderer.java @@ -16,7 +16,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import dev.dubhe.anvilcraft.block.entity.FluidTankBlockEntity; import dev.dubhe.anvilcraft.block.entity.LargeFluidTankBlockEntity; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; From 9ab35295f226842965954b7264dffe35dedcbcc7 Mon Sep 17 00:00:00 2001 From: TBPig <147127248+TBPig@users.noreply.github.com> Date: Fri, 13 Feb 2026 22:05:08 +0800 Subject: [PATCH 7/9] fix style --- .../FluidTankBlockEntityRenderer.java | 17 +++++----------- .../LargeFluidTankBlockEntityRenderer.java | 20 +++++-------------- 2 files changed, 10 insertions(+), 27 deletions(-) diff --git a/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/FluidTankBlockEntityRenderer.java b/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/FluidTankBlockEntityRenderer.java index 185f9ae8c..3b35ab339 100644 --- a/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/FluidTankBlockEntityRenderer.java +++ b/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/FluidTankBlockEntityRenderer.java @@ -23,11 +23,8 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.core.BlockPos; import net.minecraft.util.Mth; import net.minecraft.world.inventory.InventoryMenu; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions; import net.neoforged.neoforge.fluids.FluidStack; import net.neoforged.neoforge.fluids.FluidType; @@ -50,7 +47,10 @@ public void render( */ drawFluidInTank( - tank, ms, vertexConsumers, light, tank.getTank().getFluid(), + ms, + vertexConsumers, + light, + tank.getTank().getFluid(), (float) tank.getTank().getFluid().getAmount() / tank.getTank().getCapacity() ); @@ -61,14 +61,7 @@ public void render( private static final float TANK_W = 1 / 16f + 0.001f; // avoiding Z-fighting public static void drawFluidInTank( - BlockEntity be, PoseStack ms, MultiBufferSource vcp, int light, FluidStack fluid, - float fill - ) { - drawFluidInTank(be.getLevel(), be.getBlockPos(), ms, vcp, light, fluid, fill); - } - - public static void drawFluidInTank( - Level level, BlockPos pos, PoseStack ps, MultiBufferSource mbs, int light, + PoseStack ps, MultiBufferSource mbs, int light, FluidStack fluid, float fill ) { // From Modern Industrialization diff --git a/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/LargeFluidTankBlockEntityRenderer.java b/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/LargeFluidTankBlockEntityRenderer.java index d93a8821f..1f674af25 100644 --- a/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/LargeFluidTankBlockEntityRenderer.java +++ b/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/LargeFluidTankBlockEntityRenderer.java @@ -23,11 +23,8 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.core.BlockPos; import net.minecraft.util.Mth; import net.minecraft.world.inventory.InventoryMenu; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions; import net.neoforged.neoforge.fluids.FluidStack; import net.neoforged.neoforge.fluids.FluidType; @@ -50,7 +47,10 @@ public void render( */ drawFluidInTank( - tank, ms, vertexConsumers, light, tank.getTank().getFluid(), + ms, + vertexConsumers, + light, + tank.getTank().getFluid(), (float) tank.getTank().getFluid().getAmount() / tank.getTank().getCapacity() ); @@ -60,17 +60,7 @@ public void render( private static final float TANK_W = 1 / 16f + 0.001f; // avoiding Z-fighting - public static void drawFluidInTank( - BlockEntity be, PoseStack ms, MultiBufferSource vcp, int light, FluidStack fluid, - float fill - ) { - drawFluidInTank(be.getLevel(), be.getBlockPos(), ms, vcp, light, fluid, fill); - } - - public static void drawFluidInTank( - Level level, BlockPos pos, PoseStack ps, MultiBufferSource mbs, int light, - FluidStack fluid, float fill - ) { + public static void drawFluidInTank(PoseStack ps, MultiBufferSource mbs, int light, FluidStack fluid, float fill) { // From Modern Industrialization var renderProps = IClientFluidTypeExtensions.of(fluid.getFluid()); TextureAtlasSprite sprite = Minecraft.getInstance().getTextureAtlas(InventoryMenu.BLOCK_ATLAS) From 44d20083ca5e4f2036534de339960c0b4508ff93 Mon Sep 17 00:00:00 2001 From: TBPig <147127248+TBPig@users.noreply.github.com> Date: Sat, 14 Feb 2026 15:15:36 +0800 Subject: [PATCH 8/9] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=B7=A8=E5=9E=8B?= =?UTF-8?q?=E6=B5=81=E4=BD=93=E5=82=A8=E7=BD=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/fluidtank/InfinityFluidTank.java | 82 +++++ .../api/fluidtank/package-info.java | 7 + .../anvilcraft/block/LargeFluidTankBlock.java | 25 +- .../block/entity/FluidTankBlockEntity.java | 9 +- .../entity/LargeFluidTankBlockEntity.java | 42 ++- .../FluidTankBlockEntityRenderer.java | 123 ++------ .../LargeFluidTankBlockEntityRenderer.java | 290 +++++++++++++----- .../anvilcraft/init/block/ModBlocks.java | 10 +- 8 files changed, 382 insertions(+), 206 deletions(-) create mode 100644 src/main/java/dev/dubhe/anvilcraft/api/fluidtank/InfinityFluidTank.java create mode 100644 src/main/java/dev/dubhe/anvilcraft/api/fluidtank/package-info.java diff --git a/src/main/java/dev/dubhe/anvilcraft/api/fluidtank/InfinityFluidTank.java b/src/main/java/dev/dubhe/anvilcraft/api/fluidtank/InfinityFluidTank.java new file mode 100644 index 000000000..a01d79900 --- /dev/null +++ b/src/main/java/dev/dubhe/anvilcraft/api/fluidtank/InfinityFluidTank.java @@ -0,0 +1,82 @@ +package dev.dubhe.anvilcraft.api.fluidtank; + +import lombok.Getter; +import lombok.Setter; +import net.minecraft.core.HolderLookup; +import net.minecraft.nbt.CompoundTag; +import net.neoforged.neoforge.fluids.FluidStack; +import net.neoforged.neoforge.fluids.capability.IFluidHandler; +import net.neoforged.neoforge.fluids.capability.templates.FluidTank; + +import java.util.function.Predicate; + +public class InfinityFluidTank extends FluidTank { + @Setter + @Getter + private boolean isInfinity; + + public InfinityFluidTank(int capacity, Predicate validator) { + this(capacity, validator, true); + } + + public InfinityFluidTank(int capacity, Predicate validator, boolean isInfinity) { + super(capacity, validator); + this.isInfinity = isInfinity; + } + + public InfinityFluidTank(int capacity) { + this(capacity, true); + } + + public InfinityFluidTank(int capacity, boolean isInfinity) { + super(capacity); + this.isInfinity = isInfinity; + } + + public FluidTank readFromNBT(HolderLookup.Provider lookupProvider, CompoundTag nbt) { + super.readFromNBT(lookupProvider, nbt); + this.isInfinity = nbt.getBoolean("Infinity"); + return this; + } + + public CompoundTag writeToNBT(HolderLookup.Provider lookupProvider, CompoundTag nbt) { + super.writeToNBT(lookupProvider, nbt); + nbt.putBoolean("Infinity", this.isInfinity); + return nbt; + } + + @Override + public FluidTank setCapacity(int capacity) { + super.setCapacity(capacity); + if (this.isInfinity && !this.fluid.isEmpty()) this.fluid.setAmount(this.capacity); + return this; + } + + @Override + public int fill(FluidStack resource, IFluidHandler.FluidAction action) { + if (!this.isInfinity) return super.fill(resource, action); + + if (resource.isEmpty() || !this.isFluidValid(resource)) return 0; + + if (!this.fluid.isEmpty() && !FluidStack.isSameFluidSameComponents(this.fluid, resource)) return 0; + + if (!action.simulate() && this.fluid.isEmpty()) { + this.fluid = resource.copyWithAmount(this.capacity); + this.onContentsChanged(); + } + return resource.getAmount(); + + } + + @Override + public FluidStack drain(int maxDrain, IFluidHandler.FluidAction action) { + if (!this.isInfinity) return super.drain(maxDrain, action); + + return this.isEmpty() ? FluidStack.EMPTY : this.fluid.copyWithAmount(maxDrain); + } + + @Override + public int getSpace() { + return isInfinity ? Integer.MAX_VALUE : super.getSpace(); + } +} diff --git a/src/main/java/dev/dubhe/anvilcraft/api/fluidtank/package-info.java b/src/main/java/dev/dubhe/anvilcraft/api/fluidtank/package-info.java new file mode 100644 index 000000000..b61332633 --- /dev/null +++ b/src/main/java/dev/dubhe/anvilcraft/api/fluidtank/package-info.java @@ -0,0 +1,7 @@ +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +package dev.dubhe.anvilcraft.api.fluidtank; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/dev/dubhe/anvilcraft/block/LargeFluidTankBlock.java b/src/main/java/dev/dubhe/anvilcraft/block/LargeFluidTankBlock.java index a557590bf..f8cfe9d8e 100644 --- a/src/main/java/dev/dubhe/anvilcraft/block/LargeFluidTankBlock.java +++ b/src/main/java/dev/dubhe/anvilcraft/block/LargeFluidTankBlock.java @@ -57,13 +57,15 @@ public Cube3x3PartHalf[] getParts() { return Cube3x3PartHalf.values(); } + @Nullable @Override - public @Nullable BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) { + public BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) { return ModBlockEntities.LARGE_FLUID_TANK.create(blockPos, blockState); } + @Nullable @Override - public @Nullable BlockEntityTicker getTicker(Level level, BlockState state, BlockEntityType type) { + public BlockEntityTicker getTicker(Level level, BlockState state, BlockEntityType type) { return createTickerHelper( type, ModBlockEntities.LARGE_FLUID_TANK.get(), @@ -82,19 +84,14 @@ protected ItemInteractionResult useItemOn( BlockHitResult hitResult ) { InteractionResult result = super.useItemOn(stack, state, level, pos, player, hand, hitResult).result(); - if (result != InteractionResult.PASS) return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; - if (!(level.getBlockEntity(pos) instanceof LargeFluidTankBlockEntity)) { - return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; + if (result == InteractionResult.PASS) { + if (level.getBlockEntity(pos) instanceof LargeFluidTankBlockEntity tank) { + if (tank.onPlayerUse(player, hand)) { + return ItemInteractionResult.sidedSuccess(level.isClientSide()); + } + } } - - BlockPos centerPos = this.getMainPartPos(pos, state); - if (!(level.getBlockEntity(centerPos) instanceof LargeFluidTankBlockEntity tank)) { - return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; - } - if (tank.onPlayerUse(player, hand)) { - return ItemInteractionResult.sidedSuccess(level.isClientSide()); - } - return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION; + } } diff --git a/src/main/java/dev/dubhe/anvilcraft/block/entity/FluidTankBlockEntity.java b/src/main/java/dev/dubhe/anvilcraft/block/entity/FluidTankBlockEntity.java index 1680fd83d..b30a325d0 100644 --- a/src/main/java/dev/dubhe/anvilcraft/block/entity/FluidTankBlockEntity.java +++ b/src/main/java/dev/dubhe/anvilcraft/block/entity/FluidTankBlockEntity.java @@ -20,13 +20,12 @@ import net.neoforged.neoforge.fluids.capability.templates.FluidTank; public class FluidTankBlockEntity extends BlockEntity implements IFluidHandlerHolder { - public static final int CAPACITY = 16; - public static final int BIG_CAPACITY = 640; + public static final int CAPACITY = 16 * FluidType.BUCKET_VOLUME; + public static final int BIG_CAPACITY = 640 * FluidType.BUCKET_VOLUME; public static final int COOLDOWN = 100; - protected FluidTank tank = new FluidTank(CAPACITY * FluidType.BUCKET_VOLUME); + protected FluidTank tank = new FluidTank(CAPACITY); protected int cooldown = 0; - public FluidTankBlockEntity(BlockEntityType type, BlockPos pos, BlockState blockState) { super(type, pos, blockState); } @@ -44,7 +43,7 @@ protected void checkStructure() { int targetCapacity = TankUtil.isMengerStructure(this.getLevel(), this.getBlockPos(), 3) ? BIG_CAPACITY : CAPACITY; if (tank.getCapacity() != targetCapacity) { - tank.setCapacity(targetCapacity * FluidType.BUCKET_VOLUME); + tank.setCapacity(targetCapacity); } } diff --git a/src/main/java/dev/dubhe/anvilcraft/block/entity/LargeFluidTankBlockEntity.java b/src/main/java/dev/dubhe/anvilcraft/block/entity/LargeFluidTankBlockEntity.java index 0c5352d16..a1ff31e6e 100644 --- a/src/main/java/dev/dubhe/anvilcraft/block/entity/LargeFluidTankBlockEntity.java +++ b/src/main/java/dev/dubhe/anvilcraft/block/entity/LargeFluidTankBlockEntity.java @@ -1,8 +1,10 @@ package dev.dubhe.anvilcraft.block.entity; import dev.dubhe.anvilcraft.api.fluid.IFluidHandlerHolder; +import dev.dubhe.anvilcraft.api.fluidtank.InfinityFluidTank; import dev.dubhe.anvilcraft.block.LargeFluidTankBlock; import dev.dubhe.anvilcraft.block.state.Cube3x3PartHalf; +import dev.dubhe.anvilcraft.init.block.ModBlocks; import dev.dubhe.anvilcraft.util.TankUtil; import net.minecraft.core.BlockPos; import net.minecraft.core.HolderLookup; @@ -19,16 +21,14 @@ import net.neoforged.neoforge.fluids.FluidUtil; import net.neoforged.neoforge.fluids.IFluidTank; import net.neoforged.neoforge.fluids.capability.IFluidHandler; -import net.neoforged.neoforge.fluids.capability.templates.FluidTank; public class LargeFluidTankBlockEntity extends BlockEntity implements IFluidHandlerHolder { - public static final int CAPACITY = 320; - public static final int BIG_CAPACITY = 12800; + public static final int CAPACITY = 320 * FluidType.BUCKET_VOLUME; + public static final int BIG_CAPACITY = 12800 * FluidType.BUCKET_VOLUME; public static final int COOLDOWN = 100; - protected FluidTank tank = new FluidTank(CAPACITY * FluidType.BUCKET_VOLUME); + protected InfinityFluidTank tank = new InfinityFluidTank(CAPACITY, false); protected int cooldown = 0; - public LargeFluidTankBlockEntity(BlockEntityType type, BlockPos pos, BlockState blockState) { super(type, pos, blockState); } @@ -45,10 +45,17 @@ public void tick() { protected void checkStructure() { if (this.getLevel() == null) return; + if (!this.isMainPart()) { + this.getMainPart().checkStructure(); + return; + } - int targetCapacity = TankUtil.isMengerStructure(this.getLevel(), this.getBlockPos(), 9) ? BIG_CAPACITY : CAPACITY; - if (tank.getCapacity() != targetCapacity) { - tank.setCapacity(targetCapacity * FluidType.BUCKET_VOLUME); + if (TankUtil.isMengerStructure(this.getLevel(), this.getBlockPos(), 9)) { + tank.setCapacity(BIG_CAPACITY); + if (tank.getSpace() <= 0) tank.setInfinity(true); + } else { + tank.setInfinity(false); + tank.setCapacity(CAPACITY); } } @@ -83,14 +90,27 @@ public Packet getUpdatePacket() { public boolean onPlayerUse(Player player, InteractionHand hand) { checkStructure(); - return FluidUtil.interactWithFluidHandler(player, hand, tank); + return FluidUtil.interactWithFluidHandler(player, hand, this.getFluidHandler()); } public IFluidTank getTank() { - return tank; + return getMainPart().tank; } public IFluidHandler getFluidHandler() { - return tank; + return getMainPart().tank; + } + + public boolean isMainPart() { + LargeFluidTankBlock block = ModBlocks.LARGE_FLUID_TANK.get(); + return block.isMainPart(this.getBlockState()); + } + + public LargeFluidTankBlockEntity getMainPart() { + LargeFluidTankBlock block = ModBlocks.LARGE_FLUID_TANK.get(); + BlockPos mainPartPos = block.getMainPartPos(this.getBlockPos(), this.getBlockState()); + if (this.getLevel() == null) return this; + BlockEntity mainPart = this.getLevel().getBlockEntity(mainPartPos); + return mainPart instanceof LargeFluidTankBlockEntity ? (LargeFluidTankBlockEntity) mainPart : this; } } \ No newline at end of file diff --git a/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/FluidTankBlockEntityRenderer.java b/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/FluidTankBlockEntityRenderer.java index 3b35ab339..0642044b9 100644 --- a/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/FluidTankBlockEntityRenderer.java +++ b/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/FluidTankBlockEntityRenderer.java @@ -12,133 +12,78 @@ * These modifications continue to be licensed under LGPLv3. * ------------------------------------------------------------- */ + package dev.dubhe.anvilcraft.client.renderer.blockentity; import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; import dev.dubhe.anvilcraft.block.entity.FluidTankBlockEntity; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.util.Mth; import net.minecraft.world.inventory.InventoryMenu; import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions; import net.neoforged.neoforge.fluids.FluidStack; import net.neoforged.neoforge.fluids.FluidType; -import org.joml.Matrix4f; + +import static dev.dubhe.anvilcraft.client.renderer.blockentity.LargeFluidTankBlockEntityRenderer.renderFluidCube; public class FluidTankBlockEntityRenderer implements BlockEntityRenderer { public FluidTankBlockEntityRenderer(BlockEntityRendererProvider.Context context) { } - @Override public void render( FluidTankBlockEntity tank, float tickDelta, PoseStack ms, MultiBufferSource vertexConsumers, int light, int overlay) { - if (!tank.getTank().getFluid().isEmpty()) { - - /* - * - * // Uncomment to allow the liquid to rotate with the tank ms.pushPose(); ms.translate(0.5, 0.5, 0.5); - * FacingToRotation.get(tank.getForward(), tank.getUp()).push(ms); ms.translate(-0.5, -0.5, -0.5); - */ - - drawFluidInTank( - ms, - vertexConsumers, - light, - tank.getTank().getFluid(), - (float) tank.getTank().getFluid().getAmount() / tank.getTank().getCapacity() - ); - - // ms.popPose(); - } + if (tank.getTank().getFluid().isEmpty()) return; + + /* + * + * // Uncomment to allow the liquid to rotate with the tank ms.pushPose(); ms.translate(0.5, 0.5, 0.5); + * FacingToRotation.get(tank.getForward(), tank.getUp()).push(ms); ms.translate(-0.5, -0.5, -0.5); + */ + float fill = (float) tank.getTank().getFluid().getAmount() / tank.getTank().getCapacity(); + + drawFluidInTank( + ms, + vertexConsumers, + light, + tank.getTank().getFluid(), + fill + ); + + // ms.popPose(); } private static final float TANK_W = 1 / 16f + 0.001f; // avoiding Z-fighting - public static void drawFluidInTank( - PoseStack ps, MultiBufferSource mbs, int light, - FluidStack fluid, float fill - ) { + public static void drawFluidInTank(PoseStack ps, MultiBufferSource mbs, int light, FluidStack fluid, float fill) { // From Modern Industrialization var renderProps = IClientFluidTypeExtensions.of(fluid.getFluid()); TextureAtlasSprite sprite = Minecraft.getInstance().getTextureAtlas(InventoryMenu.BLOCK_ATLAS) .apply(renderProps.getStillTexture(fluid)); int color = renderProps.getTintColor(fluid); - float fillY = Mth.lerp(Mth.clamp(fill, 0, 1), TANK_W, 1 - TANK_W); // Top and bottom positions of the fluid inside the tank - float topHeight = fillY; - float bottomHeight = TANK_W; + float height = 1 - 2 * TANK_W; + + float minX = TANK_W; + float minY = TANK_W; + float minZ = TANK_W; + float maxX = 1 - TANK_W; + float maxY = 1 - TANK_W; + float maxZ = 1 - TANK_W; - // Render gas from top to bottom FluidType attributes = fluid.getFluid().getFluidType(); if (attributes.isLighterThanAir()) { - topHeight = 1 - TANK_W; - bottomHeight = 1 - fillY; + minY = maxY - fill * height; + } else { + maxY = minY + fill * height; } - float minX = TANK_W; - float minZ = TANK_W; - float maxX = (1 - TANK_W); - float maxZ = (1 - TANK_W); - float minY = bottomHeight; - float maxY = topHeight; - - // 在 render 方法中 - ps.pushPose(); - - // 获取顶点构建器 - VertexConsumer consumer = mbs.getBuffer(RenderType.translucent()); - - // 纹理映射:简单将整个 sprite 映射到每个面,不进行平铺 - float u0 = sprite.getU0(); - float u1 = sprite.getU1(); - float v0 = sprite.getV0(); - float v1 = sprite.getV1(); - - Matrix4f pose = ps.last().pose(); - - consumer.addVertex(pose, maxX, maxY, maxZ).setColor(color).setUv(u0, v0).setLight(light).setNormal(0, 1, 0); - consumer.addVertex(pose, maxX, maxY, minZ).setColor(color).setUv(u1, v0).setLight(light).setNormal(0, 1, 0); - consumer.addVertex(pose, minX, maxY, minZ).setColor(color).setUv(u1, v1).setLight(light).setNormal(0, 1, 0); - consumer.addVertex(pose, minX, maxY, maxZ).setColor(color).setUv(u0, v1).setLight(light).setNormal(0, 1, 0); - - // 北面 (Z-) - consumer.addVertex(pose, maxX, maxY, minZ).setColor(color).setUv(u0, v0).setLight(light).setNormal(0, 0, -1); - consumer.addVertex(pose, maxX, minY, minZ).setColor(color).setUv(u1, v0).setLight(light).setNormal(0, 0, -1); - consumer.addVertex(pose, minX, minY, minZ).setColor(color).setUv(u1, v1).setLight(light).setNormal(0, 0, -1); - consumer.addVertex(pose, minX, maxY, minZ).setColor(color).setUv(u0, v1).setLight(light).setNormal(0, 0, -1); - - // 南面 (Z+) - consumer.addVertex(pose, maxX, minY, maxZ).setColor(color).setUv(u0, v0).setLight(light).setNormal(0, 0, 1); - consumer.addVertex(pose, maxX, maxY, maxZ).setColor(color).setUv(u1, v0).setLight(light).setNormal(0, 0, 1); - consumer.addVertex(pose, minX, maxY, maxZ).setColor(color).setUv(u1, v1).setLight(light).setNormal(0, 0, 1); - consumer.addVertex(pose, minX, minY, maxZ).setColor(color).setUv(u0, v1).setLight(light).setNormal(0, 0, 1); - - // 西面 (X-) - consumer.addVertex(pose, minX, maxY, maxZ).setColor(color).setUv(u0, v0).setLight(light).setNormal(-1, 0, 0); - consumer.addVertex(pose, minX, maxY, minZ).setColor(color).setUv(u1, v0).setLight(light).setNormal(-1, 0, 0); - consumer.addVertex(pose, minX, minY, minZ).setColor(color).setUv(u1, v1).setLight(light).setNormal(-1, 0, 0); - consumer.addVertex(pose, minX, minY, maxZ).setColor(color).setUv(u0, v1).setLight(light).setNormal(-1, 0, 0); - - // 东面 (X+) - consumer.addVertex(pose, maxX, minY, maxZ).setColor(color).setUv(u0, v0).setLight(light).setNormal(1, 0, 0); - consumer.addVertex(pose, maxX, minY, minZ).setColor(color).setUv(u1, v0).setLight(light).setNormal(1, 0, 0); - consumer.addVertex(pose, maxX, maxY, minZ).setColor(color).setUv(u1, v1).setLight(light).setNormal(1, 0, 0); - consumer.addVertex(pose, maxX, maxY, maxZ).setColor(color).setUv(u0, v1).setLight(light).setNormal(1, 0, 0); - - // 底面 (Y-) - consumer.addVertex(pose, maxX, minY, maxZ).setColor(color).setUv(u0, v0).setLight(light).setNormal(0, -1, 0); - consumer.addVertex(pose, minX, minY, maxZ).setColor(color).setUv(u1, v0).setLight(light).setNormal(0, -1, 0); - consumer.addVertex(pose, minX, minY, minZ).setColor(color).setUv(u1, v1).setLight(light).setNormal(0, -1, 0); - consumer.addVertex(pose, maxX, minY, minZ).setColor(color).setUv(u0, v1).setLight(light).setNormal(0, -1, 0); - ps.popPose(); + renderFluidCube(ps, mbs, light, sprite, color, minX, minY, minZ, maxX, maxY, maxZ); } } diff --git a/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/LargeFluidTankBlockEntityRenderer.java b/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/LargeFluidTankBlockEntityRenderer.java index 1f674af25..d031fbdad 100644 --- a/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/LargeFluidTankBlockEntityRenderer.java +++ b/src/main/java/dev/dubhe/anvilcraft/client/renderer/blockentity/LargeFluidTankBlockEntityRenderer.java @@ -12,6 +12,7 @@ * These modifications continue to be licensed under LGPLv3. * ------------------------------------------------------------- */ + package dev.dubhe.anvilcraft.client.renderer.blockentity; import com.mojang.blaze3d.vertex.PoseStack; @@ -23,7 +24,7 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.util.Mth; +import net.minecraft.core.Direction; import net.minecraft.world.inventory.InventoryMenu; import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions; import net.neoforged.neoforge.fluids.FluidStack; @@ -34,31 +35,26 @@ public class LargeFluidTankBlockEntityRenderer implements BlockEntityRenderer { + normal[2] = -1; + minSideI = minX; + maxSideI = maxX; + minSideJ = minY; + maxSideJ = maxY; + } + case SOUTH -> { + normal[2] = 1; + minSideI = minX; + maxSideI = maxX; + minSideJ = minY; + maxSideJ = maxY; + } + case WEST -> { + normal[0] = -1; + minSideI = minY; + maxSideI = maxY; + minSideJ = minZ; + maxSideJ = maxZ; + } + case EAST -> { + normal[0] = 1; + minSideI = minY; + maxSideI = maxY; + minSideJ = minZ; + maxSideJ = maxZ; + } + case UP -> { + normal[1] = 1; + minSideI = minX; + maxSideI = maxX; + minSideJ = minZ; + maxSideJ = maxZ; + } + default -> { + normal[1] = -1; + minSideI = minX; + maxSideI = maxX; + minSideJ = minZ; + maxSideJ = maxZ; + } + } + for (float minI = minSideI; minI < maxSideI; minI += 1) { + float maxI = Math.min(minI + 1, maxSideI); + float v0 = this.v0; + float v1 = this.v0 + (maxI - minI) * this.vl; + for (float minJ = minSideJ; minJ < maxSideJ; minJ += 1) { + float maxJ = Math.min(minJ + 1, maxSideJ); + float u0 = this.u0; + float u1 = this.u0 + (maxJ - minJ) * this.ul; + switch (direction) { + case NORTH -> { + addVertex(maxI, maxJ, minZ, u0, v0, normal); + addVertex(maxI, minJ, minZ, u1, v0, normal); + addVertex(minI, minJ, minZ, u1, v1, normal); + addVertex(minI, maxJ, minZ, u0, v1, normal); + } + case SOUTH -> { + addVertex(maxI, minJ, maxZ, u0, v0, normal); + addVertex(maxI, maxJ, maxZ, u1, v0, normal); + addVertex(minI, maxJ, maxZ, u1, v1, normal); + addVertex(minI, minJ, maxZ, u0, v1, normal); + } + case WEST -> { + addVertex(minX, maxI, maxJ, u0, v0, normal); + addVertex(minX, maxI, minJ, u1, v0, normal); + addVertex(minX, minI, minJ, u1, v1, normal); + addVertex(minX, minI, maxJ, u0, v1, normal); + } + case EAST -> { + addVertex(maxX, minI, maxJ, u0, v0, normal); + addVertex(maxX, minI, minJ, u1, v0, normal); + addVertex(maxX, maxI, minJ, u1, v1, normal); + addVertex(maxX, maxI, maxJ, u0, v1, normal); + } + case UP -> { + addVertex(maxI, maxY, maxJ, u0, v0, normal); + addVertex(maxI, maxY, minJ, u1, v0, normal); + addVertex(minI, maxY, minJ, u1, v1, normal); + addVertex(minI, maxY, maxJ, u0, v1, normal); + } + default -> { + addVertex(maxI, minY, maxJ, u0, v0, normal); + addVertex(maxI, minY, minJ, u1, v0, normal); + addVertex(minI, minY, minJ, u1, v1, normal); + addVertex(minI, minY, maxJ, u0, v1, normal); + } + } + } + } + } + + public void addVertex(float x, float y, float z, float u, float v, float[] normal) { + consumer.addVertex(pose, x, y, z).setColor(color).setUv(u, v).setLight(light).setNormal(normal[0], normal[1], normal[2]); + } + } } diff --git a/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlocks.java b/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlocks.java index add71e251..a585b7fa5 100644 --- a/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlocks.java +++ b/src/main/java/dev/dubhe/anvilcraft/init/block/ModBlocks.java @@ -246,12 +246,7 @@ import static dev.dubhe.anvilcraft.api.power.IPowerComponent.OVERLOAD; import static dev.dubhe.anvilcraft.api.power.IPowerComponent.SWITCH; -@SuppressWarnings( - { - "unused", - "CodeBlock2Expr" - } -) +@SuppressWarnings({"unused", "CodeBlock2Expr"}) public class ModBlocks { static { REGISTRATE.defaultCreativeTab(ModItemGroups.ANVILCRAFT_FUNCTION_BLOCK.getKey()); @@ -1759,7 +1754,7 @@ public class ModBlocks { LargeFluidTankBlock::new ) .initialProperties(() -> Blocks.IRON_BLOCK) - .properties(p -> p.isSuffocating(ModBlocks::never).noOcclusion().isValidSpawn(Blocks::never)) + .properties(p -> p.isSuffocating(ModBlocks::never).isSuffocating(ModBlocks::never).noOcclusion().isValidSpawn(Blocks::never)) .loot(SimpleMultiPartBlock::loot) .item(SimpleMultiPartBlockItem::new) .properties((properties) -> properties.stacksTo(16)) @@ -3041,7 +3036,6 @@ public class ModBlocks { }) .register(); - public static final BlockEntry RESIN_BLOCK = REGISTRATE.block("resin_block", ResinBlock::new) .lang("Block of Resin") .initialProperties(() -> Blocks.SLIME_BLOCK) From 0b4ed9cbfd1c074cfa0c9c59248227b2b26c4509 Mon Sep 17 00:00:00 2001 From: TBPig <147127248+TBPig@users.noreply.github.com> Date: Sat, 14 Feb 2026 15:41:01 +0800 Subject: [PATCH 9/9] fix style --- .../dev/dubhe/anvilcraft/api/tooltip/ItemTooltipManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dev/dubhe/anvilcraft/api/tooltip/ItemTooltipManager.java b/src/main/java/dev/dubhe/anvilcraft/api/tooltip/ItemTooltipManager.java index 5f3846f05..547e9dd0e 100644 --- a/src/main/java/dev/dubhe/anvilcraft/api/tooltip/ItemTooltipManager.java +++ b/src/main/java/dev/dubhe/anvilcraft/api/tooltip/ItemTooltipManager.java @@ -63,7 +63,7 @@ public class ItemTooltipManager { "Attracting the anvil below, when pushed and pulled by the piston, causes adjacent copper blocks to generate charges"); map.put(ModBlocks.BATCH_CRAFTER.asItem(), "Received a redstone signal and synthesized all internal items at once, with a power consumption of 4 kW"); - map.put(ModBlocks.FISH_TANK.asItem(),""" + map.put(ModBlocks.FISH_TANK.asItem(), """ It is sturdier than it looks and can be used as a substitute for the alchemy pot to perform related anvil synthesis. Wearing it on your head provides a temporary underwater breathing effect. Right-click the top with an item in hand to place the item inside.