diff --git a/src/main/java/fr/adrien1106/reframed/ReFramed.java b/src/main/java/fr/adrien1106/reframed/ReFramed.java index 691fe87..5e6fe38 100644 --- a/src/main/java/fr/adrien1106/reframed/ReFramed.java +++ b/src/main/java/fr/adrien1106/reframed/ReFramed.java @@ -28,7 +28,6 @@ import java.util.stream.Stream; import static fr.adrien1106.reframed.util.blocks.BlockProperties.LIGHT; /** - * TODO make block pairable by right click -> for v1.6 * TODO Dynamic Ambient Occlusion -> for v1.6 * TODO add minecraft models like wall fence etc -> for v1.6 * TODO better connected textures -> maybe v1.6 ? diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedBlock.java index 05e7aef..49d2596 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedBlock.java @@ -15,7 +15,9 @@ import net.minecraft.item.ItemPlacementContext; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtHelper; import net.minecraft.recipe.book.RecipeCategory; +import net.minecraft.registry.Registries; import net.minecraft.state.StateManager; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; @@ -31,8 +33,12 @@ import net.minecraft.world.GameRules; import net.minecraft.world.World; import org.jetbrains.annotations.Nullable; +import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.stream.IntStream; +import static fr.adrien1106.reframed.block.ReFramedEntity.BLOCKSTATE_KEY; import static fr.adrien1106.reframed.util.blocks.BlockProperties.LIGHT; public class ReFramedBlock extends Block implements BlockEntityProvider, RecipeSetter { @@ -97,7 +103,7 @@ public class ReFramedBlock extends Block implements BlockEntityProvider, RecipeS @Override public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { - if(!state.isOf(newState.getBlock()) && + if(!(newState.getBlock() instanceof ReFramedBlock) && world.getBlockEntity(pos) instanceof ReFramedEntity frame_entity && world.getGameRules().getBoolean(GameRules.DO_TILE_DROPS) ) { @@ -122,14 +128,52 @@ public class ReFramedBlock extends Block implements BlockEntityProvider, RecipeS } super.onStateReplaced(state, world, pos, newState, moved); } - - @Override - public void onPlaced(World world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) { - if(world.isClient && world.getBlockEntity(pos) instanceof ReFramedEntity be) { - NbtCompound tag = BlockItem.getBlockEntityNbt(stack); - if(tag != null) be.readNbt(tag); + + public void onPlaced(World world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack, BlockState old_state, BlockEntity old_entity) { + if (!(world.getBlockEntity(pos) instanceof ReFramedEntity frame_entity)) { + onPlaced(world, pos, state, placer, stack); + return; } - super.onPlaced(world, pos, state, placer, stack); + + // apply state change keeping the old information + if (old_state.getBlock() instanceof ReFramedBlock old_frame_block + && old_entity instanceof ReFramedEntity old_frame_entity) { + Map theme_map = old_frame_block.getThemeMap(old_state, state); + theme_map.forEach((self, other) -> + frame_entity.setTheme(old_frame_entity.getTheme(self), other) + ); + + // apply any changes needed to keep previous properties + if (old_frame_entity.emitsLight() && !frame_entity.emitsLight()) { + frame_entity.toggleLight(); + world.setBlockState(pos, state.with(LIGHT, true)); + } + if (old_frame_entity.emitsRedstone() && !frame_entity.emitsRedstone()) { + frame_entity.toggleRedstone(); + world.updateNeighbors(pos, this); + } + if (old_frame_entity.isSolid() && !frame_entity.isSolid()) frame_entity.toggleSolidity(); + + // apply themes from item + NbtCompound tag = BlockItem.getBlockEntityNbt(stack); + if(tag != null) { + // determine a list of themes than can be used + Iterator free_themes = IntStream + .rangeClosed(1, frame_entity.getThemes().size()) + .filter(value -> !theme_map.containsValue(value)) + .iterator(); + // apply all the themes possible from item + for (int i = 1; tag.contains(BLOCKSTATE_KEY + i) && free_themes.hasNext(); i++) { + BlockState theme = NbtHelper.toBlockState(Registries.BLOCK.getReadOnlyWrapper(), tag.getCompound(BLOCKSTATE_KEY + i)); + if (theme == null || theme.getBlock() == Blocks.AIR) continue; + frame_entity.setTheme(theme, free_themes.next()); + } + } + } else if(world.isClient) { // prevents flashing with default texture before server sends the update + NbtCompound tag = BlockItem.getBlockEntityNbt(stack); + if(tag != null) frame_entity.readNbt(tag); + } + onPlaced(world, pos, state, placer, stack); } @Override @@ -165,10 +209,23 @@ public class ReFramedBlock extends Block implements BlockEntityProvider, RecipeS return getWeakRedstonePower(state, view, pos, dir); } + /** + * @param state - the block state to get the top theme index from + * @return the index of the top theme to use for the block + */ public int getTopThemeIndex(BlockState state) { return 1; } + /** + * @param state - the block state of the block that is being replaced + * @param new_state - the block state of the block that is replacing the block + * @return a map of the theme indexes to map when changing state so that the themes are preserved + */ + public Map getThemeMap(BlockState state, BlockState new_state) { + return Map.of(); + } + @Override public void setRecipe(RecipeExporter exporter) { ShapedRecipeJsonBuilder diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleBlock.java index 143b48c..1b76a5e 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleBlock.java @@ -7,6 +7,7 @@ import net.minecraft.block.BlockState; import net.minecraft.block.ShapeContext; import net.minecraft.block.entity.BlockEntity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.state.property.Property; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; @@ -49,6 +50,29 @@ public abstract class ReFramedDoubleBlock extends ReFramedBlock { return 0; } + @SafeVarargs + public final > boolean matchesAnyOutline(Vec3d hit, BlockPos pos, Property property, T... values) { + for (T value : values) + if (matchesOutline(hit, pos, property, value)) return true; + return false; + } + + public > boolean matchesOutline(Vec3d hit, BlockPos pos, Property property, T value) { + Vec3d rel = BlockHelper.getRelativePos(hit, pos); + return BlockHelper.cursorMatchesFace( + getOutlineShape(getDefaultState().with(property, value), null, null, null), + rel + ); + } + + public > boolean matchesShape(Vec3d hit, BlockPos pos, BlockState state, int i) { + Vec3d rel = BlockHelper.getRelativePos(hit, pos); + return BlockHelper.cursorMatchesFace( + getShape(state, i), + rel + ); + } + @Override public boolean isTransparent(BlockState state, BlockView world, BlockPos pos) { return world.getBlockEntity(pos) instanceof ThemeableBlockEntity framed_entity diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairBlock.java index cb1ca8a..ee2e6f9 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairBlock.java @@ -15,20 +15,23 @@ import net.minecraft.data.client.MultipartBlockStateSupplier; import net.minecraft.data.server.recipe.RecipeExporter; import net.minecraft.data.server.recipe.RecipeProvider; import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder; +import net.minecraft.item.BlockItem; import net.minecraft.item.ItemPlacementContext; import net.minecraft.recipe.book.RecipeCategory; import net.minecraft.state.StateManager; import net.minecraft.util.Identifier; import net.minecraft.util.function.BooleanBiFunction; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; import net.minecraft.util.shape.VoxelShape; import net.minecraft.util.shape.VoxelShapes; import net.minecraft.world.BlockView; import org.jetbrains.annotations.Nullable; +import java.util.Map; + import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder; -import static fr.adrien1106.reframed.util.blocks.BlockProperties.CORNER; -import static fr.adrien1106.reframed.util.blocks.BlockProperties.CORNER_FACE; +import static fr.adrien1106.reframed.util.blocks.BlockProperties.*; import static fr.adrien1106.reframed.util.blocks.Corner.*; import static net.minecraft.data.client.VariantSettings.Rotation.*; @@ -58,8 +61,32 @@ public class ReFramedHalfStairBlock extends WaterloggableReFramedBlock implement super.appendProperties(builder.add(CORNER,CORNER_FACE)); } + @Override + public boolean canReplace(BlockState state, ItemPlacementContext context) { + return !( + context.getPlayer().isSneaking() + || !(context.getStack().getItem() instanceof BlockItem block_item) + || ( + block_item.getBlock() != this + && block_item.getBlock() != ReFramed.SMALL_CUBE + ) + ); + } + @Override public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) { + BlockState current_state = ctx.getWorld().getBlockState(ctx.getBlockPos()); + if (current_state.isOf(ReFramed.SMALL_CUBE)) { + Corner corner = current_state.get(CORNER).getOpposite(ctx.getSide().getOpposite()); + return ReFramed.HALF_STAIRS_SLAB.getDefaultState() + .with(CORNER, corner) + .with(CORNER_FACE, corner.getDirectionIndex(ctx.getSide().getOpposite())); + } + + if (current_state.isOf(this)) + return ReFramed.HALF_STAIRS_STAIR.getDefaultState() + .with(EDGE, current_state.get(CORNER).getEdge(current_state.get(CORNER).getDirection(current_state.get(CORNER_FACE)))); + Corner corner = BlockHelper.getPlacementCorner(ctx); return super.getPlacementState(ctx) .with(CORNER, corner) @@ -71,6 +98,19 @@ public class ReFramedHalfStairBlock extends WaterloggableReFramedBlock implement return HALF_STAIR_VOXELS[state.get(CORNER_FACE) + state.get(CORNER).getID() * 3]; } + @Override + public Map getThemeMap(BlockState state, BlockState new_state) { + if (new_state.isOf(ReFramed.HALF_STAIRS_SLAB)) return Map.of(1, 1); + if (new_state.isOf(ReFramed.HALF_STAIRS_STAIR)) + return Map.of( + 1, + state.get(CORNER) + .getDirection(state.get(CORNER_FACE)) + .getDirection() == Direction.AxisDirection.POSITIVE ? 2 : 1 + ); + return super.getThemeMap(state, new_state); + } + @Override public BlockStateSupplier getMultipart() { return getHalfStairMultipart( diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairsStairBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairsStairBlock.java index d645df0..b890a40 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairsStairBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairsStairBlock.java @@ -116,13 +116,13 @@ public class ReFramedHalfStairsStairBlock extends WaterloggableReFramedDoubleBlo GBlockstate.variant(model_id, true, R0, R270)) /* Z AXIS */ .with(GBlockstate.when(EDGE, DOWN_EAST), - GBlockstate.variant(side_model_id, true, R0, R90)) + GBlockstate.variant(reverse_model_id, true, R0, R90)) .with(GBlockstate.when(EDGE, EAST_UP), - GBlockstate.variant(reverse_model_id, true, R180, R270)) + GBlockstate.variant(side_model_id, true, R180, R270)) .with(GBlockstate.when(EDGE, UP_WEST), - GBlockstate.variant(side_model_id, true, R180, R90)) + GBlockstate.variant(reverse_model_id, true, R180, R90)) .with(GBlockstate.when(EDGE, WEST_DOWN), - GBlockstate.variant(reverse_model_id, true, R0, R270)); + GBlockstate.variant(side_model_id, true, R0, R270)); } @Override diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabBlock.java index 751588e..ec309d4 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabBlock.java @@ -11,6 +11,7 @@ import net.minecraft.data.client.MultipartBlockStateSupplier; import net.minecraft.data.server.recipe.RecipeExporter; import net.minecraft.data.server.recipe.RecipeProvider; import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder; +import net.minecraft.item.BlockItem; import net.minecraft.item.ItemPlacementContext; import net.minecraft.recipe.book.RecipeCategory; import net.minecraft.state.StateManager; @@ -22,7 +23,10 @@ import net.minecraft.util.shape.VoxelShapes; import net.minecraft.world.BlockView; import org.jetbrains.annotations.Nullable; +import java.util.Map; + import static net.minecraft.data.client.VariantSettings.Rotation.*; +import static net.minecraft.state.property.Properties.AXIS; import static net.minecraft.state.property.Properties.FACING; public class ReFramedSlabBlock extends WaterloggableReFramedBlock implements BlockStateProvider { @@ -53,10 +57,24 @@ public class ReFramedSlabBlock extends WaterloggableReFramedBlock implements Blo protected void appendProperties(StateManager.Builder builder) { super.appendProperties(builder.add(FACING)); } - + + @Override + public boolean canReplace(BlockState state, ItemPlacementContext context) { + return !( + context.getPlayer().isSneaking() + || !(context.getStack().getItem() instanceof BlockItem block_item) + || block_item.getBlock() != this + ); + } + @Nullable @Override public BlockState getPlacementState(ItemPlacementContext ctx) { + BlockState current_state = ctx.getWorld().getBlockState(ctx.getBlockPos()); + if (current_state.isOf(this)) + return ReFramed.SLABS_CUBE.getDefaultState() + .with(AXIS, current_state.get(FACING).getAxis()); + return super.getPlacementState(ctx).with(FACING, ctx.getSide().getOpposite()); } @@ -76,6 +94,12 @@ public class ReFramedSlabBlock extends WaterloggableReFramedBlock implements Blo }; } + @Override + public Map getThemeMap(BlockState state, BlockState new_state) { + if (new_state.isOf(ReFramed.SLABS_CUBE)) return Map.of(1, state.get(FACING).getDirection() == Direction.AxisDirection.POSITIVE ? 2 : 1); + return super.getThemeMap(state, new_state); + } + @Override public MultipartBlockStateSupplier getMultipart() { Identifier model_id = ReFramed.id("slab_special"); diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabsCubeBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabsCubeBlock.java index 42aa1c1..9916a3d 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabsCubeBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabsCubeBlock.java @@ -19,8 +19,7 @@ import net.minecraft.util.shape.VoxelShape; import org.jetbrains.annotations.Nullable; import static fr.adrien1106.reframed.block.ReFramedSlabBlock.*; -import static net.minecraft.data.client.VariantSettings.Rotation.R0; -import static net.minecraft.data.client.VariantSettings.Rotation.R90; +import static net.minecraft.data.client.VariantSettings.Rotation.*; import static net.minecraft.state.property.Properties.AXIS; public class ReFramedSlabsCubeBlock extends ReFramedDoubleBlock implements BlockStateProvider { @@ -55,15 +54,14 @@ public class ReFramedSlabsCubeBlock extends ReFramedDoubleBlock implements Block public VoxelShape getShape(BlockState state, int i) { return switch (state.get(AXIS)) { case Y -> i == 2 ? UP : DOWN; - case Z -> i == 2 ? NORTH : SOUTH; + case Z -> i == 2 ? SOUTH : NORTH; case X -> i == 2 ? EAST : WEST; }; } @Override public int getTopThemeIndex(BlockState state) { - // when the side is shared just return one - return state.get(AXIS) == Direction.Axis.Y ? 2: super.getTopThemeIndex(state); + return 2; } @Override @@ -73,7 +71,7 @@ public class ReFramedSlabsCubeBlock extends ReFramedDoubleBlock implements Block .with(GBlockstate.when(AXIS, Direction.Axis.Y), GBlockstate.variant(model_id, true, R0, R0)) .with(GBlockstate.when(AXIS, Direction.Axis.Z), - GBlockstate.variant(model_id, true, R90, R0)) + GBlockstate.variant(model_id, true, R270, R0)) .with(GBlockstate.when(AXIS, Direction.Axis.X), GBlockstate.variant(model_id, true, R90, R90)); } diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubeBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubeBlock.java index bce79f6..be280d8 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubeBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubeBlock.java @@ -5,6 +5,7 @@ import fr.adrien1106.reframed.generator.BlockStateProvider; import fr.adrien1106.reframed.generator.GBlockstate; import fr.adrien1106.reframed.util.VoxelHelper; import fr.adrien1106.reframed.util.blocks.BlockHelper; +import fr.adrien1106.reframed.util.blocks.Corner; import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -14,18 +15,23 @@ import net.minecraft.data.client.MultipartBlockStateSupplier; import net.minecraft.data.server.recipe.RecipeExporter; import net.minecraft.data.server.recipe.RecipeProvider; import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder; +import net.minecraft.item.BlockItem; import net.minecraft.item.ItemPlacementContext; import net.minecraft.recipe.book.RecipeCategory; import net.minecraft.state.StateManager; import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.shape.VoxelShape; import net.minecraft.util.shape.VoxelShapes; import net.minecraft.world.BlockView; import org.jetbrains.annotations.Nullable; +import java.util.Map; + import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder; -import static fr.adrien1106.reframed.util.blocks.BlockProperties.CORNER; +import static fr.adrien1106.reframed.util.blocks.BlockProperties.*; import static fr.adrien1106.reframed.util.blocks.Corner.*; import static net.minecraft.data.client.VariantSettings.Rotation.*; @@ -53,8 +59,73 @@ public class ReFramedSmallCubeBlock extends WaterloggableReFramedBlock implement super.appendProperties(builder.add(CORNER)); } + @Override + public boolean canReplace(BlockState state, ItemPlacementContext context) { + Corner corner = state.get(CORNER); + return !( + context.getPlayer().isSneaking() + || !(context.getStack().getItem() instanceof BlockItem block_item) + || ( + !( + block_item.getBlock() == ReFramed.HALF_STAIR + && !(corner.hasDirection(context.getSide()) + || (corner.hasDirection(context.getSide().getOpposite()) + && BlockHelper.cursorMatchesFace( + getOutlineShape(state, context.getWorld(), context.getBlockPos(), null), + BlockHelper.getRelativePos(context.getHitPos(), context.getBlockPos()) + ) + ) + ) + ) + && !( + block_item.getBlock() == this + && !( + corner.hasDirection(context.getSide()) + && BlockHelper.cursorMatchesFace( + getOutlineShape(state, context.getWorld(), context.getBlockPos(), null), + BlockHelper.getRelativePos(context.getHitPos(), context.getBlockPos()) + ) + ) + && ((ReFramedSmallCubesStepBlock) ReFramed.SMALL_CUBES_STEP) + .matchesAnyOutline( + context.getHitPos(), + context.getBlockPos(), + EDGE, + corner.getEdge(corner.getFirstDirection()), + corner.getEdge(corner.getSecondDirection()), + corner.getEdge(corner.getThirdDirection()) + ) + ) + ) + ); + } + @Override public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) { + BlockPos pos = ctx.getBlockPos(); + BlockState current_state = ctx.getWorld().getBlockState(pos); + if (current_state.isOf(ReFramed.HALF_STAIR)) + return ReFramed.HALF_STAIRS_SLAB.getDefaultState() + .with(CORNER, current_state.get(CORNER)) + .with(CORNER_FACE, current_state.get(CORNER_FACE)); + + + if (current_state.isOf(this)) { + Vec3d hit = ctx.getHitPos(); + Corner corner = current_state.get(CORNER); + ReFramedSmallCubesStepBlock block = ((ReFramedSmallCubesStepBlock) ReFramed.SMALL_CUBES_STEP); + BlockState state = block.getDefaultState().with(EDGE, corner.getEdge(corner.getFirstDirection())); + if (!block.matchesShape( + hit, pos, state, + corner.getFirstDirection().getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2 + )) state = state.with(EDGE, corner.getEdge(corner.getSecondDirection())); + if (!block.matchesShape( + hit, pos, state, + corner.getSecondDirection().getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2 + )) state = state.with(EDGE, corner.getEdge(corner.getThirdDirection())); + return state; + } + return super.getPlacementState(ctx).with(CORNER, BlockHelper.getPlacementCorner(ctx)); } @@ -63,6 +134,19 @@ public class ReFramedSmallCubeBlock extends WaterloggableReFramedBlock implement return SMALL_CUBE_VOXELS[state.get(CORNER).getID()]; } + @Override + public Map getThemeMap(BlockState state, BlockState new_state) { + if (new_state.isOf(ReFramed.HALF_STAIRS_SLAB)) return Map.of(1, 2); + if (new_state.isOf(ReFramed.SMALL_CUBES_STEP)) + return Map.of( + 1, + state.get(CORNER) + .getOtherDirection(new_state.get(EDGE)) + .getDirection() == Direction.AxisDirection.POSITIVE ? 2 : 1 + ); + return super.getThemeMap(state, new_state); + } + @Override public BlockStateSupplier getMultipart() { Identifier small_cube_id = ReFramed.id("small_cube_special"); diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubesStepBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubesStepBlock.java index cf663bd..5e70c83 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubesStepBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubesStepBlock.java @@ -93,13 +93,13 @@ public class ReFramedSmallCubesStepBlock extends WaterloggableReFramedDoubleBloc return MultipartBlockStateSupplier.create(this) /* X AXIS */ .with(GBlockstate.when(EDGE, DOWN_EAST), - GBlockstate.variant(reverse_model_id, true, R0, R0)) + GBlockstate.variant(model_id, true, R0, R0)) .with(GBlockstate.when(EDGE, EAST_UP), - GBlockstate.variant(model_id, true, R180, R0)) + GBlockstate.variant(reverse_model_id, true, R180, R0)) .with(GBlockstate.when(EDGE, UP_WEST), - GBlockstate.variant(reverse_model_id, true, R180, R180)) + GBlockstate.variant(model_id, true, R180, R180)) .with(GBlockstate.when(EDGE, WEST_DOWN), - GBlockstate.variant(model_id, true, R0, R180)) + GBlockstate.variant(reverse_model_id, true, R0, R180)) /* Y AXIS */ .with(GBlockstate.when(EDGE, EAST_SOUTH), GBlockstate.variant(model_id, true, R90, R0)) diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedStairBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedStairBlock.java index 452fe21..b0ef401 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedStairBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedStairBlock.java @@ -16,6 +16,7 @@ import net.minecraft.data.client.When; import net.minecraft.data.server.recipe.RecipeExporter; import net.minecraft.data.server.recipe.RecipeProvider; import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder; +import net.minecraft.item.BlockItem; import net.minecraft.item.ItemPlacementContext; import net.minecraft.recipe.book.RecipeCategory; import net.minecraft.state.StateManager; @@ -30,6 +31,7 @@ import net.minecraft.world.World; import net.minecraft.world.WorldAccess; import org.jetbrains.annotations.Nullable; +import java.util.Map; import java.util.stream.Stream; import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder; @@ -63,6 +65,15 @@ public class ReFramedStairBlock extends WaterloggableReFramedBlock implements Bl super.appendProperties(builder.add(EDGE, STAIR_SHAPE)); } + @Override + public boolean canReplace(BlockState state, ItemPlacementContext context) { + return !( + context.getPlayer().isSneaking() + || !(context.getStack().getItem() instanceof BlockItem block_item) + || block_item.getBlock() != ReFramed.STEP + ); + } + @Override public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighbor_state, WorldAccess world, BlockPos pos, BlockPos moved) { return super.getStateForNeighborUpdate(state, direction, neighbor_state, world, pos, moved) @@ -70,11 +81,20 @@ public class ReFramedStairBlock extends WaterloggableReFramedBlock implements Bl } @Nullable - @Override // Pretty happy of how clean it is (also got it on first try :) ) + @Override public BlockState getPlacementState(ItemPlacementContext ctx) { - Edge face = BlockHelper.getPlacementEdge(ctx); - StairShape shape = BlockHelper.getStairsShape(face, ctx.getWorld(), ctx.getBlockPos()); - return super.getPlacementState(ctx).with(EDGE, face).with(STAIR_SHAPE, shape); + BlockState current_state = ctx.getWorld().getBlockState(ctx.getBlockPos()); + if (current_state.isOf(ReFramed.STEP)) { + Edge edge = current_state.get(EDGE).opposite(); + StairShape shape = BlockHelper.getStairsShape(edge, ctx.getWorld(), ctx.getBlockPos()); + return ReFramed.STAIRS_CUBE.getDefaultState() + .with(EDGE, edge) + .with(STAIR_SHAPE, shape); + } + + Edge edge = BlockHelper.getPlacementEdge(ctx); + StairShape shape = BlockHelper.getStairsShape(edge, ctx.getWorld(), ctx.getBlockPos()); + return super.getPlacementState(ctx).with(EDGE, edge).with(STAIR_SHAPE, shape); } @Override @@ -93,6 +113,12 @@ public class ReFramedStairBlock extends WaterloggableReFramedBlock implements Bl return STAIR_VOXELS[edge.getID() * 9 + shape.getID()]; } + @Override + public Map getThemeMap(BlockState state, BlockState new_state) { + if (new_state.isOf(ReFramed.STAIRS_CUBE)) return Map.of(1, 1); + return super.getThemeMap(state, new_state); + } + @Override public MultipartBlockStateSupplier getMultipart() { return getStairMultipart(this, false); @@ -137,94 +163,94 @@ public class ReFramedStairBlock extends WaterloggableReFramedBlock implements Bl .with(When.anyOf( GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, INNER_RIGHT), GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, INNER_RIGHT), - GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, INNER_LEFT)), + GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, INNER_RIGHT)), GBlockstate.variant(inner_id, true, R0, R180)) .with(When.anyOf( GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, INNER_LEFT), GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, INNER_RIGHT), - GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, INNER_LEFT)), + GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, INNER_RIGHT)), GBlockstate.variant(inner_id, true, R0, R270)) .with(When.anyOf( GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, INNER_LEFT), GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, INNER_RIGHT), - GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, INNER_RIGHT)), + GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, INNER_LEFT)), GBlockstate.variant(inner_id, true, R0, R0)) .with(When.anyOf( GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, INNER_RIGHT), GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, INNER_RIGHT), - GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, INNER_RIGHT)), + GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, INNER_LEFT)), GBlockstate.variant(inner_id, true, R0, R90)) /* INNER TOP */ .with(When.anyOf( - GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, INNER_LEFT), + GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, INNER_RIGHT), GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, INNER_LEFT), GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, INNER_LEFT)), GBlockstate.variant(inner_id, true, R180, R0)) .with(When.anyOf( - GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, INNER_RIGHT), + GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, INNER_LEFT), GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, INNER_LEFT), GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, INNER_LEFT)), GBlockstate.variant(inner_id, true, R180, R90)) .with(When.anyOf( GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, INNER_RIGHT), GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, INNER_LEFT), - GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, INNER_RIGHT)), + GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, INNER_LEFT)), GBlockstate.variant(inner_id, true, R180, R180)) .with(When.anyOf( GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, INNER_RIGHT), GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, INNER_LEFT), - GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, INNER_LEFT)), + GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, INNER_RIGHT)), GBlockstate.variant(inner_id, true, R180, R270)) /* OUTER BOTTOM */ .with(When.anyOf( GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, SECOND_OUTER_LEFT), - GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, SECOND_OUTER_RIGHT)), + GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, SECOND_OUTER_LEFT)), GBlockstate.variant(outer_id, true, R0, R0)) .with(When.anyOf( GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, SECOND_OUTER_RIGHT), - GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, FIRST_OUTER_RIGHT)), + GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, FIRST_OUTER_LEFT)), GBlockstate.variant(outer_id, true, R0, R90)) .with(When.anyOf( GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, FIRST_OUTER_RIGHT), - GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, FIRST_OUTER_LEFT)), + GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, FIRST_OUTER_RIGHT)), GBlockstate.variant(outer_id, true, R0, R180)) .with(When.anyOf( GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, FIRST_OUTER_LEFT), - GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, SECOND_OUTER_LEFT)), + GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, SECOND_OUTER_RIGHT)), GBlockstate.variant(outer_id, true, R0, R270)) /* OUTER TOP */ .with(When.anyOf( GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, SECOND_OUTER_LEFT), - GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, FIRST_OUTER_LEFT)), + GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, FIRST_OUTER_RIGHT)), GBlockstate.variant(outer_id, true, R180, R0)) .with(When.anyOf( GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, FIRST_OUTER_LEFT), - GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, FIRST_OUTER_RIGHT)), + GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, FIRST_OUTER_LEFT)), GBlockstate.variant(outer_id, true, R180, R90)) .with(When.anyOf( GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, FIRST_OUTER_RIGHT), - GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, SECOND_OUTER_RIGHT)), + GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, SECOND_OUTER_LEFT)), GBlockstate.variant(outer_id, true, R180, R180)) .with(When.anyOf( GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, SECOND_OUTER_RIGHT), - GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, SECOND_OUTER_LEFT)), + GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, SECOND_OUTER_RIGHT)), GBlockstate.variant(outer_id, true, R180, R270)) /* OUTER EAST */ .with(When.anyOf( GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, SECOND_OUTER_RIGHT), - GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, FIRST_OUTER_RIGHT)), + GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, FIRST_OUTER_LEFT)), GBlockstate.variant(outer_side_id, true, R0, R0)) .with(When.anyOf( GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, SECOND_OUTER_LEFT), - GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, SECOND_OUTER_RIGHT)), + GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, SECOND_OUTER_LEFT)), GBlockstate.variant(outer_side_id, true, R90, R0)) .with(When.anyOf( GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, FIRST_OUTER_LEFT), - GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, SECOND_OUTER_LEFT)), + GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, SECOND_OUTER_RIGHT)), GBlockstate.variant(outer_side_id, true, R180, R0)) .with(When.anyOf( GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, FIRST_OUTER_RIGHT), - GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, FIRST_OUTER_LEFT)), + GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, FIRST_OUTER_RIGHT)), GBlockstate.variant(outer_side_id, true, R270, R0)) /* OUTER SOUTH */ .with(When.anyOf( @@ -246,19 +272,19 @@ public class ReFramedStairBlock extends WaterloggableReFramedBlock implements Bl /* OUTER WEST */ .with(When.anyOf( GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, SECOND_OUTER_RIGHT), - GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, SECOND_OUTER_LEFT)), + GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, SECOND_OUTER_RIGHT)), GBlockstate.variant(outer_side_id, true, R0, R180)) .with(When.anyOf( GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, SECOND_OUTER_LEFT), - GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, FIRST_OUTER_LEFT)), + GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, FIRST_OUTER_RIGHT)), GBlockstate.variant(outer_side_id, true, R90, R180)) .with(When.anyOf( GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, FIRST_OUTER_LEFT), - GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, FIRST_OUTER_RIGHT)), + GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, FIRST_OUTER_LEFT)), GBlockstate.variant(outer_side_id, true, R180, R180)) .with(When.anyOf( GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, FIRST_OUTER_RIGHT), - GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, SECOND_OUTER_RIGHT)), + GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, SECOND_OUTER_LEFT)), GBlockstate.variant(outer_side_id, true, R270, R180)) /* OUTER NORTH */ .with(When.anyOf( @@ -280,43 +306,43 @@ public class ReFramedStairBlock extends WaterloggableReFramedBlock implements Bl /* OUTER BOTTOM */ .with(When.anyOf( GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, OUTER_LEFT), - GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, OUTER_RIGHT), + GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, OUTER_LEFT), GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, OUTER_RIGHT)), GBlockstate.variant(double_outer_id, true, R0, R0)) .with(When.anyOf( GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, OUTER_RIGHT), - GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, OUTER_RIGHT), + GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, OUTER_LEFT), GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, OUTER_RIGHT)), GBlockstate.variant(double_outer_id, true, R0, R90)) .with(When.anyOf( GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, OUTER_RIGHT), - GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, OUTER_LEFT), + GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, OUTER_RIGHT), GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, OUTER_RIGHT)), GBlockstate.variant(double_outer_id, true, R0, R180)) .with(When.anyOf( GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, OUTER_LEFT), - GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, OUTER_LEFT), + GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, OUTER_RIGHT), GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, OUTER_RIGHT)), GBlockstate.variant(double_outer_id, true, R0, R270)) /* OUTER TOP */ .with(When.anyOf( GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, OUTER_LEFT), - GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, OUTER_LEFT), + GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, OUTER_RIGHT), GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, OUTER_LEFT)), GBlockstate.variant(double_outer_id, true, R180, R0)) .with(When.anyOf( GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, OUTER_LEFT), - GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, OUTER_RIGHT), + GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, OUTER_LEFT), GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, OUTER_LEFT)), GBlockstate.variant(double_outer_id, true, R180, R90)) .with(When.anyOf( GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, OUTER_RIGHT), - GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, OUTER_RIGHT), + GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, OUTER_LEFT), GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, OUTER_LEFT)), GBlockstate.variant(double_outer_id, true, R180, R180)) .with(When.anyOf( GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, OUTER_RIGHT), - GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, OUTER_LEFT), + GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, OUTER_RIGHT), GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, OUTER_LEFT)), GBlockstate.variant(double_outer_id, true, R180, R270)); } @@ -382,51 +408,51 @@ public class ReFramedStairBlock extends WaterloggableReFramedBlock implements Bl .add(25, VoxelHelper::rotateCX).add(26, VoxelHelper::rotateCX) // WEST_DOWN .add(0, VoxelHelper::rotateCY) - .add(10).add(1) - .add(12).add(3) - .add(16).add(5) - .add(7, VoxelHelper::rotateCY).add(8, VoxelHelper::rotateCY) + .add(1).add(10) + .add(3).add(12) + .add(5).add(16) + .add(8, VoxelHelper::rotateCY).add(7, VoxelHelper::rotateCY) // DOWN_EAST .add(36, VoxelHelper::rotateZ) - .add(11).add(2) - .add(13).add(4) + .add(2).add(11) + .add(4).add(13) .add(41, VoxelHelper::rotateZ).add(42, VoxelHelper::rotateZ) - .add(17).add(6) + .add(6).add(17) // EAST_UP .add(45, VoxelHelper::rotateZ) - .add(20).add(29) - .add(22).add(31) - .add(24).add(35) + .add(29).add(20) + .add(31).add(22) + .add(35).add(24) .add(52, VoxelHelper::rotateZ).add(53, VoxelHelper::rotateZ) // UP_WEST .add(54, VoxelHelper::rotateZ) - .add(19).add(28) - .add(21).add(30) + .add(28).add(19) + .add(30).add(21) .add(59, VoxelHelper::rotateZ).add(60, VoxelHelper::rotateZ) - .add(23).add(34) + .add(34).add(23) // WEST_NORTH .add(0, VoxelHelper::rotateCZ) .add(1).add(28) .add(3).add(30) .add(7).add(32) - .add(44).add(69) + .add(43).add(68) // NORTH_EAST .add(72, VoxelHelper::rotateY) .add(2).add(29) .add(4).add(31) - .add(51).add(62) + .add(50).add(61) .add(8).add(33) // EAST_SOUTH .add(81, VoxelHelper::rotateY) .add(11).add(20) .add(13).add(22) .add(15).add(26) - .add(50).add(61) + .add(51).add(62) // SOUTH_WEST .add(90, VoxelHelper::rotateY) .add(10).add(19) .add(12).add(21) - .add(43).add(68) + .add(44).add(69) .add(14).add(25) .build(); } diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedStepBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedStepBlock.java index fa7f969..298d730 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedStepBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedStepBlock.java @@ -15,19 +15,27 @@ import net.minecraft.data.client.MultipartBlockStateSupplier; import net.minecraft.data.server.recipe.RecipeExporter; import net.minecraft.data.server.recipe.RecipeProvider; import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder; +import net.minecraft.item.BlockItem; import net.minecraft.item.ItemPlacementContext; import net.minecraft.recipe.book.RecipeCategory; import net.minecraft.state.StateManager; import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.shape.VoxelShape; import net.minecraft.world.BlockView; import org.jetbrains.annotations.Nullable; +import java.util.Map; + import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder; import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE; +import static fr.adrien1106.reframed.util.blocks.BlockProperties.STAIR_SHAPE; import static fr.adrien1106.reframed.util.blocks.Edge.*; import static net.minecraft.data.client.VariantSettings.Rotation.*; +import static net.minecraft.state.property.Properties.AXIS; +import static net.minecraft.state.property.Properties.FACING; public class ReFramedStepBlock extends WaterloggableReFramedBlock implements BlockStateProvider { @@ -53,9 +61,68 @@ public class ReFramedStepBlock extends WaterloggableReFramedBlock implements Blo super.appendProperties(builder.add(EDGE)); } + @Override + public boolean canReplace(BlockState state, ItemPlacementContext context) { + Edge edge = state.get(EDGE); + return !( + context.getPlayer().isSneaking() + || !(context.getStack().getItem() instanceof BlockItem block_item) + || ( + block_item.getBlock() != ReFramed.STAIR + && !( + block_item.getBlock() == this + && !( + (edge.isSide(context.getSide()) || edge.hasDirection(context.getSide())) + && BlockHelper.cursorMatchesFace( + getOutlineShape(state, context.getWorld(), context.getBlockPos(), null), + BlockHelper.getRelativePos(context.getHitPos(), context.getBlockPos()) + ) + ) + && ((ReFramedStepsSlabBlock) ReFramed.STEPS_SLAB) + .matchesAnyOutline( + context.getHitPos(), + context.getBlockPos(), + FACING, + edge.getFirstDirection(), + edge.getSecondDirection() + ) + ) + ) + ); + } + @Nullable @Override public BlockState getPlacementState(ItemPlacementContext ctx) { + BlockPos pos = ctx.getBlockPos(); + BlockState current_state = ctx.getWorld().getBlockState(pos); + if (current_state.isOf(ReFramed.STAIR)) + return ReFramed.STAIRS_CUBE.getDefaultState() + .with(EDGE, current_state.get(EDGE)) + .with(STAIR_SHAPE, current_state.get(STAIR_SHAPE)); + + + if (current_state.isOf(this)) { + Vec3d hit = ctx.getHitPos(); + Edge edge = current_state.get(EDGE); + Direction dir = edge.getFirstDirection(); + ReFramedStepsSlabBlock block = ((ReFramedStepsSlabBlock) ReFramed.STEPS_SLAB); + BlockState state = block.getDefaultState() + .with(FACING, dir) + .with(AXIS, edge.getOtherDirection(dir).getAxis()); + if (!block.matchesShape( + hit, pos, + state, + edge.getOtherDirection(dir).getDirection() == Direction.AxisDirection.POSITIVE ? 1 : 2 + )) { + dir = edge.getSecondDirection(); + state = state + .with(FACING, dir) + .with(AXIS, edge.getOtherDirection(dir).getAxis()); + } + return state; + } + return super.getPlacementState(ctx).with(EDGE, BlockHelper.getPlacementEdge(ctx)); } @@ -68,6 +135,19 @@ public class ReFramedStepBlock extends WaterloggableReFramedBlock implements Blo return STEP_VOXELS[edge.getID()]; } + @Override + public Map getThemeMap(BlockState state, BlockState new_state) { + if (new_state.isOf(ReFramed.STAIRS_CUBE)) return Map.of(1, 2); + if (new_state.isOf(ReFramed.STEPS_SLAB)) + return Map.of( + 1, + state.get(EDGE) + .getOtherDirection(new_state.get(FACING)) + .getDirection() == Direction.AxisDirection.POSITIVE ? 2 : 1 + ); + return super.getThemeMap(state, new_state); + } + @Override public BlockStateSupplier getMultipart() { Identifier model_id = ReFramed.id("step_special"); diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedStepsSlabBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedStepsSlabBlock.java index c86688e..6198e69 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedStepsSlabBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedStepsSlabBlock.java @@ -81,7 +81,7 @@ public class ReFramedStepsSlabBlock extends WaterloggableReFramedDoubleBlock imp switch (axis) { case X -> i == 1 ? Direction.WEST : Direction.EAST; case Y -> i == 1 ? Direction.DOWN : Direction.UP; - case Z -> i == 1 ? Direction.SOUTH : Direction.NORTH; + case Z -> i == 1 ? Direction.NORTH : Direction.SOUTH; } )); } @@ -99,14 +99,14 @@ public class ReFramedStepsSlabBlock extends WaterloggableReFramedDoubleBlock imp .with(GBlockstate.when(FACING, Direction.DOWN, AXIS, Axis.X), GBlockstate.variant(step_id, true, R0, R180)) .with(GBlockstate.when(FACING, Direction.DOWN, AXIS, Axis.Z), - GBlockstate.variant(step_id, true, R0, R90)) + GBlockstate.variant(step_id, true, R0, R270)) .with(GBlockstate.when(FACING, Direction.UP, AXIS, Axis.X), GBlockstate.variant(step_id, true, R180, R180)) .with(GBlockstate.when(FACING, Direction.UP, AXIS, Axis.Z), - GBlockstate.variant(step_id, true, R180, R90)) + GBlockstate.variant(step_id, true, R180, R270)) .with(GBlockstate.when(FACING, Direction.EAST, AXIS, Axis.Z), - GBlockstate.variant(step_side_id, true, R180, R0)) + GBlockstate.variant(step_side_id, true, R0, R0)) .with(GBlockstate.when(FACING, Direction.EAST, AXIS, Axis.Y), GBlockstate.variant(step_side_id, true, R90, R0)) .with(GBlockstate.when(FACING, Direction.SOUTH, AXIS, Axis.X), @@ -114,7 +114,7 @@ public class ReFramedStepsSlabBlock extends WaterloggableReFramedDoubleBlock imp .with(GBlockstate.when(FACING, Direction.SOUTH, AXIS, Axis.Y), GBlockstate.variant(step_side_id, true, R90, R90)) .with(GBlockstate.when(FACING, Direction.WEST, AXIS, Axis.Z), - GBlockstate.variant(step_side_id, true, R0, R180)) + GBlockstate.variant(step_side_id, true, R180, R180)) .with(GBlockstate.when(FACING, Direction.WEST, AXIS, Axis.Y), GBlockstate.variant(step_side_id, true, R90, R180)) .with(GBlockstate.when(FACING, Direction.NORTH, AXIS, Axis.X), diff --git a/src/main/java/fr/adrien1106/reframed/block/WaterloggableReFramedDoubleBlock.java b/src/main/java/fr/adrien1106/reframed/block/WaterloggableReFramedDoubleBlock.java index bf71cf3..60e10e9 100644 --- a/src/main/java/fr/adrien1106/reframed/block/WaterloggableReFramedDoubleBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/WaterloggableReFramedDoubleBlock.java @@ -16,6 +16,7 @@ import org.jetbrains.annotations.Nullable; public class WaterloggableReFramedDoubleBlock extends ReFramedDoubleBlock implements Waterloggable { public WaterloggableReFramedDoubleBlock(Settings settings) { super(settings); + setDefaultState(getDefaultState().with(Properties.WATERLOGGED, false)); } @Override diff --git a/src/main/java/fr/adrien1106/reframed/mixin/logic/BlockItemMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/logic/BlockItemMixin.java new file mode 100644 index 0000000..e4a2350 --- /dev/null +++ b/src/main/java/fr/adrien1106/reframed/mixin/logic/BlockItemMixin.java @@ -0,0 +1,57 @@ +package fr.adrien1106.reframed.mixin.logic; + +import fr.adrien1106.reframed.block.ReFramedBlock; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.item.BlockItem; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(BlockItem.class) +public class BlockItemMixin { + + @Unique private final ThreadLocal old_state = new ThreadLocal<>(); + @Unique private final ThreadLocal old_entity = new ThreadLocal<>(); + + @Redirect( + method = "place(Lnet/minecraft/item/ItemPlacementContext;)Lnet/minecraft/util/ActionResult;", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/block/Block;onPlaced(Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;Lnet/minecraft/entity/LivingEntity;Lnet/minecraft/item/ItemStack;)V" + ) + ) + private void placeMoreInfo(Block block, World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack itemStack) { + if (!(block instanceof ReFramedBlock frame_block)) { + block.onPlaced(world, pos, state, placer, itemStack); + return; + } + frame_block.onPlaced(world, pos, state, placer, itemStack, old_state.get(), old_entity.get()); + } + + @Inject( + method = "place(Lnet/minecraft/item/ItemPlacementContext;)Lnet/minecraft/util/ActionResult;", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/item/BlockItem;place(Lnet/minecraft/item/ItemPlacementContext;Lnet/minecraft/block/BlockState;)Z", + shift = At.Shift.BEFORE + ) + ) + private void savePreviousInfo(ItemPlacementContext context, CallbackInfoReturnable cir) { + World world = context.getWorld(); + BlockPos pos = context.getBlockPos(); + old_state.set(world.getBlockState(pos)); + old_entity.set(world.getBlockEntity(pos)); + } + +} diff --git a/src/main/java/fr/adrien1106/reframed/util/blocks/BlockHelper.java b/src/main/java/fr/adrien1106/reframed/util/blocks/BlockHelper.java index cef30ab..0306a1e 100644 --- a/src/main/java/fr/adrien1106/reframed/util/blocks/BlockHelper.java +++ b/src/main/java/fr/adrien1106/reframed/util/blocks/BlockHelper.java @@ -130,14 +130,14 @@ public class BlockHelper { return shape; } - public static String getNeighborPos(Edge face, Direction direction, Boolean reverse, Direction reference, BlockView world, BlockPos pos) { + public static String getNeighborPos(Edge edge, Direction direction, Boolean reverse, Direction reference, BlockView world, BlockPos pos) { BlockState block_state = world.getBlockState( pos.offset(reverse ? direction.getOpposite() : direction) ); if (isStair(block_state) && block_state.get(EDGE).hasDirection(reference)) { - if (block_state.get(EDGE).hasDirection(face.getLeftDirection())) return "left"; - else if (block_state.get(EDGE).hasDirection(face.getRightDirection())) return "right"; + if (block_state.get(EDGE).hasDirection(edge.getLeftDirection())) return "left"; + else if (block_state.get(EDGE).hasDirection(edge.getRightDirection())) return "right"; } return ""; } diff --git a/src/main/java/fr/adrien1106/reframed/util/blocks/Corner.java b/src/main/java/fr/adrien1106/reframed/util/blocks/Corner.java index 1b16ea4..e1843de 100644 --- a/src/main/java/fr/adrien1106/reframed/util/blocks/Corner.java +++ b/src/main/java/fr/adrien1106/reframed/util/blocks/Corner.java @@ -37,6 +37,18 @@ public enum Corner implements StringIdentifiable { return asString(); } + public Direction getFirstDirection() { + return first_direction; + } + + public Direction getSecondDirection() { + return second_direction; + } + + public Direction getThirdDirection() { + return third_direction; + } + public boolean hasDirection(Direction direction) { return this.first_direction.equals(direction) || this.second_direction.equals(direction) @@ -94,4 +106,17 @@ public enum Corner implements StringIdentifiable { Direction other_2 = second_direction == direction || first_direction == direction ? third_direction : second_direction; return getByDirections(direction, other_1.getOpposite(), other_2.getOpposite()); } + + public Edge getEdge(Direction direction) { + return Edge.getByDirections( + first_direction == direction ? second_direction : first_direction, + second_direction == direction || first_direction == direction ? third_direction : second_direction + ); + } + + public Direction getOtherDirection(Edge edge) { + if (edge.getFirstDirection() != second_direction && edge.getSecondDirection() != second_direction) return second_direction; + if (edge.getFirstDirection() != third_direction && edge.getSecondDirection() != third_direction) return third_direction; + return first_direction; + } } diff --git a/src/main/java/fr/adrien1106/reframed/util/blocks/Edge.java b/src/main/java/fr/adrien1106/reframed/util/blocks/Edge.java index 3b23296..9c8e34d 100644 --- a/src/main/java/fr/adrien1106/reframed/util/blocks/Edge.java +++ b/src/main/java/fr/adrien1106/reframed/util/blocks/Edge.java @@ -49,18 +49,10 @@ public enum Edge implements StringIdentifiable { return second_direction; } public Direction getRightDirection() { - return switch (axis) { - case X -> Direction.WEST; - case Y -> Direction.DOWN; - case Z -> Direction.SOUTH; - }; + return Direction.from(axis, Direction.AxisDirection.NEGATIVE); } public Direction getLeftDirection() { - return switch (axis) { - case X -> Direction.EAST; - case Y -> Direction.UP; - case Z -> Direction.NORTH; - }; + return Direction.from(axis, Direction.AxisDirection.POSITIVE); } public boolean hasDirection(Direction direction) { @@ -68,16 +60,32 @@ public enum Edge implements StringIdentifiable { || this.second_direction.equals(direction); } + public Direction.Axis getAxis() { + return this.axis; + } + public int getID() { return this.ID; } + public Edge opposite() { + return getByDirections(first_direction.getOpposite(), second_direction.getOpposite()); + } + public static Edge getByDirections(Direction direction_1, Direction direction_2) { return Arrays.stream(Edge.values()) .filter(value -> value.hasDirection(direction_1) && value.hasDirection(direction_2)) .findFirst().orElse(Edge.NORTH_DOWN); } + public boolean isSide(Direction side) { + return getRightDirection() == side || getLeftDirection() == side; + } + + public Direction getOtherDirection(Direction direction) { + return first_direction == direction ? second_direction : first_direction; + } + public static Edge fromId(int id) { return Arrays.stream(Edge.values()) .filter(value -> value.getID() == id) diff --git a/src/main/resources/reframed.mixins.json b/src/main/resources/reframed.mixins.json index de74135..5ed414c 100644 --- a/src/main/resources/reframed.mixins.json +++ b/src/main/resources/reframed.mixins.json @@ -6,6 +6,7 @@ "mixins": [ "BlockItemMixin", "WallBlockAccessor", + "logic.BlockItemMixin", "particles.MixinEntity", "particles.MixinLivingEntity" ],