added a pipe test block which connects to copies of itself and changes its visual and gameplay shapes

This commit is contained in:
TechnoDraconic
2026-02-15 18:28:22 -08:00
parent af1efb5c57
commit 851645e93f
7 changed files with 176 additions and 0 deletions

View File

@@ -0,0 +1,125 @@
package net.xevianlight.aphelion.block.custom;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.LevelAccessor;
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.phys.shapes.BooleanOp;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
// a lot of this is ai slop so take it with a grainlet of salt
public class PipeTestBlock extends Block {
// shortcuts for each directional property because they're pretty verbose
// t/f here means is/isn't connected outgoing in that direction
public static final BooleanProperty NORTH = BlockStateProperties.NORTH;
public static final BooleanProperty SOUTH = BlockStateProperties.SOUTH;
public static final BooleanProperty EAST = BlockStateProperties.EAST;
public static final BooleanProperty WEST = BlockStateProperties.WEST;
public static final BooleanProperty UP = BlockStateProperties.UP;
public static final BooleanProperty DOWN = BlockStateProperties.DOWN;
// Voxel shape pieces to make the actual pipe model
private static final VoxelShape CORE = Block.box(6, 6, 6, 10, 10, 10);
private static final VoxelShape NORTH_SHAPE = Block.box(6, 6, 0, 10, 10, 6);
private static final VoxelShape SOUTH_SHAPE = Block.box(6, 6, 10, 10, 10, 16);
private static final VoxelShape EAST_SHAPE = Block.box(10, 6, 6, 16, 10, 10);
private static final VoxelShape WEST_SHAPE = Block.box(0, 6, 6, 6, 10, 10);
private static final VoxelShape UP_SHAPE = Block.box(6, 10, 6, 10, 16, 10);
private static final VoxelShape DOWN_SHAPE = Block.box(6, 0, 6, 10, 6, 10);
// Assembles the "VoxelShape" of the block which i assume is just the collision/place/mine hitbox
// later this should be cached for each different shape that we need
@Override
public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) {
VoxelShape shape = CORE;
if (state.getValue(NORTH)) shape = Shapes.join(shape, NORTH_SHAPE, BooleanOp.OR);
if (state.getValue(SOUTH)) shape = Shapes.join(shape, SOUTH_SHAPE, BooleanOp.OR);
if (state.getValue(EAST)) shape = Shapes.join(shape, EAST_SHAPE, BooleanOp.OR);
if (state.getValue(WEST)) shape = Shapes.join(shape, WEST_SHAPE, BooleanOp.OR);
if (state.getValue(UP)) shape = Shapes.join(shape, UP_SHAPE, BooleanOp.OR);
if (state.getValue(DOWN)) shape = Shapes.join(shape, DOWN_SHAPE, BooleanOp.OR);
return shape;
}
public PipeTestBlock(Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any()
.setValue(NORTH, false).setValue(SOUTH, false)
.setValue(EAST, false).setValue(WEST, false)
.setValue(UP, false).setValue(DOWN, false));
}
// This method determines the state when first placed
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
return makeConnections(context.getLevel(), context.getClickedPos());
}
// Updates the block when a neighbor changes
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos currentPos, BlockPos neighborPos) {
return makeConnections(level, currentPos);
}
public static Properties getProperties() {
return Properties.of().noOcclusion();
}
private BlockState makeConnections(LevelAccessor level, BlockPos pos) {
return this.defaultBlockState()
.setValue(NORTH, canConnect(level, pos.north()))
.setValue(SOUTH, canConnect(level, pos.south()))
.setValue(EAST, canConnect(level, pos.east()))
.setValue(WEST, canConnect(level, pos.west()))
.setValue(UP, canConnect(level, pos.above()))
.setValue(DOWN, canConnect(level, pos.below()));
}
private boolean canConnect(LevelAccessor level, BlockPos neighborPos) {
// Simplest logic: connect if the neighbor is also a SimplePipeBlock
return level.getBlockState(neighborPos).getBlock() == this;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(NORTH, SOUTH, EAST, WEST, UP, DOWN);
}
// Doesn't block sunlight
// @Override
// public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos) {
// return true;
// }
/// This function doesn't do what the AI says it does. I have no idea what it actually does, though
// 2. Prevents the "black shadows" inside or around the pipe
// @Override
// public int getLightBlock(BlockState state, BlockGetter worldIn, BlockPos pos) {
// return 0;
// }
/// I don't know what this does, because Properties.noOcclusion() is the part that made the leaves keep
/// rendering their faces.
// 3. Tells adjacent blocks (like leaves) to keep rendering their faces
// @Override
// public boolean isOcclusionShapeFullBlock(BlockState state, BlockGetter worldIn, BlockPos pos) {
// return false;
// }
// This bit affects how strong the ambient occlusion effect is
@Override
public float getShadeBrightness(BlockState state, BlockGetter world, BlockPos pos) {
return 1.0F; // Maintains full brightness
}
}

View File

