Skip to content

Commit 3345cb9

Browse files
committed
Fluid Tank Block and Redstone Clock block WIP code
1 parent 3a34008 commit 3345cb9

File tree

10 files changed

+493
-8
lines changed

10 files changed

+493
-8
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ neoForge {
8484
data()
8585

8686
// example of overriding the workingDirectory set in configureEach above, uncomment if you want to use it
87-
// gameDirectory = project.file('run-data')
87+
gameDirectory = project.file('run-data')
8888

8989
// Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources.
9090
programArguments.addAll '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath()

src/main/java/net/roboxgamer/modernutils/ModernUtilsMod.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,10 @@ private void registerCapabilities(RegisterCapabilitiesEvent event) {
163163
Capabilities.ItemHandler.BLOCK,
164164
ModBlockEntities.MECHANICAL_FURNACE_BE.get(),
165165
(be, side) -> be.getCapabilityHandler(side));
166+
event.registerBlockEntity(
167+
Capabilities.FluidHandler.BLOCK,
168+
ModBlockEntities.FLUID_TANK_BE.get(),
169+
(be, side) -> be.getFluidHandler());
166170
}
167171

168172
@EventBusSubscriber(modid = MODID, bus = EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)

src/main/java/net/roboxgamer/modernutils/block/ModBlocks.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ public class ModBlocks {
4444
public static final DeferredBlock<MechanicalFurnaceBlock> MECHANICAL_FURNACE_BLOCK = registerBlock("mechanical_furnace_block", ()->
4545
new MechanicalFurnaceBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.FURNACE)));
4646

