diff --git a/gradle.properties b/gradle.properties index c2dd688..77a6cd7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ loader_version=0.15.6 # Mod Properties modrinth_id = jCpoCBpn -mod_version = 1.4 +mod_version = 1.5 maven_group = fr.adrien1106 archives_base_name = ReFramed mod_id = reframed diff --git a/src/main/java/fr/adrien1106/reframed/ReFramed.java b/src/main/java/fr/adrien1106/reframed/ReFramed.java index f546e28..8886e19 100644 --- a/src/main/java/fr/adrien1106/reframed/ReFramed.java +++ b/src/main/java/fr/adrien1106/reframed/ReFramed.java @@ -1,7 +1,6 @@ package fr.adrien1106.reframed; import fr.adrien1106.reframed.block.*; -import fr.adrien1106.reframed.util.BlockHelper; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup; import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder; @@ -25,14 +24,21 @@ import java.util.ArrayList; import java.util.function.BiConsumer; import java.util.stream.Collectors; +import static fr.adrien1106.reframed.util.blocks.BlockProperties.LIGHT; + /** - * TODO self culling, fix other models, better connected textures, preload items, better cache + * TODO make block pairable by right click -> for v1.6 + * TODO add Hammer from framed ( removes theme ) -> for v1.5.5 + * TODO add screwdriver ( iterate over theme states ) ? + * TODO add blueprint for survival friendly copy paste of a theme. -> for v1.5.5 + * TODO add minecraft models like wall fence etc -> for v1.6 + * TODO better connected textures -> maybe v1.6 ? */ public class ReFramed implements ModInitializer { public static final String MODID = "reframed"; public static final ArrayList BLOCKS = new ArrayList<>(); - public static Block CUBE, STAIRS, DOUBLE_STAIRS, SLAB, DOUBLE_SLAB, STEP, DOUBLE_STEP; + public static Block CUBE, SMALL_CUBE, SMALL_CUBES_STEP, STAIR, HALF_STAIR, STAIRS_CUBE, HALF_STAIRS_SLAB, HALF_STAIRS_STAIR, SLAB, SLABS_CUBE, STEP, STEPS_SLAB, LAYER; public static ItemGroup ITEM_GROUP; public static BlockEntityType REFRAMED_BLOCK_ENTITY; @@ -42,18 +48,19 @@ public class ReFramed implements ModInitializer { @Override public void onInitialize() { - //registerReFramed mutates FRAMES as a side effect, which is a List, so order is preserved - //the ordering is used in the creative tab, so they're roughly sorted by encounter order of the - //corresponding vanilla block in the "search" creative tab... with the non-vanilla "post" and - //"vertical slab" inserted where they fit ...and i moved the lever way up next to the pressureplate - //and button, because they're redstoney... hopefully this ordering makes sense lol - CUBE = registerReFramed("cube" , new ReFramedBlock(cp(Blocks.OAK_PLANKS))); - STAIRS = registerReFramed("stairs" , new ReFramedStairsBlock(cp(Blocks.OAK_STAIRS))); - DOUBLE_STAIRS = registerReFramed("double_stairs" , new ReFramedDoubleStairsBlock(cp(Blocks.OAK_STAIRS))); - SLAB = registerReFramed("slab" , new ReFramedSlabBlock(cp(Blocks.OAK_SLAB))); - DOUBLE_SLAB = registerReFramed("double_slab" , new ReFramedDoubleSlabBlock(cp(Blocks.OAK_SLAB))); - STEP = registerReFramed("step" , new ReFramedStepBlock(cp(Blocks.OAK_SLAB))); - DOUBLE_STEP = registerReFramed("double_step" , new ReFramedDoubleStepBlock(cp(Blocks.OAK_SLAB))); + CUBE = registerReFramed("cube" , new ReFramedBlock(cp(Blocks.OAK_PLANKS))); + SMALL_CUBE = registerReFramed("small_cube" , new ReFramedSmallCubeBlock(cp(Blocks.OAK_PLANKS))); + SMALL_CUBES_STEP = registerReFramed("small_cubes_step" , new ReFramedSmallCubesStepBlock(cp(Blocks.OAK_PLANKS))); + STAIR = registerReFramed("stair" , new ReFramedStairBlock(cp(Blocks.OAK_STAIRS))); + STAIRS_CUBE = registerReFramed("stairs_cube" , new ReFramedStairsCubeBlock(cp(Blocks.OAK_STAIRS))); + HALF_STAIR = registerReFramed("half_stair" , new ReFramedHalfStairBlock(cp(Blocks.OAK_STAIRS))); + HALF_STAIRS_SLAB = registerReFramed("half_stairs_slab" , new ReFramedHalfStairsSlabBlock(cp(Blocks.OAK_STAIRS))); + HALF_STAIRS_STAIR = registerReFramed("half_stairs_stair" , new ReFramedHalfStairsStairBlock(cp(Blocks.OAK_STAIRS))); + LAYER = registerReFramed("layer" , new ReFramedLayerBlock(cp(Blocks.OAK_SLAB))); + SLAB = registerReFramed("slab" , new ReFramedSlabBlock(cp(Blocks.OAK_SLAB))); + SLABS_CUBE = registerReFramed("slabs_cube" , new ReFramedSlabsCubeBlock(cp(Blocks.OAK_SLAB))); + STEP = registerReFramed("step" , new ReFramedStepBlock(cp(Blocks.OAK_SLAB))); + STEPS_SLAB = registerReFramed("steps_slab" , new ReFramedStepsSlabBlock(cp(Blocks.OAK_SLAB))); REFRAMED_BLOCK_ENTITY = Registry.register(Registries.BLOCK_ENTITY_TYPE, id("camo"), FabricBlockEntityTypeBuilder.create( @@ -70,7 +77,7 @@ public class ReFramed implements ModInitializer { .filter(block -> block instanceof ReFramedDoubleBlock) .toArray(Block[]::new)).build(null) ); - + ITEM_GROUP = Registry.register(Registries.ITEM_GROUP, id("tab"), FabricItemGroup.builder() .displayName(Text.translatable("itemGroup.reframed.tab")) .icon(() -> new ItemStack(SLAB)) @@ -80,7 +87,7 @@ public class ReFramed implements ModInitializer { private static AbstractBlock.Settings cp(Block base) { return AbstractBlock.Settings.copy(base) - .luminance(BlockHelper::luminance) + .luminance(state -> state.contains(LIGHT) && state.get(LIGHT) ? 15 : 0) .nonOpaque() .sounds(BlockSoundGroup.WOOD) .hardness(0.2f) diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedBlock.java index d1609c3..05e7aef 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedBlock.java @@ -2,7 +2,7 @@ package fr.adrien1106.reframed.block; import fr.adrien1106.reframed.ReFramed; import fr.adrien1106.reframed.generator.RecipeSetter; -import fr.adrien1106.reframed.util.BlockHelper; +import fr.adrien1106.reframed.util.blocks.BlockHelper; import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider; import net.minecraft.block.*; import net.minecraft.block.entity.BlockEntity; @@ -33,7 +33,7 @@ import org.jetbrains.annotations.Nullable; import java.util.List; -import static fr.adrien1106.reframed.util.BlockProperties.LIGHT; +import static fr.adrien1106.reframed.util.blocks.BlockProperties.LIGHT; public class ReFramedBlock extends Block implements BlockEntityProvider, RecipeSetter { @@ -41,6 +41,23 @@ public class ReFramedBlock extends Block implements BlockEntityProvider, RecipeS super(settings); setDefaultState(getDefaultState().with(LIGHT, false)); } + + /** + * Generates a record for the key so that it replaces the blockstate + * which may have states that returns same models + * @param state - the state_key to generate the key from + * @return a cache key with only relevant properties + */ + public Object getModelCacheKey(BlockState state) { + return ""; + } + + /** + * @return the amount of models the block can have prevents allocating too much space for a model + */ + public int getModelStateCount() { + return 1; + } //For addon devs: override this so your blocks don't end up trying to place my block entity, my BlockEntityType only handles blocks internal to the mod //Just make your own BlockEntityType, it's fine, you can even use the same ReFramedEntity class @@ -98,7 +115,7 @@ public class ReFramedBlock extends Block implements BlockEntityProvider, RecipeS && themes.stream().noneMatch(theme -> theme.getLuminance() != 0)) drops.add(new ItemStack(Items.GLOWSTONE_DUST)); if(!frame_entity.isSolid() - && themes.stream().anyMatch(theme -> theme.isSolid())) + && themes.stream().anyMatch(AbstractBlockState::isSolid)) drops.add(new ItemStack(Items.POPPED_CHORUS_FRUIT)); ItemScatterer.spawn(world, pos, drops); diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleBlock.java index 45756b6..cb708b0 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleBlock.java @@ -1,8 +1,8 @@ package fr.adrien1106.reframed.block; import fr.adrien1106.reframed.ReFramed; -import fr.adrien1106.reframed.util.BlockHelper; -import fr.adrien1106.reframed.util.ThemeableBlockEntity; +import fr.adrien1106.reframed.util.blocks.BlockHelper; +import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity; import net.minecraft.block.BlockState; import net.minecraft.block.ShapeContext; import net.minecraft.block.entity.BlockEntity; diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleEntity.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleEntity.java index 5090b0a..cecd4f6 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleEntity.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleEntity.java @@ -44,7 +44,7 @@ public class ReFramedDoubleEntity extends ReFramedEntity { public void readNbt(NbtCompound nbt) { super.readNbt(nbt); - BlockState rendered_state = second_state;// keep previous state to check if rerender is needed + BlockState rendered_state = second_state;// keep previous state_key to check if rerender is needed second_state = NbtHelper.toBlockState(Registries.BLOCK.getReadOnlyWrapper(), nbt.getCompound(BLOCKSTATE_KEY + 2)); // Force a chunk remesh on the client if the displayed blockstate has changed diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleStairsBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleStairsBlock.java deleted file mode 100644 index c7ac022..0000000 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleStairsBlock.java +++ /dev/null @@ -1,210 +0,0 @@ -package fr.adrien1106.reframed.block; - -import fr.adrien1106.reframed.ReFramed; -import fr.adrien1106.reframed.generator.BlockStateProvider; -import fr.adrien1106.reframed.util.BlockHelper; -import fr.adrien1106.reframed.util.property.Corner; -import fr.adrien1106.reframed.util.property.StairShape; -import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -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.ItemPlacementContext; -import net.minecraft.recipe.book.RecipeCategory; -import net.minecraft.state.StateManager; -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.World; -import net.minecraft.world.WorldAccess; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; - -import static fr.adrien1106.reframed.block.ReFramedStairsBlock.*; -import static fr.adrien1106.reframed.util.BlockProperties.CORNER; -import static fr.adrien1106.reframed.util.BlockProperties.STAIR_SHAPE; -import static fr.adrien1106.reframed.util.property.StairShape.STRAIGHT; - -public class ReFramedDoubleStairsBlock extends ReFramedDoubleBlock implements BlockStateProvider { - - private static final List COMPLEMENT_LIST = new ArrayList<>(52); - - public ReFramedDoubleStairsBlock(Settings settings) { - super(settings); - setDefaultState(getDefaultState().with(CORNER, Corner.NORTH_DOWN).with(STAIR_SHAPE, STRAIGHT)); - } - - @Override - protected void appendProperties(StateManager.Builder builder) { - super.appendProperties(builder.add(CORNER, STAIR_SHAPE)); - } - - @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) - .with(STAIR_SHAPE, BlockHelper.getStairsShape(this, state.get(CORNER), world, pos)); - } - - - @Nullable - @Override - public BlockState getPlacementState(ItemPlacementContext ctx) { - Corner face = BlockHelper.getPlacementCorner(ctx); - StairShape shape = BlockHelper.getStairsShape(this, face, ctx.getWorld(), ctx.getBlockPos()); - return super.getPlacementState(ctx).with(CORNER, face).with(STAIR_SHAPE, shape); - } - - @Override - public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { - super.onStateReplaced(state, world, pos, newState, moved); - - if(!state.isOf(newState.getBlock())) world.removeBlockEntity(pos); - } - - @Override - public VoxelShape getShape(BlockState state, int i) { - return i == 2 ? getComplementOutline(state) : getOutline(state); - } - - private VoxelShape getComplementOutline(BlockState state) { - StairShape shape = state.get(STAIR_SHAPE); - Corner direction = state.get(CORNER); - return switch (shape) { - case STRAIGHT -> - switch (direction) { - case DOWN_SOUTH -> COMPLEMENT_LIST.get(0); - case NORTH_DOWN -> COMPLEMENT_LIST.get(1); - case UP_NORTH -> COMPLEMENT_LIST.get(2); - case SOUTH_UP -> COMPLEMENT_LIST.get(3); - case DOWN_EAST -> COMPLEMENT_LIST.get(4); - case WEST_DOWN -> COMPLEMENT_LIST.get(5); - case UP_WEST -> COMPLEMENT_LIST.get(6); - case EAST_UP -> COMPLEMENT_LIST.get(7); - case NORTH_EAST -> COMPLEMENT_LIST.get(8); - case EAST_SOUTH -> COMPLEMENT_LIST.get(9); - case SOUTH_WEST -> COMPLEMENT_LIST.get(10); - case WEST_NORTH -> COMPLEMENT_LIST.get(11); - }; - case INNER_LEFT -> - switch (direction) { - case WEST_DOWN, NORTH_DOWN -> COMPLEMENT_LIST.get(44); - case DOWN_EAST -> COMPLEMENT_LIST.get(45); - case DOWN_SOUTH -> COMPLEMENT_LIST.get(47); - case UP_WEST, UP_NORTH, WEST_NORTH -> COMPLEMENT_LIST.get(48); - case EAST_UP, NORTH_EAST -> COMPLEMENT_LIST.get(49); - case EAST_SOUTH -> COMPLEMENT_LIST.get(50); - case SOUTH_UP, SOUTH_WEST -> COMPLEMENT_LIST.get(51); - }; - case INNER_RIGHT -> - switch (direction) { - case WEST_NORTH -> COMPLEMENT_LIST.get(44); - case NORTH_DOWN, NORTH_EAST -> COMPLEMENT_LIST.get(45); - case DOWN_EAST, DOWN_SOUTH, EAST_SOUTH -> COMPLEMENT_LIST.get(46); - case WEST_DOWN, SOUTH_WEST -> COMPLEMENT_LIST.get(47); - case UP_NORTH -> COMPLEMENT_LIST.get(49); - case EAST_UP, SOUTH_UP -> COMPLEMENT_LIST.get(50); - case UP_WEST -> COMPLEMENT_LIST.get(51); - }; - case OUTER_LEFT -> - switch (direction) { - case DOWN_EAST -> COMPLEMENT_LIST.get(43); - case WEST_DOWN, NORTH_DOWN -> COMPLEMENT_LIST.get(42); - case DOWN_SOUTH -> COMPLEMENT_LIST.get(41); - case EAST_UP, NORTH_EAST -> COMPLEMENT_LIST.get(39); - case UP_WEST, UP_NORTH, WEST_NORTH -> COMPLEMENT_LIST.get(38); - case SOUTH_UP, SOUTH_WEST -> COMPLEMENT_LIST.get(37); - case EAST_SOUTH -> COMPLEMENT_LIST.get(36); - }; - case OUTER_RIGHT -> - switch (direction) { - case NORTH_DOWN, NORTH_EAST -> COMPLEMENT_LIST.get(43); - case WEST_NORTH -> COMPLEMENT_LIST.get(42); - case WEST_DOWN, SOUTH_WEST -> COMPLEMENT_LIST.get(41); - case DOWN_EAST, DOWN_SOUTH, EAST_SOUTH -> COMPLEMENT_LIST.get(40); - case UP_NORTH -> COMPLEMENT_LIST.get(39); - case UP_WEST -> COMPLEMENT_LIST.get(37); - case EAST_UP, SOUTH_UP -> COMPLEMENT_LIST.get(36); - }; - case FIRST_OUTER_LEFT -> - switch (direction) { - case WEST_DOWN, NORTH_DOWN -> COMPLEMENT_LIST.get(14); - case SOUTH_UP -> COMPLEMENT_LIST.get(17); - case EAST_UP -> COMPLEMENT_LIST.get(19); - case EAST_SOUTH -> COMPLEMENT_LIST.get(20); - case DOWN_SOUTH -> COMPLEMENT_LIST.get(22); - case UP_NORTH, WEST_NORTH -> COMPLEMENT_LIST.get(25); - case SOUTH_WEST -> COMPLEMENT_LIST.get(28); - case UP_WEST -> COMPLEMENT_LIST.get(31); - case DOWN_EAST -> COMPLEMENT_LIST.get(34); - case NORTH_EAST -> COMPLEMENT_LIST.get(35); - }; - case FIRST_OUTER_RIGHT -> - switch (direction) { - case NORTH_DOWN -> COMPLEMENT_LIST.get(15); - case SOUTH_UP, EAST_UP -> COMPLEMENT_LIST.get(16); - case WEST_DOWN -> COMPLEMENT_LIST.get(13); - case DOWN_SOUTH, EAST_SOUTH -> COMPLEMENT_LIST.get(23); - case UP_NORTH -> COMPLEMENT_LIST.get(24); - case WEST_NORTH -> COMPLEMENT_LIST.get(26); - case UP_WEST -> COMPLEMENT_LIST.get(28); - case SOUTH_WEST -> COMPLEMENT_LIST.get(29); - case DOWN_EAST -> COMPLEMENT_LIST.get(33); - case NORTH_EAST -> COMPLEMENT_LIST.get(34); - }; - case SECOND_OUTER_LEFT -> - switch (direction) { - case DOWN_EAST -> COMPLEMENT_LIST.get(15); - case DOWN_SOUTH -> COMPLEMENT_LIST.get(13); - case UP_WEST, UP_NORTH -> COMPLEMENT_LIST.get(18); - case SOUTH_UP, SOUTH_WEST -> COMPLEMENT_LIST.get(21); - case NORTH_EAST -> COMPLEMENT_LIST.get(24); - case NORTH_DOWN -> COMPLEMENT_LIST.get(26); - case WEST_DOWN -> COMPLEMENT_LIST.get(30); - case WEST_NORTH -> COMPLEMENT_LIST.get(31); - case EAST_SOUTH -> COMPLEMENT_LIST.get(32); - case EAST_UP -> COMPLEMENT_LIST.get(35); - }; - case SECOND_OUTER_RIGHT -> - switch (direction) { - case DOWN_SOUTH, DOWN_EAST -> COMPLEMENT_LIST.get(12); - case UP_WEST -> COMPLEMENT_LIST.get(17); - case UP_NORTH -> COMPLEMENT_LIST.get(19); - case SOUTH_UP -> COMPLEMENT_LIST.get(20); - case SOUTH_WEST -> COMPLEMENT_LIST.get(22); - case NORTH_EAST, NORTH_DOWN -> COMPLEMENT_LIST.get(27); - case WEST_DOWN -> COMPLEMENT_LIST.get(29); - case WEST_NORTH -> COMPLEMENT_LIST.get(30); - case EAST_UP -> COMPLEMENT_LIST.get(32); - case EAST_SOUTH -> COMPLEMENT_LIST.get(33); - }; - }; - } - - @Override - public MultipartBlockStateSupplier getMultipart() { - return getStairMultipart(this, true); - } - - @Override - public void setRecipe(RecipeExporter exporter) { - RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE); - ShapelessRecipeJsonBuilder - .create(RecipeCategory.BUILDING_BLOCKS, this) - .input(ReFramed.STAIRS) - .input(ReFramed.STEP) - .criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE)) - .criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this)) - .offerTo(exporter); - } - - static { - VOXEL_LIST.forEach(shape -> COMPLEMENT_LIST.add(VoxelShapes.combineAndSimplify(VoxelShapes.fullCube(), shape, BooleanBiFunction.ONLY_FIRST))); - } -} diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedEntity.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedEntity.java index cb7bde1..fc70154 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedEntity.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedEntity.java @@ -1,8 +1,8 @@ package fr.adrien1106.reframed.block; import fr.adrien1106.reframed.ReFramed; -import fr.adrien1106.reframed.util.BlockProperties; -import fr.adrien1106.reframed.util.ThemeableBlockEntity; +import fr.adrien1106.reframed.util.blocks.BlockProperties; +import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.entity.BlockEntity; @@ -27,7 +27,7 @@ import java.util.Objects; //Keeping the weight of this block entity down, both in terms of memory consumption and NBT sync traffic, //is pretty important since players might place a lot of them. There were tons and tons of these at Blanketcon. -//To that end, most of the state has been crammed into a bitfield. +//To that end, most of the state_key has been crammed into a bitfield. public class ReFramedEntity extends BlockEntity implements ThemeableBlockEntity { protected BlockState first_state = Blocks.AIR.getDefaultState(); protected byte bit_field = SOLIDITY_MASK; @@ -47,7 +47,7 @@ public class ReFramedEntity extends BlockEntity implements ThemeableBlockEntity public void readNbt(NbtCompound nbt) { super.readNbt(nbt); - BlockState rendered_state = first_state; // keep previous state to check if rerender is needed + BlockState rendered_state = first_state; // keep previous state_key to check if rerender is needed first_state = NbtHelper.toBlockState(Registries.BLOCK.getReadOnlyWrapper(), nbt.getCompound(BLOCKSTATE_KEY + 1)); if (nbt.contains(BITFIELD_KEY)) bit_field = nbt.getByte(BITFIELD_KEY); diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairBlock.java new file mode 100644 index 0000000..cb1ca8a --- /dev/null +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairBlock.java @@ -0,0 +1,194 @@ +package fr.adrien1106.reframed.block; + +import fr.adrien1106.reframed.ReFramed; +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; +import net.minecraft.block.ShapeContext; +import net.minecraft.data.client.BlockStateSupplier; +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.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.shape.VoxelShape; +import net.minecraft.util.shape.VoxelShapes; +import net.minecraft.world.BlockView; +import org.jetbrains.annotations.Nullable; + +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.Corner.*; +import static net.minecraft.data.client.VariantSettings.Rotation.*; + +public class ReFramedHalfStairBlock extends WaterloggableReFramedBlock implements BlockStateProvider { + + public static final VoxelShape[] HALF_STAIR_VOXELS; + + private record ModelCacheKey(Corner corner, int face) {} + + public ReFramedHalfStairBlock(Settings settings) { + super(settings); + setDefaultState(getDefaultState().with(CORNER, NORTH_EAST_DOWN).with(CORNER_FACE, 0)); + } + + @Override + public Object getModelCacheKey(BlockState state) { + return new ModelCacheKey(state.get(CORNER), state.get(CORNER_FACE)); + } + + @Override + public int getModelStateCount() { + return 24; + } + + @Override + protected void appendProperties(StateManager.Builder builder) { + super.appendProperties(builder.add(CORNER,CORNER_FACE)); + } + + @Override + public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) { + Corner corner = BlockHelper.getPlacementCorner(ctx); + return super.getPlacementState(ctx) + .with(CORNER, corner) + .with(CORNER_FACE, corner.getDirectionIndex(ctx.getSide().getOpposite())); + } + + @Override + public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { + return HALF_STAIR_VOXELS[state.get(CORNER_FACE) + state.get(CORNER).getID() * 3]; + } + + @Override + public BlockStateSupplier getMultipart() { + return getHalfStairMultipart( + this, + ReFramed.id("half_stair_down_special"), + ReFramed.id("half_stair_side_special") + ); + } + + public static BlockStateSupplier getHalfStairMultipart(Block block, Identifier model_down, Identifier model_side) { + return MultipartBlockStateSupplier.create(block) + .with(GBlockstate.when(CORNER, NORTH_EAST_DOWN, CORNER_FACE, 1), + GBlockstate.variant(model_side, true, R0, R0)) + .with(GBlockstate.when(CORNER, NORTH_EAST_DOWN, CORNER_FACE, 0), + GBlockstate.variant(model_side, true, R90, R270)) + .with(GBlockstate.when(CORNER, NORTH_EAST_DOWN, CORNER_FACE, 2), + GBlockstate.variant(model_down, true, R0, R0)) + + .with(GBlockstate.when(CORNER, EAST_SOUTH_DOWN, CORNER_FACE, 1), + GBlockstate.variant(model_side, true, R0, R90)) + .with(GBlockstate.when(CORNER, EAST_SOUTH_DOWN, CORNER_FACE, 0), + GBlockstate.variant(model_side, true, R90, R0)) + .with(GBlockstate.when(CORNER, EAST_SOUTH_DOWN, CORNER_FACE, 2), + GBlockstate.variant(model_down, true, R0, R90)) + + .with(GBlockstate.when(CORNER, SOUTH_WEST_DOWN, CORNER_FACE, 1), + GBlockstate.variant(model_side, true, R0, R180)) + .with(GBlockstate.when(CORNER, SOUTH_WEST_DOWN, CORNER_FACE, 0), + GBlockstate.variant(model_side, true, R90, R90)) + .with(GBlockstate.when(CORNER, SOUTH_WEST_DOWN, CORNER_FACE, 2), + GBlockstate.variant(model_down, true, R0, R180)) + + .with(GBlockstate.when(CORNER, WEST_NORTH_DOWN, CORNER_FACE, 1), + GBlockstate.variant(model_side, true, R0, R270)) + .with(GBlockstate.when(CORNER, WEST_NORTH_DOWN, CORNER_FACE, 0), + GBlockstate.variant(model_side, true, R90, R180)) + .with(GBlockstate.when(CORNER, WEST_NORTH_DOWN, CORNER_FACE, 2), + GBlockstate.variant(model_down, true, R0, R270)) + + .with(GBlockstate.when(CORNER, EAST_SOUTH_UP, CORNER_FACE, 0), + GBlockstate.variant(model_side, true, R180, R0)) + .with(GBlockstate.when(CORNER, EAST_SOUTH_UP, CORNER_FACE, 1), + GBlockstate.variant(model_side, true, R270, R90)) + .with(GBlockstate.when(CORNER, EAST_SOUTH_UP, CORNER_FACE, 2), + GBlockstate.variant(model_down, true, R180, R0)) + + .with(GBlockstate.when(CORNER, SOUTH_WEST_UP, CORNER_FACE, 0), + GBlockstate.variant(model_side, true, R180, R90)) + .with(GBlockstate.when(CORNER, SOUTH_WEST_UP, CORNER_FACE, 1), + GBlockstate.variant(model_side, true, R270, R180)) + .with(GBlockstate.when(CORNER, SOUTH_WEST_UP, CORNER_FACE, 2), + GBlockstate.variant(model_down, true, R180, R90)) + + .with(GBlockstate.when(CORNER, WEST_NORTH_UP, CORNER_FACE, 0), + GBlockstate.variant(model_side, true, R180, R180)) + .with(GBlockstate.when(CORNER, WEST_NORTH_UP, CORNER_FACE, 1), + GBlockstate.variant(model_side, true, R270, R270)) + .with(GBlockstate.when(CORNER, WEST_NORTH_UP, CORNER_FACE, 2), + GBlockstate.variant(model_down, true, R180, R180)) + + .with(GBlockstate.when(CORNER, NORTH_EAST_UP, CORNER_FACE, 0), + GBlockstate.variant(model_side, true, R180, R270)) + .with(GBlockstate.when(CORNER, NORTH_EAST_UP, CORNER_FACE, 1), + GBlockstate.variant(model_side, true, R270, R0)) + .with(GBlockstate.when(CORNER, NORTH_EAST_UP, CORNER_FACE, 2), + GBlockstate.variant(model_down, true, R180, R270)); + } + + @Override + public void setRecipe(RecipeExporter exporter) { + RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE, 2); + ShapedRecipeJsonBuilder + .create(RecipeCategory.BUILDING_BLOCKS, this, 4) + .pattern("I ") + .pattern("II ") + .input('I', ReFramed.CUBE) + .criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE)) + .criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this)) + .offerTo(exporter); + } + + static { + final VoxelShape HALF_STAIR = VoxelShapes.combineAndSimplify( + createCuboidShape(8, 0, 0, 16, 16, 8), + createCuboidShape(0, 0, 0, 8, 8, 8), + BooleanBiFunction.OR + ); + HALF_STAIR_VOXELS = VoxelListBuilder.create(HALF_STAIR, 24) + .add(0 , VoxelHelper::rotateY, VoxelHelper::mirrorZ) + .add(0 , VoxelHelper::rotateCX, VoxelHelper::mirrorZ) + + .add(0 , VoxelHelper::rotateY) + .add(1 , VoxelHelper::rotateY) + .add(2 , VoxelHelper::rotateY) + + .add(3 , VoxelHelper::rotateY) + .add(4 , VoxelHelper::rotateY) + .add(5 , VoxelHelper::rotateY) + + .add(6 , VoxelHelper::rotateY) + .add(7 , VoxelHelper::rotateY) + .add(8 , VoxelHelper::rotateY) + + .add(0 , VoxelHelper::mirrorY) + .add(1 , VoxelHelper::mirrorY) + .add(2 , VoxelHelper::mirrorY) + + .add(12, VoxelHelper::rotateY) + .add(13, VoxelHelper::rotateY) + .add(14, VoxelHelper::rotateY) + + .add(15, VoxelHelper::rotateY) + .add(16, VoxelHelper::rotateY) + .add(17, VoxelHelper::rotateY) + + .add(18, VoxelHelper::rotateY) + .add(19, VoxelHelper::rotateY) + .add(20, VoxelHelper::rotateY) + .build(); + } +} diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairsSlabBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairsSlabBlock.java new file mode 100644 index 0000000..e0c6c41 --- /dev/null +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairsSlabBlock.java @@ -0,0 +1,103 @@ +package fr.adrien1106.reframed.block; + +import fr.adrien1106.reframed.ReFramed; +import fr.adrien1106.reframed.generator.BlockStateProvider; +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; +import net.minecraft.block.ShapeContext; +import net.minecraft.data.client.BlockStateSupplier; +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.ItemPlacementContext; +import net.minecraft.recipe.book.RecipeCategory; +import net.minecraft.state.StateManager; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.world.BlockView; +import org.jetbrains.annotations.Nullable; + +import static fr.adrien1106.reframed.block.ReFramedHalfStairBlock.HALF_STAIR_VOXELS; +import static fr.adrien1106.reframed.block.ReFramedHalfStairBlock.getHalfStairMultipart; +import static fr.adrien1106.reframed.block.ReFramedSlabBlock.getSlabShape; +import static fr.adrien1106.reframed.block.ReFramedSmallCubeBlock.SMALL_CUBE_VOXELS; +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.Corner.NORTH_EAST_DOWN; +import static net.minecraft.util.shape.VoxelShapes.empty; + +public class ReFramedHalfStairsSlabBlock extends WaterloggableReFramedDoubleBlock implements BlockStateProvider { + + private record ModelCacheKey(Corner corner, int face) {} + + public ReFramedHalfStairsSlabBlock(Settings settings) { + super(settings); + setDefaultState(getDefaultState().with(CORNER, NORTH_EAST_DOWN).with(CORNER_FACE, 0)); + } + + @Override + public Object getModelCacheKey(BlockState state) { + return new ModelCacheKey(state.get(CORNER), state.get(CORNER_FACE)); + } + + @Override + public int getModelStateCount() { + return 24; + } + + @Override + protected void appendProperties(StateManager.Builder builder) { + super.appendProperties(builder.add(CORNER,CORNER_FACE)); + } + + @Override + public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) { + Corner corner = BlockHelper.getPlacementCorner(ctx); + return super.getPlacementState(ctx) + .with(CORNER, corner) + .with(CORNER_FACE, corner.getDirectionIndex(ctx.getSide().getOpposite())); + } + + @Override + public VoxelShape getCullingShape(BlockState state, BlockView view, BlockPos pos) { + return isGhost(view, pos) ? empty(): getSlabShape(state.get(CORNER).getDirection(state.get(CORNER_FACE))); + } + + @Override + public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { + return getSlabShape(state.get(CORNER).getDirection(state.get(CORNER_FACE))); + } + + @Override + public VoxelShape getShape(BlockState state, int i) { + Corner corner = state.get(CORNER); + int face = state.get(CORNER_FACE); + return i == 2 + ? SMALL_CUBE_VOXELS[corner.getOpposite(face).getID()] + : HALF_STAIR_VOXELS[face + corner.getID() * 3]; + } + + @Override + public BlockStateSupplier getMultipart() { + return getHalfStairMultipart( + this, + ReFramed.id("half_stairs_slab_down_special"), + ReFramed.id("half_stairs_slab_side_special") + ); + } + + @Override + public void setRecipe(RecipeExporter exporter) { + RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE, 2); + ShapelessRecipeJsonBuilder + .create(RecipeCategory.BUILDING_BLOCKS, this) + .input(ReFramed.HALF_STAIR) + .input(ReFramed.SMALL_CUBE) + .criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE)) + .criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this)) + .offerTo(exporter); + } +} diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairsStairBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairsStairBlock.java new file mode 100644 index 0000000..d645df0 --- /dev/null +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedHalfStairsStairBlock.java @@ -0,0 +1,138 @@ +package fr.adrien1106.reframed.block; + +import fr.adrien1106.reframed.ReFramed; +import fr.adrien1106.reframed.generator.BlockStateProvider; +import fr.adrien1106.reframed.generator.GBlockstate; +import fr.adrien1106.reframed.util.blocks.BlockHelper; +import fr.adrien1106.reframed.util.blocks.Corner; +import fr.adrien1106.reframed.util.blocks.Edge; +import fr.adrien1106.reframed.util.blocks.StairShape; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.ShapeContext; +import net.minecraft.data.client.BlockStateSupplier; +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.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.shape.VoxelShape; +import net.minecraft.world.BlockView; +import org.jetbrains.annotations.Nullable; + +import static fr.adrien1106.reframed.block.ReFramedHalfStairBlock.HALF_STAIR_VOXELS; +import static fr.adrien1106.reframed.block.ReFramedStairBlock.getStairShape; +import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE; +import static fr.adrien1106.reframed.util.blocks.Edge.*; +import static net.minecraft.data.client.VariantSettings.Rotation.*; +import static net.minecraft.util.shape.VoxelShapes.empty; + +public class ReFramedHalfStairsStairBlock extends WaterloggableReFramedDoubleBlock implements BlockStateProvider { + public ReFramedHalfStairsStairBlock(Settings settings) { + super(settings); + setDefaultState(getDefaultState().with(EDGE, NORTH_DOWN)); + } + + @Override + public Object getModelCacheKey(BlockState state) { + return state.get(EDGE); + } + + @Override + public int getModelStateCount() { + return 12; + } + + @Override + protected void appendProperties(StateManager.Builder builder) { + super.appendProperties(builder.add(EDGE)); + } + + @Nullable + @Override + public BlockState getPlacementState(ItemPlacementContext ctx) { + return super.getPlacementState(ctx).with(EDGE, BlockHelper.getPlacementEdge(ctx)); + } + + @Override + public VoxelShape getCullingShape(BlockState state, BlockView view, BlockPos pos) { + return isGhost(view, pos) ? empty(): getStairShape(state.get(EDGE), StairShape.STRAIGHT); + } + + @Override + public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { + return getStairShape(state.get(EDGE), StairShape.STRAIGHT); + } + + @Override + public VoxelShape getShape(BlockState state, int i) { + Edge edge = state.get(EDGE); + Direction side = i == 1 + ? edge.getRightDirection() + : edge.getLeftDirection(); + Corner corner = Corner.getByDirections( + edge.getFirstDirection(), + edge.getSecondDirection(), + side + + ); + return HALF_STAIR_VOXELS[corner.getID() * 3 + corner.getDirectionIndex(side)]; + } + + @Override + public int getTopThemeIndex(BlockState state) { + return 2; + } + + @Override + public BlockStateSupplier getMultipart() { + Identifier model_id = ReFramed.id("half_stairs_stair_down_special"); + Identifier side_model_id = ReFramed.id("half_stairs_stair_side_special"); + Identifier reverse_model_id = ReFramed.id("half_stairs_stair_reverse_special"); + return MultipartBlockStateSupplier.create(this) + /* X AXIS */ + .with(GBlockstate.when(EDGE, NORTH_DOWN), + GBlockstate.variant(side_model_id, true, R90, R180)) + .with(GBlockstate.when(EDGE, DOWN_SOUTH), + GBlockstate.variant(side_model_id, true, R0, R180)) + .with(GBlockstate.when(EDGE, SOUTH_UP), + GBlockstate.variant(side_model_id, true, R270, R180)) + .with(GBlockstate.when(EDGE, UP_NORTH), + GBlockstate.variant(side_model_id, true, R180, R180)) + /* Y AXIS */ + .with(GBlockstate.when(EDGE, NORTH_EAST), + GBlockstate.variant(model_id, true, R0, R0)) + .with(GBlockstate.when(EDGE, EAST_SOUTH), + GBlockstate.variant(model_id, true, R0, R90)) + .with(GBlockstate.when(EDGE, SOUTH_WEST), + GBlockstate.variant(model_id, true, R0, R180)) + .with(GBlockstate.when(EDGE, WEST_NORTH), + GBlockstate.variant(model_id, true, R0, R270)) + /* Z AXIS */ + .with(GBlockstate.when(EDGE, DOWN_EAST), + GBlockstate.variant(side_model_id, true, R0, R90)) + .with(GBlockstate.when(EDGE, EAST_UP), + GBlockstate.variant(reverse_model_id, true, R180, R270)) + .with(GBlockstate.when(EDGE, UP_WEST), + GBlockstate.variant(side_model_id, true, R180, R90)) + .with(GBlockstate.when(EDGE, WEST_DOWN), + GBlockstate.variant(reverse_model_id, true, R0, R270)); + } + + @Override + public void setRecipe(RecipeExporter exporter) { + RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE, 2); + ShapelessRecipeJsonBuilder + .create(RecipeCategory.BUILDING_BLOCKS, this) + .input(ReFramed.HALF_STAIR, 2) + .criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE)) + .criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this)) + .offerTo(exporter); + } +} diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedLayerBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedLayerBlock.java new file mode 100644 index 0000000..e7e8be5 --- /dev/null +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedLayerBlock.java @@ -0,0 +1,117 @@ +package fr.adrien1106.reframed.block; + +import fr.adrien1106.reframed.ReFramed; +import fr.adrien1106.reframed.generator.GBlockstate; +import fr.adrien1106.reframed.util.VoxelHelper; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.ShapeContext; +import net.minecraft.data.client.MultipartBlockStateSupplier; +import net.minecraft.item.ItemPlacementContext; +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.shape.VoxelShape; +import net.minecraft.world.BlockView; +import org.jetbrains.annotations.Nullable; + +import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder; +import static net.minecraft.data.client.VariantSettings.Rotation.*; +import static net.minecraft.state.property.Properties.FACING; +import static net.minecraft.state.property.Properties.LAYERS; + +public class ReFramedLayerBlock extends ReFramedSlabBlock { + + public static final VoxelShape[] LAYER_VOXELS; + private record ModelCacheKey(Direction face, int layer) {} + + public ReFramedLayerBlock(Settings settings) { + super(settings); + setDefaultState(getDefaultState().with(LAYERS, 1)); + } + + @Override + public Object getModelCacheKey(BlockState state) { + return new ModelCacheKey(state.get(FACING), state.get(LAYERS)); + } + + @Override + public int getModelStateCount() { + return 48; + } + + @Override + protected void appendProperties(StateManager.Builder builder) { + super.appendProperties(builder.add(LAYERS)); + } + + @Override + public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { + return LAYER_VOXELS[state.get(FACING).getId() * 8 + state.get(LAYERS) - 1]; + } + + @Override + public boolean canReplace(BlockState state, ItemPlacementContext ctx) { + return !(!state.isOf(this) || ctx.getPlayer().isSneaking() || state.get(LAYERS) == 8); + } + + @Override + public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) { + BlockState previous = ctx.getWorld().getBlockState(ctx.getBlockPos()); + if (!previous.isOf(this)) return super.getPlacementState(ctx); + return previous.with(LAYERS, previous.get(LAYERS) + 1); + } + + @Override + public MultipartBlockStateSupplier getMultipart() { + String model_pattern = "layer_x_special"; + MultipartBlockStateSupplier supplier = MultipartBlockStateSupplier.create(this); + for (int i = 1; i <= 8; i++) { + Identifier model = ReFramed.id(model_pattern.replace("x", i + "")); + supplier + .with(GBlockstate.when(FACING, Direction.DOWN, LAYERS, i), + GBlockstate.variant(model, true, R0, R0)) + .with(GBlockstate.when(FACING, Direction.SOUTH, LAYERS, i), + GBlockstate.variant(model, true, R90, R0)) + .with(GBlockstate.when(FACING, Direction.UP, LAYERS, i), + GBlockstate.variant(model, true, R180, R0)) + .with(GBlockstate.when(FACING, Direction.NORTH, LAYERS, i), + GBlockstate.variant(model, true, R270, R0)) + .with(GBlockstate.when(FACING, Direction.WEST, LAYERS, i), + GBlockstate.variant(model, true, R90, R90)) + .with(GBlockstate.when(FACING, Direction.EAST, LAYERS, i), + GBlockstate.variant(model, true, R90, R270)); + } + return supplier; + } + + static { + VoxelListBuilder builder = VoxelListBuilder.create(createCuboidShape(0, 0, 0, 16, 2, 16), 48) + .add(createCuboidShape(0, 0, 0, 16, 4, 16)) + .add(createCuboidShape(0, 0, 0, 16, 6, 16)) + .add(createCuboidShape(0, 0, 0, 16, 8, 16)) + .add(createCuboidShape(0, 0, 0, 16, 10, 16)) + .add(createCuboidShape(0, 0, 0, 16, 12, 16)) + .add(createCuboidShape(0, 0, 0, 16, 14, 16)) + .add(createCuboidShape(0, 0, 0, 16, 16, 16)); + + for (int i = 0; i < 8; i++) { + builder.add(i, VoxelHelper::mirrorY); + } + for (int i = 0; i < 8; i++) { + builder.add(i, VoxelHelper::rotateX); + } + for (int i = 0; i < 8; i++) { + builder.add(i, VoxelHelper::rotateCX); + } + for (int i = 0; i < 8; i++) { + builder.add(i, VoxelHelper::rotateCZ); + } + for (int i = 0; i < 8; i++) { + builder.add(i, VoxelHelper::rotateZ); + } + + LAYER_VOXELS = builder.build(); + } +} diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabBlock.java index fa65921..751588e 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabBlock.java @@ -38,6 +38,16 @@ public class ReFramedSlabBlock extends WaterloggableReFramedBlock implements Blo super(settings); setDefaultState(getDefaultState().with(FACING, Direction.DOWN)); } + + @Override + public Object getModelCacheKey(BlockState state) { + return state.get(FACING); + } + + @Override + public int getModelStateCount() { + return 6; + } @Override protected void appendProperties(StateManager.Builder builder) { diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleSlabBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabsCubeBlock.java similarity index 83% rename from src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleSlabBlock.java rename to src/main/java/fr/adrien1106/reframed/block/ReFramedSlabsCubeBlock.java index 5f11422..42aa1c1 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleSlabBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedSlabsCubeBlock.java @@ -13,7 +13,6 @@ import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder; import net.minecraft.item.ItemPlacementContext; import net.minecraft.recipe.book.RecipeCategory; import net.minecraft.state.StateManager; -import net.minecraft.state.property.Properties; import net.minecraft.util.Identifier; import net.minecraft.util.math.Direction; import net.minecraft.util.shape.VoxelShape; @@ -24,26 +23,37 @@ import static net.minecraft.data.client.VariantSettings.Rotation.R0; import static net.minecraft.data.client.VariantSettings.Rotation.R90; import static net.minecraft.state.property.Properties.AXIS; -public class ReFramedDoubleSlabBlock extends ReFramedDoubleBlock implements BlockStateProvider { - public ReFramedDoubleSlabBlock(Settings settings) { +public class ReFramedSlabsCubeBlock extends ReFramedDoubleBlock implements BlockStateProvider { + + public ReFramedSlabsCubeBlock(Settings settings) { super(settings); - setDefaultState(getDefaultState().with(Properties.AXIS, Direction.Axis.Y)); + setDefaultState(getDefaultState().with(AXIS, Direction.Axis.Y)); + } + + @Override + public Object getModelCacheKey(BlockState state) { + return state.get(AXIS); + } + + @Override + public int getModelStateCount() { + return 3; } @Override protected void appendProperties(StateManager.Builder builder) { - super.appendProperties(builder.add(Properties.AXIS)); + super.appendProperties(builder.add(AXIS)); } @Nullable @Override public BlockState getPlacementState(ItemPlacementContext ctx) { - return super.getPlacementState(ctx).with(Properties.AXIS, ctx.getSide().getAxis()); + return super.getPlacementState(ctx).with(AXIS, ctx.getSide().getAxis()); } @Override public VoxelShape getShape(BlockState state, int i) { - return switch (state.get(Properties.AXIS)) { + return switch (state.get(AXIS)) { case Y -> i == 2 ? UP : DOWN; case Z -> i == 2 ? NORTH : SOUTH; case X -> i == 2 ? EAST : WEST; diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubeBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubeBlock.java new file mode 100644 index 0000000..bce79f6 --- /dev/null +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubeBlock.java @@ -0,0 +1,113 @@ +package fr.adrien1106.reframed.block; + +import fr.adrien1106.reframed.ReFramed; +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 net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.ShapeContext; +import net.minecraft.data.client.BlockStateSupplier; +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.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.shape.VoxelShape; +import net.minecraft.util.shape.VoxelShapes; +import net.minecraft.world.BlockView; +import org.jetbrains.annotations.Nullable; + +import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder; +import static fr.adrien1106.reframed.util.blocks.BlockProperties.CORNER; +import static fr.adrien1106.reframed.util.blocks.Corner.*; +import static net.minecraft.data.client.VariantSettings.Rotation.*; + +public class ReFramedSmallCubeBlock extends WaterloggableReFramedBlock implements BlockStateProvider { + + public static final VoxelShape[] SMALL_CUBE_VOXELS; + + public ReFramedSmallCubeBlock(Settings settings) { + super(settings); + setDefaultState(getDefaultState().with(CORNER, NORTH_EAST_DOWN)); + } + + @Override + public Object getModelCacheKey(BlockState state) { + return state.get(CORNER); + } + + @Override + public int getModelStateCount() { + return 8; + } + + @Override + protected void appendProperties(StateManager.Builder builder) { + super.appendProperties(builder.add(CORNER)); + } + + @Override + public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) { + return super.getPlacementState(ctx).with(CORNER, BlockHelper.getPlacementCorner(ctx)); + } + + @Override + public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { + return SMALL_CUBE_VOXELS[state.get(CORNER).getID()]; + } + + @Override + public BlockStateSupplier getMultipart() { + Identifier small_cube_id = ReFramed.id("small_cube_special"); + return MultipartBlockStateSupplier.create(this) + .with(GBlockstate.when(CORNER, NORTH_EAST_DOWN), + GBlockstate.variant(small_cube_id, true, R0, R0)) + .with(GBlockstate.when(CORNER, EAST_SOUTH_DOWN), + GBlockstate.variant(small_cube_id, true, R0, R90)) + .with(GBlockstate.when(CORNER, SOUTH_WEST_DOWN), + GBlockstate.variant(small_cube_id, true, R0, R180)) + .with(GBlockstate.when(CORNER, WEST_NORTH_DOWN), + GBlockstate.variant(small_cube_id, true, R0, R270)) + .with(GBlockstate.when(CORNER, EAST_SOUTH_UP), + GBlockstate.variant(small_cube_id, true, R180, R0)) + .with(GBlockstate.when(CORNER, SOUTH_WEST_UP), + GBlockstate.variant(small_cube_id, true, R180, R90)) + .with(GBlockstate.when(CORNER, WEST_NORTH_UP), + GBlockstate.variant(small_cube_id, true, R180, R180)) + .with(GBlockstate.when(CORNER, NORTH_EAST_UP), + GBlockstate.variant(small_cube_id, true, R180, R270)); + } + + @Override + public void setRecipe(RecipeExporter exporter) { + RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE, 8); + ShapelessRecipeJsonBuilder + .create(RecipeCategory.BUILDING_BLOCKS, this, 8) + .input(ReFramed.CUBE) + .criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE)) + .criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this)) + .offerTo(exporter); + } + + static { + final VoxelShape SMALL_CUBE = VoxelShapes.cuboid(.5f, 0f, 0f, 1f, .5f, .5f); + + SMALL_CUBE_VOXELS = VoxelListBuilder.create(SMALL_CUBE, 8) + .add(VoxelHelper::rotateY) + .add(VoxelHelper::rotateY) + .add(VoxelHelper::rotateY) + + .add(SMALL_CUBE, VoxelHelper::mirrorY) + .add(VoxelHelper::rotateY) + .add(VoxelHelper::rotateY) + .add(VoxelHelper::rotateY) + .build(); + } +} diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubesStepBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubesStepBlock.java new file mode 100644 index 0000000..cf663bd --- /dev/null +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedSmallCubesStepBlock.java @@ -0,0 +1,133 @@ +package fr.adrien1106.reframed.block; + +import fr.adrien1106.reframed.ReFramed; +import fr.adrien1106.reframed.generator.BlockStateProvider; +import fr.adrien1106.reframed.generator.GBlockstate; +import fr.adrien1106.reframed.util.blocks.BlockHelper; +import fr.adrien1106.reframed.util.blocks.Corner; +import fr.adrien1106.reframed.util.blocks.Edge; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.ShapeContext; +import net.minecraft.data.client.BlockStateSupplier; +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.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.shape.VoxelShape; +import net.minecraft.world.BlockView; +import org.jetbrains.annotations.Nullable; + +import static fr.adrien1106.reframed.block.ReFramedSmallCubeBlock.SMALL_CUBE_VOXELS; +import static fr.adrien1106.reframed.block.ReFramedStepBlock.getStepShape; +import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE; +import static fr.adrien1106.reframed.util.blocks.Edge.*; +import static net.minecraft.data.client.VariantSettings.Rotation.*; +import static net.minecraft.util.shape.VoxelShapes.empty; + +public class ReFramedSmallCubesStepBlock extends WaterloggableReFramedDoubleBlock implements BlockStateProvider { + + public ReFramedSmallCubesStepBlock(Settings settings) { + super(settings); + setDefaultState(getDefaultState().with(EDGE, Edge.NORTH_DOWN)); + } + + @Override + public Object getModelCacheKey(BlockState state) { + return state.get(EDGE); + } + + @Override + public int getModelStateCount() { + return 12; + } + + @Override + protected void appendProperties(StateManager.Builder builder) { + super.appendProperties(builder.add(EDGE)); + } + + @Nullable + @Override + public BlockState getPlacementState(ItemPlacementContext ctx) { + return super.getPlacementState(ctx).with(EDGE, BlockHelper.getPlacementEdge(ctx)); + } + + @Override + public VoxelShape getCullingShape(BlockState state, BlockView view, BlockPos pos) { + return isGhost(view, pos) ? empty(): getStepShape(state.get(EDGE)); + } + + @Override + public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { + return getStepShape(state.get(EDGE)); + } + + @Override + public VoxelShape getShape(BlockState state, int i) { + Edge edge = state.get(EDGE); + return SMALL_CUBE_VOXELS[Corner.getByDirections( + edge.getFirstDirection(), + edge.getSecondDirection(), + i == 1 + ? edge.getRightDirection() + : edge.getLeftDirection() + ).getID()]; + } + + @Override + public int getTopThemeIndex(BlockState state) { + return 2; + } + + @Override + public BlockStateSupplier getMultipart() { + Identifier model_id = ReFramed.id("small_cubes_step_special"); + Identifier reverse_model_id = ReFramed.id("small_cubes_step_reverse_special"); + return MultipartBlockStateSupplier.create(this) + /* X AXIS */ + .with(GBlockstate.when(EDGE, DOWN_EAST), + GBlockstate.variant(reverse_model_id, true, R0, R0)) + .with(GBlockstate.when(EDGE, EAST_UP), + GBlockstate.variant(model_id, true, R180, R0)) + .with(GBlockstate.when(EDGE, UP_WEST), + GBlockstate.variant(reverse_model_id, true, R180, R180)) + .with(GBlockstate.when(EDGE, WEST_DOWN), + GBlockstate.variant(model_id, true, R0, R180)) + /* Y AXIS */ + .with(GBlockstate.when(EDGE, EAST_SOUTH), + GBlockstate.variant(model_id, true, R90, R0)) + .with(GBlockstate.when(EDGE, SOUTH_WEST), + GBlockstate.variant(model_id, true, R90, R90)) + .with(GBlockstate.when(EDGE, WEST_NORTH), + GBlockstate.variant(model_id, true, R90, R180)) + .with(GBlockstate.when(EDGE, NORTH_EAST), + GBlockstate.variant(model_id, true, R90, R270)) + /* Z AXIS */ + .with(GBlockstate.when(EDGE, DOWN_SOUTH), + GBlockstate.variant(reverse_model_id, true, R0, R90)) + .with(GBlockstate.when(EDGE, NORTH_DOWN), + GBlockstate.variant(model_id, true, R0, R270)) + .with(GBlockstate.when(EDGE, UP_NORTH), + GBlockstate.variant(reverse_model_id, true, R180, R270)) + .with(GBlockstate.when(EDGE, SOUTH_UP), + GBlockstate.variant(model_id, true, R180, R90)); + } + + @Override + public void setRecipe(RecipeExporter exporter) { + RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE, 4); + ShapelessRecipeJsonBuilder + .create(RecipeCategory.BUILDING_BLOCKS, this) + .input(ReFramed.SMALL_CUBE, 2) + .criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE)) + .criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this)) + .offerTo(exporter); + } +} diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedStairBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedStairBlock.java new file mode 100644 index 0000000..452fe21 --- /dev/null +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedStairBlock.java @@ -0,0 +1,433 @@ +package fr.adrien1106.reframed.block; + +import fr.adrien1106.reframed.ReFramed; +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.Edge; +import fr.adrien1106.reframed.util.blocks.StairShape; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.ShapeContext; +import net.minecraft.data.client.MultipartBlockStateSupplier; +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.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 net.minecraft.world.World; +import net.minecraft.world.WorldAccess; +import org.jetbrains.annotations.Nullable; + +import java.util.stream.Stream; + +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 fr.adrien1106.reframed.util.blocks.StairShape.*; +import static net.minecraft.data.client.VariantSettings.Rotation.*; + +public class ReFramedStairBlock extends WaterloggableReFramedBlock implements BlockStateProvider { + public static final VoxelShape[] STAIR_VOXELS; + private record ModelCacheKey(Edge edge, StairShape shape) {} + + public ReFramedStairBlock(Settings settings) { + super(settings); + setDefaultState(getDefaultState().with(EDGE, Edge.NORTH_DOWN).with(STAIR_SHAPE, STRAIGHT)); + } + + @Override + public Object getModelCacheKey(BlockState state) { + return new ModelCacheKey(state.get(EDGE), state.get(STAIR_SHAPE)); + } + + @Override + public int getModelStateCount() { + return 108; // Has 12 * 9 state combination and 52 models still reduces cache size + } + + @Override + protected void appendProperties(StateManager.Builder builder) { + super.appendProperties(builder.add(EDGE, STAIR_SHAPE)); + } + + @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) + .with(STAIR_SHAPE, BlockHelper.getStairsShape(state.get(EDGE), world, pos)); + } + + @Nullable + @Override // Pretty happy of how clean it is (also got it on first try :) ) + 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); + } + + @Override + public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { + super.onStateReplaced(state, world, pos, newState, moved); + + if(!state.isOf(newState.getBlock())) world.removeBlockEntity(pos); + } + + @Override + public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { + return getStairShape(state.get(EDGE), state.get(STAIR_SHAPE)); + } + + public static VoxelShape getStairShape(Edge edge, StairShape shape) { + return STAIR_VOXELS[edge.getID() * 9 + shape.getID()]; + } + + @Override + public MultipartBlockStateSupplier getMultipart() { + return getStairMultipart(this, false); + } + + public static MultipartBlockStateSupplier getStairMultipart(Block block, boolean is_double) { + String infix = is_double ? "s_cube" : ""; + Identifier straight_id = ReFramed.id("stair" + infix + "_special"); + Identifier double_outer_id = ReFramed.id("outers_stair" + infix + "_special"); + Identifier inner_id = ReFramed.id("inner_stair" + infix + "_special"); + Identifier outer_id = ReFramed.id("outer_stair" + infix + "_special"); + Identifier outer_side_id = ReFramed.id("outer_side_stair" + infix + "_special"); + return MultipartBlockStateSupplier.create(block) + /* STRAIGHT X AXIS */ + .with(GBlockstate.when(EDGE, DOWN_EAST, STAIR_SHAPE, STRAIGHT), + GBlockstate.variant(straight_id, true, R0, R0)) + .with(GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, STRAIGHT), + GBlockstate.variant(straight_id, true, R180, R0)) + .with(GBlockstate.when(EDGE, UP_WEST, STAIR_SHAPE, STRAIGHT), + GBlockstate.variant(straight_id, true, R180, R180)) + .with(GBlockstate.when(EDGE, WEST_DOWN, STAIR_SHAPE, STRAIGHT), + GBlockstate.variant(straight_id, true, R0, R180)) + /* STRAIGHT Y AXIS */ + .with(GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, STRAIGHT), + GBlockstate.variant(straight_id, true, R90, R0)) + .with(GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, STRAIGHT), + GBlockstate.variant(straight_id, true, R90, R90)) + .with(GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, STRAIGHT), + GBlockstate.variant(straight_id, true, R90, R180)) + .with(GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, STRAIGHT), + GBlockstate.variant(straight_id, true, R90, R270)) + /* STRAIGHT Z AXIS */ + .with(GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, STRAIGHT), + GBlockstate.variant(straight_id, true, R0, R90)) + .with(GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, STRAIGHT), + GBlockstate.variant(straight_id, true, R0, R270)) + .with(GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, STRAIGHT), + GBlockstate.variant(straight_id, true, R180, R270)) + .with(GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, STRAIGHT), + GBlockstate.variant(straight_id, true, R180, R90)) + /* INNER BOTTOM */ + .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.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.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.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.variant(inner_id, true, R0, R90)) + /* INNER TOP */ + .with(When.anyOf( + GBlockstate.when(EDGE, EAST_UP, STAIR_SHAPE, INNER_LEFT), + 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_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.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.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.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.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.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.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.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.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.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.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.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.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.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.variant(outer_side_id, true, R270, R0)) + /* OUTER SOUTH */ + .with(When.anyOf( + GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, SECOND_OUTER_RIGHT), + GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, FIRST_OUTER_RIGHT)), + GBlockstate.variant(outer_side_id, true, R0, R90)) + .with(When.anyOf( + GBlockstate.when(EDGE, SOUTH_WEST, STAIR_SHAPE, SECOND_OUTER_LEFT), + GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, SECOND_OUTER_RIGHT)), + GBlockstate.variant(outer_side_id, true, R90, R90)) + .with(When.anyOf( + GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, FIRST_OUTER_LEFT), + GBlockstate.when(EDGE, SOUTH_UP, STAIR_SHAPE, SECOND_OUTER_LEFT)), + GBlockstate.variant(outer_side_id, true, R180, R90)) + .with(When.anyOf( + GBlockstate.when(EDGE, EAST_SOUTH, STAIR_SHAPE, FIRST_OUTER_RIGHT), + GBlockstate.when(EDGE, DOWN_SOUTH, STAIR_SHAPE, FIRST_OUTER_LEFT)), + GBlockstate.variant(outer_side_id, true, R270, R90)) + /* 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.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.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.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.variant(outer_side_id, true, R270, R180)) + /* OUTER NORTH */ + .with(When.anyOf( + GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, SECOND_OUTER_RIGHT), + GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, SECOND_OUTER_LEFT)), + GBlockstate.variant(outer_side_id, true, R0, R270)) + .with(When.anyOf( + GBlockstate.when(EDGE, NORTH_EAST, STAIR_SHAPE, SECOND_OUTER_LEFT), + GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, FIRST_OUTER_LEFT)), + GBlockstate.variant(outer_side_id, true, R90, R270)) + .with(When.anyOf( + GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, FIRST_OUTER_LEFT), + GBlockstate.when(EDGE, UP_NORTH, STAIR_SHAPE, FIRST_OUTER_RIGHT)), + GBlockstate.variant(outer_side_id, true, R180, R270)) + .with(When.anyOf( + GBlockstate.when(EDGE, WEST_NORTH, STAIR_SHAPE, FIRST_OUTER_RIGHT), + GBlockstate.when(EDGE, NORTH_DOWN, STAIR_SHAPE, SECOND_OUTER_RIGHT)), + GBlockstate.variant(outer_side_id, true, R270, R270)) + /* 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, 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, 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_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, 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, 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_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, 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, WEST_NORTH, STAIR_SHAPE, OUTER_LEFT)), + GBlockstate.variant(double_outer_id, true, R180, R270)); + } + + @Override + public void setRecipe(RecipeExporter exporter) { + RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE); + ShapedRecipeJsonBuilder + .create(RecipeCategory.BUILDING_BLOCKS, this, 4) + .pattern("I ") + .pattern("II ") + .pattern("III") + .input('I', ReFramed.CUBE) + .criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE)) + .criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this)) + .offerTo(exporter); + } + + static { + final VoxelShape STRAIGHT = VoxelShapes.combineAndSimplify( + createCuboidShape(0, 8, 0, 16, 16, 8), + createCuboidShape(0, 0, 0, 16, 8, 16), + BooleanBiFunction.OR + ); + final VoxelShape INNER = Stream.of( + createCuboidShape(0, 8, 0, 16, 16, 8), + createCuboidShape(0, 8, 8, 8, 16, 16), + createCuboidShape(0, 0, 0, 16, 8, 16) + ).reduce((v1, v2) -> VoxelShapes.combineAndSimplify(v1, v2, BooleanBiFunction.OR)).get(); + final VoxelShape OUTER = Stream.of( + createCuboidShape(0, 8, 0, 8, 16, 8), + createCuboidShape(8, 0, 0, 16, 8, 8), + createCuboidShape(0, 0, 0, 8, 8, 16) + ).reduce((v1, v2) -> VoxelShapes.combineAndSimplify(v1, v2, BooleanBiFunction.OR)).get(); + final VoxelShape JUNCTION = VoxelShapes.combineAndSimplify( + createCuboidShape(0, 8, 0, 8, 16, 8), + createCuboidShape(0, 0, 0, 16, 8, 16), + BooleanBiFunction.OR + ); + + STAIR_VOXELS = VoxelListBuilder.create(STRAIGHT, 108) + .add(INNER).add(VoxelHelper::rotateY) + .add(OUTER).add(VoxelHelper::rotateY) + .add(JUNCTION).add(VoxelHelper::rotateY) + .add(JUNCTION, VoxelHelper::rotateX, VoxelHelper::rotateZ).add(VoxelHelper::rotateZ) + // DOWN_SOUTH + .add(0, VoxelHelper::rotateCX) + .add(1, VoxelHelper::rotateCX).add(2, VoxelHelper::rotateCX) + .add(3, VoxelHelper::rotateCX).add(4, VoxelHelper::rotateCX) + .add(5, VoxelHelper::rotateCX).add(6, VoxelHelper::rotateCX) + .add(7, VoxelHelper::rotateCX).add(8, VoxelHelper::rotateCX) + // SOUTH_UP + .add(9, VoxelHelper::rotateCX) + .add(10, VoxelHelper::rotateCX).add(11, VoxelHelper::rotateCX) + .add(12, VoxelHelper::rotateCX).add(13, VoxelHelper::rotateCX) + .add(14, VoxelHelper::rotateCX).add(15, VoxelHelper::rotateCX) + .add(16, VoxelHelper::rotateCX).add(17, VoxelHelper::rotateCX) + // UP_NORTH + .add(18, VoxelHelper::rotateCX) + .add(19, VoxelHelper::rotateCX).add(20, VoxelHelper::rotateCX) + .add(21, VoxelHelper::rotateCX).add(22, VoxelHelper::rotateCX) + .add(23, VoxelHelper::rotateCX).add(24, VoxelHelper::rotateCX) + .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) + // DOWN_EAST + .add(36, VoxelHelper::rotateZ) + .add(11).add(2) + .add(13).add(4) + .add(41, VoxelHelper::rotateZ).add(42, VoxelHelper::rotateZ) + .add(17).add(6) + // EAST_UP + .add(45, VoxelHelper::rotateZ) + .add(20).add(29) + .add(22).add(31) + .add(24).add(35) + .add(52, VoxelHelper::rotateZ).add(53, VoxelHelper::rotateZ) + // UP_WEST + .add(54, VoxelHelper::rotateZ) + .add(19).add(28) + .add(21).add(30) + .add(59, VoxelHelper::rotateZ).add(60, VoxelHelper::rotateZ) + .add(23).add(34) + // WEST_NORTH + .add(0, VoxelHelper::rotateCZ) + .add(1).add(28) + .add(3).add(30) + .add(7).add(32) + .add(44).add(69) + // NORTH_EAST + .add(72, VoxelHelper::rotateY) + .add(2).add(29) + .add(4).add(31) + .add(51).add(62) + .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) + // SOUTH_WEST + .add(90, VoxelHelper::rotateY) + .add(10).add(19) + .add(12).add(21) + .add(43).add(68) + .add(14).add(25) + .build(); + } +} diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedStairsBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedStairsBlock.java deleted file mode 100644 index ce7283b..0000000 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedStairsBlock.java +++ /dev/null @@ -1,525 +0,0 @@ -package fr.adrien1106.reframed.block; - -import fr.adrien1106.reframed.ReFramed; -import fr.adrien1106.reframed.generator.GBlockstate; -import fr.adrien1106.reframed.generator.BlockStateProvider; -import fr.adrien1106.reframed.util.BlockHelper; -import fr.adrien1106.reframed.util.VoxelHelper; -import fr.adrien1106.reframed.util.property.Corner; -import fr.adrien1106.reframed.util.property.StairShape; -import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.ShapeContext; -import net.minecraft.data.client.*; -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.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.math.Direction.Axis; -import net.minecraft.util.shape.VoxelShape; -import net.minecraft.util.shape.VoxelShapes; -import net.minecraft.world.BlockView; -import net.minecraft.world.World; -import net.minecraft.world.WorldAccess; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Stream; - -import static fr.adrien1106.reframed.util.BlockProperties.*; -import static fr.adrien1106.reframed.util.property.StairShape.*; -import static net.minecraft.data.client.VariantSettings.Rotation.*; -import static fr.adrien1106.reframed.util.property.Corner.*; - -public class ReFramedStairsBlock extends WaterloggableReFramedBlock implements BlockStateProvider { - - public static final List VOXEL_LIST = new ArrayList<>(52); - - public ReFramedStairsBlock(Settings settings) { - super(settings); - setDefaultState(getDefaultState().with(CORNER, Corner.NORTH_DOWN).with(STAIR_SHAPE, STRAIGHT)); - } - - @Override - protected void appendProperties(StateManager.Builder builder) { - super.appendProperties(builder.add(CORNER, STAIR_SHAPE)); - } - - @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) - .with(STAIR_SHAPE, BlockHelper.getStairsShape(state.getBlock(), state.get(CORNER), world, pos)); - } - - @Nullable - @Override // Pretty happy of how clean it is (also got it on first try :) ) - public BlockState getPlacementState(ItemPlacementContext ctx) { - Corner face = BlockHelper.getPlacementCorner(ctx); - StairShape shape = BlockHelper.getStairsShape(this, face, ctx.getWorld(), ctx.getBlockPos()); - return super.getPlacementState(ctx).with(CORNER, face).with(STAIR_SHAPE, shape); - } - - @Override - public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { - super.onStateReplaced(state, world, pos, newState, moved); - - if(!state.isOf(newState.getBlock())) world.removeBlockEntity(pos); - } - - /* ---------------------------------- DON'T GO FURTHER IF YOU LIKE HAVING EYES ---------------------------------- */ - @Override - public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { - return getOutline(state); - } - - public static VoxelShape getOutline(BlockState state) { - StairShape shape = state.get(STAIR_SHAPE); - Corner direction = state.get(CORNER); - return switch (shape) { - case STRAIGHT -> - switch (direction) { - case DOWN_SOUTH -> VOXEL_LIST.get(0); - case NORTH_DOWN -> VOXEL_LIST.get(1); - case UP_NORTH -> VOXEL_LIST.get(2); - case SOUTH_UP -> VOXEL_LIST.get(3); - case DOWN_EAST -> VOXEL_LIST.get(4); - case WEST_DOWN -> VOXEL_LIST.get(5); - case UP_WEST -> VOXEL_LIST.get(6); - case EAST_UP -> VOXEL_LIST.get(7); - case NORTH_EAST -> VOXEL_LIST.get(8); - case EAST_SOUTH -> VOXEL_LIST.get(9); - case SOUTH_WEST -> VOXEL_LIST.get(10); - case WEST_NORTH -> VOXEL_LIST.get(11); - }; - case INNER_LEFT -> - switch (direction) { - case WEST_DOWN, NORTH_DOWN -> VOXEL_LIST.get(44); - case DOWN_EAST -> VOXEL_LIST.get(45); - case DOWN_SOUTH -> VOXEL_LIST.get(47); - case UP_WEST, UP_NORTH, WEST_NORTH -> VOXEL_LIST.get(48); - case EAST_UP, NORTH_EAST -> VOXEL_LIST.get(49); - case EAST_SOUTH -> VOXEL_LIST.get(50); - case SOUTH_UP, SOUTH_WEST -> VOXEL_LIST.get(51); - }; - case INNER_RIGHT -> - switch (direction) { - case WEST_NORTH -> VOXEL_LIST.get(44); - case NORTH_DOWN, NORTH_EAST -> VOXEL_LIST.get(45); - case DOWN_EAST, DOWN_SOUTH, EAST_SOUTH -> VOXEL_LIST.get(46); - case WEST_DOWN, SOUTH_WEST -> VOXEL_LIST.get(47); - case UP_NORTH -> VOXEL_LIST.get(49); - case EAST_UP, SOUTH_UP -> VOXEL_LIST.get(50); - case UP_WEST -> VOXEL_LIST.get(51); - }; - case OUTER_LEFT -> - switch (direction) { - case DOWN_EAST -> VOXEL_LIST.get(43); - case WEST_DOWN, NORTH_DOWN -> VOXEL_LIST.get(42); - case DOWN_SOUTH -> VOXEL_LIST.get(41); - case EAST_UP, NORTH_EAST -> VOXEL_LIST.get(39); - case UP_WEST, UP_NORTH, WEST_NORTH -> VOXEL_LIST.get(38); - case SOUTH_UP, SOUTH_WEST -> VOXEL_LIST.get(37); - case EAST_SOUTH -> VOXEL_LIST.get(36); - }; - case OUTER_RIGHT -> - switch (direction) { - case NORTH_DOWN, NORTH_EAST -> VOXEL_LIST.get(43); - case WEST_NORTH -> VOXEL_LIST.get(42); - case WEST_DOWN, SOUTH_WEST -> VOXEL_LIST.get(41); - case DOWN_EAST, DOWN_SOUTH, EAST_SOUTH -> VOXEL_LIST.get(40); - case UP_NORTH -> VOXEL_LIST.get(39); - case UP_WEST -> VOXEL_LIST.get(37); - case EAST_UP, SOUTH_UP -> VOXEL_LIST.get(36); - }; - case FIRST_OUTER_LEFT -> - switch (direction) { - case WEST_DOWN, NORTH_DOWN -> VOXEL_LIST.get(14); - case SOUTH_UP -> VOXEL_LIST.get(17); - case EAST_UP -> VOXEL_LIST.get(19); - case EAST_SOUTH -> VOXEL_LIST.get(20); - case DOWN_SOUTH -> VOXEL_LIST.get(22); - case UP_NORTH, WEST_NORTH -> VOXEL_LIST.get(25); - case SOUTH_WEST -> VOXEL_LIST.get(28); - case UP_WEST -> VOXEL_LIST.get(31); - case DOWN_EAST -> VOXEL_LIST.get(34); - case NORTH_EAST -> VOXEL_LIST.get(35); - }; - case FIRST_OUTER_RIGHT -> - switch (direction) { - case NORTH_DOWN -> VOXEL_LIST.get(15); - case SOUTH_UP, EAST_UP -> VOXEL_LIST.get(16); - case WEST_DOWN -> VOXEL_LIST.get(13); - case DOWN_SOUTH, EAST_SOUTH -> VOXEL_LIST.get(23); - case UP_NORTH -> VOXEL_LIST.get(24); - case WEST_NORTH -> VOXEL_LIST.get(26); - case UP_WEST -> VOXEL_LIST.get(28); - case SOUTH_WEST -> VOXEL_LIST.get(29); - case DOWN_EAST -> VOXEL_LIST.get(33); - case NORTH_EAST -> VOXEL_LIST.get(34); - }; - case SECOND_OUTER_LEFT -> - switch (direction) { - case DOWN_EAST -> VOXEL_LIST.get(15); - case DOWN_SOUTH -> VOXEL_LIST.get(13); - case UP_WEST, UP_NORTH -> VOXEL_LIST.get(18); - case SOUTH_UP, SOUTH_WEST -> VOXEL_LIST.get(21); - case NORTH_EAST -> VOXEL_LIST.get(24); - case NORTH_DOWN -> VOXEL_LIST.get(26); - case WEST_DOWN -> VOXEL_LIST.get(30); - case WEST_NORTH -> VOXEL_LIST.get(31); - case EAST_SOUTH -> VOXEL_LIST.get(32); - case EAST_UP -> VOXEL_LIST.get(35); - }; - case SECOND_OUTER_RIGHT -> - switch (direction) { - case DOWN_SOUTH, DOWN_EAST -> VOXEL_LIST.get(12); - case UP_WEST -> VOXEL_LIST.get(17); - case UP_NORTH -> VOXEL_LIST.get(19); - case SOUTH_UP -> VOXEL_LIST.get(20); - case SOUTH_WEST -> VOXEL_LIST.get(22); - case NORTH_EAST, NORTH_DOWN -> VOXEL_LIST.get(27); - case WEST_DOWN -> VOXEL_LIST.get(29); - case WEST_NORTH -> VOXEL_LIST.get(30); - case EAST_UP -> VOXEL_LIST.get(32); - case EAST_SOUTH -> VOXEL_LIST.get(33); - }; - }; - } - - @Override - public MultipartBlockStateSupplier getMultipart() { - return getStairMultipart(this, false); - } - - public static MultipartBlockStateSupplier getStairMultipart(Block block, boolean is_double) { - String prefix = is_double ? "double_" : ""; - Identifier straight_id = ReFramed.id(prefix + "stairs_special"); - Identifier double_outer_id = ReFramed.id(prefix + "outers_stairs_special"); - Identifier inner_id = ReFramed.id(prefix + "inner_stairs_special"); - Identifier outer_id = ReFramed.id(prefix + "outer_stairs_special"); - Identifier outer_side_id = ReFramed.id(prefix + "outer_side_stairs_special"); - return MultipartBlockStateSupplier.create(block) - /* STRAIGHT X AXIS */ - .with(GBlockstate.when(CORNER, DOWN_EAST, STAIR_SHAPE, STRAIGHT), - GBlockstate.variant(straight_id, true, R0, R0)) - .with(GBlockstate.when(CORNER, EAST_UP, STAIR_SHAPE, STRAIGHT), - GBlockstate.variant(straight_id, true, R180, R0)) - .with(GBlockstate.when(CORNER, UP_WEST, STAIR_SHAPE, STRAIGHT), - GBlockstate.variant(straight_id, true, R180, R180)) - .with(GBlockstate.when(CORNER, WEST_DOWN, STAIR_SHAPE, STRAIGHT), - GBlockstate.variant(straight_id, true, R0, R180)) - /* STRAIGHT Y AXIS */ - .with(GBlockstate.when(CORNER, EAST_SOUTH, STAIR_SHAPE, STRAIGHT), - GBlockstate.variant(straight_id, true, R90, R0)) - .with(GBlockstate.when(CORNER, SOUTH_WEST, STAIR_SHAPE, STRAIGHT), - GBlockstate.variant(straight_id, true, R90, R90)) - .with(GBlockstate.when(CORNER, WEST_NORTH, STAIR_SHAPE, STRAIGHT), - GBlockstate.variant(straight_id, true, R90, R180)) - .with(GBlockstate.when(CORNER, NORTH_EAST, STAIR_SHAPE, STRAIGHT), - GBlockstate.variant(straight_id, true, R90, R270)) - /* STRAIGHT Z AXIS */ - .with(GBlockstate.when(CORNER, DOWN_SOUTH, STAIR_SHAPE, STRAIGHT), - GBlockstate.variant(straight_id, true, R0, R90)) - .with(GBlockstate.when(CORNER, NORTH_DOWN, STAIR_SHAPE, STRAIGHT), - GBlockstate.variant(straight_id, true, R0, R270)) - .with(GBlockstate.when(CORNER, UP_NORTH, STAIR_SHAPE, STRAIGHT), - GBlockstate.variant(straight_id, true, R180, R270)) - .with(GBlockstate.when(CORNER, SOUTH_UP, STAIR_SHAPE, STRAIGHT), - GBlockstate.variant(straight_id, true, R180, R90)) - /* INNER BOTTOM */ - .with(When.anyOf( - GBlockstate.when(CORNER, NORTH_DOWN, STAIR_SHAPE, INNER_LEFT), - GBlockstate.when(CORNER, WEST_NORTH, STAIR_SHAPE, INNER_RIGHT), - GBlockstate.when(CORNER, WEST_DOWN, STAIR_SHAPE, INNER_LEFT)), - GBlockstate.variant(inner_id, true, R0, R180)) - .with(When.anyOf( - GBlockstate.when(CORNER, NORTH_DOWN, STAIR_SHAPE, INNER_RIGHT), - GBlockstate.when(CORNER, NORTH_EAST, STAIR_SHAPE, INNER_RIGHT), - GBlockstate.when(CORNER, DOWN_EAST, STAIR_SHAPE, INNER_LEFT)), - GBlockstate.variant(inner_id, true, R0, R270)) - .with(When.anyOf( - GBlockstate.when(CORNER, DOWN_SOUTH, STAIR_SHAPE, INNER_RIGHT), - GBlockstate.when(CORNER, EAST_SOUTH, STAIR_SHAPE, INNER_RIGHT), - GBlockstate.when(CORNER, DOWN_EAST, STAIR_SHAPE, INNER_RIGHT)), - GBlockstate.variant(inner_id, true, R0, R0)) - .with(When.anyOf( - GBlockstate.when(CORNER, DOWN_SOUTH, STAIR_SHAPE, INNER_LEFT), - GBlockstate.when(CORNER, SOUTH_WEST, STAIR_SHAPE, INNER_RIGHT), - GBlockstate.when(CORNER, WEST_DOWN, STAIR_SHAPE, INNER_RIGHT)), - GBlockstate.variant(inner_id, true, R0, R90)) - /* INNER TOP */ - .with(When.anyOf( - GBlockstate.when(CORNER, EAST_UP, STAIR_SHAPE, INNER_LEFT), - GBlockstate.when(CORNER, NORTH_EAST, STAIR_SHAPE, INNER_LEFT), - GBlockstate.when(CORNER, UP_NORTH, STAIR_SHAPE, INNER_RIGHT)), - GBlockstate.variant(inner_id, true, R180, R0)) - .with(When.anyOf( - GBlockstate.when(CORNER, EAST_UP, STAIR_SHAPE, INNER_RIGHT), - GBlockstate.when(CORNER, EAST_SOUTH, STAIR_SHAPE, INNER_LEFT), - GBlockstate.when(CORNER, SOUTH_UP, STAIR_SHAPE, INNER_RIGHT)), - GBlockstate.variant(inner_id, true, R180, R90)) - .with(When.anyOf( - GBlockstate.when(CORNER, SOUTH_UP, STAIR_SHAPE, INNER_LEFT), - GBlockstate.when(CORNER, SOUTH_WEST, STAIR_SHAPE, INNER_LEFT), - GBlockstate.when(CORNER, UP_WEST, STAIR_SHAPE, INNER_RIGHT)), - GBlockstate.variant(inner_id, true, R180, R180)) - .with(When.anyOf( - GBlockstate.when(CORNER, UP_NORTH, STAIR_SHAPE, INNER_LEFT), - GBlockstate.when(CORNER, WEST_NORTH, STAIR_SHAPE, INNER_LEFT), - GBlockstate.when(CORNER, UP_WEST, STAIR_SHAPE, INNER_LEFT)), - GBlockstate.variant(inner_id, true, R180, R270)) - /* OUTER BOTTOM */ - .with(When.anyOf( - GBlockstate.when(CORNER, DOWN_SOUTH, STAIR_SHAPE, SECOND_OUTER_RIGHT), - GBlockstate.when(CORNER, DOWN_EAST, STAIR_SHAPE, SECOND_OUTER_RIGHT)), - GBlockstate.variant(outer_id, true, R0, R0)) - .with(When.anyOf( - GBlockstate.when(CORNER, DOWN_SOUTH, STAIR_SHAPE, SECOND_OUTER_LEFT), - GBlockstate.when(CORNER, WEST_DOWN, STAIR_SHAPE, FIRST_OUTER_RIGHT)), - GBlockstate.variant(outer_id, true, R0, R90)) - .with(When.anyOf( - GBlockstate.when(CORNER, NORTH_DOWN, STAIR_SHAPE, FIRST_OUTER_LEFT), - GBlockstate.when(CORNER, WEST_DOWN, STAIR_SHAPE, FIRST_OUTER_LEFT)), - GBlockstate.variant(outer_id, true, R0, R180)) - .with(When.anyOf( - GBlockstate.when(CORNER, NORTH_DOWN, STAIR_SHAPE, FIRST_OUTER_RIGHT), - GBlockstate.when(CORNER, DOWN_EAST, STAIR_SHAPE, SECOND_OUTER_LEFT)), - GBlockstate.variant(outer_id, true, R0, R270)) - /* OUTER TOP */ - .with(When.anyOf( - GBlockstate.when(CORNER, UP_NORTH, STAIR_SHAPE, SECOND_OUTER_RIGHT), - GBlockstate.when(CORNER, EAST_UP, STAIR_SHAPE, FIRST_OUTER_LEFT)), - GBlockstate.variant(outer_id, true, R180, R0)) - .with(When.anyOf( - GBlockstate.when(CORNER, SOUTH_UP, STAIR_SHAPE, FIRST_OUTER_RIGHT), - GBlockstate.when(CORNER, EAST_UP, STAIR_SHAPE, FIRST_OUTER_RIGHT)), - GBlockstate.variant(outer_id, true, R180, R90)) - .with(When.anyOf( - GBlockstate.when(CORNER, SOUTH_UP, STAIR_SHAPE, FIRST_OUTER_LEFT), - GBlockstate.when(CORNER, UP_WEST, STAIR_SHAPE, SECOND_OUTER_RIGHT)), - GBlockstate.variant(outer_id, true, R180, R180)) - .with(When.anyOf( - GBlockstate.when(CORNER, UP_NORTH, STAIR_SHAPE, SECOND_OUTER_LEFT), - GBlockstate.when(CORNER, UP_WEST, STAIR_SHAPE, SECOND_OUTER_LEFT)), - GBlockstate.variant(outer_id, true, R180, R270)) - /* OUTER EAST */ - .with(When.anyOf( - GBlockstate.when(CORNER, EAST_SOUTH, STAIR_SHAPE, SECOND_OUTER_RIGHT), - GBlockstate.when(CORNER, DOWN_EAST, STAIR_SHAPE, FIRST_OUTER_RIGHT)), - GBlockstate.variant(outer_side_id, true, R0, R0)) - .with(When.anyOf( - GBlockstate.when(CORNER, EAST_SOUTH, STAIR_SHAPE, SECOND_OUTER_LEFT), - GBlockstate.when(CORNER, EAST_UP, STAIR_SHAPE, SECOND_OUTER_RIGHT)), - GBlockstate.variant(outer_side_id, true, R90, R0)) - .with(When.anyOf( - GBlockstate.when(CORNER, NORTH_EAST, STAIR_SHAPE, FIRST_OUTER_LEFT), - GBlockstate.when(CORNER, EAST_UP, STAIR_SHAPE, SECOND_OUTER_LEFT)), - GBlockstate.variant(outer_side_id, true, R180, R0)) - .with(When.anyOf( - GBlockstate.when(CORNER, NORTH_EAST, STAIR_SHAPE, FIRST_OUTER_RIGHT), - GBlockstate.when(CORNER, DOWN_EAST, STAIR_SHAPE, FIRST_OUTER_LEFT)), - GBlockstate.variant(outer_side_id, true, R270, R0)) - /* OUTER SOUTH */ - .with(When.anyOf( - GBlockstate.when(CORNER, SOUTH_WEST, STAIR_SHAPE, SECOND_OUTER_RIGHT), - GBlockstate.when(CORNER, DOWN_SOUTH, STAIR_SHAPE, FIRST_OUTER_LEFT)), - GBlockstate.variant(outer_side_id, true, R0, R90)) - .with(When.anyOf( - GBlockstate.when(CORNER, SOUTH_WEST, STAIR_SHAPE, SECOND_OUTER_LEFT), - GBlockstate.when(CORNER, SOUTH_UP, STAIR_SHAPE, SECOND_OUTER_LEFT)), - GBlockstate.variant(outer_side_id, true, R90, R90)) - .with(When.anyOf( - GBlockstate.when(CORNER, EAST_SOUTH, STAIR_SHAPE, FIRST_OUTER_LEFT), - GBlockstate.when(CORNER, SOUTH_UP, STAIR_SHAPE, SECOND_OUTER_RIGHT)), - GBlockstate.variant(outer_side_id, true, R180, R90)) - .with(When.anyOf( - GBlockstate.when(CORNER, EAST_SOUTH, STAIR_SHAPE, FIRST_OUTER_RIGHT), - GBlockstate.when(CORNER, DOWN_SOUTH, STAIR_SHAPE, FIRST_OUTER_RIGHT)), - GBlockstate.variant(outer_side_id, true, R270, R90)) - /* OUTER WEST */ - .with(When.anyOf( - GBlockstate.when(CORNER, WEST_NORTH, STAIR_SHAPE, SECOND_OUTER_RIGHT), - GBlockstate.when(CORNER, WEST_DOWN, STAIR_SHAPE, SECOND_OUTER_LEFT)), - GBlockstate.variant(outer_side_id, true, R0, R180)) - .with(When.anyOf( - GBlockstate.when(CORNER, WEST_NORTH, STAIR_SHAPE, SECOND_OUTER_LEFT), - GBlockstate.when(CORNER, UP_WEST, STAIR_SHAPE, FIRST_OUTER_LEFT)), - GBlockstate.variant(outer_side_id, true, R90, R180)) - .with(When.anyOf( - GBlockstate.when(CORNER, SOUTH_WEST, STAIR_SHAPE, FIRST_OUTER_LEFT), - GBlockstate.when(CORNER, UP_WEST, STAIR_SHAPE, FIRST_OUTER_RIGHT)), - GBlockstate.variant(outer_side_id, true, R180, R180)) - .with(When.anyOf( - GBlockstate.when(CORNER, SOUTH_WEST, STAIR_SHAPE, FIRST_OUTER_RIGHT), - GBlockstate.when(CORNER, WEST_DOWN, STAIR_SHAPE, SECOND_OUTER_RIGHT)), - GBlockstate.variant(outer_side_id, true, R270, R180)) - /* OUTER NORTH */ - .with(When.anyOf( - GBlockstate.when(CORNER, NORTH_EAST, STAIR_SHAPE, SECOND_OUTER_RIGHT), - GBlockstate.when(CORNER, NORTH_DOWN, STAIR_SHAPE, SECOND_OUTER_RIGHT)), - GBlockstate.variant(outer_side_id, true, R0, R270)) - .with(When.anyOf( - GBlockstate.when(CORNER, NORTH_EAST, STAIR_SHAPE, SECOND_OUTER_LEFT), - GBlockstate.when(CORNER, UP_NORTH, STAIR_SHAPE, FIRST_OUTER_RIGHT)), - GBlockstate.variant(outer_side_id, true, R90, R270)) - .with(When.anyOf( - GBlockstate.when(CORNER, WEST_NORTH, STAIR_SHAPE, FIRST_OUTER_LEFT), - GBlockstate.when(CORNER, UP_NORTH, STAIR_SHAPE, FIRST_OUTER_LEFT)), - GBlockstate.variant(outer_side_id, true, R180, R270)) - .with(When.anyOf( - GBlockstate.when(CORNER, WEST_NORTH, STAIR_SHAPE, FIRST_OUTER_RIGHT), - GBlockstate.when(CORNER, NORTH_DOWN, STAIR_SHAPE, SECOND_OUTER_LEFT)), - GBlockstate.variant(outer_side_id, true, R270, R270)) - /* OUTER BOTTOM */ - .with(When.anyOf( - GBlockstate.when(CORNER, DOWN_SOUTH, STAIR_SHAPE, OUTER_RIGHT), - GBlockstate.when(CORNER, DOWN_EAST, STAIR_SHAPE, OUTER_RIGHT), - GBlockstate.when(CORNER, EAST_SOUTH, STAIR_SHAPE, OUTER_RIGHT)), - GBlockstate.variant(double_outer_id, true, R0, R0)) - .with(When.anyOf( - GBlockstate.when(CORNER, DOWN_SOUTH, STAIR_SHAPE, OUTER_LEFT), - GBlockstate.when(CORNER, WEST_DOWN, STAIR_SHAPE, OUTER_RIGHT), - GBlockstate.when(CORNER, SOUTH_WEST, STAIR_SHAPE, OUTER_RIGHT)), - GBlockstate.variant(double_outer_id, true, R0, R90)) - .with(When.anyOf( - GBlockstate.when(CORNER, NORTH_DOWN, STAIR_SHAPE, OUTER_LEFT), - GBlockstate.when(CORNER, WEST_DOWN, STAIR_SHAPE, OUTER_LEFT), - GBlockstate.when(CORNER, WEST_NORTH, STAIR_SHAPE, OUTER_RIGHT)), - GBlockstate.variant(double_outer_id, true, R0, R180)) - .with(When.anyOf( - GBlockstate.when(CORNER, NORTH_DOWN, STAIR_SHAPE, OUTER_RIGHT), - GBlockstate.when(CORNER, DOWN_EAST, STAIR_SHAPE, OUTER_LEFT), - GBlockstate.when(CORNER, NORTH_EAST, STAIR_SHAPE, OUTER_RIGHT)), - GBlockstate.variant(double_outer_id, true, R0, R270)) - /* OUTER TOP */ - .with(When.anyOf( - GBlockstate.when(CORNER, UP_NORTH, STAIR_SHAPE, OUTER_RIGHT), - GBlockstate.when(CORNER, EAST_UP, STAIR_SHAPE, OUTER_LEFT), - GBlockstate.when(CORNER, NORTH_EAST, STAIR_SHAPE, OUTER_LEFT)), - GBlockstate.variant(double_outer_id, true, R180, R0)) - .with(When.anyOf( - GBlockstate.when(CORNER, SOUTH_UP, STAIR_SHAPE, OUTER_RIGHT), - GBlockstate.when(CORNER, EAST_UP, STAIR_SHAPE, OUTER_RIGHT), - GBlockstate.when(CORNER, EAST_SOUTH, STAIR_SHAPE, OUTER_LEFT)), - GBlockstate.variant(double_outer_id, true, R180, R90)) - .with(When.anyOf( - GBlockstate.when(CORNER, SOUTH_UP, STAIR_SHAPE, OUTER_LEFT), - GBlockstate.when(CORNER, UP_WEST, STAIR_SHAPE, OUTER_RIGHT), - GBlockstate.when(CORNER, SOUTH_WEST, STAIR_SHAPE, OUTER_LEFT)), - GBlockstate.variant(double_outer_id, true, R180, R180)) - .with(When.anyOf( - GBlockstate.when(CORNER, UP_NORTH, STAIR_SHAPE, OUTER_LEFT), - GBlockstate.when(CORNER, UP_WEST, STAIR_SHAPE, OUTER_LEFT), - GBlockstate.when(CORNER, WEST_NORTH, STAIR_SHAPE, OUTER_LEFT)), - GBlockstate.variant(double_outer_id, true, R180, R270)); - } - - @Override - public void setRecipe(RecipeExporter exporter) { - RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE); - ShapedRecipeJsonBuilder - .create(RecipeCategory.BUILDING_BLOCKS, this, 4) - .pattern("I ") - .pattern("II ") - .pattern("III") - .input('I', ReFramed.CUBE) - .criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE)) - .criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this)) - .offerTo(exporter); - } - - static { - final VoxelShape STRAIGHT = Stream.of( - VoxelShapes.cuboid(0.0f, 0.0f, 0.0f, 1.0f, 0.5f, 1.0f), - VoxelShapes.cuboid(0.0f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f) - ).reduce((previous, current) -> VoxelShapes.combineAndSimplify(previous, current, BooleanBiFunction.OR)).get(); - final VoxelShape JUNCTION = Stream.of( - VoxelShapes.cuboid(0.0f, 0.0f, 0.0f, 1.0f, 0.5f, 1.0f), - VoxelShapes.cuboid(0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f) - ).reduce((previous, current) -> VoxelShapes.combineAndSimplify(previous, current, BooleanBiFunction.OR)).get(); - final VoxelShape OUTER = Stream.of( - VoxelShapes.cuboid(0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f), - VoxelShapes.cuboid(0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.5f), - VoxelShapes.cuboid(0.0f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f), - VoxelShapes.cuboid(0.5f, 0.0f, 0.5f, 1.0f, 0.5f, 1.0f) - ).reduce((previous, current) -> VoxelShapes.combineAndSimplify(previous, current, BooleanBiFunction.OR)).get(); - final VoxelShape INNER = Stream.of( - VoxelShapes.cuboid(0.0f, 0.0f, 0.0f, 1.0f, 0.5f, 1.0f), - VoxelShapes.cuboid(0.0f, 0.5f, 0.0f, 0.5f, 1.0f, 1.0f), - VoxelShapes.cuboid(0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.5f) - ).reduce((previous, current) -> VoxelShapes.combineAndSimplify(previous, current, BooleanBiFunction.OR)).get(); - - VOXEL_LIST.add(STRAIGHT); - VOXEL_LIST.add(VoxelHelper.mirror(STRAIGHT, Axis.Z)); - VOXEL_LIST.add(VoxelHelper.mirror(VoxelHelper.rotateCounterClockwise(STRAIGHT, Axis.X), Axis.Z)); - VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(STRAIGHT, Axis.X)); - - VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(STRAIGHT, Axis.Y)); - VOXEL_LIST.add(VoxelHelper.mirror(VoxelHelper.rotateCounterClockwise(STRAIGHT, Axis.Y), Axis.X)); - VOXEL_LIST.add(VoxelHelper.mirror(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(STRAIGHT, Axis.Y), Axis.Z), Axis.X)); - VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(STRAIGHT, Axis.Y), Axis.Z)); - - VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.rotateClockwise(STRAIGHT, Axis.Z), Axis.Y)); - VOXEL_LIST.add(VoxelHelper.rotateClockwise(STRAIGHT, Axis.Z)); - VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(STRAIGHT, Axis.Z), Axis.Y)); - VOXEL_LIST.add(VoxelHelper.mirror(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(STRAIGHT, Axis.Z), Axis.Y), Axis.Z)); - - VOXEL_LIST.add(JUNCTION); - VOXEL_LIST.add(VoxelHelper.rotateClockwise(JUNCTION, Axis.Y)); - VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(JUNCTION, Axis.Y), Axis.Y)); - VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.Y)); - - VOXEL_LIST.add(VoxelHelper.mirror(JUNCTION, Axis.Y)); - VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.mirror(JUNCTION, Axis.Y), Axis.Y)); - VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(VoxelHelper.mirror(JUNCTION, Axis.Y), Axis.Y), Axis.Y)); - VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.mirror(JUNCTION, Axis.Y), Axis.Y)); - - VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X)); - VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Z)); - VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Z), Axis.Z)); - VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Z)); - - VOXEL_LIST.add(VoxelHelper.mirror(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Z)); - VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.mirror(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Z), Axis.Z)); - VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(VoxelHelper.mirror(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Z), Axis.Z), Axis.Z)); - VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.mirror(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Z), Axis.Z)); - - VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Y)); - VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Y), Axis.X)); - VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Y), Axis.X), Axis.X)); - VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Y), Axis.X)); - - VOXEL_LIST.add(VoxelHelper.mirror(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Y), Axis.X)); - VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.mirror(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Y), Axis.X), Axis.X)); - VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(VoxelHelper.mirror(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Y), Axis.X), Axis.X), Axis.X)); - VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.mirror(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(JUNCTION, Axis.X), Axis.Y), Axis.X), Axis.X)); - - VOXEL_LIST.add(OUTER); - VOXEL_LIST.add(VoxelHelper.rotateClockwise(OUTER, Axis.Y)); - VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.rotateCounterClockwise(OUTER, Axis.Y), Axis.Y)); - VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(OUTER, Axis.Y)); - - VOXEL_LIST.add(VoxelHelper.mirror(OUTER, Axis.Y)); - VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.mirror(OUTER, Axis.Y), Axis.Y)); - VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.rotateCounterClockwise(VoxelHelper.mirror(OUTER, Axis.Y), Axis.Y), Axis.Y)); - VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.mirror(OUTER, Axis.Y), Axis.Y)); - - VOXEL_LIST.add(INNER); - VOXEL_LIST.add(VoxelHelper.rotateClockwise(INNER, Axis.Y)); - VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.rotateCounterClockwise(INNER, Axis.Y), Axis.Y)); - VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(INNER, Axis.Y)); - - VOXEL_LIST.add(VoxelHelper.mirror(INNER, Axis.Y)); - VOXEL_LIST.add(VoxelHelper.rotateClockwise(VoxelHelper.mirror(INNER, Axis.Y), Axis.Y)); - VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.rotateCounterClockwise(VoxelHelper.mirror(INNER, Axis.Y), Axis.Y), Axis.Y)); - VOXEL_LIST.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.mirror(INNER, Axis.Y), Axis.Y)); - } -} diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedStairsCubeBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedStairsCubeBlock.java new file mode 100644 index 0000000..60b44f9 --- /dev/null +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedStairsCubeBlock.java @@ -0,0 +1,100 @@ +package fr.adrien1106.reframed.block; + +import fr.adrien1106.reframed.ReFramed; +import fr.adrien1106.reframed.generator.BlockStateProvider; +import fr.adrien1106.reframed.util.blocks.BlockHelper; +import fr.adrien1106.reframed.util.blocks.Edge; +import fr.adrien1106.reframed.util.blocks.StairShape; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +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.ItemPlacementContext; +import net.minecraft.recipe.book.RecipeCategory; +import net.minecraft.state.StateManager; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.world.World; +import net.minecraft.world.WorldAccess; +import org.jetbrains.annotations.Nullable; + +import static fr.adrien1106.reframed.block.ReFramedStairBlock.*; +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; + +public class ReFramedStairsCubeBlock extends ReFramedDoubleBlock implements BlockStateProvider { + + private static final VoxelShape[] STAIRS_CUBE_VOXELS = VoxelListBuilder.buildFrom(STAIR_VOXELS); + private record ModelCacheKey(Edge edge, StairShape shape) {} + + public ReFramedStairsCubeBlock(Settings settings) { + super(settings); + setDefaultState(getDefaultState().with(EDGE, Edge.NORTH_DOWN).with(STAIR_SHAPE, StairShape.STRAIGHT)); + } + + @Override + public Object getModelCacheKey(BlockState state) { + return new ModelCacheKey(state.get(EDGE), state.get(STAIR_SHAPE)); + } + + @Override + public int getModelStateCount() { + return 108; // Has 12 * 9 state combination and 52 models still reduces cache size + } + + @Override + protected void appendProperties(StateManager.Builder builder) { + super.appendProperties(builder.add(EDGE, STAIR_SHAPE)); + } + + @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) + .with(STAIR_SHAPE, BlockHelper.getStairsShape(state.get(EDGE), world, pos)); + } + + + @Nullable + @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); + } + + @Override + public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { + super.onStateReplaced(state, world, pos, newState, moved); + + if(!state.isOf(newState.getBlock())) world.removeBlockEntity(pos); + } + + @Override + public VoxelShape getShape(BlockState state, int i) { + Edge edge = state.get(EDGE); + StairShape shape = state.get(STAIR_SHAPE); + return i == 2 ? STAIRS_CUBE_VOXELS[edge.getID() * 9 + shape.getID()] : getStairShape(edge, shape); + } + + @Override + public MultipartBlockStateSupplier getMultipart() { + return getStairMultipart(this, true); + } + + @Override + public void setRecipe(RecipeExporter exporter) { + RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, this, ReFramed.CUBE); + ShapelessRecipeJsonBuilder + .create(RecipeCategory.BUILDING_BLOCKS, this) + .input(ReFramed.STAIR) + .input(ReFramed.STEP) + .criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE)) + .criterion(FabricRecipeProvider.hasItem(this), FabricRecipeProvider.conditionsFromItem(this)) + .offerTo(exporter); + } +} diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedStepBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedStepBlock.java index a5c7841..fa7f969 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedStepBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedStepBlock.java @@ -1,15 +1,16 @@ package fr.adrien1106.reframed.block; import fr.adrien1106.reframed.ReFramed; -import fr.adrien1106.reframed.generator.GBlockstate; import fr.adrien1106.reframed.generator.BlockStateProvider; -import fr.adrien1106.reframed.util.BlockHelper; +import fr.adrien1106.reframed.generator.GBlockstate; import fr.adrien1106.reframed.util.VoxelHelper; -import fr.adrien1106.reframed.util.property.Corner; +import fr.adrien1106.reframed.util.blocks.BlockHelper; +import fr.adrien1106.reframed.util.blocks.Edge; import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.ShapeContext; +import net.minecraft.data.client.BlockStateSupplier; import net.minecraft.data.client.MultipartBlockStateSupplier; import net.minecraft.data.server.recipe.RecipeExporter; import net.minecraft.data.server.recipe.RecipeProvider; @@ -19,88 +20,85 @@ 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.shape.VoxelShape; -import net.minecraft.util.shape.VoxelShapes; import net.minecraft.world.BlockView; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.List; - -import static fr.adrien1106.reframed.util.BlockProperties.CORNER; -import static fr.adrien1106.reframed.util.property.Corner.*; +import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder; +import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE; +import static fr.adrien1106.reframed.util.blocks.Edge.*; import static net.minecraft.data.client.VariantSettings.Rotation.*; public class ReFramedStepBlock extends WaterloggableReFramedBlock implements BlockStateProvider { - public static final List STEP_VOXELS = new ArrayList<>(12); + public static final VoxelShape[] STEP_VOXELS; public ReFramedStepBlock(Settings settings) { super(settings); - setDefaultState(getDefaultState().with(CORNER, Corner.NORTH_DOWN)); + setDefaultState(getDefaultState().with(EDGE, Edge.NORTH_DOWN)); + } + + @Override + public Object getModelCacheKey(BlockState state) { + return state.get(EDGE); + } + + @Override + public int getModelStateCount() { + return 12; } @Override protected void appendProperties(StateManager.Builder builder) { - super.appendProperties(builder.add(CORNER)); + super.appendProperties(builder.add(EDGE)); } @Nullable @Override public BlockState getPlacementState(ItemPlacementContext ctx) { - return super.getPlacementState(ctx).with(CORNER, BlockHelper.getPlacementCorner(ctx)); + return super.getPlacementState(ctx).with(EDGE, BlockHelper.getPlacementEdge(ctx)); } @Override public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { - return switch (state.get(CORNER)) { - case DOWN_SOUTH -> STEP_VOXELS.get(0); - case NORTH_DOWN -> STEP_VOXELS.get(1); - case UP_NORTH -> STEP_VOXELS.get(2); - case SOUTH_UP -> STEP_VOXELS.get(3); - case DOWN_EAST -> STEP_VOXELS.get(4); - case WEST_DOWN -> STEP_VOXELS.get(5); - case UP_WEST -> STEP_VOXELS.get(6); - case EAST_UP -> STEP_VOXELS.get(7); - case NORTH_EAST -> STEP_VOXELS.get(8); - case EAST_SOUTH -> STEP_VOXELS.get(9); - case SOUTH_WEST -> STEP_VOXELS.get(10); - case WEST_NORTH -> STEP_VOXELS.get(11); - }; + return getStepShape(state.get(EDGE)); + } + + public static VoxelShape getStepShape(Edge edge) { + return STEP_VOXELS[edge.getID()]; } @Override - public MultipartBlockStateSupplier getMultipart() { - Identifier step_id = ReFramed.id("step_special"); + public BlockStateSupplier getMultipart() { + Identifier model_id = ReFramed.id("step_special"); return MultipartBlockStateSupplier.create(this) /* X AXIS */ - .with(GBlockstate.when(CORNER, DOWN_EAST), - GBlockstate.variant(step_id, true, R0, R0)) - .with(GBlockstate.when(CORNER, EAST_UP), - GBlockstate.variant(step_id, true, R180, R0)) - .with(GBlockstate.when(CORNER, UP_WEST), - GBlockstate.variant(step_id, true, R180, R180)) - .with(GBlockstate.when(CORNER, WEST_DOWN), - GBlockstate.variant(step_id, true, R0, R180)) + .with(GBlockstate.when(EDGE, DOWN_EAST), + GBlockstate.variant(model_id, true, R0, R0)) + .with(GBlockstate.when(EDGE, EAST_UP), + GBlockstate.variant(model_id, true, R180, R0)) + .with(GBlockstate.when(EDGE, UP_WEST), + GBlockstate.variant(model_id, true, R180, R180)) + .with(GBlockstate.when(EDGE, WEST_DOWN), + GBlockstate.variant(model_id, true, R0, R180)) /* Y AXIS */ - .with(GBlockstate.when(CORNER, EAST_SOUTH), - GBlockstate.variant(step_id, true, R90, R0)) - .with(GBlockstate.when(CORNER, SOUTH_WEST), - GBlockstate.variant(step_id, true, R90, R90)) - .with(GBlockstate.when(CORNER, WEST_NORTH), - GBlockstate.variant(step_id, true, R90, R180)) - .with(GBlockstate.when(CORNER, NORTH_EAST), - GBlockstate.variant(step_id, true, R90, R270)) + .with(GBlockstate.when(EDGE, EAST_SOUTH), + GBlockstate.variant(model_id, true, R90, R0)) + .with(GBlockstate.when(EDGE, SOUTH_WEST), + GBlockstate.variant(model_id, true, R90, R90)) + .with(GBlockstate.when(EDGE, WEST_NORTH), + GBlockstate.variant(model_id, true, R90, R180)) + .with(GBlockstate.when(EDGE, NORTH_EAST), + GBlockstate.variant(model_id, true, R90, R270)) /* Z AXIS */ - .with(GBlockstate.when(CORNER, DOWN_SOUTH), - GBlockstate.variant(step_id, true, R0, R90)) - .with(GBlockstate.when(CORNER, NORTH_DOWN), - GBlockstate.variant(step_id, true, R0, R270)) - .with(GBlockstate.when(CORNER, UP_NORTH), - GBlockstate.variant(step_id, true, R180, R270)) - .with(GBlockstate.when(CORNER, SOUTH_UP), - GBlockstate.variant(step_id, true, R180, R90)); + .with(GBlockstate.when(EDGE, DOWN_SOUTH), + GBlockstate.variant(model_id, true, R0, R90)) + .with(GBlockstate.when(EDGE, NORTH_DOWN), + GBlockstate.variant(model_id, true, R0, R270)) + .with(GBlockstate.when(EDGE, UP_NORTH), + GBlockstate.variant(model_id, true, R180, R270)) + .with(GBlockstate.when(EDGE, SOUTH_UP), + GBlockstate.variant(model_id, true, R180, R90)); } @Override @@ -116,21 +114,22 @@ public class ReFramedStepBlock extends WaterloggableReFramedBlock implements Blo } static { - final VoxelShape STEP = VoxelShapes.cuboid(0f, 0f, .5f, 1f, .5f, 1f); + final VoxelShape STEP = createCuboidShape(0, 0, 0, 16, 8, 8); - STEP_VOXELS.add(STEP); - STEP_VOXELS.add(VoxelHelper.mirror(STEP, Direction.Axis.Z)); - STEP_VOXELS.add(VoxelHelper.mirror(VoxelHelper.rotateCounterClockwise(STEP, Direction.Axis.X), Direction.Axis.Z)); - STEP_VOXELS.add(VoxelHelper.rotateCounterClockwise(STEP, Direction.Axis.X)); + STEP_VOXELS = VoxelListBuilder.create(STEP, 12) + .add(VoxelHelper::rotateCX) + .add(VoxelHelper::rotateCX) + .add(VoxelHelper::rotateCX) - STEP_VOXELS.add(VoxelHelper.rotateCounterClockwise(STEP, Direction.Axis.Y)); - STEP_VOXELS.add(VoxelHelper.mirror(VoxelHelper.rotateCounterClockwise(STEP, Direction.Axis.Y), Direction.Axis.X)); - STEP_VOXELS.add(VoxelHelper.mirror(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(STEP, Direction.Axis.Y), Direction.Axis.Z), Direction.Axis.X)); - STEP_VOXELS.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(STEP, Direction.Axis.Y), Direction.Axis.Z)); + .add(STEP, VoxelHelper::rotateCY) + .add(VoxelHelper::rotateZ) + .add(VoxelHelper::rotateZ) + .add(VoxelHelper::rotateZ) - STEP_VOXELS.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.rotateClockwise(STEP, Direction.Axis.Z), Direction.Axis.Y)); - STEP_VOXELS.add(VoxelHelper.rotateClockwise(STEP, Direction.Axis.Z)); - STEP_VOXELS.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(STEP, Direction.Axis.Z), Direction.Axis.Y)); - STEP_VOXELS.add(VoxelHelper.mirror(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(STEP, Direction.Axis.Z), Direction.Axis.Y), Direction.Axis.Z)); + .add(STEP, VoxelHelper::rotateCZ) + .add(VoxelHelper::rotateY) + .add(VoxelHelper::rotateY) + .add(VoxelHelper::rotateY) + .build(); } } diff --git a/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleStepBlock.java b/src/main/java/fr/adrien1106/reframed/block/ReFramedStepsSlabBlock.java similarity index 74% rename from src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleStepBlock.java rename to src/main/java/fr/adrien1106/reframed/block/ReFramedStepsSlabBlock.java index 5e76f44..c86688e 100644 --- a/src/main/java/fr/adrien1106/reframed/block/ReFramedDoubleStepBlock.java +++ b/src/main/java/fr/adrien1106/reframed/block/ReFramedStepsSlabBlock.java @@ -1,9 +1,10 @@ package fr.adrien1106.reframed.block; import fr.adrien1106.reframed.ReFramed; -import fr.adrien1106.reframed.generator.GBlockstate; import fr.adrien1106.reframed.generator.BlockStateProvider; -import fr.adrien1106.reframed.util.BlockHelper; +import fr.adrien1106.reframed.generator.GBlockstate; +import fr.adrien1106.reframed.util.blocks.BlockHelper; +import fr.adrien1106.reframed.util.blocks.Edge; import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -24,19 +25,31 @@ import net.minecraft.util.shape.VoxelShape; import net.minecraft.world.BlockView; import org.jetbrains.annotations.Nullable; -import static fr.adrien1106.reframed.block.ReFramedSlabBlock.*; -import static fr.adrien1106.reframed.block.ReFramedStepBlock.STEP_VOXELS; +import static fr.adrien1106.reframed.block.ReFramedSlabBlock.getSlabShape; +import static fr.adrien1106.reframed.block.ReFramedStepBlock.getStepShape; import static net.minecraft.data.client.VariantSettings.Rotation.*; -import static net.minecraft.state.property.Properties.FACING; import static net.minecraft.state.property.Properties.AXIS; +import static net.minecraft.state.property.Properties.FACING; import static net.minecraft.util.shape.VoxelShapes.empty; -public class ReFramedDoubleStepBlock extends WaterloggableReFramedDoubleBlock implements BlockStateProvider { - public ReFramedDoubleStepBlock(Settings settings) { +public class ReFramedStepsSlabBlock extends WaterloggableReFramedDoubleBlock implements BlockStateProvider { + private record ModelCacheKey(Direction facing, Axis axis) {} + + public ReFramedStepsSlabBlock(Settings settings) { super(settings); setDefaultState(getDefaultState().with(FACING, Direction.DOWN).with(AXIS, Axis.X)); } + @Override + public Object getModelCacheKey(BlockState state) { + return new ModelCacheKey(state.get(FACING), state.get(AXIS)); + } + + @Override + public int getModelStateCount() { + return 18; + } + @Override protected void appendProperties(StateManager.Builder builder) { super.appendProperties(builder.add(FACING, AXIS)); @@ -63,36 +76,41 @@ public class ReFramedDoubleStepBlock extends WaterloggableReFramedDoubleBlock im @Override public VoxelShape getShape(BlockState state, int i) { Axis axis = state.get(AXIS); - return STEP_VOXELS.get(switch (state.get(FACING)) { - case DOWN -> axis == Axis.Z ? (i == 1 ? 0 : 1): (i == 1 ? 4 : 5 ); - case UP -> axis == Axis.Z ? (i == 1 ? 3 : 2): (i == 1 ? 7 : 6 ); - case NORTH -> axis == Axis.Y ? (i == 1 ? 1 : 2): (i == 1 ? 11 : 8 ); - case SOUTH -> axis == Axis.Y ? (i == 1 ? 0 : 3): (i == 1 ? 9 : 10); - case EAST -> axis == Axis.Y ? (i == 1 ? 4 : 7): (i == 1 ? 8 : 9 ); - case WEST -> axis == Axis.Y ? (i == 1 ? 5 : 6): (i == 1 ? 10 : 11); - }); + return getStepShape(Edge.getByDirections( + state.get(FACING), + 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; + } + )); + } + + @Override + public int getTopThemeIndex(BlockState state) { + return 2; } @Override public MultipartBlockStateSupplier getMultipart() { - Identifier step_id = ReFramed.id("double_step_special"); - Identifier step_side_id = ReFramed.id("double_step_side_special"); + Identifier step_id = ReFramed.id("steps_slab_special"); + Identifier step_side_id = ReFramed.id("steps_slab_side_special"); return MultipartBlockStateSupplier.create(this) .with(GBlockstate.when(FACING, Direction.DOWN, AXIS, Axis.X), - GBlockstate.variant(step_id, true, R0, R0)) + GBlockstate.variant(step_id, true, R0, R180)) .with(GBlockstate.when(FACING, Direction.DOWN, AXIS, Axis.Z), GBlockstate.variant(step_id, true, R0, R90)) .with(GBlockstate.when(FACING, Direction.UP, AXIS, Axis.X), - GBlockstate.variant(step_id, true, R180, R0)) + GBlockstate.variant(step_id, true, R180, R180)) .with(GBlockstate.when(FACING, Direction.UP, AXIS, Axis.Z), GBlockstate.variant(step_id, true, R180, R90)) .with(GBlockstate.when(FACING, Direction.EAST, AXIS, Axis.Z), - GBlockstate.variant(step_side_id, true, R0, R0)) + GBlockstate.variant(step_side_id, true, R180, 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), - GBlockstate.variant(step_side_id, true, R0, R90)) + GBlockstate.variant(step_side_id, true, R180, R90)) .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), diff --git a/src/main/java/fr/adrien1106/reframed/client/ReFramedClient.java b/src/main/java/fr/adrien1106/reframed/client/ReFramedClient.java index a59f789..59e08fb 100644 --- a/src/main/java/fr/adrien1106/reframed/client/ReFramedClient.java +++ b/src/main/java/fr/adrien1106/reframed/client/ReFramedClient.java @@ -26,31 +26,68 @@ public class ReFramedClient implements ClientModInitializer { //all frames mustn't be on the SOLID layer because they are not opaque! BlockRenderLayerMap.INSTANCE.putBlocks(RenderLayer.getCutout(), ReFramed.BLOCKS.toArray(new Block[0])); - HELPER.addReFramedModel("cube_special" , HELPER.auto(new Identifier("block/cube"))); - HELPER.addReFramedModel("slab_special" , HELPER.auto(new Identifier("block/slab"))); - HELPER.addReFramedModel("double_slab_special" , HELPER.autoDouble(new Identifier("block/slab"), new Identifier("block/slab_top"))); - HELPER.addReFramedModel("stairs_special" , HELPER.auto(ReFramed.id("block/stairs"))); - HELPER.addReFramedModel("outers_stairs_special" , HELPER.auto(ReFramed.id("block/double_outer_stairs"))); - HELPER.addReFramedModel("inner_stairs_special" , HELPER.auto(ReFramed.id("block/inner_stairs"))); - HELPER.addReFramedModel("outer_stairs_special" , HELPER.auto(ReFramed.id("block/outer_stairs"))); - HELPER.addReFramedModel("outer_side_stairs_special" , HELPER.auto(ReFramed.id("block/outer_side_stairs"))); - HELPER.addReFramedModel("double_stairs_special" , HELPER.autoDouble(ReFramed.id("block/stairs"), ReFramed.id("block/stairs_complement"))); - HELPER.addReFramedModel("double_outers_stairs_special" , HELPER.autoDouble(ReFramed.id("block/double_outer_stairs"), ReFramed.id("block/double_outer_stairs_complement"))); - HELPER.addReFramedModel("double_inner_stairs_special" , HELPER.autoDouble(ReFramed.id("block/inner_stairs"), ReFramed.id("block/inner_stairs_complement"))); - HELPER.addReFramedModel("double_outer_stairs_special" , HELPER.autoDouble(ReFramed.id("block/outer_stairs"), ReFramed.id("block/outer_stairs_complement"))); - HELPER.addReFramedModel("double_outer_side_stairs_special", HELPER.autoDouble(ReFramed.id("block/outer_side_stairs"), ReFramed.id("block/outer_side_stairs_complement"))); - HELPER.addReFramedModel("step_special" , HELPER.auto(ReFramed.id("block/step"))); - HELPER.addReFramedModel("double_step_special" , HELPER.autoDouble(ReFramed.id("block/step"), ReFramed.id("block/step_complement_slab"))); - HELPER.addReFramedModel("double_step_side_special" , HELPER.autoDouble(ReFramed.id("block/step_side"), ReFramed.id("block/step_side_complement_slab"))); + // CUBE + HELPER.addReFramedModel("cube_special" , HELPER.auto(new Identifier("block/cube"))); + // SMALL_CUBE + HELPER.addReFramedModel("small_cube_special" , HELPER.auto(ReFramed.id("block/small_cube/base"))); + // SMALL_CUBES_STEP + HELPER.addReFramedModel("small_cubes_step_special" , HELPER.autoDouble(ReFramed.id("block/small_cube/base"), ReFramed.id("block/small_cube/step/base"))); + HELPER.addReFramedModel("small_cubes_step_reverse_special" , HELPER.autoDouble(ReFramed.id("block/small_cube/step/base"), ReFramed.id("block/small_cube/base"))); + // SLAB + HELPER.addReFramedModel("slab_special" , HELPER.auto(new Identifier("block/slab"))); + // SLAB_CUBE + HELPER.addReFramedModel("double_slab_special" , HELPER.autoDouble(new Identifier("block/slab"), new Identifier("block/slab_top"))); + // STAIR + HELPER.addReFramedModel("stair_special" , HELPER.auto(ReFramed.id("block/stair/straight"))); + HELPER.addReFramedModel("outers_stair_special" , HELPER.auto(ReFramed.id("block/stair/double_outer"))); + HELPER.addReFramedModel("inner_stair_special" , HELPER.auto(ReFramed.id("block/stair/inner"))); + HELPER.addReFramedModel("outer_stair_special" , HELPER.auto(ReFramed.id("block/stair/outer"))); + HELPER.addReFramedModel("outer_side_stair_special" , HELPER.auto(ReFramed.id("block/stair/outer_side"))); + // STAIRS_CUBE + HELPER.addReFramedModel("stairs_cube_special" , HELPER.autoDouble(ReFramed.id("block/stair/straight"), ReFramed.id("block/stair/cube/straight"))); + HELPER.addReFramedModel("outers_stairs_cube_special" , HELPER.autoDouble(ReFramed.id("block/stair/double_outer"), ReFramed.id("block/stair/cube/double_outer"))); + HELPER.addReFramedModel("inner_stairs_cube_special" , HELPER.autoDouble(ReFramed.id("block/stair/inner"), ReFramed.id("block/stair/cube/inner"))); + HELPER.addReFramedModel("outer_stairs_cube_special" , HELPER.autoDouble(ReFramed.id("block/stair/outer"), ReFramed.id("block/stair/cube/outer"))); + HELPER.addReFramedModel("outer_side_stairs_cube_special" , HELPER.autoDouble(ReFramed.id("block/stair/outer_side"), ReFramed.id("block/stair/cube/outer_side"))); + // HALF_STAIR + HELPER.addReFramedModel("half_stair_down_special" , HELPER.auto(ReFramed.id("block/half_stair/down"))); + HELPER.addReFramedModel("half_stair_side_special" , HELPER.auto(ReFramed.id("block/half_stair/side"))); + // HALF_STAIRS_SLAB + HELPER.addReFramedModel("half_stairs_slab_down_special" , HELPER.autoDouble(ReFramed.id("block/half_stair/down"), ReFramed.id("block/half_stair/slab/down"))); + HELPER.addReFramedModel("half_stairs_slab_side_special" , HELPER.autoDouble(ReFramed.id("block/half_stair/side"), ReFramed.id("block/half_stair/slab/side"))); + // HALF_STAIRS_STAIR + HELPER.addReFramedModel("half_stairs_stair_down_special" , HELPER.autoDouble(ReFramed.id("block/half_stair/down"), ReFramed.id("block/half_stair/stair/down"))); + HELPER.addReFramedModel("half_stairs_stair_side_special" , HELPER.autoDouble(ReFramed.id("block/half_stair/side"), ReFramed.id("block/half_stair/stair/side"))); + HELPER.addReFramedModel("half_stairs_stair_reverse_special" , HELPER.autoDouble(ReFramed.id("block/half_stair/stair/side"), ReFramed.id("block/half_stair/side"))); + // STEP + HELPER.addReFramedModel("step_special" , HELPER.auto(ReFramed.id("block/step/down"))); + // STEPS_SLAB + HELPER.addReFramedModel("steps_slab_special" , HELPER.autoDouble(ReFramed.id("block/step/down"), ReFramed.id("block/step/slab/down"))); + HELPER.addReFramedModel("steps_slab_side_special" , HELPER.autoDouble(ReFramed.id("block/step/side"), ReFramed.id("block/step/slab/side"))); + // LAYER + HELPER.addReFramedModel("layer_1_special" , HELPER.auto(new Identifier("block/snow_height2"))); + HELPER.addReFramedModel("layer_2_special" , HELPER.auto(new Identifier("block/snow_height4"))); + HELPER.addReFramedModel("layer_3_special" , HELPER.auto(new Identifier("block/snow_height6"))); + HELPER.addReFramedModel("layer_4_special" , HELPER.auto(new Identifier("block/snow_height8"))); + HELPER.addReFramedModel("layer_5_special" , HELPER.auto(new Identifier("block/snow_height10"))); + HELPER.addReFramedModel("layer_6_special" , HELPER.auto(new Identifier("block/snow_height12"))); + HELPER.addReFramedModel("layer_7_special" , HELPER.auto(new Identifier("block/snow_height14"))); + HELPER.addReFramedModel("layer_8_special" , HELPER.auto(new Identifier("block/cube"))); //item model assignments (in lieu of models/item/___.json) HELPER.assignItemModel("cube_special" , ReFramed.CUBE); + HELPER.assignItemModel("small_cube_special" , ReFramed.SMALL_CUBE); + HELPER.assignItemModel("small_cubes_step_special" , ReFramed.SMALL_CUBES_STEP); HELPER.assignItemModel("slab_special" , ReFramed.SLAB); - HELPER.assignItemModel("double_slab_special" , ReFramed.DOUBLE_SLAB); - HELPER.assignItemModel("stairs_special" , ReFramed.STAIRS); - HELPER.assignItemModel("double_stairs_special" , ReFramed.DOUBLE_STAIRS); + HELPER.assignItemModel("double_slab_special" , ReFramed.SLABS_CUBE); + HELPER.assignItemModel("stair_special" , ReFramed.STAIR); + HELPER.assignItemModel("stairs_cube_special" , ReFramed.STAIRS_CUBE); + HELPER.assignItemModel("half_stair_down_special" , ReFramed.HALF_STAIR); + HELPER.assignItemModel("half_stairs_slab_down_special" , ReFramed.HALF_STAIRS_SLAB); + HELPER.assignItemModel("half_stairs_stair_down_special", ReFramed.HALF_STAIRS_STAIR); HELPER.assignItemModel("step_special" , ReFramed.STEP); - HELPER.assignItemModel("double_step_special" , ReFramed.DOUBLE_STEP); + HELPER.assignItemModel("steps_slab_special" , ReFramed.STEPS_SLAB); + HELPER.assignItemModel("layer_1_special" , ReFramed.LAYER); } private void privateInit() { diff --git a/src/main/java/fr/adrien1106/reframed/client/model/DoubleRetexturingBakedModel.java b/src/main/java/fr/adrien1106/reframed/client/model/DoubleRetexturingBakedModel.java index a8bf841..a50806c 100644 --- a/src/main/java/fr/adrien1106/reframed/client/model/DoubleRetexturingBakedModel.java +++ b/src/main/java/fr/adrien1106/reframed/client/model/DoubleRetexturingBakedModel.java @@ -5,7 +5,6 @@ import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel; import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; import net.minecraft.block.BlockState; -import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.texture.Sprite; import net.minecraft.item.ItemStack; import net.minecraft.util.math.BlockPos; @@ -45,7 +44,7 @@ public class DoubleRetexturingBakedModel extends ForwardingBakedModel implements } @Override - public List models() { + public List models() { return List.of(model_1, model_2); } } diff --git a/src/main/java/fr/adrien1106/reframed/client/model/MultiRetexturableModel.java b/src/main/java/fr/adrien1106/reframed/client/model/MultiRetexturableModel.java index b1d7cea..17ea436 100644 --- a/src/main/java/fr/adrien1106/reframed/client/model/MultiRetexturableModel.java +++ b/src/main/java/fr/adrien1106/reframed/client/model/MultiRetexturableModel.java @@ -1,10 +1,10 @@ package fr.adrien1106.reframed.client.model; -import net.minecraft.client.render.model.BakedModel; +import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel; import java.util.List; public interface MultiRetexturableModel { - List models(); + List models(); } diff --git a/src/main/java/fr/adrien1106/reframed/client/model/QuadPosBounds.java b/src/main/java/fr/adrien1106/reframed/client/model/QuadPosBounds.java index 392a9f4..c6cca3d 100644 --- a/src/main/java/fr/adrien1106/reframed/client/model/QuadPosBounds.java +++ b/src/main/java/fr/adrien1106/reframed/client/model/QuadPosBounds.java @@ -1,11 +1,14 @@ package fr.adrien1106.reframed.client.model; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView; import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView; import net.minecraft.util.math.Direction; import net.minecraft.util.math.MathHelper; import org.joml.Vector3f; +@Environment(EnvType.CLIENT) public record QuadPosBounds(float min_x, float max_x, float min_y, float max_y, float min_z, float max_z) { public static QuadPosBounds read(QuadView quad) { @@ -76,4 +79,15 @@ public record QuadPosBounds(float min_x, float max_x, float min_y, float max_y, quad.pos(i, pos); } } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof QuadPosBounds other)) return false; + return MathHelper.approximatelyEquals(min_x, other.min_x) + && MathHelper.approximatelyEquals(min_y, other.min_y) + && MathHelper.approximatelyEquals(min_z, other.min_z) + && MathHelper.approximatelyEquals(max_x, other.max_x) + && MathHelper.approximatelyEquals(max_y, other.max_y) + && MathHelper.approximatelyEquals(max_z, other.max_z); + } } diff --git a/src/main/java/fr/adrien1106/reframed/client/model/QuadUvBounds.java b/src/main/java/fr/adrien1106/reframed/client/model/QuadUvBounds.java index b06d9cf..3b314cd 100644 --- a/src/main/java/fr/adrien1106/reframed/client/model/QuadUvBounds.java +++ b/src/main/java/fr/adrien1106/reframed/client/model/QuadUvBounds.java @@ -1,10 +1,13 @@ package fr.adrien1106.reframed.client.model; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView; import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView; import net.minecraft.client.texture.Sprite; import net.minecraft.util.math.MathHelper; +@Environment(EnvType.CLIENT) public record QuadUvBounds(float minU, float maxU, float minV, float maxV) { public static QuadUvBounds read(QuadView quad) { float u0 = quad.u(0), u1 = quad.u(1), u2 = quad.u(2), u3 = quad.u(3); diff --git a/src/main/java/fr/adrien1106/reframed/client/model/RetexturingBakedModel.java b/src/main/java/fr/adrien1106/reframed/client/model/RetexturingBakedModel.java index 548bdd9..5ce4b48 100644 --- a/src/main/java/fr/adrien1106/reframed/client/model/RetexturingBakedModel.java +++ b/src/main/java/fr/adrien1106/reframed/client/model/RetexturingBakedModel.java @@ -1,17 +1,15 @@ package fr.adrien1106.reframed.client.model; +import fr.adrien1106.reframed.block.ReFramedBlock; import fr.adrien1106.reframed.block.ReFramedEntity; import fr.adrien1106.reframed.client.ReFramedClient; -import fr.adrien1106.reframed.client.model.apperance.SpriteProperties; import fr.adrien1106.reframed.mixin.MinecraftAccessor; import fr.adrien1106.reframed.client.model.apperance.CamoAppearance; import fr.adrien1106.reframed.client.model.apperance.CamoAppearanceManager; import fr.adrien1106.reframed.client.model.apperance.WeightedComputedAppearance; -import fr.adrien1106.reframed.util.ThemeableBlockEntity; -import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh; -import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder; -import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView; -import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter; +import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity; +import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; +import net.fabricmc.fabric.api.renderer.v1.mesh.*; import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel; import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; import net.minecraft.block.BlockState; @@ -26,34 +24,43 @@ import net.minecraft.util.math.Direction; import net.minecraft.util.math.random.Random; import net.minecraft.world.BlockRenderView; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; public abstract class RetexturingBakedModel extends ForwardingBakedModel { public RetexturingBakedModel(BakedModel base_model, CamoAppearanceManager tam, int theme_index, ModelBakeSettings settings, BlockState item_state, boolean ao) { this.wrapped = base_model; //field from the superclass; vanilla getQuads etc. will delegate through to this - this.tam = tam; + this.appearance_manager = tam; this.theme_index = theme_index; this.uv_lock = settings.isUvLocked(); this.item_state = item_state; this.ao = ao; + + int cache_size = 64; // default is 64 why don't ask me and it should get overwritten + if (item_state.getBlock() instanceof ReFramedBlock frame_block) cache_size = frame_block.getModelStateCount() + 1; + BASE_MESH_CACHE = new Object2ObjectLinkedOpenHashMap<>(cache_size, 0.25f) { + @Override + protected void rehash(int v) {} + }; } - protected final CamoAppearanceManager tam; + protected final CamoAppearanceManager appearance_manager; protected final int theme_index; protected final boolean uv_lock; - protected final BlockState item_state; protected final boolean ao; + protected final BlockState item_state; - /* ----------------------------------------------- CACHE ELEMENT ------------------------------------------------ */ - // TODO make static ? for connected textures ? - protected record MeshCacheKey(BlockState state, TransformCacheKey transform) {} - protected record TransformCacheKey(CamoAppearance appearance, int model_id) {} - protected final ConcurrentMap retextured_transforms = new ConcurrentHashMap<>(); - protected final ConcurrentMap retextured_meshes = new ConcurrentHashMap<>(); //mutable, append-only cache + protected record MeshCacheKey(Object state_key, CamoAppearance appearance, int model_id) {} + /** cache that store retextured models */ + protected final Object2ObjectLinkedOpenHashMap RETEXTURED_MESH_CACHE = + new Object2ObjectLinkedOpenHashMap<>(128, 0.25f) { + @Override + protected void rehash(int v) {} + }; + + /** cache that stores the base meshes which has the size of the amount of models */ + protected final Object2ObjectLinkedOpenHashMap BASE_MESH_CACHE; protected static final Direction[] DIRECTIONS_AND_NULL; static { @@ -62,11 +69,12 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel { System.arraycopy(values, 0, DIRECTIONS_AND_NULL, 0, values.length); } - protected final ConcurrentMap jsonToMesh = new ConcurrentHashMap<>(); - - protected Mesh getBaseMesh(BlockState state) { + protected Mesh getBaseMesh(Object key, BlockState state) { //Convert models to re-texturable Meshes lazily, the first time we encounter each blockstate - return jsonToMesh.computeIfAbsent(state, this::convertModel); + if (BASE_MESH_CACHE.containsKey(key)) return BASE_MESH_CACHE.getAndMoveToFirst(key); + Mesh mesh = convertModel(state); + BASE_MESH_CACHE.putAndMoveToFirst(key, mesh); + return mesh; } protected abstract Mesh convertModel(BlockState state); @@ -78,39 +86,42 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel { @Override public Sprite getParticleSprite() { - return tam.getDefaultAppearance(theme_index).getSprites(Direction.UP, 0).get(0).sprite(); + return appearance_manager.getDefaultAppearance(theme_index).getSprites(Direction.UP, 0).get(0).sprite(); } @Override public void emitBlockQuads(BlockRenderView world, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { + // skip render if block not a frame (which should always be the case + if (!(state.getBlock() instanceof ReFramedBlock frame_block)) return; BlockState theme = (world.getBlockEntity(pos) instanceof ThemeableBlockEntity s) ? s.getTheme(theme_index) : null; QuadEmitter quad_emitter = context.getEmitter(); if(theme == null || theme.isAir()) { - getUntintedRetexturedMesh(new MeshCacheKey(state, new TransformCacheKey(tam.getDefaultAppearance(theme_index), 0)), 0).outputTo(quad_emitter); + getRetexturedMesh( + new MeshCacheKey( + frame_block.getModelCacheKey(state), + appearance_manager.getDefaultAppearance(theme_index), + 0 + ), + state + ).outputTo(quad_emitter); return; } if(theme.getBlock() == Blocks.BARRIER) return; - CamoAppearance camo = tam.getCamoAppearance(world, theme, pos, theme_index); + CamoAppearance camo = appearance_manager.getCamoAppearance(world, theme, pos, theme_index, false); long seed = theme.getRenderingSeed(pos); int model_id = 0; if (camo instanceof WeightedComputedAppearance wca) model_id = wca.getAppearanceIndex(seed); - + int tint = 0xFF000000 | MinecraftClient.getInstance().getBlockColors().getColor(theme, world, pos, 0); - Mesh untintedMesh = getUntintedRetexturedMesh( - new MeshCacheKey( - state, - new TransformCacheKey(camo, model_id) - ), - seed - ); + Mesh untintedMesh = getRetexturedMesh(new MeshCacheKey(frame_block.getModelCacheKey(state), camo, model_id), state); //The specific tint might vary a lot; imagine grass color smoothly changing. Trying to bake the tint into //the cached mesh will pollute it with a ton of single-use meshes with only slightly different colors. if(tint == 0xFFFFFFFF) { untintedMesh.outputTo(quad_emitter); } else { - context.pushTransform(new TintingTransformer(camo, tint, seed)); + context.pushTransform(new TintingTransformer(camo, model_id, tint)); untintedMesh.outputTo(quad_emitter); context.popTransform(); } @@ -120,121 +131,72 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel { public void emitItemQuads(ItemStack stack, Supplier randomSupplier, RenderContext context) { //cheeky: if the item has NBT data, pluck out the blockstate from it & look up the item color provider //none of this is accessible unless you're in creative mode doing ctrl-pick btw - CamoAppearance nbtAppearance; + CamoAppearance appearance; int tint; BlockState theme = ReFramedEntity.readStateFromItem(stack, theme_index); if(!theme.isAir()) { - nbtAppearance = tam.getCamoAppearance(null, theme, null, theme_index); + appearance = appearance_manager.getCamoAppearance(null, theme, null, theme_index, true); tint = 0xFF000000 | ((MinecraftAccessor) MinecraftClient.getInstance()).getItemColors().getColor(new ItemStack(theme.getBlock()), 0); } else { - nbtAppearance = tam.getDefaultAppearance(theme_index); + appearance = appearance_manager.getDefaultAppearance(theme_index); tint = 0xFFFFFFFF; } - Mesh untintedMesh = getUntintedRetexturedMesh(new MeshCacheKey(item_state, new TransformCacheKey(nbtAppearance, 0)), 0); + Mesh untintedMesh = getRetexturedMesh(new MeshCacheKey("I", appearance, 0), item_state); QuadEmitter quad_emitter = context.getEmitter(); if(tint == 0xFFFFFFFF) { untintedMesh.outputTo(quad_emitter); } else { - context.pushTransform(new TintingTransformer(nbtAppearance, tint, 0)); + context.pushTransform(new TintingTransformer(appearance, 0, tint)); untintedMesh.outputTo(quad_emitter); context.popTransform(); } } - protected Mesh getUntintedRetexturedMesh(MeshCacheKey key, long seed) { - return retextured_meshes.computeIfAbsent(key, (k) -> createUntintedRetexturedMesh(k, seed)); + protected Mesh getRetexturedMesh(MeshCacheKey key, BlockState state) { + if (RETEXTURED_MESH_CACHE.containsKey(key)) return RETEXTURED_MESH_CACHE.getAndMoveToFirst(key); + Mesh mesh = transformMesh(key, state); + RETEXTURED_MESH_CACHE.putAndMoveToFirst(key, mesh); + return mesh; } - protected Mesh createUntintedRetexturedMesh(MeshCacheKey key, long seed) { - RetexturingTransformer transformer = retextured_transforms.computeIfAbsent(key.transform, (k) -> new RetexturingTransformer(k.appearance, seed)); - return pretransformMesh(getBaseMesh(key.state), transformer); - } - - private static Mesh pretransformMesh(Mesh mesh, RetexturingTransformer transform) { + protected Mesh transformMesh(MeshCacheKey key, BlockState state) { MeshBuilder builder = ReFramedClient.HELPER.getFabricRenderer().meshBuilder(); QuadEmitter emitter = builder.getEmitter(); - mesh.forEach(quad -> { + AtomicInteger quad_index = new AtomicInteger(); + getBaseMesh(key.state_key, state).forEach(quad -> { int i = -1; do { emitter.copyFrom(quad); - i = transform.transform(emitter, i); + i = key.appearance.transformQuad(emitter, i, quad_index.get(), key.model_id, ao, uv_lock); } while (i > 0); + // kinda weird to do it like that but other directions don't use the quad_index so it doesn't matter + if (quad.cullFace() == null) quad_index.getAndIncrement(); }); return builder.build(); } - - public class RetexturingTransformer { - private final long seed; - protected RetexturingTransformer(CamoAppearance ta, long seed) { - this.ta = ta; - this.seed = seed; - } - - protected final CamoAppearance ta; - public int transform(QuadEmitter quad, int i) { - if(quad.tag() == 0) return 0; //Pass the quad through unmodified. - - Direction direction = quad.nominalFace(); - List sprites = ta.getSprites(direction, seed); - if (i == -1) i = sprites.size(); - - SpriteProperties properties = sprites.get(sprites.size() - i); - i--; - QuadPosBounds bounds = properties.bounds(); - - if (bounds == null) { // sprite applies anywhere e.g. default behaviour - quad.material(ta.getRenderMaterial(ao)); - quad.spriteBake( - properties.sprite(), - MutableQuadView.BAKE_NORMALIZED - | properties.flags() - | (uv_lock ? MutableQuadView.BAKE_LOCK_UV : 0) - ); - quad.tag(i+1); - quad.emit(); - return i; - } - - // verify if sprite covers the current quad and apply the new size - QuadPosBounds origin_bounds = QuadPosBounds.read(quad, false); - if (!bounds.matches(origin_bounds)) return i; - - // apply new quad shape - quad.material(ta.getRenderMaterial(ao)); - bounds.intersection(origin_bounds, direction.getAxis()).apply(quad, origin_bounds); - quad.spriteBake( // seems to work without the flags and break with it - properties.sprite(), - MutableQuadView.BAKE_NORMALIZED - | MutableQuadView.BAKE_LOCK_UV - ); - quad.tag(i+1); - quad.emit(); - return i; - } - } - protected static class TintingTransformer implements RenderContext.QuadTransform { - private final long seed; - protected TintingTransformer(CamoAppearance ta, int tint, long seed) { - this.ta = ta; + private final CamoAppearance appearance; + private final int model_id; + private final int tint; + + protected TintingTransformer(CamoAppearance appearance, int model_id, int tint) { + this.appearance = appearance; + this.model_id = model_id; this.tint = tint; - this.seed = seed; } - - protected final CamoAppearance ta; - protected final int tint; - + @Override public boolean transform(MutableQuadView quad) { - if(quad.tag() == 0) return true; + int camo_quad_index = quad.tag() - ((quad.tag() >>> 8) << 8); + if(camo_quad_index == 0) return true; + + if(appearance.hasColor(quad.nominalFace(), model_id, camo_quad_index)) quad.color(tint, tint, tint, tint); - if(ta.hasColor(quad.nominalFace(), seed, quad.tag())) quad.color(tint, tint, tint, tint); - return true; } } diff --git a/src/main/java/fr/adrien1106/reframed/client/model/UnbakedAutoRetexturedModel.java b/src/main/java/fr/adrien1106/reframed/client/model/UnbakedAutoRetexturedModel.java index dba3f74..b789e9f 100644 --- a/src/main/java/fr/adrien1106/reframed/client/model/UnbakedAutoRetexturedModel.java +++ b/src/main/java/fr/adrien1106/reframed/client/model/UnbakedAutoRetexturedModel.java @@ -43,7 +43,7 @@ public class UnbakedAutoRetexturedModel extends UnbakedRetexturedModel { Renderer r = ReFramedClient.HELPER.getFabricRenderer(); MeshBuilder builder = r.meshBuilder(); QuadEmitter emitter = builder.getEmitter(); - RenderMaterial mat = tam.getCachedMaterial(state, false); + RenderMaterial mat = appearance_manager.getCachedMaterial(state, false); Random rand = Random.create(42); diff --git a/src/main/java/fr/adrien1106/reframed/client/model/UnbakedJsonRetexturedModel.java b/src/main/java/fr/adrien1106/reframed/client/model/UnbakedJsonRetexturedModel.java index 914ce00..48e5617 100644 --- a/src/main/java/fr/adrien1106/reframed/client/model/UnbakedJsonRetexturedModel.java +++ b/src/main/java/fr/adrien1106/reframed/client/model/UnbakedJsonRetexturedModel.java @@ -51,7 +51,7 @@ public class UnbakedJsonRetexturedModel extends UnbakedRetexturedModel { Renderer r = ReFramedClient.HELPER.getFabricRenderer(); MeshBuilder builder = r.meshBuilder(); QuadEmitter emitter = builder.getEmitter(); - RenderMaterial mat = tam.getCachedMaterial(state, false); + RenderMaterial mat = appearance_manager.getCachedMaterial(state, false); Random rand = Random.create(42); diff --git a/src/main/java/fr/adrien1106/reframed/client/model/UnbakedRetexturedModel.java b/src/main/java/fr/adrien1106/reframed/client/model/UnbakedRetexturedModel.java index 8345833..948cd0f 100644 --- a/src/main/java/fr/adrien1106/reframed/client/model/UnbakedRetexturedModel.java +++ b/src/main/java/fr/adrien1106/reframed/client/model/UnbakedRetexturedModel.java @@ -14,7 +14,7 @@ public abstract class UnbakedRetexturedModel implements UnbakedModel { protected int theme_index = 1; protected BlockState item_state; - protected boolean ao = true; + protected final boolean ao = true; public UnbakedRetexturedModel(Identifier parent) { this.parent = parent; diff --git a/src/main/java/fr/adrien1106/reframed/client/model/apperance/CamoAppearance.java b/src/main/java/fr/adrien1106/reframed/client/model/apperance/CamoAppearance.java index ad219e5..5fcd555 100644 --- a/src/main/java/fr/adrien1106/reframed/client/model/apperance/CamoAppearance.java +++ b/src/main/java/fr/adrien1106/reframed/client/model/apperance/CamoAppearance.java @@ -1,13 +1,80 @@ package fr.adrien1106.reframed.client.model.apperance; +import fr.adrien1106.reframed.client.model.QuadPosBounds; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial; +import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView; +import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter; import net.minecraft.util.math.Direction; import org.jetbrains.annotations.NotNull; import java.util.List; -public interface CamoAppearance { - @NotNull RenderMaterial getRenderMaterial(boolean ao); - @NotNull List getSprites(Direction dir, long seed); - boolean hasColor(Direction dir, long seed, int index); +@Environment(EnvType.CLIENT) +public abstract class CamoAppearance { + protected final int id; + protected final RenderMaterial ao_material; + protected final RenderMaterial material; + + protected CamoAppearance(RenderMaterial ao_material, RenderMaterial material, int id) { + this.id = id; + + this.ao_material = ao_material; + this.material = material; + } + + public abstract @NotNull List getSprites(Direction dir, int model_id); + public abstract boolean hasColor(Direction dir, int model_id, int index); + + public @NotNull RenderMaterial getRenderMaterial(boolean ao) { + return ao && ao_material != null? ao_material : material; + } + + public int transformQuad(QuadEmitter quad, int i, int quad_index, int model_id, boolean ao, boolean uv_lock) { + if(quad.tag() == 0) return 0; // Pass the quad through unmodified. + + Direction direction = quad.nominalFace(); + List sprites = getSprites(direction, model_id); + if (i == -1) i = sprites.size(); + + SpriteProperties properties = sprites.get(sprites.size() - i); + int tag = i + (quad_index << 8); + i--; + QuadPosBounds bounds = properties.bounds(); + + if (bounds == null) { // sprite applies anywhere e.g. default behaviour + quad.material(getRenderMaterial(ao)); + quad.spriteBake( + properties.sprite(), + MutableQuadView.BAKE_NORMALIZED + | properties.flags() + | (uv_lock ? MutableQuadView.BAKE_LOCK_UV : 0) + ); + quad.tag(tag); + quad.emit(); + return i; + } + + // verify if sprite covers the current quad and apply the new size + QuadPosBounds origin_bounds = QuadPosBounds.read(quad, false); + if (!bounds.matches(origin_bounds)) return i; + + // apply new quad shape + quad.material(getRenderMaterial(ao)); + bounds.intersection(origin_bounds, direction.getAxis()).apply(quad, origin_bounds); + quad.spriteBake( // seems to work without the flags and break with it + properties.sprite(), + MutableQuadView.BAKE_NORMALIZED + | MutableQuadView.BAKE_LOCK_UV + ); + quad.tag(tag); + quad.emit(); + return i; + } + + @Override + public int hashCode() { + return id; + } } diff --git a/src/main/java/fr/adrien1106/reframed/client/model/apperance/CamoAppearanceManager.java b/src/main/java/fr/adrien1106/reframed/client/model/apperance/CamoAppearanceManager.java index 949545b..f6a5c64 100644 --- a/src/main/java/fr/adrien1106/reframed/client/model/apperance/CamoAppearanceManager.java +++ b/src/main/java/fr/adrien1106/reframed/client/model/apperance/CamoAppearanceManager.java @@ -1,10 +1,14 @@ package fr.adrien1106.reframed.client.model.apperance; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import fr.adrien1106.reframed.ReFramed; import fr.adrien1106.reframed.client.ReFramedClient; import fr.adrien1106.reframed.client.model.DynamicBakedModel; import fr.adrien1106.reframed.client.model.QuadPosBounds; import fr.adrien1106.reframed.mixin.model.WeightedBakedModelAccessor; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.renderer.v1.Renderer; import net.fabricmc.fabric.api.renderer.v1.material.BlendMode; import net.fabricmc.fabric.api.renderer.v1.material.MaterialFinder; @@ -29,10 +33,10 @@ import net.minecraft.util.math.random.Random; import net.minecraft.world.BlockRenderView; import java.util.*; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; +@Environment(EnvType.CLIENT) public class CamoAppearanceManager { public CamoAppearanceManager(Function spriteLookup) { @@ -40,20 +44,20 @@ public class CamoAppearanceManager { for(BlendMode blend : BlendMode.values()) { finder.clear().disableDiffuse(false).blendMode(blend); - materialsWithoutAo.put(blend, finder.ambientOcclusion(TriState.FALSE).find()); - materialsWithAo.put(blend, finder.ambientOcclusion(TriState.DEFAULT).find()); //not "true" since that *forces* AO, i just want to *allow* AO + materials.put(blend, finder.ambientOcclusion(TriState.FALSE).find()); + ao_materials.put(blend, finder.ambientOcclusion(TriState.DEFAULT).find()); //not "true" since that *forces* AO, i just want to *allow* AO } Sprite sprite = spriteLookup.apply(DEFAULT_SPRITE_MAIN); if(sprite == null) throw new IllegalStateException("Couldn't locate " + DEFAULT_SPRITE_MAIN + " !"); - this.default_appearance = new SingleSpriteAppearance(sprite, materialsWithoutAo.get(BlendMode.CUTOUT), serial_number.getAndIncrement()); + this.default_appearance = new SingleSpriteAppearance(sprite, materials.get(BlendMode.CUTOUT), serial_number.getAndIncrement()); sprite = spriteLookup.apply(DEFAULT_SPRITE_SECONDARY); if(sprite == null) throw new IllegalStateException("Couldn't locate " + DEFAULT_SPRITE_MAIN + " !"); - this.accent_appearance = new SingleSpriteAppearance(sprite, materialsWithoutAo.get(BlendMode.CUTOUT), serial_number.getAndIncrement()); + this.accent_appearance = new SingleSpriteAppearance(sprite, materials.get(BlendMode.CUTOUT), serial_number.getAndIncrement()); sprite = spriteLookup.apply(BARRIER_SPRITE_ID); - this.barrierItemAppearance = new SingleSpriteAppearance(sprite, materialsWithoutAo.get(BlendMode.CUTOUT), serial_number.getAndIncrement()); + this.barrierItemAppearance = new SingleSpriteAppearance(sprite, materials.get(BlendMode.CUTOUT), serial_number.getAndIncrement()); } protected static final SpriteIdentifier DEFAULT_SPRITE_MAIN = new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, new Identifier(ReFramed.MODID, "block/framed_block")); @@ -63,29 +67,41 @@ public class CamoAppearanceManager { private final CamoAppearance default_appearance; private final CamoAppearance accent_appearance; private final CamoAppearance barrierItemAppearance; - - private final ConcurrentHashMap appearanceCache = new ConcurrentHashMap<>(); //Mutable, append-only cache + + private static final Cache APPEARANCE_CACHE = CacheBuilder.newBuilder().maximumSize(2048).build(); + private final AtomicInteger serial_number = new AtomicInteger(0); //Mutable - private final EnumMap materialsWithAo = new EnumMap<>(BlendMode.class); - private final EnumMap materialsWithoutAo = new EnumMap<>(BlendMode.class); //Immutable contents + private final EnumMap ao_materials = new EnumMap<>(BlendMode.class); + private final EnumMap materials = new EnumMap<>(BlendMode.class); //Immutable contents public CamoAppearance getDefaultAppearance(int appearance) { return appearance == 2 ? accent_appearance: default_appearance; } - public CamoAppearance getCamoAppearance(BlockRenderView world, BlockState state, BlockPos pos, int theme_index) { + public CamoAppearance getCamoAppearance(BlockRenderView world, BlockState state, BlockPos pos, int theme_index, boolean item) { BakedModel model = MinecraftClient.getInstance().getBlockRenderManager().getModel(state); // add support for connected textures and more generally any compatible models injected so that they return baked quads if (model instanceof DynamicBakedModel dynamic_model) { - return computeAppearance(dynamic_model.computeQuads(world, state, pos, theme_index), state); + // cache items as they get rendered more often + if (item && APPEARANCE_CACHE.asMap().containsKey(state)) return APPEARANCE_CACHE.getIfPresent(state); + + CamoAppearance appearance = computeAppearance(dynamic_model.computeQuads(world, state, pos, theme_index), state); + if (item) APPEARANCE_CACHE.put(state, appearance); + return appearance; } - return appearanceCache.computeIfAbsent(state, block_state -> computeAppearance(model, block_state)); + + // refresh cache + if (APPEARANCE_CACHE.asMap().containsKey(state)) return APPEARANCE_CACHE.getIfPresent(state); + + CamoAppearance appearance = computeAppearance(model, state); + APPEARANCE_CACHE.put(state, appearance); + return appearance; } public RenderMaterial getCachedMaterial(BlockState state, boolean ao) { - Map m = ao ? materialsWithAo : materialsWithoutAo; + Map m = ao ? ao_materials : materials; return m.get(BlendMode.fromRenderLayer(RenderLayers.getBlockLayer(state))); } diff --git a/src/main/java/fr/adrien1106/reframed/client/model/apperance/ComputedAppearance.java b/src/main/java/fr/adrien1106/reframed/client/model/apperance/ComputedAppearance.java index 52ccee0..3918144 100644 --- a/src/main/java/fr/adrien1106/reframed/client/model/apperance/ComputedAppearance.java +++ b/src/main/java/fr/adrien1106/reframed/client/model/apperance/ComputedAppearance.java @@ -1,38 +1,30 @@ package fr.adrien1106.reframed.client.model.apperance; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial; import net.minecraft.util.math.Direction; import org.jetbrains.annotations.NotNull; import java.util.List; -public class ComputedAppearance implements CamoAppearance { +@Environment(EnvType.CLIENT) +public class ComputedAppearance extends CamoAppearance { private final Appearance appearance; - private final int id; - private final RenderMaterial matWithAo; - private final RenderMaterial matWithoutAo; - public ComputedAppearance(@NotNull Appearance appearance, RenderMaterial withAo, RenderMaterial withoutAo, int id) { + public ComputedAppearance(@NotNull Appearance appearance, RenderMaterial ao_material, RenderMaterial material, int id) { + super(ao_material, material, id); this.appearance = appearance; - this.id = id; - - this.matWithAo = withAo; - this.matWithoutAo = withoutAo; } @Override - public @NotNull RenderMaterial getRenderMaterial(boolean ao) { - return ao ? matWithAo : matWithoutAo; - } - - @Override - public @NotNull List getSprites(Direction dir, long seed) { + public @NotNull List getSprites(Direction dir, int model_id) { return appearance.sprites().get(dir); } @Override - public boolean hasColor(Direction dir, long seed, int index) { - List properties = getSprites(dir, seed); + public boolean hasColor(Direction dir, int model_id, int index) { + List properties = getSprites(dir, model_id); if (index != 0) index = properties.size() - index; return properties.get(index).has_colors(); } @@ -40,13 +32,7 @@ public class ComputedAppearance implements CamoAppearance { @Override public boolean equals(Object o) { if(this == o) return true; - if(o == null || getClass() != o.getClass()) return false; - ComputedAppearance that = (ComputedAppearance) o; + if(!(o instanceof ComputedAppearance that)) return false; return id == that.id; } - - @Override - public int hashCode() { - return id; - } } diff --git a/src/main/java/fr/adrien1106/reframed/client/model/apperance/SingleSpriteAppearance.java b/src/main/java/fr/adrien1106/reframed/client/model/apperance/SingleSpriteAppearance.java index d62e38f..9c8054a 100644 --- a/src/main/java/fr/adrien1106/reframed/client/model/apperance/SingleSpriteAppearance.java +++ b/src/main/java/fr/adrien1106/reframed/client/model/apperance/SingleSpriteAppearance.java @@ -1,5 +1,7 @@ package fr.adrien1106.reframed.client.model.apperance; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial; import net.minecraft.client.texture.Sprite; import net.minecraft.util.math.Direction; @@ -7,47 +9,34 @@ import org.jetbrains.annotations.NotNull; import java.util.List; -public class SingleSpriteAppearance implements CamoAppearance { +@Environment(EnvType.CLIENT) +public class SingleSpriteAppearance extends CamoAppearance { private final @NotNull Sprite defaultSprite; - private final RenderMaterial mat; - private final int id; public SingleSpriteAppearance(@NotNull Sprite defaultSprite, RenderMaterial mat, int id) { + super(null, mat, id); this.defaultSprite = defaultSprite; - this.mat = mat; - this.id = id; } @Override - public @NotNull RenderMaterial getRenderMaterial(boolean ao) { - return mat; - } - - @Override - public @NotNull List getSprites(Direction dir, long seed) { + public @NotNull List getSprites(Direction dir, int model_id) { return List.of(new SpriteProperties(defaultSprite, 0, null, false)); } @Override - public boolean hasColor(Direction dir, long seed, int index) { + public boolean hasColor(Direction dir, int model_id, int index) { return false; } @Override public boolean equals(Object o) { if(this == o) return true; - if(o == null || getClass() != o.getClass()) return false; - SingleSpriteAppearance that = (SingleSpriteAppearance) o; + if(!(o instanceof SingleSpriteAppearance that)) return false; return id == that.id; } - @Override - public int hashCode() { - return id; - } - @Override public String toString() { - return "SingleSpriteAppearance[defaultSprite=%s, mat=%s, id=%d]".formatted(defaultSprite, mat, id); + return "SingleSpriteAppearance[defaultSprite=%s, mat=%s, id=%d]".formatted(defaultSprite, material, id); } } diff --git a/src/main/java/fr/adrien1106/reframed/client/model/apperance/WeightedComputedAppearance.java b/src/main/java/fr/adrien1106/reframed/client/model/apperance/WeightedComputedAppearance.java index 4751711..443dd92 100644 --- a/src/main/java/fr/adrien1106/reframed/client/model/apperance/WeightedComputedAppearance.java +++ b/src/main/java/fr/adrien1106/reframed/client/model/apperance/WeightedComputedAppearance.java @@ -1,5 +1,7 @@ package fr.adrien1106.reframed.client.model.apperance; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial; import net.minecraft.util.collection.Weighted; import net.minecraft.util.collection.Weighting; @@ -9,25 +11,15 @@ import org.jetbrains.annotations.NotNull; import java.util.List; -public class WeightedComputedAppearance implements CamoAppearance { +@Environment(EnvType.CLIENT) +public class WeightedComputedAppearance extends CamoAppearance { private final List> appearances; private final int total_weight; - private final int id; - private final RenderMaterial matWithAo; - private final RenderMaterial matWithoutAo; - public WeightedComputedAppearance(@NotNull List> appearances, RenderMaterial withAo, RenderMaterial withoutAo, int id) { + public WeightedComputedAppearance(@NotNull List> appearances, RenderMaterial ao_material, RenderMaterial material, int id) { + super(ao_material, material, id); this.appearances = appearances; this.total_weight = Weighting.getWeightSum(appearances); - this.id = id; - - this.matWithAo = withAo; - this.matWithoutAo = withoutAo; - } - - @Override - public @NotNull RenderMaterial getRenderMaterial(boolean ao) { - return ao ? matWithAo : matWithoutAo; } @@ -37,21 +29,19 @@ public class WeightedComputedAppearance implements CamoAppearance { .map(appearances::indexOf).orElse(0); } - private Appearance getAppearance(long seed) { - Random random = Random.create(seed); - return Weighting.getAt(appearances, Math.abs((int)random.nextLong()) % total_weight) - .map(Weighted.Present::getData).get(); + private Appearance getAppearance(int model_id) { + return appearances.get(model_id).getData(); } @Override - public @NotNull List getSprites(Direction dir, long seed) { - return getAppearance(seed).sprites().get(dir); + public @NotNull List getSprites(Direction dir, int model_id) { + return getAppearance(model_id).sprites().get(dir); } @Override - public boolean hasColor(Direction dir, long seed, int index) { - List properties = getSprites(dir, seed); + public boolean hasColor(Direction dir, int model_id, int index) { + List properties = getSprites(dir, model_id); if (index != 0) index = properties.size() - index; return properties.get(index).has_colors(); } @@ -59,13 +49,7 @@ public class WeightedComputedAppearance implements CamoAppearance { @Override public boolean equals(Object o) { if(this == o) return true; - if(o == null || getClass() != o.getClass()) return false; - WeightedComputedAppearance that = (WeightedComputedAppearance) o; + if(!(o instanceof WeightedComputedAppearance that)) return false; return id == that.id; } - - @Override - public int hashCode() { - return id; - } } diff --git a/src/main/java/fr/adrien1106/reframed/generator/GLanguage.java b/src/main/java/fr/adrien1106/reframed/generator/GLanguage.java index 61dc3fb..d9270fb 100644 --- a/src/main/java/fr/adrien1106/reframed/generator/GLanguage.java +++ b/src/main/java/fr/adrien1106/reframed/generator/GLanguage.java @@ -17,9 +17,7 @@ public class GLanguage extends FabricLanguageProvider { public void generateTranslations(TranslationBuilder builder) { builder.add(Registries.ITEM_GROUP.getKey(ReFramed.ITEM_GROUP).get(), "Frames"); builder.add("advancements.reframed.description", "Get all the frame types."); - ReFramed.BLOCKS.forEach(block -> { - builder.add(block, beautify(Registries.BLOCK.getId(block).getPath()) + " Frame"); - }); + ReFramed.BLOCKS.forEach(block -> builder.add(block, beautify(Registries.BLOCK.getId(block).getPath()) + " Frame")); } private static String beautify(String name) { diff --git a/src/main/java/fr/adrien1106/reframed/mixin/BlockItemMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/BlockItemMixin.java index 6db8bd1..7e081da 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/BlockItemMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/BlockItemMixin.java @@ -11,9 +11,7 @@ import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtHelper; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @@ -23,8 +21,6 @@ import static fr.adrien1106.reframed.block.ReFramedEntity.BLOCKSTATE_KEY; @Mixin(BlockItem.class) public class BlockItemMixin { - @Shadow @Final @Deprecated private Block block; - @Inject( method = "writeNbtToBlockEntity", at = @At( @@ -41,6 +37,7 @@ public class BlockItemMixin { || !Block.isShapeFullCube(block.getBlock().getDefaultState().getCollisionShape(world, pos)) ) return; NbtCompound new_comp = new NbtCompound(); + player.getOffHandStack().decrement(1); new_comp.put(BLOCKSTATE_KEY + 1, NbtHelper.fromBlockState(block.getBlock().getDefaultState())); compound.set(new_comp); } diff --git a/src/main/java/fr/adrien1106/reframed/mixin/CompatMixinPlugin.java b/src/main/java/fr/adrien1106/reframed/mixin/CompatMixinPlugin.java index da1115b..a0a36a5 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/CompatMixinPlugin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/CompatMixinPlugin.java @@ -21,9 +21,11 @@ public class CompatMixinPlugin implements IMixinConfigPlugin { "fr.adrien1106.reframed.mixin.compat.AthenaBakedModelMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(0)), "fr.adrien1106.reframed.mixin.compat.AthenaWrappedGetterMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(0)), "fr.adrien1106.reframed.mixin.render.TerrainRenderContextMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)), - "fr.adrien1106.reframed.mixin.compat.IndiumTerrainRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)), "fr.adrien1106.reframed.mixin.render.BlockRenderInfoMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)), + "fr.adrien1106.reframed.mixin.render.AbstractBlockRenderContextMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)), + "fr.adrien1106.reframed.mixin.compat.IndiumTerrainRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)), "fr.adrien1106.reframed.mixin.compat.IndiumTerrainBlockRenderInfoMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)), + "fr.adrien1106.reframed.mixin.compat.IndiumAbstractBlockRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)), "fr.adrien1106.reframed.mixin.compat.SodiumBlockOcclusionCacheMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(2)) ); diff --git a/src/main/java/fr/adrien1106/reframed/mixin/compat/AthenaBakedModelMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/compat/AthenaBakedModelMixin.java index ba6833d..2bbcb90 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/compat/AthenaBakedModelMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/compat/AthenaBakedModelMixin.java @@ -6,7 +6,7 @@ import earth.terrarium.athena.api.client.models.AthenaBlockModel; import fr.adrien1106.reframed.client.ReFramedClient; import fr.adrien1106.reframed.client.model.DynamicBakedModel; import fr.adrien1106.reframed.compat.RebakedAthenaModel; -import fr.adrien1106.reframed.util.ThemeableBlockEntity; +import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.fabricmc.fabric.api.renderer.v1.Renderer; import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView; @@ -56,8 +56,7 @@ public abstract class AthenaBakedModelMixin implements DynamicBakedModel, BakedM level.getBlockEntity(pos) instanceof ThemeableBlockEntity framed_entity ? framed_entity.getTheme(theme_index) : state, pos, direction) - ) - .forEach(sprite -> face_quads.computeIfPresent(direction, (d, quads) -> { + ).forEach(sprite -> face_quads.computeIfPresent(direction, (d, quads) -> { Sprite texture = textures.get(sprite.sprite()); if (texture == null) return quads; emitter.square(direction, sprite.left(), sprite.bottom(), sprite.right(), sprite.top(), sprite.depth()); diff --git a/src/main/java/fr/adrien1106/reframed/mixin/compat/AthenaConnectedBlockModelMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/compat/AthenaConnectedBlockModelMixin.java index efc633b..ce1e96c 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/compat/AthenaConnectedBlockModelMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/compat/AthenaConnectedBlockModelMixin.java @@ -3,7 +3,7 @@ package fr.adrien1106.reframed.mixin.compat; import earth.terrarium.athena.api.client.utils.AppearanceAndTintGetter; import earth.terrarium.athena.api.client.utils.CtmUtils; import earth.terrarium.athena.impl.client.models.ConnectedBlockModel; -import fr.adrien1106.reframed.util.ThemeableBlockEntity; +import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity; import net.minecraft.block.BlockState; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; diff --git a/src/main/java/fr/adrien1106/reframed/mixin/compat/AthenaWrappedGetterMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/compat/AthenaWrappedGetterMixin.java index 73e1ea7..bb31415 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/compat/AthenaWrappedGetterMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/compat/AthenaWrappedGetterMixin.java @@ -2,7 +2,7 @@ package fr.adrien1106.reframed.mixin.compat; import com.llamalad7.mixinextras.sugar.Local; import earth.terrarium.athena.api.client.fabric.WrappedGetter; -import fr.adrien1106.reframed.util.ThemeableBlockEntity; +import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity; import net.minecraft.block.BlockState; import net.minecraft.util.math.BlockPos; import net.minecraft.world.BlockRenderView; diff --git a/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumAbstractBlockRenderContextMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumAbstractBlockRenderContextMixin.java new file mode 100644 index 0000000..e9d2f43 --- /dev/null +++ b/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumAbstractBlockRenderContextMixin.java @@ -0,0 +1,29 @@ +package fr.adrien1106.reframed.mixin.compat; + +import com.llamalad7.mixinextras.sugar.Local; +import fr.adrien1106.reframed.util.blocks.BlockHelper; +import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin; +import link.infra.indium.renderer.mesh.MutableQuadViewImpl; +import link.infra.indium.renderer.render.AbstractBlockRenderContext; +import link.infra.indium.renderer.render.BlockRenderInfo; +import net.minecraft.util.math.Direction; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(AbstractBlockRenderContext.class) +public abstract class IndiumAbstractBlockRenderContextMixin { + + @Shadow(remap = false) protected BlockRenderInfo blockInfo; + + @Shadow public abstract boolean isFaceCulled(@Nullable Direction face); + + @Redirect(method = "renderQuad", at = @At(value = "INVOKE", target = "Llink/infra/indium/renderer/render/AbstractBlockRenderContext;isFaceCulled(Lnet/minecraft/util/math/Direction;)Z")) + private boolean shouldDrawInnerQuad(AbstractBlockRenderContext instance, Direction face, @Local(argsOnly = true) MutableQuadViewImpl quad) { + if (face != null || quad.tag() == 0 || !(blockInfo instanceof IBlockRenderInfoMixin info) || info.getThemeIndex() == 0) return isFaceCulled(face); + + return !BlockHelper.shouldDrawInnerFace(blockInfo.blockState, blockInfo.blockView, blockInfo.blockPos, quad.tag() >>> 8, info.getThemeIndex()); + } +} diff --git a/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumTerrainBlockRenderInfoMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumTerrainBlockRenderInfoMixin.java index 4f6ec46..1fef1c3 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumTerrainBlockRenderInfoMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumTerrainBlockRenderInfoMixin.java @@ -1,8 +1,8 @@ package fr.adrien1106.reframed.mixin.compat; -import fr.adrien1106.reframed.util.BlockHelper; -import fr.adrien1106.reframed.util.IBlockRenderInfoMixin; -import fr.adrien1106.reframed.util.ThemeableBlockEntity; +import fr.adrien1106.reframed.util.blocks.BlockHelper; +import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin; +import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity; import link.infra.indium.renderer.render.BlockRenderInfo; import link.infra.indium.renderer.render.TerrainBlockRenderInfo; import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockOcclusionCache; @@ -18,7 +18,7 @@ import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(TerrainBlockRenderInfo.class) public abstract class IndiumTerrainBlockRenderInfoMixin extends BlockRenderInfo implements IBlockRenderInfoMixin { - @Unique private int theme_index = 1; + @Unique private int theme_index = 0; @Redirect( method = "shouldDrawFaceInner", @@ -40,4 +40,9 @@ public abstract class IndiumTerrainBlockRenderInfoMixin extends BlockRenderInfo this.theme_index = theme_index; prepareForBlock(blockState, blockPos, seed, modelAo); } + + @Override + public int getThemeIndex() { + return theme_index; + } } diff --git a/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumTerrainRenderContextMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumTerrainRenderContextMixin.java index c7ebd61..42c5534 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumTerrainRenderContextMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/compat/IndiumTerrainRenderContextMixin.java @@ -1,11 +1,13 @@ package fr.adrien1106.reframed.mixin.compat; import fr.adrien1106.reframed.client.model.MultiRetexturableModel; -import fr.adrien1106.reframed.util.IBlockRenderInfoMixin; -import fr.adrien1106.reframed.util.IMultipartBakedModelMixin; +import fr.adrien1106.reframed.util.blocks.BlockHelper; +import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin; +import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin; import link.infra.indium.renderer.render.AbstractBlockRenderContext; import link.infra.indium.renderer.render.TerrainRenderContext; import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderContext; +import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel; import net.minecraft.client.render.model.BakedModel; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -29,13 +31,14 @@ public abstract class IndiumTerrainRenderContextMixin extends AbstractBlockRende if (!(ctx.model() instanceof IMultipartBakedModelMixin wrapped) || !(wrapped.getModel(ctx.state()) instanceof MultiRetexturableModel retexturing_model)) return; - List models = retexturing_model.models(); + List models = retexturing_model.models(); + BlockHelper.computeInnerCull(ctx.state(), models); int i = 0; - for (BakedModel bakedModel : models) { + for (BakedModel model : models) { i++; aoCalc.clear(); - ((IBlockRenderInfoMixin) blockInfo).prepareForBlock(ctx.state(), ctx.pos(), ctx.seed(), bakedModel.useAmbientOcclusion(), i); - bakedModel.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this); + ((IBlockRenderInfoMixin) blockInfo).prepareForBlock(ctx.state(), ctx.pos(), ctx.seed(), model.useAmbientOcclusion(), i); + model.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this); } ci.cancel(); } diff --git a/src/main/java/fr/adrien1106/reframed/mixin/compat/SodiumBlockOcclusionCacheMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/compat/SodiumBlockOcclusionCacheMixin.java index 437f8a7..3e6c28d 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/compat/SodiumBlockOcclusionCacheMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/compat/SodiumBlockOcclusionCacheMixin.java @@ -1,8 +1,8 @@ package fr.adrien1106.reframed.mixin.compat; import com.llamalad7.mixinextras.sugar.Local; -import fr.adrien1106.reframed.util.BlockHelper; -import fr.adrien1106.reframed.util.ThemeableBlockEntity; +import fr.adrien1106.reframed.util.blocks.BlockHelper; +import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity; import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockOcclusionCache; import net.minecraft.block.BlockState; import net.minecraft.util.math.BlockPos; diff --git a/src/main/java/fr/adrien1106/reframed/mixin/particles/MixinBlockDustParticle.java b/src/main/java/fr/adrien1106/reframed/mixin/particles/MixinBlockDustParticle.java index 5348a91..95e03c0 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/particles/MixinBlockDustParticle.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/particles/MixinBlockDustParticle.java @@ -1,7 +1,7 @@ package fr.adrien1106.reframed.mixin.particles; import fr.adrien1106.reframed.block.ReFramedBlock; -import fr.adrien1106.reframed.util.ThemeableBlockEntity; +import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity; import net.minecraft.block.BlockState; import net.minecraft.client.MinecraftClient; import net.minecraft.client.particle.BlockDustParticle; diff --git a/src/main/java/fr/adrien1106/reframed/mixin/particles/MixinEntity.java b/src/main/java/fr/adrien1106/reframed/mixin/particles/MixinEntity.java index bbba8fb..bb1afd1 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/particles/MixinEntity.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/particles/MixinEntity.java @@ -2,7 +2,7 @@ package fr.adrien1106.reframed.mixin.particles; import com.llamalad7.mixinextras.sugar.Local; import fr.adrien1106.reframed.block.ReFramedBlock; -import fr.adrien1106.reframed.util.ThemeableBlockEntity; +import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity; import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; import net.minecraft.util.math.BlockPos; diff --git a/src/main/java/fr/adrien1106/reframed/mixin/particles/MixinLivingEntity.java b/src/main/java/fr/adrien1106/reframed/mixin/particles/MixinLivingEntity.java index d19193f..13dba79 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/particles/MixinLivingEntity.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/particles/MixinLivingEntity.java @@ -2,7 +2,7 @@ package fr.adrien1106.reframed.mixin.particles; import com.llamalad7.mixinextras.sugar.Local; import fr.adrien1106.reframed.block.ReFramedBlock; -import fr.adrien1106.reframed.util.ThemeableBlockEntity; +import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity; import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; diff --git a/src/main/java/fr/adrien1106/reframed/mixin/render/AbstractBlockRenderContextMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/render/AbstractBlockRenderContextMixin.java new file mode 100644 index 0000000..6d02c28 --- /dev/null +++ b/src/main/java/fr/adrien1106/reframed/mixin/render/AbstractBlockRenderContextMixin.java @@ -0,0 +1,36 @@ +package fr.adrien1106.reframed.mixin.render; + +import com.llamalad7.mixinextras.sugar.Local; +import fr.adrien1106.reframed.util.blocks.BlockHelper; +import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin; +import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl; +import net.fabricmc.fabric.impl.client.indigo.renderer.render.AbstractBlockRenderContext; +import net.fabricmc.fabric.impl.client.indigo.renderer.render.BlockRenderInfo; +import net.minecraft.util.math.Direction; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(AbstractBlockRenderContext.class) +public abstract class AbstractBlockRenderContextMixin { + + @Shadow public abstract boolean isFaceCulled(@Nullable Direction face); + + @Shadow(remap = false) @Final protected BlockRenderInfo blockInfo; + + @Redirect( + method = "renderQuad", + at = @At( + value = "INVOKE", + target = "Lnet/fabricmc/fabric/impl/client/indigo/renderer/render/AbstractBlockRenderContext;isFaceCulled(Lnet/minecraft/util/math/Direction;)Z" + ) + ) + private boolean shouldDrawInnerQuad(AbstractBlockRenderContext instance, Direction face, @Local(argsOnly = true) MutableQuadViewImpl quad) { + if (face != null || quad.tag() == 0 || !(blockInfo instanceof IBlockRenderInfoMixin info) || info.getThemeIndex() == 0) return isFaceCulled(face); + + return !BlockHelper.shouldDrawInnerFace(blockInfo.blockState, blockInfo.blockView, blockInfo.blockPos, quad.tag() >>> 8, info.getThemeIndex()); + } +} diff --git a/src/main/java/fr/adrien1106/reframed/mixin/render/BlockRenderInfoMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/render/BlockRenderInfoMixin.java index 059fb1c..9a5485c 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/render/BlockRenderInfoMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/render/BlockRenderInfoMixin.java @@ -1,9 +1,9 @@ package fr.adrien1106.reframed.mixin.render; import com.llamalad7.mixinextras.sugar.Local; -import fr.adrien1106.reframed.util.BlockHelper; -import fr.adrien1106.reframed.util.IBlockRenderInfoMixin; -import fr.adrien1106.reframed.util.ThemeableBlockEntity; +import fr.adrien1106.reframed.util.blocks.BlockHelper; +import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin; +import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity; import net.fabricmc.fabric.impl.client.indigo.renderer.render.BlockRenderInfo; import net.minecraft.block.BlockState; import net.minecraft.block.entity.BlockEntity; @@ -24,8 +24,7 @@ public abstract class BlockRenderInfoMixin implements IBlockRenderInfoMixin { @Shadow public abstract void prepareForBlock(BlockState blockState, BlockPos blockPos, boolean modelAo); @Shadow public BlockRenderView blockView; - @Unique - private int theme_index = 1; + @Unique private int theme_index = 0; @ModifyArg(method = "prepareForBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/RenderLayers;" + @@ -47,4 +46,9 @@ public abstract class BlockRenderInfoMixin implements IBlockRenderInfoMixin { this.theme_index = theme_index; prepareForBlock(state, pos, ao); } + + @Override + public int getThemeIndex() { + return theme_index; + } } diff --git a/src/main/java/fr/adrien1106/reframed/mixin/render/MultipartBakedModelMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/render/MultipartBakedModelMixin.java index 86c1819..2183590 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/render/MultipartBakedModelMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/render/MultipartBakedModelMixin.java @@ -1,6 +1,6 @@ package fr.adrien1106.reframed.mixin.render; -import fr.adrien1106.reframed.util.IMultipartBakedModelMixin; +import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin; import net.minecraft.block.BlockState; import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.MultipartBakedModel; diff --git a/src/main/java/fr/adrien1106/reframed/mixin/render/TerrainRenderContextMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/render/TerrainRenderContextMixin.java index 18eac23..ddb93ef 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/render/TerrainRenderContextMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/render/TerrainRenderContextMixin.java @@ -1,8 +1,10 @@ package fr.adrien1106.reframed.mixin.render; import fr.adrien1106.reframed.client.model.MultiRetexturableModel; -import fr.adrien1106.reframed.util.IBlockRenderInfoMixin; -import fr.adrien1106.reframed.util.IMultipartBakedModelMixin; +import fr.adrien1106.reframed.util.blocks.BlockHelper; +import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin; +import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin; +import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel; import net.fabricmc.fabric.impl.client.indigo.renderer.render.AbstractBlockRenderContext; import net.fabricmc.fabric.impl.client.indigo.renderer.render.TerrainRenderContext; import net.minecraft.block.BlockState; @@ -28,13 +30,14 @@ public abstract class TerrainRenderContextMixin extends AbstractBlockRenderConte if (!(wrapper instanceof IMultipartBakedModelMixin wrapped) || !(wrapped.getModel(state) instanceof MultiRetexturableModel retexturing_model)) return; - List models = retexturing_model.models(); + List models = retexturing_model.models(); + BlockHelper.computeInnerCull(state, models); int i = 0; - for (BakedModel bakedModel : models) { + for (BakedModel model : models) { i++; aoCalc.clear(); - ((IBlockRenderInfoMixin) blockInfo).prepareForBlock(state, pos, bakedModel.useAmbientOcclusion(), i); - bakedModel.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this); + ((IBlockRenderInfoMixin) blockInfo).prepareForBlock(state, pos, model.useAmbientOcclusion(), i); + model.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this); } ci.cancel(); } diff --git a/src/main/java/fr/adrien1106/reframed/mixin/sound/BlockItemMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/sound/BlockItemMixin.java index 2ee7502..739adde 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/sound/BlockItemMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/sound/BlockItemMixin.java @@ -2,7 +2,7 @@ package fr.adrien1106.reframed.mixin.sound; import com.llamalad7.mixinextras.sugar.Local; import fr.adrien1106.reframed.block.ReFramedBlock; -import fr.adrien1106.reframed.util.ThemeableBlockEntity; +import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.item.BlockItem; diff --git a/src/main/java/fr/adrien1106/reframed/mixin/sound/EntityMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/sound/EntityMixin.java index d00f353..ab882df 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/sound/EntityMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/sound/EntityMixin.java @@ -2,7 +2,7 @@ package fr.adrien1106.reframed.mixin.sound; import com.llamalad7.mixinextras.sugar.Local; import fr.adrien1106.reframed.block.ReFramedBlock; -import fr.adrien1106.reframed.util.ThemeableBlockEntity; +import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.entity.Entity; diff --git a/src/main/java/fr/adrien1106/reframed/mixin/sound/LivingEntityMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/sound/LivingEntityMixin.java index 1d63f6a..ffcd7c9 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/sound/LivingEntityMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/sound/LivingEntityMixin.java @@ -1,7 +1,7 @@ package fr.adrien1106.reframed.mixin.sound; import fr.adrien1106.reframed.block.ReFramedBlock; -import fr.adrien1106.reframed.util.ThemeableBlockEntity; +import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.entity.LivingEntity; diff --git a/src/main/java/fr/adrien1106/reframed/mixin/sound/WorldRendererMixin.java b/src/main/java/fr/adrien1106/reframed/mixin/sound/WorldRendererMixin.java index 8d2b11d..7f22f6c 100644 --- a/src/main/java/fr/adrien1106/reframed/mixin/sound/WorldRendererMixin.java +++ b/src/main/java/fr/adrien1106/reframed/mixin/sound/WorldRendererMixin.java @@ -2,7 +2,7 @@ package fr.adrien1106.reframed.mixin.sound; import com.llamalad7.mixinextras.sugar.Local; import fr.adrien1106.reframed.block.ReFramedBlock; -import fr.adrien1106.reframed.util.ThemeableBlockEntity; +import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.client.render.WorldRenderer; diff --git a/src/main/java/fr/adrien1106/reframed/util/VoxelHelper.java b/src/main/java/fr/adrien1106/reframed/util/VoxelHelper.java index 885e552..ba4d0d8 100644 --- a/src/main/java/fr/adrien1106/reframed/util/VoxelHelper.java +++ b/src/main/java/fr/adrien1106/reframed/util/VoxelHelper.java @@ -5,68 +5,201 @@ import net.minecraft.util.math.Direction; import net.minecraft.util.shape.VoxelShape; import net.minecraft.util.shape.VoxelShapes; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; + +import static net.minecraft.util.shape.VoxelShapes.*; + public class VoxelHelper { + + /* ---------------------------------------- Methods for VoxelListBuilder ---------------------------------------- */ + public static VoxelShape rotateX(VoxelShape shape) { + return rotateClockwise(shape, Direction.Axis.X); + } + + public static VoxelShape rotateY(VoxelShape shape) { + return rotateClockwise(shape, Direction.Axis.Y); + } + public static VoxelShape rotateZ(VoxelShape shape) { + return rotateClockwise(shape, Direction.Axis.Z); + } + + public static VoxelShape rotateCX(VoxelShape shape) { + return rotateCounterClockwise(shape, Direction.Axis.X); + } + + public static VoxelShape rotateCY(VoxelShape shape) { + return rotateCounterClockwise(shape, Direction.Axis.Y); + } + public static VoxelShape rotateCZ(VoxelShape shape) { + return rotateCounterClockwise(shape, Direction.Axis.Z); + } + + public static VoxelShape mirrorX(VoxelShape shape) { + return mirror(shape, Direction.Axis.X); + } + + public static VoxelShape mirrorY(VoxelShape shape) { + return mirror(shape, Direction.Axis.Y); + } + public static VoxelShape mirrorZ(VoxelShape shape) { + return mirror(shape, Direction.Axis.Z); + } + public static VoxelShape rotateClockwise(VoxelShape shape, Direction.Axis axis) { - VoxelShape[] buffer = new VoxelShape[]{ shape, VoxelShapes.empty() }; - switch (axis) { - case Y: - buffer[0].forEachBox((minX, minY, minZ, maxX, maxY, maxZ) -> buffer[1] = VoxelShapes.combineAndSimplify( buffer[1], VoxelShapes.cuboid( 1 - maxZ, minY, minX, 1 - minZ, maxY, maxX), BooleanBiFunction.OR)); - break; - case X: - buffer[0].forEachBox((minX, minY, minZ, maxX, maxY, maxZ) -> buffer[1] = VoxelShapes.combineAndSimplify( buffer[1], VoxelShapes.cuboid( minX, 1 - maxZ, minY, maxX, 1 - minZ, maxY), BooleanBiFunction.OR)); - break; - case Z: - buffer[0].forEachBox((minX, minY, minZ, maxX, maxY, maxZ) -> buffer[1] = VoxelShapes.combineAndSimplify( buffer[1], VoxelShapes.cuboid( 1 - maxY, minX, minZ, 1 - minY, maxX, maxZ), BooleanBiFunction.OR)); - break; - } - return buffer[1]; + AtomicReference new_shape = new AtomicReference<>(empty()); + shape.forEachBox((minX, minY, minZ, maxX, maxY, maxZ) -> + new_shape.getAndUpdate(s -> + combineAndSimplify( + s, + switch (axis) { + case Y -> cuboid(1 - maxZ, minY, minX, 1 - minZ, maxY, maxX); + case X -> cuboid(minX, 1 - maxZ, minY, maxX, 1 - minZ, maxY); + case Z -> cuboid(1 - maxY, minX, minZ, 1 - minY, maxX, maxZ); + }, + BooleanBiFunction.OR + ) + ) + ); + return new_shape.get(); } public static VoxelShape rotateCounterClockwise(VoxelShape shape, Direction.Axis axis) { - VoxelShape[] buffer = new VoxelShape[]{ shape, VoxelShapes.empty() }; - switch (axis) { - case Y: - buffer[0].forEachBox((minX, minY, minZ, maxX, maxY, maxZ) -> buffer[1] = VoxelShapes.combineAndSimplify( buffer[1], VoxelShapes.cuboid( minZ, minY, 1 - maxX, maxZ, maxY, 1 - minX), BooleanBiFunction.OR)); - break; - case X: - buffer[0].forEachBox((minX, minY, minZ, maxX, maxY, maxZ) -> buffer[1] = VoxelShapes.combineAndSimplify( buffer[1], VoxelShapes.cuboid( minX, minZ, 1 - maxY, maxX, maxZ, 1 - minY), BooleanBiFunction.OR)); - break; - case Z: - buffer[0].forEachBox((minX, minY, minZ, maxX, maxY, maxZ) -> buffer[1] = VoxelShapes.combineAndSimplify( buffer[1], VoxelShapes.cuboid( minY, 1 - maxX, minZ, maxY, 1 - minX, maxZ), BooleanBiFunction.OR)); - break; - } - return buffer[1]; + AtomicReference new_shape = new AtomicReference<>(empty()); + shape.forEachBox((minX, minY, minZ, maxX, maxY, maxZ) -> + new_shape.getAndUpdate(s -> + combineAndSimplify( + s, + switch (axis) { + case Y -> cuboid(minZ, minY, 1 - maxX, maxZ, maxY, 1 - minX); + case X -> cuboid(minX, minZ, 1 - maxY, maxX, maxZ, 1 - minY); + case Z -> cuboid(minY, 1 - maxX, minZ, maxY, 1 - minX, maxZ); + }, + BooleanBiFunction.OR + ) + ) + ); + return new_shape.get(); } public static VoxelShape mirror(VoxelShape shape, Direction.Axis axis) { - VoxelShape[] buffer = new VoxelShape[]{ shape, VoxelShapes.empty() }; - switch (axis) { - case Y: - buffer[0].forEachBox((minX, minY, minZ, maxX, maxY, maxZ) -> buffer[1] = VoxelShapes.combineAndSimplify( buffer[1], VoxelShapes.cuboid( minX, 1 - maxY, minZ, maxX, 1 - minY, maxZ), BooleanBiFunction.OR)); - break; - case X: - buffer[0].forEachBox((minX, minY, minZ, maxX, maxY, maxZ) -> buffer[1] = VoxelShapes.combineAndSimplify( buffer[1], VoxelShapes.cuboid( 1 - maxX, minY, minZ, 1 - minX, maxY, maxZ), BooleanBiFunction.OR)); - break; - case Z: - buffer[0].forEachBox((minX, minY, minZ, maxX, maxY, maxZ) -> buffer[1] = VoxelShapes.combineAndSimplify( buffer[1], VoxelShapes.cuboid( minX, minY, 1 - maxZ, maxX, maxY, 1 - minZ), BooleanBiFunction.OR)); - break; - } - return buffer[1]; + AtomicReference new_shape = new AtomicReference<>(empty()); + shape.forEachBox((minX, minY, minZ, maxX, maxY, maxZ) -> + new_shape.getAndUpdate(s -> + combineAndSimplify( + s, + switch (axis) { + case Y -> cuboid(minX, 1 - maxY, minZ, maxX, 1 - minY, maxZ); + case X -> cuboid(1 - maxX, minY, minZ, 1 - minX, maxY, maxZ); + case Z -> cuboid(minX, minY, 1 - maxZ, maxX, maxY, 1 - minZ); + }, + BooleanBiFunction.OR + ) + ) + ); + return new_shape.get(); } public static VoxelShape offset(VoxelShape shape, Direction.Axis axis, float offset) { - VoxelShape[] buffer = new VoxelShape[]{ shape, VoxelShapes.empty() }; - switch (axis) { - case Y: - buffer[0].forEachBox((minX, minY, minZ, maxX, maxY, maxZ) -> buffer[1] = VoxelShapes.combineAndSimplify( buffer[1], VoxelShapes.cuboid( minX, offset + minY, minZ, maxX, offset + maxY, maxZ), BooleanBiFunction.OR)); - break; - case X: - buffer[0].forEachBox((minX, minY, minZ, maxX, maxY, maxZ) -> buffer[1] = VoxelShapes.combineAndSimplify( buffer[1], VoxelShapes.cuboid( offset + minX, minY, minZ, offset + maxX, maxY, maxZ), BooleanBiFunction.OR)); - break; - case Z: - buffer[0].forEachBox((minX, minY, minZ, maxX, maxY, maxZ) -> buffer[1] = VoxelShapes.combineAndSimplify( buffer[1], VoxelShapes.cuboid( minX, minY, offset + minZ, maxX, maxY, offset + maxZ), BooleanBiFunction.OR)); - break; + AtomicReference new_shape = new AtomicReference<>(empty()); + shape.forEachBox((minX, minY, minZ, maxX, maxY, maxZ) -> + new_shape.getAndUpdate(s -> + combineAndSimplify( + s, + switch (axis) { + case Y -> cuboid(minX, offset + minY, minZ, maxX, offset + maxY, maxZ); + case X -> cuboid(offset + minX, minY, minZ, offset + maxX, maxY, maxZ); + case Z -> cuboid(minX, minY, offset + minZ, maxX, maxY, offset + maxZ); + }, + BooleanBiFunction.OR + ) + ) + ); + return new_shape.get(); + } + + public static class VoxelListBuilder { + private final List voxels; + + /** + * A simple class that helps to get cleaner shape list generation (Hopefully) + * @param base_shape - the shape to start with + * @param size - the amount of shapes expected + */ + private VoxelListBuilder(VoxelShape base_shape, int size) { + voxels = new ArrayList<>(size); + voxels.add(base_shape); + } + + public static VoxelListBuilder create(VoxelShape base_shape, int size) { + return new VoxelListBuilder(base_shape, size); + } + + /** + * Add shape by applying modification to previous shape + * @param modifications - the modifications to apply @See {@link VoxelHelper} methods + * @return this instance + */ + @SafeVarargs + public final VoxelListBuilder add(Function... modifications) { + return add(voxels.size() - 1, modifications); + } + + /** + * Add shape by applying modifications to given shape + * @param ref - the index of the reference shape + * @param modifications - the modifications to apply @See {@link VoxelHelper} methods + * @return this instance + */ + @SafeVarargs + public final VoxelListBuilder add(int ref, Function... modifications) { + return add(voxels.get(ref), modifications); + } + + /** + * Add shape by applying modifications to given shape + * @param ref - the shape you want to add and apply modifications if present + * @param modifications - the modifications to apply @See {@link VoxelHelper} methods + * @return this instance + */ + @SafeVarargs + public final VoxelListBuilder add(VoxelShape ref, Function... modifications) { + for(Function modif: modifications) { + ref = modif.apply(ref); + } + voxels.add(ref); + return this; + } + + /** + * @return the final array of voxel shapes + */ + public VoxelShape[] build() { + return voxels.toArray(new VoxelShape[0]); + } + + /** + * build a new set of voxels based on th negation of the references and a full cube + * @param ref_voxels - the reference to subtract from the wanted shape + * @return the array of complementary voxels + */ + public static VoxelShape[] buildFrom(VoxelShape[] ref_voxels) { + return buildFrom(VoxelShapes.fullCube(), ref_voxels); + } + + /** + * build a new set of voxels based on th negation of the references and a wanted_shape + * @param ref_voxels - the reference to subtract from the wanted shape + * @return the array of complementary voxels + */ + public static VoxelShape[] buildFrom(VoxelShape wanted_shape, VoxelShape[] ref_voxels) { + VoxelShape[] shapes = new VoxelShape[ref_voxels.length]; + for (int i = 0; i < shapes.length; i++) { + shapes[i] = VoxelShapes.combineAndSimplify(wanted_shape, ref_voxels[i], BooleanBiFunction.ONLY_FIRST); + } + return shapes; } - return buffer[1]; } } diff --git a/src/main/java/fr/adrien1106/reframed/util/BlockHelper.java b/src/main/java/fr/adrien1106/reframed/util/blocks/BlockHelper.java similarity index 63% rename from src/main/java/fr/adrien1106/reframed/util/BlockHelper.java rename to src/main/java/fr/adrien1106/reframed/util/blocks/BlockHelper.java index ca18ffb..df7037d 100644 --- a/src/main/java/fr/adrien1106/reframed/util/BlockHelper.java +++ b/src/main/java/fr/adrien1106/reframed/util/blocks/BlockHelper.java @@ -1,9 +1,19 @@ -package fr.adrien1106.reframed.util; +package fr.adrien1106.reframed.util.blocks; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import fr.adrien1106.reframed.block.ReFramedBlock; import fr.adrien1106.reframed.block.ReFramedEntity; -import fr.adrien1106.reframed.util.property.Corner; -import fr.adrien1106.reframed.util.property.StairShape; +import fr.adrien1106.reframed.block.ReFramedStairBlock; +import fr.adrien1106.reframed.block.ReFramedStairsCubeBlock; +import fr.adrien1106.reframed.client.ReFramedClient; +import fr.adrien1106.reframed.client.model.QuadPosBounds; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.renderer.v1.Renderer; +import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial; +import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter; +import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel; import net.minecraft.block.Block; import net.minecraft.block.BlockEntityProvider; import net.minecraft.block.BlockState; @@ -14,42 +24,56 @@ import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvents; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; +import net.minecraft.util.Pair; import net.minecraft.util.function.BooleanBiFunction; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.random.Random; import net.minecraft.util.shape.VoxelShape; import net.minecraft.util.shape.VoxelShapes; +import net.minecraft.world.BlockRenderView; import net.minecraft.world.BlockView; import net.minecraft.world.World; -import java.util.Arrays; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; -import static fr.adrien1106.reframed.util.BlockProperties.CORNER; -import static fr.adrien1106.reframed.util.BlockProperties.LIGHT; -import static fr.adrien1106.reframed.util.property.StairShape.*; +import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE; +import static fr.adrien1106.reframed.util.blocks.BlockProperties.LIGHT; +import static fr.adrien1106.reframed.util.blocks.StairShape.*; import static net.minecraft.util.shape.VoxelShapes.combine; public class BlockHelper { + // self culling cache of the models not made thread local so that it is only computed once + private static final Cache INNER_CULL_MAP = CacheBuilder.newBuilder().maximumSize(1024).build(); + private record CullElement(Block block, Object state_key, int model) {} + public static Corner getPlacementCorner(ItemPlacementContext ctx) { + Direction side = ctx.getSide().getOpposite(); + Vec3d pos = getHitPos(ctx.getHitPos(), ctx.getBlockPos()); + Pair sides = getHitSides(pos, side); + + return Corner.getByDirections(side, sides.getLeft(), sides.getRight()); + } + + private static Pair getHitSides(Vec3d pos, Direction side) { + Iterator axes = Stream.of(Direction.Axis.values()) + .filter(axis -> !axis.equals(side.getAxis())).iterator(); + return new Pair<>(getHitDirection(axes.next(), pos), getHitDirection(axes.next(), pos)); + } + + public static Edge getPlacementEdge(ItemPlacementContext ctx) { Direction side = ctx.getSide().getOpposite(); Vec3d pos = getHitPos(ctx.getHitPos(), ctx.getBlockPos()); Direction.Axis axis = getHitAxis(pos, side); - Direction part_direction = Direction.from( - axis, - axis.choose(pos.x, pos.y, pos.z) > 0 - ? Direction.AxisDirection.POSITIVE - : Direction.AxisDirection.NEGATIVE - ); + Direction part_direction = getHitDirection(axis, pos); - return Corner.getByDirections(side, part_direction); + return Edge.getByDirections(side, part_direction); } public static Direction.Axis getHitAxis(Vec3d pos, Direction side) { @@ -58,7 +82,16 @@ public class BlockHelper { Math.abs(axis_1.choose(pos.x, pos.y, pos.z)) > Math.abs(axis_2.choose(pos.x, pos.y, pos.z)) ? axis_1 : axis_2 - ).get(); + ).orElse(null); + } + + public static Direction getHitDirection(Direction.Axis axis, Vec3d pos) { + return Direction.from( + axis, + axis.choose(pos.x, pos.y, pos.z) > 0 + ? Direction.AxisDirection.POSITIVE + : Direction.AxisDirection.NEGATIVE + ); } public static Vec3d getRelativePos(Vec3d pos, BlockPos block_pos) { @@ -78,28 +111,28 @@ public class BlockHelper { ); } - public static StairShape getStairsShape(Block block, Corner face, BlockView world, BlockPos pos) { + public static StairShape getStairsShape(Edge face, BlockView world, BlockPos pos) { StairShape shape = STRAIGHT; - String sol = getNeighborPos(face, face.getFirstDirection(), true, face.getSecondDirection(), world, pos, block); + String sol = getNeighborPos(face, face.getFirstDirection(), true, face.getSecondDirection(), world, pos); switch (sol) { case "right": return INNER_RIGHT; case "left": return INNER_LEFT; } - sol = getNeighborPos(face, face.getSecondDirection(), true, face.getFirstDirection(), world, pos, block); + sol = getNeighborPos(face, face.getSecondDirection(), true, face.getFirstDirection(), world, pos); switch (sol) { case "right": return INNER_RIGHT; case "left": return INNER_LEFT; } - sol = getNeighborPos(face, face.getFirstDirection(), false, face.getSecondDirection(), world, pos, block); + sol = getNeighborPos(face, face.getFirstDirection(), false, face.getSecondDirection(), world, pos); switch (sol) { case "right" -> shape = FIRST_OUTER_RIGHT; case "left" -> shape = FIRST_OUTER_LEFT; } - sol = getNeighborPos(face, face.getSecondDirection(), false, face.getFirstDirection(), world, pos, block); + sol = getNeighborPos(face, face.getSecondDirection(), false, face.getFirstDirection(), world, pos); switch (sol) { case "right" -> { if (shape.equals(STRAIGHT)) shape = SECOND_OUTER_RIGHT; @@ -114,18 +147,23 @@ public class BlockHelper { return shape; } - public static String getNeighborPos(Corner face, Direction direction, Boolean reverse, Direction reference, BlockView world, BlockPos pos, Block block) { + public static String getNeighborPos(Edge face, Direction direction, Boolean reverse, Direction reference, BlockView world, BlockPos pos) { BlockState block_state = world.getBlockState( pos.offset(reverse ? direction.getOpposite() : direction) ); - if (block_state.isOf(block) && block_state.get(CORNER).hasDirection(reference)) { - if (block_state.get(CORNER).hasDirection(face.getLeftDirection())) return "left"; - else if (block_state.get(CORNER).hasDirection(face.getRightDirection())) return "right"; + 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"; } return ""; } + public static boolean isStair(BlockState state) { + return state.getBlock() instanceof ReFramedStairBlock + || state.getBlock() instanceof ReFramedStairsCubeBlock; + } + public static ActionResult useCamo(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit, int theme_index) { if(!(world.getBlockEntity(pos) instanceof ReFramedEntity block_entity)) return ActionResult.PASS; @@ -141,17 +179,18 @@ public class BlockHelper { // check for default light emission if (placement_state.getLuminance() > 0 - && themes.stream().noneMatch(theme -> theme.getLuminance() > 0)) - if (block_entity.emitsLight()) Block.dropStack(world, pos, new ItemStack(Items.GLOWSTONE_DUST)); - else block_entity.toggleLight(); + && themes.stream().noneMatch(theme -> theme.getLuminance() > 0) + && !block_entity.emitsLight() + ) + block_entity.toggleLight(); world.setBlockState(pos, state.with(LIGHT, block_entity.emitsLight())); // check for default redstone emission if (placement_state.getWeakRedstonePower(world, pos, Direction.NORTH) > 0 - && themes.stream().noneMatch(theme -> theme.getWeakRedstonePower(world, pos, Direction.NORTH) > 0)) - if (block_entity.emitsRedstone()) Block.dropStack(world, pos, new ItemStack(Items.GLOWSTONE_DUST)); - else block_entity.toggleRedstone(); + && themes.stream().noneMatch(theme -> theme.getWeakRedstonePower(world, pos, Direction.NORTH) > 0) + && !block_entity.emitsRedstone() + ) block_entity.toggleRedstone(); if(!player.isCreative()) held.decrement(1); world.playSound(player, pos, placement_state.getSoundGroup().getPlaceSound(), SoundCategory.BLOCKS, 1f, 1.1f); @@ -172,10 +211,6 @@ public class BlockHelper { if(state.contains(LIGHT) && held.getItem() == Items.GLOWSTONE_DUST) { block_entity.toggleLight(); world.setBlockState(pos, state.with(LIGHT, block_entity.emitsLight())); - - if(!player.isCreative()) - if (block_entity.emitsLight()) held.decrement(1); - else held.increment(1); world.playSound(player, pos, SoundEvents.BLOCK_GLASS_HIT, SoundCategory.BLOCKS, 1f, 1f); return ActionResult.SUCCESS; } @@ -183,10 +218,6 @@ public class BlockHelper { // frame will emit redstone if applied with redstone torch can deactivate redstone block camo emission if(held.getItem() == Items.REDSTONE_TORCH && ext.canAddRedstoneEmission(state, world, pos)) { block_entity.toggleRedstone(); - - if(!player.isCreative()) - if (block_entity.emitsRedstone()) held.decrement(1); - else held.increment(1); world.playSound(player, pos, SoundEvents.BLOCK_LEVER_CLICK, SoundCategory.BLOCKS, 1f, 1f); return ActionResult.SUCCESS; } @@ -194,10 +225,6 @@ public class BlockHelper { // Frame will lose its collision if applied with popped chorus fruit if(held.getItem() == Items.POPPED_CHORUS_FRUIT && ext.canRemoveCollision(state, world, pos)) { block_entity.toggleSolidity(); - - if(!player.isCreative()) - if (!block_entity.isSolid()) held.decrement(1); - else held.increment(1); world.playSound(player, pos, SoundEvents.ITEM_CHORUS_FRUIT_TELEPORT, SoundCategory.BLOCKS, 1f, 1f); return ActionResult.SUCCESS; } @@ -205,7 +232,70 @@ public class BlockHelper { return ActionResult.PASS; } + /** + * compute which quad might cull with another model quad + * @param state - the state of the model + * @param models - list of models on the same block + */ + @Environment(EnvType.CLIENT) + public static void computeInnerCull(BlockState state, List models) { + if (!(state.getBlock() instanceof ReFramedBlock frame_block)) return; + Object key = frame_block.getModelCacheKey(state); + if (INNER_CULL_MAP.asMap().containsKey(new CullElement(frame_block, key, 1))) return; + + Renderer r = ReFramedClient.HELPER.getFabricRenderer(); + QuadEmitter quad_emitter = r.meshBuilder().getEmitter(); + RenderMaterial material = r.materialFinder().clear().find(); + Random random = Random.create(); + + List> model_bounds = models.stream() + .map(ForwardingBakedModel::getWrappedModel) + .filter(Objects::nonNull) + .map(wrapped -> wrapped.getQuads(state, null, random)) + .map(quads -> quads.stream().map(quad -> { + quad_emitter.fromVanilla(quad, material, null); + return QuadPosBounds.read(quad_emitter, false); + }).toList()).toList(); + + Integer[] cull_array; + for(int self_id = 1; self_id <= model_bounds.size(); self_id++) { + List self_bounds = model_bounds.get(self_id - 1); + cull_array = new Integer[self_bounds.size()]; + for (int self_quad = 0; self_quad < cull_array.length; self_quad++) { + QuadPosBounds self_bound = self_bounds.get(self_quad); + for(int other_id = 1; other_id <= model_bounds.size(); other_id++) { + if (other_id == self_id) continue; + if (model_bounds.get(other_id - 1).stream().anyMatch(other_bound -> other_bound.equals(self_bound))) { + cull_array[self_quad] = other_id; + break; + } + } + } + INNER_CULL_MAP.put(new CullElement(frame_block, key, self_id), cull_array); + } + } + + @Environment(EnvType.CLIENT) + public static boolean shouldDrawInnerFace(BlockState state, BlockRenderView view, BlockPos pos, int quad_index, int theme_index) { + if ( !(state.getBlock() instanceof ReFramedBlock frame_block) + || !(view.getBlockEntity(pos) instanceof ThemeableBlockEntity frame_entity) + ) return true; + CullElement key = new CullElement(frame_block, frame_block.getModelCacheKey(state), theme_index); + if (!INNER_CULL_MAP.asMap().containsKey(key)) return true; + + // needs to be Integer object because array is initialized with null not 0 + Integer cull_theme = Objects.requireNonNull(INNER_CULL_MAP.getIfPresent(key))[quad_index]; + if (cull_theme == null) return true; // no culling possible + + BlockState self_theme = frame_entity.getTheme(theme_index); + BlockState other_theme = frame_entity.getTheme(cull_theme); + + if (self_theme.isSideInvisible(other_theme, null)) return false; + return !self_theme.isOpaque() || !other_theme.isOpaque(); + } + // Doing this method from scratch as it is simpler to do than injecting everywhere + @Environment(EnvType.CLIENT) public static boolean shouldDrawSide(BlockState self_state, BlockView world, BlockPos pos, Direction side, BlockPos other_pos, int theme_index) { ThemeableBlockEntity self = world.getBlockEntity(pos) instanceof ThemeableBlockEntity e ? e : null; ThemeableBlockEntity other = world.getBlockEntity(other_pos) instanceof ThemeableBlockEntity e ? e : null; @@ -298,8 +388,4 @@ public class BlockHelper { .reduce((prev, current) -> prev && current).orElse(false) ); } - - public static int luminance(BlockState state) { - return state.contains(LIGHT) && state.get(LIGHT) ? 15 : 0; - } } diff --git a/src/main/java/fr/adrien1106/reframed/util/BlockProperties.java b/src/main/java/fr/adrien1106/reframed/util/blocks/BlockProperties.java similarity index 61% rename from src/main/java/fr/adrien1106/reframed/util/BlockProperties.java rename to src/main/java/fr/adrien1106/reframed/util/blocks/BlockProperties.java index 11aab58..a53ea94 100644 --- a/src/main/java/fr/adrien1106/reframed/util/BlockProperties.java +++ b/src/main/java/fr/adrien1106/reframed/util/blocks/BlockProperties.java @@ -1,12 +1,13 @@ -package fr.adrien1106.reframed.util; +package fr.adrien1106.reframed.util.blocks; -import fr.adrien1106.reframed.util.property.Corner; -import fr.adrien1106.reframed.util.property.StairShape; import net.minecraft.state.property.BooleanProperty; import net.minecraft.state.property.EnumProperty; +import net.minecraft.state.property.IntProperty; public class BlockProperties { public static final BooleanProperty LIGHT = BooleanProperty.of("emits_light"); + public static final EnumProperty EDGE = EnumProperty.of("edge", Edge.class); public static final EnumProperty CORNER = EnumProperty.of("corner", Corner.class); + public static final IntProperty CORNER_FACE = IntProperty.of("face", 0, 2); public static final EnumProperty STAIR_SHAPE = EnumProperty.of("shape", StairShape.class); } diff --git a/src/main/java/fr/adrien1106/reframed/util/blocks/Corner.java b/src/main/java/fr/adrien1106/reframed/util/blocks/Corner.java new file mode 100644 index 0000000..1b16ea4 --- /dev/null +++ b/src/main/java/fr/adrien1106/reframed/util/blocks/Corner.java @@ -0,0 +1,97 @@ +package fr.adrien1106.reframed.util.blocks; + +import net.minecraft.util.StringIdentifiable; +import net.minecraft.util.math.Direction; + +import java.util.Arrays; + +public enum Corner implements StringIdentifiable { + NORTH_EAST_DOWN("north_east_down", Direction.NORTH, Direction.EAST, Direction.DOWN, 0), + EAST_SOUTH_DOWN("east_south_down", Direction.EAST, Direction.SOUTH, Direction.DOWN, 1), + SOUTH_WEST_DOWN("south_west_down", Direction.SOUTH, Direction.WEST, Direction.DOWN, 2), + WEST_NORTH_DOWN("west_north_down", Direction.WEST, Direction.NORTH, Direction.DOWN, 3), + NORTH_EAST_UP("north_east_up", Direction.NORTH, Direction.EAST, Direction.UP, 4), + EAST_SOUTH_UP("east_south_up", Direction.EAST, Direction.SOUTH, Direction.UP, 5), + SOUTH_WEST_UP("south_west_up", Direction.SOUTH, Direction.WEST, Direction.UP, 6), + WEST_NORTH_UP("west_north_up", Direction.WEST, Direction.NORTH, Direction.UP, 7); + + private final String name; + private final Direction first_direction; + private final Direction second_direction; + private final Direction third_direction; + private final int ID; + + Corner(String name, Direction first_direction, Direction second_direction, Direction third_direction, int id) { + this.name = name; + this.first_direction = first_direction; + this.second_direction = second_direction; + this.third_direction = third_direction; + this.ID = id; + } + + public String asString() { + return this.name; + } + + public String toString() { + return asString(); + } + + public boolean hasDirection(Direction direction) { + return this.first_direction.equals(direction) + || this.second_direction.equals(direction) + || this.third_direction.equals(direction); + } + + public int getID() { + return this.ID; + } + + public static Corner getByDirections(Direction direction_1, Direction direction_2, Direction direction_3) { + return Arrays.stream(Corner.values()) + .filter(value -> value.hasDirection(direction_1) && value.hasDirection(direction_2) && value.hasDirection(direction_3)) + .findFirst().orElse(Corner.NORTH_EAST_DOWN); + } + + public static Corner fromId(int id) { + return Arrays.stream(Corner.values()) + .filter(value -> value.getID() == id) + .findFirst().orElse(Corner.NORTH_EAST_DOWN); + } + + public static Corner fromName(String name) { + return Arrays.stream(Corner.values()) + .filter(value -> value.name().equals(name)) + .findFirst().orElse(Corner.NORTH_EAST_DOWN); + } + + public int getDirectionIndex(Direction side) { + return side == second_direction ? 1 : side == third_direction ? 2 : 0; + } + + public Direction getDirection(int index) { + return index == 1 ? second_direction : index == 2 ? third_direction : first_direction; + } + + public Corner getOpposite() { + return getByDirections(first_direction.getOpposite(), second_direction.getOpposite(), third_direction.getOpposite()); + } + + /** + * @param index - an index of the direction to keep and use as reference + * @return the opposite corner on same direction plane + */ + public Corner getOpposite(int index) { + return getOpposite(getDirection(index)); + } + + /** + * @param direction - a direction to keep and use as reference + * @return the opposite corner on same direction plane + */ + public Corner getOpposite(Direction direction) { + Direction other_1 = first_direction == direction ? second_direction : first_direction; + Direction other_2 = second_direction == direction || first_direction == direction ? third_direction : second_direction; + return getByDirections(direction, other_1.getOpposite(), other_2.getOpposite()); + } +} diff --git a/src/main/java/fr/adrien1106/reframed/util/property/Corner.java b/src/main/java/fr/adrien1106/reframed/util/blocks/Edge.java similarity index 58% rename from src/main/java/fr/adrien1106/reframed/util/property/Corner.java rename to src/main/java/fr/adrien1106/reframed/util/blocks/Edge.java index f95b3d0..3b23296 100644 --- a/src/main/java/fr/adrien1106/reframed/util/property/Corner.java +++ b/src/main/java/fr/adrien1106/reframed/util/blocks/Edge.java @@ -1,37 +1,35 @@ -package fr.adrien1106.reframed.util.property; +package fr.adrien1106.reframed.util.blocks; import net.minecraft.util.StringIdentifiable; import net.minecraft.util.math.Direction; import java.util.Arrays; -public enum Corner implements StringIdentifiable { - NORTH_DOWN("north_down", Direction.NORTH, Direction.DOWN, Direction.EAST, 0), - DOWN_SOUTH("down_south", Direction.DOWN, Direction.SOUTH, Direction.EAST, 1), - SOUTH_UP("south_up", Direction.SOUTH, Direction.UP, Direction.EAST, 2), - UP_NORTH("up_north", Direction.UP, Direction.NORTH, Direction.EAST, 3), - WEST_DOWN("west_down", Direction.WEST, Direction.DOWN, Direction.SOUTH, 4), - DOWN_EAST("down_east", Direction.DOWN, Direction.EAST, Direction.SOUTH, 5), - EAST_UP("east_up", Direction.EAST, Direction.UP, Direction.SOUTH, 6), - UP_WEST("up_west", Direction.UP, Direction.WEST, Direction.SOUTH, 7), - WEST_NORTH("west_north", Direction.WEST, Direction.NORTH, Direction.DOWN, 8), - NORTH_EAST("north_east", Direction.NORTH, Direction.EAST, Direction.DOWN, 9), - EAST_SOUTH("east_south", Direction.EAST, Direction.SOUTH, Direction.DOWN, 10), - SOUTH_WEST("south_west", Direction.SOUTH, Direction.WEST, Direction.DOWN, 11); +public enum Edge implements StringIdentifiable { + NORTH_DOWN("north_down", Direction.NORTH, Direction.DOWN, Direction.Axis.X, 0), + DOWN_SOUTH("down_south", Direction.DOWN, Direction.SOUTH, Direction.Axis.X, 1), + SOUTH_UP("south_up", Direction.SOUTH, Direction.UP, Direction.Axis.X, 2), + UP_NORTH("up_north", Direction.UP, Direction.NORTH, Direction.Axis.X, 3), + WEST_DOWN("west_down", Direction.WEST, Direction.DOWN, Direction.Axis.Z, 4), + DOWN_EAST("down_east", Direction.DOWN, Direction.EAST, Direction.Axis.Z, 5), + EAST_UP("east_up", Direction.EAST, Direction.UP, Direction.Axis.Z, 6), + UP_WEST("up_west", Direction.UP, Direction.WEST, Direction.Axis.Z, 7), + WEST_NORTH("west_north", Direction.WEST, Direction.NORTH, Direction.Axis.Y, 8), + NORTH_EAST("north_east", Direction.NORTH, Direction.EAST, Direction.Axis.Y, 9), + EAST_SOUTH("east_south", Direction.EAST, Direction.SOUTH, Direction.Axis.Y, 10), + SOUTH_WEST("south_west", Direction.SOUTH, Direction.WEST, Direction.Axis.Y, 11); private final String name; private final Direction first_direction; private final Direction second_direction; - private final Direction right_direction; - private final Direction left_direction; + private final Direction.Axis axis; private final int ID; - Corner(String name, Direction first_direction, Direction second_direction, Direction right_direction, int id) { + Edge(String name, Direction first_direction, Direction second_direction, Direction.Axis axis, int id) { this.name = name; this.first_direction = first_direction; this.second_direction = second_direction; - this.right_direction = right_direction; - this.left_direction = right_direction.getOpposite(); + this.axis = axis; this.ID = id; } @@ -51,10 +49,18 @@ public enum Corner implements StringIdentifiable { return second_direction; } public Direction getRightDirection() { - return right_direction; + return switch (axis) { + case X -> Direction.WEST; + case Y -> Direction.DOWN; + case Z -> Direction.SOUTH; + }; } public Direction getLeftDirection() { - return left_direction; + return switch (axis) { + case X -> Direction.EAST; + case Y -> Direction.UP; + case Z -> Direction.NORTH; + }; } public boolean hasDirection(Direction direction) { @@ -66,21 +72,21 @@ public enum Corner implements StringIdentifiable { return this.ID; } - public static Corner getByDirections(Direction direction_1, Direction direction_2) { - return Arrays.stream(Corner.values()) + 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(Corner.NORTH_DOWN); + .findFirst().orElse(Edge.NORTH_DOWN); } - public static Corner fromId(int id) { - return Arrays.stream(Corner.values()) + public static Edge fromId(int id) { + return Arrays.stream(Edge.values()) .filter(value -> value.getID() == id) - .findFirst().orElse(Corner.NORTH_DOWN); + .findFirst().orElse(Edge.NORTH_DOWN); } - public static Corner fromName(String name) { - return Arrays.stream(Corner.values()) + public static Edge fromName(String name) { + return Arrays.stream(Edge.values()) .filter(value -> value.name().equals(name)) - .findFirst().orElse(Corner.NORTH_DOWN); + .findFirst().orElse(Edge.NORTH_DOWN); } } diff --git a/src/main/java/fr/adrien1106/reframed/util/ReframedInteractible.java b/src/main/java/fr/adrien1106/reframed/util/blocks/ReframedInteractible.java similarity index 93% rename from src/main/java/fr/adrien1106/reframed/util/ReframedInteractible.java rename to src/main/java/fr/adrien1106/reframed/util/blocks/ReframedInteractible.java index 13a7e72..4209add 100644 --- a/src/main/java/fr/adrien1106/reframed/util/ReframedInteractible.java +++ b/src/main/java/fr/adrien1106/reframed/util/blocks/ReframedInteractible.java @@ -1,4 +1,4 @@ -package fr.adrien1106.reframed.util; +package fr.adrien1106.reframed.util.blocks; import net.minecraft.block.BlockState; import net.minecraft.util.math.BlockPos; diff --git a/src/main/java/fr/adrien1106/reframed/util/property/StairShape.java b/src/main/java/fr/adrien1106/reframed/util/blocks/StairShape.java similarity index 96% rename from src/main/java/fr/adrien1106/reframed/util/property/StairShape.java rename to src/main/java/fr/adrien1106/reframed/util/blocks/StairShape.java index eef0c51..5019e89 100644 --- a/src/main/java/fr/adrien1106/reframed/util/property/StairShape.java +++ b/src/main/java/fr/adrien1106/reframed/util/blocks/StairShape.java @@ -1,4 +1,4 @@ -package fr.adrien1106.reframed.util.property; +package fr.adrien1106.reframed.util.blocks; import net.minecraft.util.StringIdentifiable; diff --git a/src/main/java/fr/adrien1106/reframed/util/ThemeableBlockEntity.java b/src/main/java/fr/adrien1106/reframed/util/blocks/ThemeableBlockEntity.java similarity index 82% rename from src/main/java/fr/adrien1106/reframed/util/ThemeableBlockEntity.java rename to src/main/java/fr/adrien1106/reframed/util/blocks/ThemeableBlockEntity.java index 2213826..ace75e0 100644 --- a/src/main/java/fr/adrien1106/reframed/util/ThemeableBlockEntity.java +++ b/src/main/java/fr/adrien1106/reframed/util/blocks/ThemeableBlockEntity.java @@ -1,4 +1,4 @@ -package fr.adrien1106.reframed.util; +package fr.adrien1106.reframed.util.blocks; import net.minecraft.block.BlockState; diff --git a/src/main/java/fr/adrien1106/reframed/util/IBlockRenderInfoMixin.java b/src/main/java/fr/adrien1106/reframed/util/mixin/IBlockRenderInfoMixin.java similarity index 81% rename from src/main/java/fr/adrien1106/reframed/util/IBlockRenderInfoMixin.java rename to src/main/java/fr/adrien1106/reframed/util/mixin/IBlockRenderInfoMixin.java index 69aaeb6..30e0672 100644 --- a/src/main/java/fr/adrien1106/reframed/util/IBlockRenderInfoMixin.java +++ b/src/main/java/fr/adrien1106/reframed/util/mixin/IBlockRenderInfoMixin.java @@ -1,4 +1,4 @@ -package fr.adrien1106.reframed.util; +package fr.adrien1106.reframed.util.mixin; import net.minecraft.block.BlockState; import net.minecraft.util.math.BlockPos; @@ -8,4 +8,6 @@ public interface IBlockRenderInfoMixin { void prepareForBlock(BlockState state, BlockPos pos, boolean ao, int theme_index); void prepareForBlock(BlockState state, BlockPos pos, long seed, boolean ao, int theme_index); + + int getThemeIndex(); } diff --git a/src/main/java/fr/adrien1106/reframed/util/IMultipartBakedModelMixin.java b/src/main/java/fr/adrien1106/reframed/util/mixin/IMultipartBakedModelMixin.java similarity index 81% rename from src/main/java/fr/adrien1106/reframed/util/IMultipartBakedModelMixin.java rename to src/main/java/fr/adrien1106/reframed/util/mixin/IMultipartBakedModelMixin.java index 275f01d..8b7a01c 100644 --- a/src/main/java/fr/adrien1106/reframed/util/IMultipartBakedModelMixin.java +++ b/src/main/java/fr/adrien1106/reframed/util/mixin/IMultipartBakedModelMixin.java @@ -1,4 +1,4 @@ -package fr.adrien1106.reframed.util; +package fr.adrien1106.reframed.util.mixin; import net.minecraft.block.BlockState; import net.minecraft.client.render.model.BakedModel; diff --git a/src/main/resources/assets/reframed/models/block/half_stair/down.json b/src/main/resources/assets/reframed/models/block/half_stair/down.json new file mode 100644 index 0000000..2df9bc2 --- /dev/null +++ b/src/main/resources/assets/reframed/models/block/half_stair/down.json @@ -0,0 +1,55 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "particle": "#side" + }, + "elements": [ + { + "from": [8, 0, 8], + "to": [16, 8, 16], + "faces": { + "east": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "east"}, + "south": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "south"}, + "west": {"uv": [8, 8, 16, 16], "texture": "#side"}, + "up": {"uv": [8, 8, 16, 16], "texture": "#top"}, + "down": {"uv": [8, 0, 16, 8], "texture": "#bottom", "cullface": "down"} + } + }, + { + "from": [8, 0, 0], + "to": [16, 8, 8], + "faces": { + "north": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "north"}, + "east": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "east"}, + "up": {"uv": [8, 0, 16, 8], "texture": "#top"}, + "down": {"uv": [8, 8, 16, 16], "texture": "#bottom", "cullface": "down"} + } + }, + { + "from": [0, 0, 0], + "to": [8, 8, 8], + "faces": { + "north": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "north"}, + "south": {"uv": [0, 8, 8, 16], "texture": "#side"}, + "west": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "west"}, + "up": {"uv": [0, 0, 8, 8], "texture": "#top"}, + "down": {"uv": [0, 8, 8, 16], "texture": "#bottom", "cullface": "down"} + } + } + ], + "display": { + "thirdperson_lefthand": { + "rotation": [75, -135, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "gui": { + "rotation": [30, 135, 0], + "scale": [0.625, 0.625, 0.625] + }, + "head": { + "rotation": [0, -90, 0] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/reframed/models/block/half_stair/side.json b/src/main/resources/assets/reframed/models/block/half_stair/side.json new file mode 100644 index 0000000..039ea0d --- /dev/null +++ b/src/main/resources/assets/reframed/models/block/half_stair/side.json @@ -0,0 +1,55 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "particle": "#side" + }, + "elements": [ + { + "from": [8, 8, 0], + "to": [16, 16, 8], + "faces": { + "north": {"uv": [0, 0, 8, 8], "texture": "#side", "cullface": "north"}, + "east": {"uv": [8, 0, 16, 8], "texture": "#side", "cullface": "east"}, + "south": {"uv": [8, 0, 16, 8], "texture": "#side"}, + "west": {"uv": [0, 0, 8, 8], "texture": "#side"}, + "up": {"uv": [8, 0, 16, 8], "texture": "#top", "cullface": "up"} + } + }, + { + "from": [8, 0, 0], + "to": [16, 8, 8], + "faces": { + "north": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "north"}, + "east": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "east"}, + "west": {"uv": [0, 8, 8, 16], "texture": "#side"}, + "down": {"uv": [8, 8, 16, 16], "texture": "#bottom", "cullface": "down"} + } + }, + { + "from": [8, 0, 8], + "to": [16, 8, 16], + "faces": { + "east": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "east"}, + "south": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "south"}, + "west": {"uv": [8, 8, 16, 16], "texture": "#side"}, + "up": {"uv": [8, 8, 16, 16], "texture": "#top"}, + "down": {"uv": [8, 0, 16, 8], "texture": "#bottom", "cullface": "down"} + } + } + ], + "display": { + "thirdperson_lefthand": { + "rotation": [75, -135, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "gui": { + "rotation": [30, 135, 0], + "scale": [0.625, 0.625, 0.625] + }, + "head": { + "rotation": [0, -90, 0] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/reframed/models/block/half_stair/slab/down.json b/src/main/resources/assets/reframed/models/block/half_stair/slab/down.json new file mode 100644 index 0000000..b56aa5e --- /dev/null +++ b/src/main/resources/assets/reframed/models/block/half_stair/slab/down.json @@ -0,0 +1,35 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "particle": "#side" + }, + "elements": [ + { + "from": [0, 0, 8], + "to": [8, 8, 16], + "faces": { + "north": {"uv": [8, 8, 16, 16], "texture": "#side"}, + "east": {"uv": [0, 8, 8, 16], "texture": "#side"}, + "south": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "south"}, + "west": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "west"}, + "up": {"uv": [0, 8, 8, 16], "texture": "#top"}, + "down": {"uv": [0, 0, 8, 8], "texture": "#bottom", "cullface": "down"} + } + } + ], + "display": { + "thirdperson_lefthand": { + "rotation": [75, -135, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "gui": { + "rotation": [30, 135, 0], + "scale": [0.625, 0.625, 0.625] + }, + "head": { + "rotation": [0, -90, 0] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/reframed/models/block/half_stair/slab/side.json b/src/main/resources/assets/reframed/models/block/half_stair/slab/side.json new file mode 100644 index 0000000..ca813e3 --- /dev/null +++ b/src/main/resources/assets/reframed/models/block/half_stair/slab/side.json @@ -0,0 +1,35 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "particle": "#side" + }, + "elements": [ + { + "from": [8, 8, 8], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 8, 8], "texture": "#side"}, + "east": {"uv": [0, 0, 8, 8], "texture": "#side", "cullface": "east"}, + "south": {"uv": [8, 0, 16, 8], "texture": "#side", "cullface": "south"}, + "west": {"uv": [8, 0, 16, 8], "texture": "#side"}, + "up": {"uv": [8, 8, 16, 16], "texture": "#top", "cullface": "up"}, + "down": {"uv": [8, 0, 16, 8], "texture": "#bottom"} + } + } + ], + "display": { + "thirdperson_lefthand": { + "rotation": [75, -135, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "gui": { + "rotation": [30, 135, 0], + "scale": [0.625, 0.625, 0.625] + }, + "head": { + "rotation": [0, -90, 0] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/reframed/models/block/half_stair/stair/down.json b/src/main/resources/assets/reframed/models/block/half_stair/stair/down.json new file mode 100644 index 0000000..adba846 --- /dev/null +++ b/src/main/resources/assets/reframed/models/block/half_stair/stair/down.json @@ -0,0 +1,55 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "particle": "#side" + }, + "elements": [ + { + "from": [8, 8, 8], + "to": [16, 16, 16], + "faces": { + "east": {"uv": [0, 0, 8, 8], "texture": "#side", "cullface": "east"}, + "south": {"uv": [8, 0, 16, 8], "texture": "#side", "cullface": "south"}, + "west": {"uv": [8, 0, 16, 8], "texture": "#side"}, + "up": {"uv": [8, 8, 16, 16], "texture": "#top", "cullface": "up"}, + "down": {"uv": [8, 0, 16, 8], "texture": "#bottom"} + } + }, + { + "from": [8, 8, 0], + "to": [16, 16, 8], + "faces": { + "north": {"uv": [0, 0, 8, 8], "texture": "#side", "cullface": "north"}, + "east": {"uv": [8, 0, 16, 8], "texture": "#side", "cullface": "east"}, + "up": {"uv": [8, 0, 16, 8], "texture": "#top", "cullface": "up"}, + "down": {"uv": [8, 8, 16, 16], "texture": "#bottom"} + } + }, + { + "from": [0, 8, 0], + "to": [8, 16, 8], + "faces": { + "north": {"uv": [8, 0, 16, 8], "texture": "#side", "cullface": "north"}, + "south": {"uv": [0, 0, 8, 8], "texture": "#side"}, + "west": {"uv": [0, 0, 8, 8], "texture": "#side", "cullface": "west"}, + "up": {"uv": [0, 0, 8, 8], "texture": "#top", "cullface": "up"}, + "down": {"uv": [0, 8, 8, 16], "texture": "#bottom"} + } + } + ], + "display": { + "thirdperson_lefthand": { + "rotation": [75, -135, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "gui": { + "rotation": [30, 135, 0], + "scale": [0.625, 0.625, 0.625] + }, + "head": { + "rotation": [0, -90, 0] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/reframed/models/block/half_stair/stair/side.json b/src/main/resources/assets/reframed/models/block/half_stair/stair/side.json new file mode 100644 index 0000000..f917223 --- /dev/null +++ b/src/main/resources/assets/reframed/models/block/half_stair/stair/side.json @@ -0,0 +1,55 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "particle": "#side" + }, + "elements": [ + { + "from": [0, 8, 0], + "to": [8, 16, 8], + "faces": { + "north": {"uv": [0, 0, 8, 8], "texture": "#side", "cullface": "north"}, + "east": {"uv": [8, 0, 16, 8], "texture": "#side"}, + "south": {"uv": [0, 0, 8, 8], "texture": "#side"}, + "west": {"uv": [0, 0, 8, 8], "texture": "#side", "cullface": "west"}, + "up": {"uv": [0, 0, 8, 8], "texture": "#top", "cullface": "up"} + } + }, + { + "from": [0, 0, 0], + "to": [8, 8, 8], + "faces": { + "north": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "north"}, + "east": {"uv": [8, 8, 16, 16], "texture": "#side"}, + "west": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "west"}, + "down": {"uv": [0, 8, 8, 16], "texture": "#bottom", "cullface": "down"} + } + }, + { + "from": [0, 0, 8], + "to": [8, 8, 16], + "faces": { + "east": {"uv": [0, 8, 8, 16], "texture": "#side"}, + "south": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "south"}, + "west": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "west"}, + "up": {"uv": [0, 8, 8, 16], "texture": "#top"}, + "down": {"uv": [0, 0, 8, 8], "texture": "#bottom", "cullface": "down"} + } + } + ], + "display": { + "thirdperson_lefthand": { + "rotation": [75, -135, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "gui": { + "rotation": [30, 135, 0], + "scale": [0.625, 0.625, 0.625] + }, + "head": { + "rotation": [0, -90, 0] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/reframed/models/block/small_cube/base.json b/src/main/resources/assets/reframed/models/block/small_cube/base.json new file mode 100644 index 0000000..81d3699 --- /dev/null +++ b/src/main/resources/assets/reframed/models/block/small_cube/base.json @@ -0,0 +1,35 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "particle": "#side" + }, + "elements": [ + { + "from": [8, 0, 0], + "to": [16, 8, 8], + "faces": { + "north": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "north"}, + "east": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "east"}, + "south": {"uv": [8, 8, 16, 16], "texture": "#side"}, + "west": {"uv": [0, 8, 8, 16], "texture": "#side"}, + "up": {"uv": [8, 0, 16, 8], "texture": "#top"}, + "down": {"uv": [8, 8, 16, 16], "texture": "#bottom", "cullface": "down"} + } + } + ], + "display": { + "thirdperson_lefthand": { + "rotation": [75, -135, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "gui": { + "rotation": [30, 135, 0], + "scale": [0.625, 0.625, 0.625] + }, + "head": { + "rotation": [0, -90, 0] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/reframed/models/block/small_cube/step/base.json b/src/main/resources/assets/reframed/models/block/small_cube/step/base.json new file mode 100644 index 0000000..e30b52e --- /dev/null +++ b/src/main/resources/assets/reframed/models/block/small_cube/step/base.json @@ -0,0 +1,35 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "particle": "#side" + }, + "elements": [ + { + "from": [8, 0, 8], + "to": [16, 8, 16], + "faces": { + "north": {"uv": [0, 8, 8, 16], "texture": "#side"}, + "east": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "east"}, + "south": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "south"}, + "west": {"uv": [0, 8, 8, 16], "texture": "#side"}, + "up": {"uv": [8, 0, 16, 8], "texture": "#top"}, + "down": {"uv": [8, 8, 16, 16], "texture": "#bottom", "cullface": "down"} + } + } + ], + "display": { + "thirdperson_lefthand": { + "rotation": [75, -135, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "gui": { + "rotation": [30, 135, 0], + "scale": [0.625, 0.625, 0.625] + }, + "head": { + "rotation": [0, -90, 0] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/reframed/models/block/double_outer_stairs_complement.json b/src/main/resources/assets/reframed/models/block/stair/cube/double_outer.json similarity index 100% rename from src/main/resources/assets/reframed/models/block/double_outer_stairs_complement.json rename to src/main/resources/assets/reframed/models/block/stair/cube/double_outer.json diff --git a/src/main/resources/assets/reframed/models/block/inner_stairs_complement.json b/src/main/resources/assets/reframed/models/block/stair/cube/inner.json similarity index 100% rename from src/main/resources/assets/reframed/models/block/inner_stairs_complement.json rename to src/main/resources/assets/reframed/models/block/stair/cube/inner.json diff --git a/src/main/resources/assets/reframed/models/block/outer_stairs_complement.json b/src/main/resources/assets/reframed/models/block/stair/cube/outer.json similarity index 100% rename from src/main/resources/assets/reframed/models/block/outer_stairs_complement.json rename to src/main/resources/assets/reframed/models/block/stair/cube/outer.json diff --git a/src/main/resources/assets/reframed/models/block/outer_side_stairs_complement.json b/src/main/resources/assets/reframed/models/block/stair/cube/outer_side.json similarity index 100% rename from src/main/resources/assets/reframed/models/block/outer_side_stairs_complement.json rename to src/main/resources/assets/reframed/models/block/stair/cube/outer_side.json diff --git a/src/main/resources/assets/reframed/models/block/stairs_complement.json b/src/main/resources/assets/reframed/models/block/stair/cube/straight.json similarity index 100% rename from src/main/resources/assets/reframed/models/block/stairs_complement.json rename to src/main/resources/assets/reframed/models/block/stair/cube/straight.json diff --git a/src/main/resources/assets/reframed/models/block/double_outer_stairs.json b/src/main/resources/assets/reframed/models/block/stair/double_outer.json similarity index 100% rename from src/main/resources/assets/reframed/models/block/double_outer_stairs.json rename to src/main/resources/assets/reframed/models/block/stair/double_outer.json diff --git a/src/main/resources/assets/reframed/models/block/inner_stairs.json b/src/main/resources/assets/reframed/models/block/stair/inner.json similarity index 100% rename from src/main/resources/assets/reframed/models/block/inner_stairs.json rename to src/main/resources/assets/reframed/models/block/stair/inner.json diff --git a/src/main/resources/assets/reframed/models/block/outer_stairs.json b/src/main/resources/assets/reframed/models/block/stair/outer.json similarity index 100% rename from src/main/resources/assets/reframed/models/block/outer_stairs.json rename to src/main/resources/assets/reframed/models/block/stair/outer.json diff --git a/src/main/resources/assets/reframed/models/block/outer_side_stairs.json b/src/main/resources/assets/reframed/models/block/stair/outer_side.json similarity index 100% rename from src/main/resources/assets/reframed/models/block/outer_side_stairs.json rename to src/main/resources/assets/reframed/models/block/stair/outer_side.json diff --git a/src/main/resources/assets/reframed/models/block/stairs.json b/src/main/resources/assets/reframed/models/block/stair/straight.json similarity index 100% rename from src/main/resources/assets/reframed/models/block/stairs.json rename to src/main/resources/assets/reframed/models/block/stair/straight.json diff --git a/src/main/resources/assets/reframed/models/block/step.json b/src/main/resources/assets/reframed/models/block/step/down.json similarity index 100% rename from src/main/resources/assets/reframed/models/block/step.json rename to src/main/resources/assets/reframed/models/block/step/down.json diff --git a/src/main/resources/assets/reframed/models/block/step_side.json b/src/main/resources/assets/reframed/models/block/step/side.json similarity index 100% rename from src/main/resources/assets/reframed/models/block/step_side.json rename to src/main/resources/assets/reframed/models/block/step/side.json diff --git a/src/main/resources/assets/reframed/models/block/step_complement_slab.json b/src/main/resources/assets/reframed/models/block/step/slab/down.json similarity index 100% rename from src/main/resources/assets/reframed/models/block/step_complement_slab.json rename to src/main/resources/assets/reframed/models/block/step/slab/down.json diff --git a/src/main/resources/assets/reframed/models/block/step_side_complement_slab.json b/src/main/resources/assets/reframed/models/block/step/slab/side.json similarity index 100% rename from src/main/resources/assets/reframed/models/block/step_side_complement_slab.json rename to src/main/resources/assets/reframed/models/block/step/slab/side.json diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index b96c19f..ce39b5b 100755 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -30,7 +30,7 @@ "fabricloader": "^${loader_version}", "fabric-api": "*" }, - "suggest": { + "suggests": { "athena": "^${athena_version}", "sodium": "^${sodium_version}", "indium": "^${indium_version}" diff --git a/src/main/resources/reframed.mixins.json b/src/main/resources/reframed.mixins.json index b0280b4..059e59b 100644 --- a/src/main/resources/reframed.mixins.json +++ b/src/main/resources/reframed.mixins.json @@ -14,6 +14,7 @@ "compat.AthenaBakedModelMixin", "compat.AthenaConnectedBlockModelMixin", "compat.AthenaWrappedGetterMixin", + "compat.IndiumAbstractBlockRenderContextMixin", "compat.IndiumTerrainBlockRenderInfoMixin", "compat.IndiumTerrainRenderContextMixin", "compat.SodiumBlockOcclusionCacheMixin", @@ -21,6 +22,7 @@ "particles.AccessorParticle", "particles.AccessorSpriteBillboardParticle", "particles.MixinBlockDustParticle", + "render.AbstractBlockRenderContextMixin", "render.BlockRenderInfoMixin", "render.MultipartBakedModelMixin", "render.TerrainRenderContextMixin",