@@ -20,4 +20,5 @@ public class ModBlocks {
public static final DeferredBlock<Block> VAF_MULTIBLOCK_DUMMY_BLOCK = BLOCKS.register("vaf_dummy_block", () -> new VAFMultiblockDummyBlock(VAFMultiblockDummyBlock.getProperties()));
public static final DeferredBlock<Block> OXYGEN_TEST_BLOCK = BLOCKS.register("oxygen_test_block", () -> new OxygenTestBlock(OxygenTestBlock.getProperties()));
public static final DeferredBlock<Block> ROCKET_ASSEMBLER_BLOCK = BLOCKS.register("rocket_assembler_block", () -> new RocketAssemblerBlock(RocketAssemblerBlock.getProperties()));
public static final DeferredBlock<Block> PIPE_TEST_BLOCK = BLOCKS.register("pipe", () -> new PipeTestBlock(PipeTestBlock.getProperties()));
}

View File

@@ -36,6 +36,7 @@ public static final DeferredItem<Item> MUSIC_DISC_BIT_SHIFT = ITEMS.register("mu
public static final DeferredItem<BlockItem> ARC_FURNACE_CASING_BLOCK = ITEMS.register("arc_furnace_casing", () -> new BlockItem(ModBlocks.ARC_FURNACE_CASING_BLOCK.get(), ArcFurnaceCasingBlock.getItemProperties()));
public static final DeferredItem<BlockItem> VACUUM_ARC_FURNACE_CONTROLLER = ITEMS.register("vacuum_arc_furnace_controller", () -> new BlockItem(ModBlocks.VACUUM_ARC_FURNACE_CONTROLLER.get(), VacuumArcFurnaceController.getItemProperties()));
public static final DeferredItem<BlockItem> OXYGEN_TEST_BLOCK = ITEMS.register("oxygen_test_block", () -> new BlockItem(ModBlocks.OXYGEN_TEST_BLOCK.get(), new Item.Properties()));
public static final DeferredItem<BlockItem> PIPE_TEST_BLOCK = ITEMS.register("pipe", () -> new BlockItem(ModBlocks.PIPE_TEST_BLOCK.get(), new Item.Properties()));
public static final DeferredItem<BlockItem> LAUNCH_PAD = ITEMS.register("launch_pad", () -> new BlockItem(ModBlocks.LAUNCH_PAD.get(), LaunchPad.getItemProperties()));
public static final DeferredItem<BlockItem> ROCKET_ASSEMBLER_BLOCK = ITEMS.register("rocket_assembler_block", () -> new BlockItem(ModBlocks.ROCKET_ASSEMBLER_BLOCK.get(), RocketAssemblerBlock.getItemProperties()));
// public static final DeferredItem<BlockItem> VAF_MULTIBLOCK_DUMMY_BLOCK = ITEMS.register("vaf_multiblock_dummy_block", () -> new BlockItem(ModBlocks.VAF_MULTIBLOCK_DUMMY_BLOCK.get(), VAFMultiblockDummyBlock.getItemProperties()));

View File

@@ -0,0 +1,11 @@
{
"multipart": [
{ "apply": { "model": "aphelion:block/pipe_core" }},
{ "when": { "north": "true" }, "apply": { "model": "aphelion:block/pipe_side" }},
{ "when": { "east": "true" }, "apply": { "model": "aphelion:block/pipe_side", "y": 90 }},
{ "when": { "south": "true" }, "apply": { "model": "aphelion:block/pipe_side", "y": 180 }},
{ "when": { "west": "true" }, "apply": { "model": "aphelion:block/pipe_side", "y": 270 }},
{ "when": { "up": "true" }, "apply": { "model": "aphelion:block/pipe_side", "x": 270 }},
{ "when": { "down": "true" }, "apply": { "model": "aphelion:block/pipe_side", "x": 90 }}
]
}

View File

@@ -0,0 +1,20 @@
{
"ambientocclusion": false,
"textures": {
"texture": "aphelion:block/pipe_texture"
},
"elements": [
{
"from": [ 6, 6, 6 ],
"to": [ 10, 10, 10 ],
"faces": {
"down": { "texture": "#texture", "uv": [ 6, 6, 10, 10 ] },
"up": { "texture": "#texture", "uv": [ 6, 6, 10, 10 ] },
"north": { "texture": "#texture", "uv": [ 6, 6, 10, 10 ] },
"south": { "texture": "#texture", "uv": [ 6, 6, 10, 10 ] },
"west": { "texture": "#texture", "uv": [ 6, 6, 10, 10 ] },
"east": { "texture": "#texture", "uv": [ 6, 6, 10, 10 ] }
}
}
]
}

View File

@@ -0,0 +1,18 @@
{
"textures": {
"texture": "aphelion:block/pipe_texture"
},
"elements": [
{
"from": [ 6, 6, 0 ],
"to": [ 10, 10, 6 ],
"faces": {
"down": { "texture": "#texture", "uv": [ 6, 0, 10, 6 ] },
"up": { "texture": "#texture", "uv": [ 6, 0, 10, 6 ] },
"north": { "texture": "#texture", "uv": [ 6, 6, 10, 10 ] },
"west": { "texture": "#texture", "uv": [ 0, 6, 6, 10 ] },
"east": { "texture": "#texture", "uv": [ 0, 6, 6, 10 ] }
}
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B