47+
public static final DeferredBlock<RedstoneClockBlock> REDSTONE_CLOCK_BLOCK = registerWIPBlock("redstone_clock_block", ()->
48+
new RedstoneClockBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.STONE)));
49+
50+
public static final DeferredBlock<FluidTankBlock> FLUID_TANK_BLOCK = registerWIPBlock("fluid_tank_block", ()->
51+
new FluidTankBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.IRON_BLOCK)));
52+
4753
private static <T extends Block> DeferredBlock<T> registerWIPBlock(String name, Supplier<T> block) {
4854
DeferredBlock<T> toReturn = WIP_BLOCKS.register(name, block);
4955
registerWIPBlockItem(name, toReturn);
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package net.roboxgamer.modernutils.block.custom;
2+
3+
import net.minecraft.core.BlockPos;
4+
import net.minecraft.core.component.DataComponents;
5+
import net.minecraft.network.chat.Component;
6+
import net.minecraft.sounds.SoundSource;
7+
import net.minecraft.world.InteractionHand;
8+
import net.minecraft.world.ItemInteractionResult;
9+
import net.minecraft.world.entity.player.Player;
10+
import net.minecraft.world.item.*;
11+
import net.minecraft.world.item.component.CustomData;
12+
import net.minecraft.world.level.Level;
13+
import net.minecraft.world.level.block.Block;
14+
import net.minecraft.world.level.block.EntityBlock;
15+
import net.minecraft.world.level.block.entity.BlockEntity;
16+
import net.minecraft.world.level.block.state.BlockState;
17+
import net.minecraft.world.level.material.Fluid;
18+
import net.minecraft.world.level.material.Fluids;
19+
import net.minecraft.world.level.storage.loot.LootParams;
20+
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
21+
import net.minecraft.world.phys.BlockHitResult;
22+
import net.neoforged.neoforge.common.SoundActions;
23+
import net.neoforged.neoforge.fluids.FluidStack;
24+
import net.neoforged.neoforge.fluids.capability.IFluidHandler;
25+
import net.neoforged.neoforge.items.ItemHandlerHelper;
26+
import net.roboxgamer.modernutils.block.entity.custom.FluidTankBlockEntity;
27+
import org.jetbrains.annotations.NotNull;
28+
import org.jetbrains.annotations.Nullable;
29+
30+
import java.util.Collections;
31+
import java.util.List;
32+
33+
public class FluidTankBlock extends Block implements EntityBlock {
34+
public FluidTankBlock(Properties properties) {
35+
super(properties);
36+
}
37+
public static int capacity = 10000;
38+
39+
@Override
40+
public @Nullable BlockEntity newBlockEntity(@NotNull BlockPos pos, @NotNull BlockState state) {
41+
return new FluidTankBlockEntity(pos, state, capacity);
42+
}
43+
44+
@Override
45+
protected @NotNull ItemInteractionResult useItemOn(@NotNull ItemStack stack, @NotNull BlockState state, @NotNull Level level, @NotNull BlockPos pos, @NotNull Player player, @NotNull InteractionHand hand, @NotNull BlockHitResult hitResult) {
46+
if (!(level.getBlockEntity(pos) instanceof FluidTankBlockEntity tankBE)) {
47+
return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
48+
}
49+
var tank = tankBE.getFluidHandler();
50+
51+
Item item = stack.getItem();
52+
53+
// Case 1: Player is holding a filled bucket
54+
if (item instanceof BucketItem bucketItem && !(item instanceof MobBucketItem)) {
55+
Fluid fluidInBucket = bucketItem.content;
56+
57+
// If the bucket is filled with a fluid, try to insert it into the tank
58+
if (fluidInBucket != Fluids.EMPTY) {
59+
FluidStack fluidStack = new FluidStack(fluidInBucket, 1000); // Buckets contain 1000 mB
60+
int filledAmount = tank.fill(fluidStack, IFluidHandler.FluidAction.EXECUTE);
61+
62+
if (filledAmount > 0) {
63+
if (!level.isClientSide) {
64+
// Replace filled bucket with an empty bucket
65+
if (!player.getAbilities().instabuild) {
66+
stack.shrink(1);
67+
ItemStack emptyBucket = new ItemStack(Items.BUCKET);
68+
if (!player.addItem(emptyBucket)) {
69+
player.drop(emptyBucket, false);
70+
}
71+
}
72+
}
73+
var sound = bucketItem.content.getFluidType().getSound(player, level, pos, SoundActions.BUCKET_EMPTY);
74+
var soundSource = SoundSource.BLOCKS;
75+
if (sound != null) {
76+
level.playSound(player, pos, sound, soundSource, 1.0F, 1.0F);
77+
}
78+
return ItemInteractionResult.sidedSuccess(level.isClientSide);
79+
}
80+
}
81+
}
82+
83+
// Case 2: Player is holding an empty bucket and trying to extract fluid from the tank
84+
if (stack.is(Items.BUCKET)) {
85+
FluidStack tankFluid = tank.getFluid();
86+
if (!tankFluid.isEmpty() && tankFluid.getAmount() >= 1000) { // Check if there's enough fluid in the tank
87+
Fluid fluidToExtract = tankFluid.getFluid();
88+
89+
// Try to extract 1000 mB (1 bucket worth) from the tank
90+
FluidStack extractedFluid = tank.drain(1000, IFluidHandler.FluidAction.EXECUTE);
91+
if (!extractedFluid.isEmpty() && extractedFluid.getAmount() == 1000) {
92+
if (!level.isClientSide) {
93+
// Replace empty bucket with a filled bucket
94+
if (!player.getAbilities().instabuild) {
95+
stack.shrink(1);
96+
ItemStack filledBucket = new ItemStack(fluidToExtract.getBucket());
97+
ItemHandlerHelper.giveItemToPlayer(player, filledBucket);
98+
}
99+
}
100+
var sound = fluidToExtract.getFluidType().getSound(player, level, pos, SoundActions.BUCKET_FILL);
101+
var soundSource = SoundSource.BLOCKS;
102+
if (sound != null) {
103+
level.playSound(player, pos, sound, soundSource, 1.0F, 1.0F);
104+
}
105+
return ItemInteractionResult.sidedSuccess(level.isClientSide);
106+
}
107+
}
108+
}
109+
110+
return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
111+
}
112+
113+
@Override
114+
protected @NotNull List<ItemStack> getDrops(@NotNull BlockState state, LootParams.Builder params) {
115+
BlockEntity be = params.getOptionalParameter(LootContextParams.BLOCK_ENTITY);
116+
ItemStack itemStack = new ItemStack(state.getBlock());
117+
if (be instanceof FluidTankBlockEntity fluidTankBE && fluidTankBE.getFluidHandler().getFluidAmount() != 0) {
118+
be.saveToItem(itemStack, params.getLevel().registryAccess());
119+
}
120+
return Collections.singletonList(itemStack);
121+
}
122+
123+
@Override
124+
public void appendHoverText(@NotNull ItemStack stack, Item.@NotNull TooltipContext context, @NotNull List<Component> tooltipComponents, @NotNull TooltipFlag tooltipFlag) {
125+
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
126+
if (stack.has(DataComponents.BLOCK_ENTITY_DATA)) {
127+
CustomData data = stack.get(DataComponents.BLOCK_ENTITY_DATA);
128+
if (data != null) {
129+
var tag = data.copyTag().getCompound("modernutils");
130+
var fluid = tag.getCompound("fluidTank").getCompound("Fluid");
131+
FluidStack fluidStack = FluidStack.parseOptional(context.level().registryAccess(),fluid);
132+
tooltipComponents.add(Component.literal("Fluid: " + fluidStack.getFluid()));
133+
tooltipComponents.add(Component.literal("Amount: " + fluidStack.getAmount()));
134+
}
135+
}
136+
}
137+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package net.roboxgamer.modernutils.block.custom;
2+
3+
import net.minecraft.core.BlockPos;
4+
import net.minecraft.core.Direction;
5+
import net.minecraft.server.level.ServerLevel;
6+
import net.minecraft.world.InteractionHand;
7+
import net.minecraft.world.InteractionResult;
8+
import net.minecraft.world.entity.player.Player;
9+
import net.minecraft.world.item.context.BlockPlaceContext;
10+
import net.minecraft.world.level.BlockGetter;
11+
import net.minecraft.world.level.Level;
12+
import net.minecraft.world.level.block.Block;
13+
import net.minecraft.world.level.block.EntityBlock;
14+
import net.minecraft.world.level.block.entity.BlockEntity;
15+
import net.minecraft.world.level.block.entity.BlockEntityTicker;
16+
import net.minecraft.world.level.block.entity.BlockEntityType;
17+
import net.minecraft.world.level.block.state.BlockState;
18+
import net.minecraft.world.level.block.state.StateDefinition;
19+
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
20+
import net.minecraft.world.level.block.state.properties.BooleanProperty;
21+
import net.minecraft.world.level.block.state.properties.IntegerProperty;
22+
import net.minecraft.world.phys.BlockHitResult;
23+
import net.roboxgamer.modernutils.block.entity.ModBlockEntities;
24+
import net.roboxgamer.modernutils.block.entity.custom.MechanicalCrafterBlockEntity;
25+
import net.roboxgamer.modernutils.block.entity.custom.RedstoneClockBlockEntity;
26+
import org.jetbrains.annotations.NotNull;
27+
import org.jetbrains.annotations.Nullable;
28+
29+
public class RedstoneClockBlock extends Block implements EntityBlock {
30+
public static BooleanProperty POWERED = BlockStateProperties.POWERED;
31+
public static IntegerProperty POWER = BlockStateProperties.POWER;
32+
public RedstoneClockBlock(Properties properties) {
33+
super(properties);
34+
this.registerDefaultState(this.defaultBlockState().setValue(POWERED, false).setValue(POWER,0));
35+
}
36+
37+
@Override
38+
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
39+
builder.add(POWERED);
40+
builder.add(POWER);
41+
}
42+
43+
@Override
44+
public @Nullable BlockState getStateForPlacement(@NotNull BlockPlaceContext context) {
45+
Level level = context.getLevel();
46+
BlockPos pos = context.getClickedPos();
47+
return this.defaultBlockState()
48+
.setValue(POWERED, level.hasNeighborSignal(pos));
49+
}
50+
51+
@Override
52+
protected void neighborChanged(@NotNull BlockState state, @NotNull Level level, @NotNull BlockPos pos, @NotNull Block neighborBlock, @NotNull BlockPos neighborPos, boolean movedByPiston) {
53+
if (level instanceof ServerLevel serverLevel) {
54+
boolean currentPowered = state.getValue(POWERED);
55+
boolean isGettingPowered = level.hasNeighborSignal(pos);
56+
if (isGettingPowered != currentPowered) {
57+
serverLevel.setBlock(pos, state.setValue(POWERED, isGettingPowered), Block.UPDATE_ALL);
58+
}
59+
if (level.getBlockEntity(pos) instanceof MechanicalCrafterBlockEntity blockEntity) {
60+
blockEntity.setChanged();
61+
}
62+
}
63+
super.neighborChanged(state, level, pos, neighborBlock, neighborPos, movedByPiston);
64+
}
65+
66+
@Override
67+
public @Nullable BlockEntity newBlockEntity(@NotNull BlockPos pos, @NotNull BlockState state) {
68+
return new RedstoneClockBlockEntity(pos, state);
69+
}
70+
71+
@Override
72+
public @Nullable <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, @NotNull BlockState blockState, @NotNull BlockEntityType<T> blockEntityType) {
73+
return level.isClientSide ? null : ((level1, pos, state, blockEntity) -> ((RedstoneClockBlockEntity) blockEntity).tick());
74+
}
75+
76+
@Override
77+
protected @NotNull InteractionResult useWithoutItem(@NotNull BlockState state, Level level, @NotNull BlockPos pos, @NotNull Player player, @NotNull BlockHitResult hitResult) {
78+
if (level.isClientSide) {
79+
return InteractionResult.SUCCESS;
80+
}
81+
var hand = player.getUsedItemHand();
82+
if (hand != InteractionHand.MAIN_HAND) return InteractionResult.PASS;
83+
BlockEntity be = level.getBlockEntity(pos);
84+
if (!(be instanceof RedstoneClockBlockEntity blockEntity)) return InteractionResult.PASS;
85+
// When we right-click on the block, we toggle the redstone mode to the next mode
86+
blockEntity.getRedstoneManager().setRedstoneMode(blockEntity.getRedstoneManager().getNextRedstoneMode());
87+
return InteractionResult.CONSUME;
88+
}
89+
90+
@Override
91+
protected int getSignal(@NotNull BlockState state, @NotNull BlockGetter level, @NotNull BlockPos pos, @NotNull Direction direction) {
92+
//return level.getBlockEntity(pos, ModBlockEntities.REDSTONE_CLOCK_BE.get()).orElseThrow().getOutputSignal();
93+
return state.getValue(POWER);
94+
}
95+
}

src/main/java/net/roboxgamer/modernutils/block/entity/ModBlockEntities.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,7 @@
77
import net.neoforged.neoforge.registries.DeferredRegister;
88
import net.roboxgamer.modernutils.ModernUtilsMod;
99
import net.roboxgamer.modernutils.block.ModBlocks;
10-
import net.roboxgamer.modernutils.block.entity.custom.BatteryBlockEntity;
11-
import net.roboxgamer.modernutils.block.entity.custom.ExampleInventoryBlockEntity;
12-
import net.roboxgamer.modernutils.block.entity.custom.MagicBlockBlockEntity;
13-
import net.roboxgamer.modernutils.block.entity.custom.MechanicalCrafterBlockEntity;
14-
import net.roboxgamer.modernutils.block.entity.custom.MechanicalFurnaceBlockEntity;
15-
import net.roboxgamer.modernutils.block.entity.custom.MiniChestBlockEntity;
10+
import net.roboxgamer.modernutils.block.entity.custom.*;
1611

1712
import java.util.function.Supplier;
1813

@@ -56,6 +51,18 @@ public class ModBlockEntities {
5651
ModBlocks.MECHANICAL_FURNACE_BLOCK.get())
5752
.build(null));
5853

54+
public static final Supplier<BlockEntityType<RedstoneClockBlockEntity>> REDSTONE_CLOCK_BE =
55+
BLOCK_ENTITIES.register("redstone_clock_be", () -> BlockEntityType.Builder.
56+
of(RedstoneClockBlockEntity::new,
57+
ModBlocks.REDSTONE_CLOCK_BLOCK.get())
58+
.build(null));
59+
60+
public static final Supplier<BlockEntityType<FluidTankBlockEntity>> FLUID_TANK_BE =
61+
BLOCK_ENTITIES.register("fluid_tank_be", () -> BlockEntityType.Builder.
62+
of(FluidTankBlockEntity::new,
63+
ModBlocks.FLUID_TANK_BLOCK.get())
64+
.build(null));
65+
5966

6067
public static void register(IEventBus eventBus) {
6168
BLOCK_ENTITIES.register(eventBus);

0 commit comments

Comments
 (0)