Merge pull request 'v1.5 new shapes + self culling + caching + coding tools/cleanup' (#10) from dev into master
All checks were successful
deploy / deploy (push) Successful in 5m42s
All checks were successful
deploy / deploy (push) Successful in 5m42s
Reviewed-on: #10
This commit is contained in:
commit
186cca3e27
@ -9,7 +9,7 @@ loader_version=0.15.6
|
|||||||
|
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
modrinth_id = jCpoCBpn
|
modrinth_id = jCpoCBpn
|
||||||
mod_version = 1.4
|
mod_version = 1.5
|
||||||
maven_group = fr.adrien1106
|
maven_group = fr.adrien1106
|
||||||
archives_base_name = ReFramed
|
archives_base_name = ReFramed
|
||||||
mod_id = reframed
|
mod_id = reframed
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package fr.adrien1106.reframed;
|
package fr.adrien1106.reframed;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.block.*;
|
import fr.adrien1106.reframed.block.*;
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
|
||||||
import net.fabricmc.api.ModInitializer;
|
import net.fabricmc.api.ModInitializer;
|
||||||
import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup;
|
import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup;
|
||||||
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
|
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.function.BiConsumer;
|
||||||
import java.util.stream.Collectors;
|
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 class ReFramed implements ModInitializer {
|
||||||
public static final String MODID = "reframed";
|
public static final String MODID = "reframed";
|
||||||
|
|
||||||
public static final ArrayList<Block> BLOCKS = new ArrayList<>();
|
public static final ArrayList<Block> 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 ItemGroup ITEM_GROUP;
|
||||||
|
|
||||||
public static BlockEntityType<ReFramedEntity> REFRAMED_BLOCK_ENTITY;
|
public static BlockEntityType<ReFramedEntity> REFRAMED_BLOCK_ENTITY;
|
||||||
@ -42,18 +48,19 @@ public class ReFramed implements ModInitializer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInitialize() {
|
public void onInitialize() {
|
||||||
//registerReFramed mutates FRAMES as a side effect, which is a List, so order is preserved
|
CUBE = registerReFramed("cube" , new ReFramedBlock(cp(Blocks.OAK_PLANKS)));
|
||||||
//the ordering is used in the creative tab, so they're roughly sorted by encounter order of the
|
SMALL_CUBE = registerReFramed("small_cube" , new ReFramedSmallCubeBlock(cp(Blocks.OAK_PLANKS)));
|
||||||
//corresponding vanilla block in the "search" creative tab... with the non-vanilla "post" and
|
SMALL_CUBES_STEP = registerReFramed("small_cubes_step" , new ReFramedSmallCubesStepBlock(cp(Blocks.OAK_PLANKS)));
|
||||||
//"vertical slab" inserted where they fit ...and i moved the lever way up next to the pressureplate
|
STAIR = registerReFramed("stair" , new ReFramedStairBlock(cp(Blocks.OAK_STAIRS)));
|
||||||
//and button, because they're redstoney... hopefully this ordering makes sense lol
|
STAIRS_CUBE = registerReFramed("stairs_cube" , new ReFramedStairsCubeBlock(cp(Blocks.OAK_STAIRS)));
|
||||||
CUBE = registerReFramed("cube" , new ReFramedBlock(cp(Blocks.OAK_PLANKS)));
|
HALF_STAIR = registerReFramed("half_stair" , new ReFramedHalfStairBlock(cp(Blocks.OAK_STAIRS)));
|
||||||
STAIRS = registerReFramed("stairs" , new ReFramedStairsBlock(cp(Blocks.OAK_STAIRS)));
|
HALF_STAIRS_SLAB = registerReFramed("half_stairs_slab" , new ReFramedHalfStairsSlabBlock(cp(Blocks.OAK_STAIRS)));
|
||||||
DOUBLE_STAIRS = registerReFramed("double_stairs" , new ReFramedDoubleStairsBlock(cp(Blocks.OAK_STAIRS)));
|
HALF_STAIRS_STAIR = registerReFramed("half_stairs_stair" , new ReFramedHalfStairsStairBlock(cp(Blocks.OAK_STAIRS)));
|
||||||
SLAB = registerReFramed("slab" , new ReFramedSlabBlock(cp(Blocks.OAK_SLAB)));
|
LAYER = registerReFramed("layer" , new ReFramedLayerBlock(cp(Blocks.OAK_SLAB)));
|
||||||
DOUBLE_SLAB = registerReFramed("double_slab" , new ReFramedDoubleSlabBlock(cp(Blocks.OAK_SLAB)));
|
SLAB = registerReFramed("slab" , new ReFramedSlabBlock(cp(Blocks.OAK_SLAB)));
|
||||||
STEP = registerReFramed("step" , new ReFramedStepBlock(cp(Blocks.OAK_SLAB)));
|
SLABS_CUBE = registerReFramed("slabs_cube" , new ReFramedSlabsCubeBlock(cp(Blocks.OAK_SLAB)));
|
||||||
DOUBLE_STEP = registerReFramed("double_step" , new ReFramedDoubleStepBlock(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"),
|
REFRAMED_BLOCK_ENTITY = Registry.register(Registries.BLOCK_ENTITY_TYPE, id("camo"),
|
||||||
FabricBlockEntityTypeBuilder.create(
|
FabricBlockEntityTypeBuilder.create(
|
||||||
@ -70,7 +77,7 @@ public class ReFramed implements ModInitializer {
|
|||||||
.filter(block -> block instanceof ReFramedDoubleBlock)
|
.filter(block -> block instanceof ReFramedDoubleBlock)
|
||||||
.toArray(Block[]::new)).build(null)
|
.toArray(Block[]::new)).build(null)
|
||||||
);
|
);
|
||||||
|
|
||||||
ITEM_GROUP = Registry.register(Registries.ITEM_GROUP, id("tab"), FabricItemGroup.builder()
|
ITEM_GROUP = Registry.register(Registries.ITEM_GROUP, id("tab"), FabricItemGroup.builder()
|
||||||
.displayName(Text.translatable("itemGroup.reframed.tab"))
|
.displayName(Text.translatable("itemGroup.reframed.tab"))
|
||||||
.icon(() -> new ItemStack(SLAB))
|
.icon(() -> new ItemStack(SLAB))
|
||||||
@ -80,7 +87,7 @@ public class ReFramed implements ModInitializer {
|
|||||||
|
|
||||||
private static AbstractBlock.Settings cp(Block base) {
|
private static AbstractBlock.Settings cp(Block base) {
|
||||||
return AbstractBlock.Settings.copy(base)
|
return AbstractBlock.Settings.copy(base)
|
||||||
.luminance(BlockHelper::luminance)
|
.luminance(state -> state.contains(LIGHT) && state.get(LIGHT) ? 15 : 0)
|
||||||
.nonOpaque()
|
.nonOpaque()
|
||||||
.sounds(BlockSoundGroup.WOOD)
|
.sounds(BlockSoundGroup.WOOD)
|
||||||
.hardness(0.2f)
|
.hardness(0.2f)
|
||||||
|
@ -2,7 +2,7 @@ package fr.adrien1106.reframed.block;
|
|||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
import fr.adrien1106.reframed.generator.RecipeSetter;
|
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.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
import net.minecraft.block.*;
|
import net.minecraft.block.*;
|
||||||
import net.minecraft.block.entity.BlockEntity;
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
@ -33,7 +33,7 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
|
|
||||||
import java.util.List;
|
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 {
|
public class ReFramedBlock extends Block implements BlockEntityProvider, RecipeSetter {
|
||||||
|
|
||||||
@ -41,6 +41,23 @@ public class ReFramedBlock extends Block implements BlockEntityProvider, RecipeS
|
|||||||
super(settings);
|
super(settings);
|
||||||
setDefaultState(getDefaultState().with(LIGHT, false));
|
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
|
//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
|
//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))
|
&& themes.stream().noneMatch(theme -> theme.getLuminance() != 0))
|
||||||
drops.add(new ItemStack(Items.GLOWSTONE_DUST));
|
drops.add(new ItemStack(Items.GLOWSTONE_DUST));
|
||||||
if(!frame_entity.isSolid()
|
if(!frame_entity.isSolid()
|
||||||
&& themes.stream().anyMatch(theme -> theme.isSolid()))
|
&& themes.stream().anyMatch(AbstractBlockState::isSolid))
|
||||||
drops.add(new ItemStack(Items.POPPED_CHORUS_FRUIT));
|
drops.add(new ItemStack(Items.POPPED_CHORUS_FRUIT));
|
||||||
|
|
||||||
ItemScatterer.spawn(world, pos, drops);
|
ItemScatterer.spawn(world, pos, drops);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package fr.adrien1106.reframed.block;
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.ShapeContext;
|
import net.minecraft.block.ShapeContext;
|
||||||
import net.minecraft.block.entity.BlockEntity;
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
|
@ -44,7 +44,7 @@ public class ReFramedDoubleEntity extends ReFramedEntity {
|
|||||||
public void readNbt(NbtCompound nbt) {
|
public void readNbt(NbtCompound nbt) {
|
||||||
super.readNbt(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));
|
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
|
// Force a chunk remesh on the client if the displayed blockstate has changed
|
||||||
|
@ -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<VoxelShape> 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<Block, BlockState> 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)));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +1,8 @@
|
|||||||
package fr.adrien1106.reframed.block;
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
import fr.adrien1106.reframed.util.BlockProperties;
|
import fr.adrien1106.reframed.util.blocks.BlockProperties;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.block.entity.BlockEntity;
|
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,
|
//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.
|
//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 {
|
public class ReFramedEntity extends BlockEntity implements ThemeableBlockEntity {
|
||||||
protected BlockState first_state = Blocks.AIR.getDefaultState();
|
protected BlockState first_state = Blocks.AIR.getDefaultState();
|
||||||
protected byte bit_field = SOLIDITY_MASK;
|
protected byte bit_field = SOLIDITY_MASK;
|
||||||
@ -47,7 +47,7 @@ public class ReFramedEntity extends BlockEntity implements ThemeableBlockEntity
|
|||||||
public void readNbt(NbtCompound nbt) {
|
public void readNbt(NbtCompound nbt) {
|
||||||
super.readNbt(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));
|
first_state = NbtHelper.toBlockState(Registries.BLOCK.getReadOnlyWrapper(), nbt.getCompound(BLOCKSTATE_KEY + 1));
|
||||||
if (nbt.contains(BITFIELD_KEY)) bit_field = nbt.getByte(BITFIELD_KEY);
|
if (nbt.contains(BITFIELD_KEY)) bit_field = nbt.getByte(BITFIELD_KEY);
|
||||||
|
|
||||||
|
@ -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<Block, BlockState> 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();
|
||||||
|
}
|
||||||
|
}
|
@ -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<Block, BlockState> 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);
|
||||||
|
}
|
||||||
|
}
|
@ -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<Block, BlockState> 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);
|
||||||
|
}
|
||||||
|
}
|
@ -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<Block, BlockState> 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();
|
||||||
|
}
|
||||||
|
}
|
@ -38,6 +38,16 @@ public class ReFramedSlabBlock extends WaterloggableReFramedBlock implements Blo
|
|||||||
super(settings);
|
super(settings);
|
||||||
setDefaultState(getDefaultState().with(FACING, Direction.DOWN));
|
setDefaultState(getDefaultState().with(FACING, Direction.DOWN));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getModelCacheKey(BlockState state) {
|
||||||
|
return state.get(FACING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getModelStateCount() {
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
@ -13,7 +13,6 @@ import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder;
|
|||||||
import net.minecraft.item.ItemPlacementContext;
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
import net.minecraft.recipe.book.RecipeCategory;
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
import net.minecraft.state.StateManager;
|
import net.minecraft.state.StateManager;
|
||||||
import net.minecraft.state.property.Properties;
|
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
import net.minecraft.util.shape.VoxelShape;
|
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.data.client.VariantSettings.Rotation.R90;
|
||||||
import static net.minecraft.state.property.Properties.AXIS;
|
import static net.minecraft.state.property.Properties.AXIS;
|
||||||
|
|
||||||
public class ReFramedDoubleSlabBlock extends ReFramedDoubleBlock implements BlockStateProvider {
|
public class ReFramedSlabsCubeBlock extends ReFramedDoubleBlock implements BlockStateProvider {
|
||||||
public ReFramedDoubleSlabBlock(Settings settings) {
|
|
||||||
|
public ReFramedSlabsCubeBlock(Settings settings) {
|
||||||
super(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
|
@Override
|
||||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
super.appendProperties(builder.add(Properties.AXIS));
|
super.appendProperties(builder.add(AXIS));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public BlockState getPlacementState(ItemPlacementContext ctx) {
|
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
|
@Override
|
||||||
public VoxelShape getShape(BlockState state, int i) {
|
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 Y -> i == 2 ? UP : DOWN;
|
||||||
case Z -> i == 2 ? NORTH : SOUTH;
|
case Z -> i == 2 ? NORTH : SOUTH;
|
||||||
case X -> i == 2 ? EAST : WEST;
|
case X -> i == 2 ? EAST : WEST;
|
@ -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<Block, BlockState> 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();
|
||||||
|
}
|
||||||
|
}
|
@ -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<Block, BlockState> 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);
|
||||||
|
}
|
||||||
|
}
|
@ -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<Block, BlockState> 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();
|
||||||
|
}
|
||||||
|
}
|
@ -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<VoxelShape> 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<Block, BlockState> 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));
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<Block, BlockState> 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);
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,16 @@
|
|||||||
package fr.adrien1106.reframed.block;
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
import fr.adrien1106.reframed.generator.GBlockstate;
|
|
||||||
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
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.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.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.ShapeContext;
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.data.client.BlockStateSupplier;
|
||||||
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
import net.minecraft.data.client.MultipartBlockStateSupplier;
|
||||||
import net.minecraft.data.server.recipe.RecipeExporter;
|
import net.minecraft.data.server.recipe.RecipeExporter;
|
||||||
import net.minecraft.data.server.recipe.RecipeProvider;
|
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.state.StateManager;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Direction;
|
|
||||||
import net.minecraft.util.shape.VoxelShape;
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
import net.minecraft.util.shape.VoxelShapes;
|
|
||||||
import net.minecraft.world.BlockView;
|
import net.minecraft.world.BlockView;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder;
|
||||||
import java.util.List;
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
|
||||||
|
import static fr.adrien1106.reframed.util.blocks.Edge.*;
|
||||||
import static fr.adrien1106.reframed.util.BlockProperties.CORNER;
|
|
||||||
import static fr.adrien1106.reframed.util.property.Corner.*;
|
|
||||||
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
|
||||||
public class ReFramedStepBlock extends WaterloggableReFramedBlock implements BlockStateProvider {
|
public class ReFramedStepBlock extends WaterloggableReFramedBlock implements BlockStateProvider {
|
||||||
|
|
||||||
public static final List<VoxelShape> STEP_VOXELS = new ArrayList<>(12);
|
public static final VoxelShape[] STEP_VOXELS;
|
||||||
|
|
||||||
public ReFramedStepBlock(Settings settings) {
|
public ReFramedStepBlock(Settings settings) {
|
||||||
super(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
|
@Override
|
||||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
super.appendProperties(builder.add(CORNER));
|
super.appendProperties(builder.add(EDGE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public BlockState getPlacementState(ItemPlacementContext ctx) {
|
public BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
return super.getPlacementState(ctx).with(CORNER, BlockHelper.getPlacementCorner(ctx));
|
return super.getPlacementState(ctx).with(EDGE, BlockHelper.getPlacementEdge(ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
return switch (state.get(CORNER)) {
|
return getStepShape(state.get(EDGE));
|
||||||
case DOWN_SOUTH -> STEP_VOXELS.get(0);
|
}
|
||||||
case NORTH_DOWN -> STEP_VOXELS.get(1);
|
|
||||||
case UP_NORTH -> STEP_VOXELS.get(2);
|
public static VoxelShape getStepShape(Edge edge) {
|
||||||
case SOUTH_UP -> STEP_VOXELS.get(3);
|
return STEP_VOXELS[edge.getID()];
|
||||||
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);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MultipartBlockStateSupplier getMultipart() {
|
public BlockStateSupplier getMultipart() {
|
||||||
Identifier step_id = ReFramed.id("step_special");
|
Identifier model_id = ReFramed.id("step_special");
|
||||||
return MultipartBlockStateSupplier.create(this)
|
return MultipartBlockStateSupplier.create(this)
|
||||||
/* X AXIS */
|
/* X AXIS */
|
||||||
.with(GBlockstate.when(CORNER, DOWN_EAST),
|
.with(GBlockstate.when(EDGE, DOWN_EAST),
|
||||||
GBlockstate.variant(step_id, true, R0, R0))
|
GBlockstate.variant(model_id, true, R0, R0))
|
||||||
.with(GBlockstate.when(CORNER, EAST_UP),
|
.with(GBlockstate.when(EDGE, EAST_UP),
|
||||||
GBlockstate.variant(step_id, true, R180, R0))
|
GBlockstate.variant(model_id, true, R180, R0))
|
||||||
.with(GBlockstate.when(CORNER, UP_WEST),
|
.with(GBlockstate.when(EDGE, UP_WEST),
|
||||||
GBlockstate.variant(step_id, true, R180, R180))
|
GBlockstate.variant(model_id, true, R180, R180))
|
||||||
.with(GBlockstate.when(CORNER, WEST_DOWN),
|
.with(GBlockstate.when(EDGE, WEST_DOWN),
|
||||||
GBlockstate.variant(step_id, true, R0, R180))
|
GBlockstate.variant(model_id, true, R0, R180))
|
||||||
/* Y AXIS */
|
/* Y AXIS */
|
||||||
.with(GBlockstate.when(CORNER, EAST_SOUTH),
|
.with(GBlockstate.when(EDGE, EAST_SOUTH),
|
||||||
GBlockstate.variant(step_id, true, R90, R0))
|
GBlockstate.variant(model_id, true, R90, R0))
|
||||||
.with(GBlockstate.when(CORNER, SOUTH_WEST),
|
.with(GBlockstate.when(EDGE, SOUTH_WEST),
|
||||||
GBlockstate.variant(step_id, true, R90, R90))
|
GBlockstate.variant(model_id, true, R90, R90))
|
||||||
.with(GBlockstate.when(CORNER, WEST_NORTH),
|
.with(GBlockstate.when(EDGE, WEST_NORTH),
|
||||||
GBlockstate.variant(step_id, true, R90, R180))
|
GBlockstate.variant(model_id, true, R90, R180))
|
||||||
.with(GBlockstate.when(CORNER, NORTH_EAST),
|
.with(GBlockstate.when(EDGE, NORTH_EAST),
|
||||||
GBlockstate.variant(step_id, true, R90, R270))
|
GBlockstate.variant(model_id, true, R90, R270))
|
||||||
/* Z AXIS */
|
/* Z AXIS */
|
||||||
.with(GBlockstate.when(CORNER, DOWN_SOUTH),
|
.with(GBlockstate.when(EDGE, DOWN_SOUTH),
|
||||||
GBlockstate.variant(step_id, true, R0, R90))
|
GBlockstate.variant(model_id, true, R0, R90))
|
||||||
.with(GBlockstate.when(CORNER, NORTH_DOWN),
|
.with(GBlockstate.when(EDGE, NORTH_DOWN),
|
||||||
GBlockstate.variant(step_id, true, R0, R270))
|
GBlockstate.variant(model_id, true, R0, R270))
|
||||||
.with(GBlockstate.when(CORNER, UP_NORTH),
|
.with(GBlockstate.when(EDGE, UP_NORTH),
|
||||||
GBlockstate.variant(step_id, true, R180, R270))
|
GBlockstate.variant(model_id, true, R180, R270))
|
||||||
.with(GBlockstate.when(CORNER, SOUTH_UP),
|
.with(GBlockstate.when(EDGE, SOUTH_UP),
|
||||||
GBlockstate.variant(step_id, true, R180, R90));
|
GBlockstate.variant(model_id, true, R180, R90));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -116,21 +114,22 @@ public class ReFramedStepBlock extends WaterloggableReFramedBlock implements Blo
|
|||||||
}
|
}
|
||||||
|
|
||||||
static {
|
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 = VoxelListBuilder.create(STEP, 12)
|
||||||
STEP_VOXELS.add(VoxelHelper.mirror(STEP, Direction.Axis.Z));
|
.add(VoxelHelper::rotateCX)
|
||||||
STEP_VOXELS.add(VoxelHelper.mirror(VoxelHelper.rotateCounterClockwise(STEP, Direction.Axis.X), Direction.Axis.Z));
|
.add(VoxelHelper::rotateCX)
|
||||||
STEP_VOXELS.add(VoxelHelper.rotateCounterClockwise(STEP, Direction.Axis.X));
|
.add(VoxelHelper::rotateCX)
|
||||||
|
|
||||||
STEP_VOXELS.add(VoxelHelper.rotateCounterClockwise(STEP, Direction.Axis.Y));
|
.add(STEP, VoxelHelper::rotateCY)
|
||||||
STEP_VOXELS.add(VoxelHelper.mirror(VoxelHelper.rotateCounterClockwise(STEP, Direction.Axis.Y), Direction.Axis.X));
|
.add(VoxelHelper::rotateZ)
|
||||||
STEP_VOXELS.add(VoxelHelper.mirror(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(STEP, Direction.Axis.Y), Direction.Axis.Z), Direction.Axis.X));
|
.add(VoxelHelper::rotateZ)
|
||||||
STEP_VOXELS.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateCounterClockwise(STEP, Direction.Axis.Y), Direction.Axis.Z));
|
.add(VoxelHelper::rotateZ)
|
||||||
|
|
||||||
STEP_VOXELS.add(VoxelHelper.rotateCounterClockwise(VoxelHelper.rotateClockwise(STEP, Direction.Axis.Z), Direction.Axis.Y));
|
.add(STEP, VoxelHelper::rotateCZ)
|
||||||
STEP_VOXELS.add(VoxelHelper.rotateClockwise(STEP, Direction.Axis.Z));
|
.add(VoxelHelper::rotateY)
|
||||||
STEP_VOXELS.add(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(STEP, Direction.Axis.Z), Direction.Axis.Y));
|
.add(VoxelHelper::rotateY)
|
||||||
STEP_VOXELS.add(VoxelHelper.mirror(VoxelHelper.rotateClockwise(VoxelHelper.rotateClockwise(STEP, Direction.Axis.Z), Direction.Axis.Y), Direction.Axis.Z));
|
.add(VoxelHelper::rotateY)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package fr.adrien1106.reframed.block;
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
import fr.adrien1106.reframed.generator.GBlockstate;
|
|
||||||
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
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.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
@ -24,19 +25,31 @@ import net.minecraft.util.shape.VoxelShape;
|
|||||||
import net.minecraft.world.BlockView;
|
import net.minecraft.world.BlockView;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import static fr.adrien1106.reframed.block.ReFramedSlabBlock.*;
|
import static fr.adrien1106.reframed.block.ReFramedSlabBlock.getSlabShape;
|
||||||
import static fr.adrien1106.reframed.block.ReFramedStepBlock.STEP_VOXELS;
|
import static fr.adrien1106.reframed.block.ReFramedStepBlock.getStepShape;
|
||||||
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
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.AXIS;
|
||||||
|
import static net.minecraft.state.property.Properties.FACING;
|
||||||
import static net.minecraft.util.shape.VoxelShapes.empty;
|
import static net.minecraft.util.shape.VoxelShapes.empty;
|
||||||
|
|
||||||
public class ReFramedDoubleStepBlock extends WaterloggableReFramedDoubleBlock implements BlockStateProvider {
|
public class ReFramedStepsSlabBlock extends WaterloggableReFramedDoubleBlock implements BlockStateProvider {
|
||||||
public ReFramedDoubleStepBlock(Settings settings) {
|
private record ModelCacheKey(Direction facing, Axis axis) {}
|
||||||
|
|
||||||
|
public ReFramedStepsSlabBlock(Settings settings) {
|
||||||
super(settings);
|
super(settings);
|
||||||
setDefaultState(getDefaultState().with(FACING, Direction.DOWN).with(AXIS, Axis.X));
|
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
|
@Override
|
||||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
super.appendProperties(builder.add(FACING, AXIS));
|
super.appendProperties(builder.add(FACING, AXIS));
|
||||||
@ -63,36 +76,41 @@ public class ReFramedDoubleStepBlock extends WaterloggableReFramedDoubleBlock im
|
|||||||
@Override
|
@Override
|
||||||
public VoxelShape getShape(BlockState state, int i) {
|
public VoxelShape getShape(BlockState state, int i) {
|
||||||
Axis axis = state.get(AXIS);
|
Axis axis = state.get(AXIS);
|
||||||
return STEP_VOXELS.get(switch (state.get(FACING)) {
|
return getStepShape(Edge.getByDirections(
|
||||||
case DOWN -> axis == Axis.Z ? (i == 1 ? 0 : 1): (i == 1 ? 4 : 5 );
|
state.get(FACING),
|
||||||
case UP -> axis == Axis.Z ? (i == 1 ? 3 : 2): (i == 1 ? 7 : 6 );
|
switch (axis) {
|
||||||
case NORTH -> axis == Axis.Y ? (i == 1 ? 1 : 2): (i == 1 ? 11 : 8 );
|
case X -> i == 1 ? Direction.WEST : Direction.EAST;
|
||||||
case SOUTH -> axis == Axis.Y ? (i == 1 ? 0 : 3): (i == 1 ? 9 : 10);
|
case Y -> i == 1 ? Direction.DOWN : Direction.UP;
|
||||||
case EAST -> axis == Axis.Y ? (i == 1 ? 4 : 7): (i == 1 ? 8 : 9 );
|
case Z -> i == 1 ? Direction.SOUTH : Direction.NORTH;
|
||||||
case WEST -> axis == Axis.Y ? (i == 1 ? 5 : 6): (i == 1 ? 10 : 11);
|
}
|
||||||
});
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTopThemeIndex(BlockState state) {
|
||||||
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MultipartBlockStateSupplier getMultipart() {
|
public MultipartBlockStateSupplier getMultipart() {
|
||||||
Identifier step_id = ReFramed.id("double_step_special");
|
Identifier step_id = ReFramed.id("steps_slab_special");
|
||||||
Identifier step_side_id = ReFramed.id("double_step_side_special");
|
Identifier step_side_id = ReFramed.id("steps_slab_side_special");
|
||||||
return MultipartBlockStateSupplier.create(this)
|
return MultipartBlockStateSupplier.create(this)
|
||||||
.with(GBlockstate.when(FACING, Direction.DOWN, AXIS, Axis.X),
|
.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),
|
.with(GBlockstate.when(FACING, Direction.DOWN, AXIS, Axis.Z),
|
||||||
GBlockstate.variant(step_id, true, R0, R90))
|
GBlockstate.variant(step_id, true, R0, R90))
|
||||||
.with(GBlockstate.when(FACING, Direction.UP, AXIS, Axis.X),
|
.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),
|
.with(GBlockstate.when(FACING, Direction.UP, AXIS, Axis.Z),
|
||||||
GBlockstate.variant(step_id, true, R180, R90))
|
GBlockstate.variant(step_id, true, R180, R90))
|
||||||
|
|
||||||
.with(GBlockstate.when(FACING, Direction.EAST, AXIS, Axis.Z),
|
.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),
|
.with(GBlockstate.when(FACING, Direction.EAST, AXIS, Axis.Y),
|
||||||
GBlockstate.variant(step_side_id, true, R90, R0))
|
GBlockstate.variant(step_side_id, true, R90, R0))
|
||||||
.with(GBlockstate.when(FACING, Direction.SOUTH, AXIS, Axis.X),
|
.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),
|
.with(GBlockstate.when(FACING, Direction.SOUTH, AXIS, Axis.Y),
|
||||||
GBlockstate.variant(step_side_id, true, R90, R90))
|
GBlockstate.variant(step_side_id, true, R90, R90))
|
||||||
.with(GBlockstate.when(FACING, Direction.WEST, AXIS, Axis.Z),
|
.with(GBlockstate.when(FACING, Direction.WEST, AXIS, Axis.Z),
|
@ -26,31 +26,68 @@ public class ReFramedClient implements ClientModInitializer {
|
|||||||
//all frames mustn't be on the SOLID layer because they are not opaque!
|
//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]));
|
BlockRenderLayerMap.INSTANCE.putBlocks(RenderLayer.getCutout(), ReFramed.BLOCKS.toArray(new Block[0]));
|
||||||
|
|
||||||
HELPER.addReFramedModel("cube_special" , HELPER.auto(new Identifier("block/cube")));
|
// CUBE
|
||||||
HELPER.addReFramedModel("slab_special" , HELPER.auto(new Identifier("block/slab")));
|
HELPER.addReFramedModel("cube_special" , HELPER.auto(new Identifier("block/cube")));
|
||||||
HELPER.addReFramedModel("double_slab_special" , HELPER.autoDouble(new Identifier("block/slab"), new Identifier("block/slab_top")));
|
// SMALL_CUBE
|
||||||
HELPER.addReFramedModel("stairs_special" , HELPER.auto(ReFramed.id("block/stairs")));
|
HELPER.addReFramedModel("small_cube_special" , HELPER.auto(ReFramed.id("block/small_cube/base")));
|
||||||
HELPER.addReFramedModel("outers_stairs_special" , HELPER.auto(ReFramed.id("block/double_outer_stairs")));
|
// SMALL_CUBES_STEP
|
||||||
HELPER.addReFramedModel("inner_stairs_special" , HELPER.auto(ReFramed.id("block/inner_stairs")));
|
HELPER.addReFramedModel("small_cubes_step_special" , HELPER.autoDouble(ReFramed.id("block/small_cube/base"), ReFramed.id("block/small_cube/step/base")));
|
||||||
HELPER.addReFramedModel("outer_stairs_special" , HELPER.auto(ReFramed.id("block/outer_stairs")));
|
HELPER.addReFramedModel("small_cubes_step_reverse_special" , HELPER.autoDouble(ReFramed.id("block/small_cube/step/base"), ReFramed.id("block/small_cube/base")));
|
||||||
HELPER.addReFramedModel("outer_side_stairs_special" , HELPER.auto(ReFramed.id("block/outer_side_stairs")));
|
// SLAB
|
||||||
HELPER.addReFramedModel("double_stairs_special" , HELPER.autoDouble(ReFramed.id("block/stairs"), ReFramed.id("block/stairs_complement")));
|
HELPER.addReFramedModel("slab_special" , HELPER.auto(new Identifier("block/slab")));
|
||||||
HELPER.addReFramedModel("double_outers_stairs_special" , HELPER.autoDouble(ReFramed.id("block/double_outer_stairs"), ReFramed.id("block/double_outer_stairs_complement")));
|
// SLAB_CUBE
|
||||||
HELPER.addReFramedModel("double_inner_stairs_special" , HELPER.autoDouble(ReFramed.id("block/inner_stairs"), ReFramed.id("block/inner_stairs_complement")));
|
HELPER.addReFramedModel("double_slab_special" , HELPER.autoDouble(new Identifier("block/slab"), new Identifier("block/slab_top")));
|
||||||
HELPER.addReFramedModel("double_outer_stairs_special" , HELPER.autoDouble(ReFramed.id("block/outer_stairs"), ReFramed.id("block/outer_stairs_complement")));
|
// STAIR
|
||||||
HELPER.addReFramedModel("double_outer_side_stairs_special", HELPER.autoDouble(ReFramed.id("block/outer_side_stairs"), ReFramed.id("block/outer_side_stairs_complement")));
|
HELPER.addReFramedModel("stair_special" , HELPER.auto(ReFramed.id("block/stair/straight")));
|
||||||
HELPER.addReFramedModel("step_special" , HELPER.auto(ReFramed.id("block/step")));
|
HELPER.addReFramedModel("outers_stair_special" , HELPER.auto(ReFramed.id("block/stair/double_outer")));
|
||||||
HELPER.addReFramedModel("double_step_special" , HELPER.autoDouble(ReFramed.id("block/step"), ReFramed.id("block/step_complement_slab")));
|
HELPER.addReFramedModel("inner_stair_special" , HELPER.auto(ReFramed.id("block/stair/inner")));
|
||||||
HELPER.addReFramedModel("double_step_side_special" , HELPER.autoDouble(ReFramed.id("block/step_side"), ReFramed.id("block/step_side_complement_slab")));
|
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)
|
//item model assignments (in lieu of models/item/___.json)
|
||||||
HELPER.assignItemModel("cube_special" , ReFramed.CUBE);
|
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("slab_special" , ReFramed.SLAB);
|
||||||
HELPER.assignItemModel("double_slab_special" , ReFramed.DOUBLE_SLAB);
|
HELPER.assignItemModel("double_slab_special" , ReFramed.SLABS_CUBE);
|
||||||
HELPER.assignItemModel("stairs_special" , ReFramed.STAIRS);
|
HELPER.assignItemModel("stair_special" , ReFramed.STAIR);
|
||||||
HELPER.assignItemModel("double_stairs_special" , ReFramed.DOUBLE_STAIRS);
|
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("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() {
|
private void privateInit() {
|
||||||
|
@ -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.model.ForwardingBakedModel;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.client.render.model.BakedModel;
|
|
||||||
import net.minecraft.client.texture.Sprite;
|
import net.minecraft.client.texture.Sprite;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
@ -45,7 +44,7 @@ public class DoubleRetexturingBakedModel extends ForwardingBakedModel implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<BakedModel> models() {
|
public List<ForwardingBakedModel> models() {
|
||||||
return List.of(model_1, model_2);
|
return List.of(model_1, model_2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package fr.adrien1106.reframed.client.model;
|
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;
|
import java.util.List;
|
||||||
|
|
||||||
public interface MultiRetexturableModel {
|
public interface MultiRetexturableModel {
|
||||||
|
|
||||||
List<BakedModel> models();
|
List<ForwardingBakedModel> models();
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
package fr.adrien1106.reframed.client.model;
|
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.MutableQuadView;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
|
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
import org.joml.Vector3f;
|
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 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) {
|
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);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package fr.adrien1106.reframed.client.model;
|
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.MutableQuadView;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
|
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
|
||||||
import net.minecraft.client.texture.Sprite;
|
import net.minecraft.client.texture.Sprite;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
public record QuadUvBounds(float minU, float maxU, float minV, float maxV) {
|
public record QuadUvBounds(float minU, float maxU, float minV, float maxV) {
|
||||||
public static QuadUvBounds read(QuadView quad) {
|
public static QuadUvBounds read(QuadView quad) {
|
||||||
float u0 = quad.u(0), u1 = quad.u(1), u2 = quad.u(2), u3 = quad.u(3);
|
float u0 = quad.u(0), u1 = quad.u(1), u2 = quad.u(2), u3 = quad.u(3);
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
package fr.adrien1106.reframed.client.model;
|
package fr.adrien1106.reframed.client.model;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.block.ReFramedBlock;
|
||||||
import fr.adrien1106.reframed.block.ReFramedEntity;
|
import fr.adrien1106.reframed.block.ReFramedEntity;
|
||||||
import fr.adrien1106.reframed.client.ReFramedClient;
|
import fr.adrien1106.reframed.client.ReFramedClient;
|
||||||
import fr.adrien1106.reframed.client.model.apperance.SpriteProperties;
|
|
||||||
import fr.adrien1106.reframed.mixin.MinecraftAccessor;
|
import fr.adrien1106.reframed.mixin.MinecraftAccessor;
|
||||||
import fr.adrien1106.reframed.client.model.apperance.CamoAppearance;
|
import fr.adrien1106.reframed.client.model.apperance.CamoAppearance;
|
||||||
import fr.adrien1106.reframed.client.model.apperance.CamoAppearanceManager;
|
import fr.adrien1106.reframed.client.model.apperance.CamoAppearanceManager;
|
||||||
import fr.adrien1106.reframed.client.model.apperance.WeightedComputedAppearance;
|
import fr.adrien1106.reframed.client.model.apperance.WeightedComputedAppearance;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder;
|
import net.fabricmc.fabric.api.renderer.v1.mesh.*;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
|
||||||
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
|
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||||
import net.minecraft.block.BlockState;
|
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.util.math.random.Random;
|
||||||
import net.minecraft.world.BlockRenderView;
|
import net.minecraft.world.BlockRenderView;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
||||||
public RetexturingBakedModel(BakedModel base_model, CamoAppearanceManager tam, int theme_index, ModelBakeSettings settings, BlockState item_state, boolean ao) {
|
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.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.theme_index = theme_index;
|
||||||
this.uv_lock = settings.isUvLocked();
|
this.uv_lock = settings.isUvLocked();
|
||||||
this.item_state = item_state;
|
this.item_state = item_state;
|
||||||
this.ao = ao;
|
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 int theme_index;
|
||||||
protected final boolean uv_lock;
|
protected final boolean uv_lock;
|
||||||
protected final BlockState item_state;
|
|
||||||
protected final boolean ao;
|
protected final boolean ao;
|
||||||
|
protected final BlockState item_state;
|
||||||
|
|
||||||
/* ----------------------------------------------- CACHE ELEMENT ------------------------------------------------ */
|
protected record MeshCacheKey(Object state_key, CamoAppearance appearance, int model_id) {}
|
||||||
// TODO make static ? for connected textures ?
|
/** cache that store retextured models */
|
||||||
protected record MeshCacheKey(BlockState state, TransformCacheKey transform) {}
|
protected final Object2ObjectLinkedOpenHashMap<MeshCacheKey, Mesh> RETEXTURED_MESH_CACHE =
|
||||||
protected record TransformCacheKey(CamoAppearance appearance, int model_id) {}
|
new Object2ObjectLinkedOpenHashMap<>(128, 0.25f) {
|
||||||
protected final ConcurrentMap<TransformCacheKey, RetexturingTransformer> retextured_transforms = new ConcurrentHashMap<>();
|
@Override
|
||||||
protected final ConcurrentMap<MeshCacheKey, Mesh> retextured_meshes = new ConcurrentHashMap<>(); //mutable, append-only cache
|
protected void rehash(int v) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** cache that stores the base meshes which has the size of the amount of models */
|
||||||
|
protected final Object2ObjectLinkedOpenHashMap<Object, Mesh> BASE_MESH_CACHE;
|
||||||
|
|
||||||
protected static final Direction[] DIRECTIONS_AND_NULL;
|
protected static final Direction[] DIRECTIONS_AND_NULL;
|
||||||
static {
|
static {
|
||||||
@ -62,11 +69,12 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
|||||||
System.arraycopy(values, 0, DIRECTIONS_AND_NULL, 0, values.length);
|
System.arraycopy(values, 0, DIRECTIONS_AND_NULL, 0, values.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final ConcurrentMap<BlockState, Mesh> jsonToMesh = new ConcurrentHashMap<>();
|
protected Mesh getBaseMesh(Object key, BlockState state) {
|
||||||
|
|
||||||
protected Mesh getBaseMesh(BlockState state) {
|
|
||||||
//Convert models to re-texturable Meshes lazily, the first time we encounter each blockstate
|
//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);
|
protected abstract Mesh convertModel(BlockState state);
|
||||||
@ -78,39 +86,42 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Sprite getParticleSprite() {
|
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
|
@Override
|
||||||
public void emitBlockQuads(BlockRenderView world, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
|
public void emitBlockQuads(BlockRenderView world, BlockState state, BlockPos pos, Supplier<Random> 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;
|
BlockState theme = (world.getBlockEntity(pos) instanceof ThemeableBlockEntity s) ? s.getTheme(theme_index) : null;
|
||||||
QuadEmitter quad_emitter = context.getEmitter();
|
QuadEmitter quad_emitter = context.getEmitter();
|
||||||
if(theme == null || theme.isAir()) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if(theme.getBlock() == Blocks.BARRIER) 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);
|
long seed = theme.getRenderingSeed(pos);
|
||||||
int model_id = 0;
|
int model_id = 0;
|
||||||
if (camo instanceof WeightedComputedAppearance wca) model_id = wca.getAppearanceIndex(seed);
|
if (camo instanceof WeightedComputedAppearance wca) model_id = wca.getAppearanceIndex(seed);
|
||||||
|
|
||||||
int tint = 0xFF000000 | MinecraftClient.getInstance().getBlockColors().getColor(theme, world, pos, 0);
|
int tint = 0xFF000000 | MinecraftClient.getInstance().getBlockColors().getColor(theme, world, pos, 0);
|
||||||
Mesh untintedMesh = getUntintedRetexturedMesh(
|
Mesh untintedMesh = getRetexturedMesh(new MeshCacheKey(frame_block.getModelCacheKey(state), camo, model_id), state);
|
||||||
new MeshCacheKey(
|
|
||||||
state,
|
|
||||||
new TransformCacheKey(camo, model_id)
|
|
||||||
),
|
|
||||||
seed
|
|
||||||
);
|
|
||||||
|
|
||||||
//The specific tint might vary a lot; imagine grass color smoothly changing. Trying to bake the tint into
|
//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.
|
//the cached mesh will pollute it with a ton of single-use meshes with only slightly different colors.
|
||||||
if(tint == 0xFFFFFFFF) {
|
if(tint == 0xFFFFFFFF) {
|
||||||
untintedMesh.outputTo(quad_emitter);
|
untintedMesh.outputTo(quad_emitter);
|
||||||
} else {
|
} else {
|
||||||
context.pushTransform(new TintingTransformer(camo, tint, seed));
|
context.pushTransform(new TintingTransformer(camo, model_id, tint));
|
||||||
untintedMesh.outputTo(quad_emitter);
|
untintedMesh.outputTo(quad_emitter);
|
||||||
context.popTransform();
|
context.popTransform();
|
||||||
}
|
}
|
||||||
@ -120,121 +131,72 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
|||||||
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
|
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
|
||||||
//cheeky: if the item has NBT data, pluck out the blockstate from it & look up the item color provider
|
//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
|
//none of this is accessible unless you're in creative mode doing ctrl-pick btw
|
||||||
CamoAppearance nbtAppearance;
|
CamoAppearance appearance;
|
||||||
int tint;
|
int tint;
|
||||||
BlockState theme = ReFramedEntity.readStateFromItem(stack, theme_index);
|
BlockState theme = ReFramedEntity.readStateFromItem(stack, theme_index);
|
||||||
if(!theme.isAir()) {
|
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);
|
tint = 0xFF000000 | ((MinecraftAccessor) MinecraftClient.getInstance()).getItemColors().getColor(new ItemStack(theme.getBlock()), 0);
|
||||||
} else {
|
} else {
|
||||||
nbtAppearance = tam.getDefaultAppearance(theme_index);
|
appearance = appearance_manager.getDefaultAppearance(theme_index);
|
||||||
tint = 0xFFFFFFFF;
|
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();
|
QuadEmitter quad_emitter = context.getEmitter();
|
||||||
if(tint == 0xFFFFFFFF) {
|
if(tint == 0xFFFFFFFF) {
|
||||||
untintedMesh.outputTo(quad_emitter);
|
untintedMesh.outputTo(quad_emitter);
|
||||||
} else {
|
} else {
|
||||||
context.pushTransform(new TintingTransformer(nbtAppearance, tint, 0));
|
context.pushTransform(new TintingTransformer(appearance, 0, tint));
|
||||||
untintedMesh.outputTo(quad_emitter);
|
untintedMesh.outputTo(quad_emitter);
|
||||||
context.popTransform();
|
context.popTransform();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Mesh getUntintedRetexturedMesh(MeshCacheKey key, long seed) {
|
protected Mesh getRetexturedMesh(MeshCacheKey key, BlockState state) {
|
||||||
return retextured_meshes.computeIfAbsent(key, (k) -> createUntintedRetexturedMesh(k, seed));
|
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) {
|
protected Mesh transformMesh(MeshCacheKey key, BlockState state) {
|
||||||
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) {
|
|
||||||
MeshBuilder builder = ReFramedClient.HELPER.getFabricRenderer().meshBuilder();
|
MeshBuilder builder = ReFramedClient.HELPER.getFabricRenderer().meshBuilder();
|
||||||
QuadEmitter emitter = builder.getEmitter();
|
QuadEmitter emitter = builder.getEmitter();
|
||||||
|
|
||||||
mesh.forEach(quad -> {
|
AtomicInteger quad_index = new AtomicInteger();
|
||||||
|
getBaseMesh(key.state_key, state).forEach(quad -> {
|
||||||
int i = -1;
|
int i = -1;
|
||||||
do {
|
do {
|
||||||
emitter.copyFrom(quad);
|
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);
|
} 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();
|
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<SpriteProperties> 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 {
|
protected static class TintingTransformer implements RenderContext.QuadTransform {
|
||||||
private final long seed;
|
private final CamoAppearance appearance;
|
||||||
protected TintingTransformer(CamoAppearance ta, int tint, long seed) {
|
private final int model_id;
|
||||||
this.ta = ta;
|
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.tint = tint;
|
||||||
this.seed = seed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final CamoAppearance ta;
|
|
||||||
protected final int tint;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean transform(MutableQuadView quad) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ public class UnbakedAutoRetexturedModel extends UnbakedRetexturedModel {
|
|||||||
Renderer r = ReFramedClient.HELPER.getFabricRenderer();
|
Renderer r = ReFramedClient.HELPER.getFabricRenderer();
|
||||||
MeshBuilder builder = r.meshBuilder();
|
MeshBuilder builder = r.meshBuilder();
|
||||||
QuadEmitter emitter = builder.getEmitter();
|
QuadEmitter emitter = builder.getEmitter();
|
||||||
RenderMaterial mat = tam.getCachedMaterial(state, false);
|
RenderMaterial mat = appearance_manager.getCachedMaterial(state, false);
|
||||||
|
|
||||||
Random rand = Random.create(42);
|
Random rand = Random.create(42);
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ public class UnbakedJsonRetexturedModel extends UnbakedRetexturedModel {
|
|||||||
Renderer r = ReFramedClient.HELPER.getFabricRenderer();
|
Renderer r = ReFramedClient.HELPER.getFabricRenderer();
|
||||||
MeshBuilder builder = r.meshBuilder();
|
MeshBuilder builder = r.meshBuilder();
|
||||||
QuadEmitter emitter = builder.getEmitter();
|
QuadEmitter emitter = builder.getEmitter();
|
||||||
RenderMaterial mat = tam.getCachedMaterial(state, false);
|
RenderMaterial mat = appearance_manager.getCachedMaterial(state, false);
|
||||||
|
|
||||||
Random rand = Random.create(42);
|
Random rand = Random.create(42);
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ public abstract class UnbakedRetexturedModel implements UnbakedModel {
|
|||||||
|
|
||||||
protected int theme_index = 1;
|
protected int theme_index = 1;
|
||||||
protected BlockState item_state;
|
protected BlockState item_state;
|
||||||
protected boolean ao = true;
|
protected final boolean ao = true;
|
||||||
|
|
||||||
public UnbakedRetexturedModel(Identifier parent) {
|
public UnbakedRetexturedModel(Identifier parent) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
|
@ -1,13 +1,80 @@
|
|||||||
package fr.adrien1106.reframed.client.model.apperance;
|
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.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 net.minecraft.util.math.Direction;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface CamoAppearance {
|
@Environment(EnvType.CLIENT)
|
||||||
@NotNull RenderMaterial getRenderMaterial(boolean ao);
|
public abstract class CamoAppearance {
|
||||||
@NotNull List<SpriteProperties> getSprites(Direction dir, long seed);
|
protected final int id;
|
||||||
boolean hasColor(Direction dir, long seed, int index);
|
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<SpriteProperties> 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<SpriteProperties> 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
package fr.adrien1106.reframed.client.model.apperance;
|
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.ReFramed;
|
||||||
import fr.adrien1106.reframed.client.ReFramedClient;
|
import fr.adrien1106.reframed.client.ReFramedClient;
|
||||||
import fr.adrien1106.reframed.client.model.DynamicBakedModel;
|
import fr.adrien1106.reframed.client.model.DynamicBakedModel;
|
||||||
import fr.adrien1106.reframed.client.model.QuadPosBounds;
|
import fr.adrien1106.reframed.client.model.QuadPosBounds;
|
||||||
import fr.adrien1106.reframed.mixin.model.WeightedBakedModelAccessor;
|
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.Renderer;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
|
import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.material.MaterialFinder;
|
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 net.minecraft.world.BlockRenderView;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
public class CamoAppearanceManager {
|
public class CamoAppearanceManager {
|
||||||
|
|
||||||
public CamoAppearanceManager(Function<SpriteIdentifier, Sprite> spriteLookup) {
|
public CamoAppearanceManager(Function<SpriteIdentifier, Sprite> spriteLookup) {
|
||||||
@ -40,20 +44,20 @@ public class CamoAppearanceManager {
|
|||||||
for(BlendMode blend : BlendMode.values()) {
|
for(BlendMode blend : BlendMode.values()) {
|
||||||
finder.clear().disableDiffuse(false).blendMode(blend);
|
finder.clear().disableDiffuse(false).blendMode(blend);
|
||||||
|
|
||||||
materialsWithoutAo.put(blend, finder.ambientOcclusion(TriState.FALSE).find());
|
materials.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
|
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);
|
Sprite sprite = spriteLookup.apply(DEFAULT_SPRITE_MAIN);
|
||||||
if(sprite == null) throw new IllegalStateException("Couldn't locate " + 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);
|
sprite = spriteLookup.apply(DEFAULT_SPRITE_SECONDARY);
|
||||||
if(sprite == null) throw new IllegalStateException("Couldn't locate " + DEFAULT_SPRITE_MAIN + " !");
|
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);
|
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"));
|
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 default_appearance;
|
||||||
private final CamoAppearance accent_appearance;
|
private final CamoAppearance accent_appearance;
|
||||||
private final CamoAppearance barrierItemAppearance;
|
private final CamoAppearance barrierItemAppearance;
|
||||||
|
|
||||||
private final ConcurrentHashMap<BlockState, CamoAppearance> appearanceCache = new ConcurrentHashMap<>(); //Mutable, append-only cache
|
private static final Cache<BlockState, CamoAppearance> APPEARANCE_CACHE = CacheBuilder.newBuilder().maximumSize(2048).build();
|
||||||
|
|
||||||
private final AtomicInteger serial_number = new AtomicInteger(0); //Mutable
|
private final AtomicInteger serial_number = new AtomicInteger(0); //Mutable
|
||||||
|
|
||||||
private final EnumMap<BlendMode, RenderMaterial> materialsWithAo = new EnumMap<>(BlendMode.class);
|
private final EnumMap<BlendMode, RenderMaterial> ao_materials = new EnumMap<>(BlendMode.class);
|
||||||
private final EnumMap<BlendMode, RenderMaterial> materialsWithoutAo = new EnumMap<>(BlendMode.class); //Immutable contents
|
private final EnumMap<BlendMode, RenderMaterial> materials = new EnumMap<>(BlendMode.class); //Immutable contents
|
||||||
|
|
||||||
public CamoAppearance getDefaultAppearance(int appearance) {
|
public CamoAppearance getDefaultAppearance(int appearance) {
|
||||||
return appearance == 2 ? accent_appearance: default_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);
|
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
|
// add support for connected textures and more generally any compatible models injected so that they return baked quads
|
||||||
if (model instanceof DynamicBakedModel dynamic_model) {
|
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) {
|
public RenderMaterial getCachedMaterial(BlockState state, boolean ao) {
|
||||||
Map<BlendMode, RenderMaterial> m = ao ? materialsWithAo : materialsWithoutAo;
|
Map<BlendMode, RenderMaterial> m = ao ? ao_materials : materials;
|
||||||
return m.get(BlendMode.fromRenderLayer(RenderLayers.getBlockLayer(state)));
|
return m.get(BlendMode.fromRenderLayer(RenderLayers.getBlockLayer(state)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,38 +1,30 @@
|
|||||||
package fr.adrien1106.reframed.client.model.apperance;
|
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.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ComputedAppearance implements CamoAppearance {
|
@Environment(EnvType.CLIENT)
|
||||||
|
public class ComputedAppearance extends CamoAppearance {
|
||||||
private final Appearance appearance;
|
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.appearance = appearance;
|
||||||
this.id = id;
|
|
||||||
|
|
||||||
this.matWithAo = withAo;
|
|
||||||
this.matWithoutAo = withoutAo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull RenderMaterial getRenderMaterial(boolean ao) {
|
public @NotNull List<SpriteProperties> getSprites(Direction dir, int model_id) {
|
||||||
return ao ? matWithAo : matWithoutAo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull List<SpriteProperties> getSprites(Direction dir, long seed) {
|
|
||||||
return appearance.sprites().get(dir);
|
return appearance.sprites().get(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasColor(Direction dir, long seed, int index) {
|
public boolean hasColor(Direction dir, int model_id, int index) {
|
||||||
List<SpriteProperties> properties = getSprites(dir, seed);
|
List<SpriteProperties> properties = getSprites(dir, model_id);
|
||||||
if (index != 0) index = properties.size() - index;
|
if (index != 0) index = properties.size() - index;
|
||||||
return properties.get(index).has_colors();
|
return properties.get(index).has_colors();
|
||||||
}
|
}
|
||||||
@ -40,13 +32,7 @@ public class ComputedAppearance implements CamoAppearance {
|
|||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if(this == o) return true;
|
if(this == o) return true;
|
||||||
if(o == null || getClass() != o.getClass()) return false;
|
if(!(o instanceof ComputedAppearance that)) return false;
|
||||||
ComputedAppearance that = (ComputedAppearance) o;
|
|
||||||
return id == that.id;
|
return id == that.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package fr.adrien1106.reframed.client.model.apperance;
|
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.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
||||||
import net.minecraft.client.texture.Sprite;
|
import net.minecraft.client.texture.Sprite;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
@ -7,47 +9,34 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class SingleSpriteAppearance implements CamoAppearance {
|
@Environment(EnvType.CLIENT)
|
||||||
|
public class SingleSpriteAppearance extends CamoAppearance {
|
||||||
private final @NotNull Sprite defaultSprite;
|
private final @NotNull Sprite defaultSprite;
|
||||||
private final RenderMaterial mat;
|
|
||||||
private final int id;
|
|
||||||
|
|
||||||
public SingleSpriteAppearance(@NotNull Sprite defaultSprite, RenderMaterial mat, int id) {
|
public SingleSpriteAppearance(@NotNull Sprite defaultSprite, RenderMaterial mat, int id) {
|
||||||
|
super(null, mat, id);
|
||||||
this.defaultSprite = defaultSprite;
|
this.defaultSprite = defaultSprite;
|
||||||
this.mat = mat;
|
|
||||||
this.id = id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull RenderMaterial getRenderMaterial(boolean ao) {
|
public @NotNull List<SpriteProperties> getSprites(Direction dir, int model_id) {
|
||||||
return mat;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull List<SpriteProperties> getSprites(Direction dir, long seed) {
|
|
||||||
return List.of(new SpriteProperties(defaultSprite, 0, null, false));
|
return List.of(new SpriteProperties(defaultSprite, 0, null, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasColor(Direction dir, long seed, int index) {
|
public boolean hasColor(Direction dir, int model_id, int index) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if(this == o) return true;
|
if(this == o) return true;
|
||||||
if(o == null || getClass() != o.getClass()) return false;
|
if(!(o instanceof SingleSpriteAppearance that)) return false;
|
||||||
SingleSpriteAppearance that = (SingleSpriteAppearance) o;
|
|
||||||
return id == that.id;
|
return id == that.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package fr.adrien1106.reframed.client.model.apperance;
|
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.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
||||||
import net.minecraft.util.collection.Weighted;
|
import net.minecraft.util.collection.Weighted;
|
||||||
import net.minecraft.util.collection.Weighting;
|
import net.minecraft.util.collection.Weighting;
|
||||||
@ -9,25 +11,15 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class WeightedComputedAppearance implements CamoAppearance {
|
@Environment(EnvType.CLIENT)
|
||||||
|
public class WeightedComputedAppearance extends CamoAppearance {
|
||||||
private final List<Weighted.Present<Appearance>> appearances;
|
private final List<Weighted.Present<Appearance>> appearances;
|
||||||
private final int total_weight;
|
private final int total_weight;
|
||||||
private final int id;
|
|
||||||
private final RenderMaterial matWithAo;
|
|
||||||
private final RenderMaterial matWithoutAo;
|
|
||||||
|
|
||||||
public WeightedComputedAppearance(@NotNull List<Weighted.Present<Appearance>> appearances, RenderMaterial withAo, RenderMaterial withoutAo, int id) {
|
public WeightedComputedAppearance(@NotNull List<Weighted.Present<Appearance>> appearances, RenderMaterial ao_material, RenderMaterial material, int id) {
|
||||||
|
super(ao_material, material, id);
|
||||||
this.appearances = appearances;
|
this.appearances = appearances;
|
||||||
this.total_weight = Weighting.getWeightSum(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);
|
.map(appearances::indexOf).orElse(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Appearance getAppearance(long seed) {
|
private Appearance getAppearance(int model_id) {
|
||||||
Random random = Random.create(seed);
|
return appearances.get(model_id).getData();
|
||||||
return Weighting.getAt(appearances, Math.abs((int)random.nextLong()) % total_weight)
|
|
||||||
.map(Weighted.Present::getData).get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull List<SpriteProperties> getSprites(Direction dir, long seed) {
|
public @NotNull List<SpriteProperties> getSprites(Direction dir, int model_id) {
|
||||||
return getAppearance(seed).sprites().get(dir);
|
return getAppearance(model_id).sprites().get(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasColor(Direction dir, long seed, int index) {
|
public boolean hasColor(Direction dir, int model_id, int index) {
|
||||||
List<SpriteProperties> properties = getSprites(dir, seed);
|
List<SpriteProperties> properties = getSprites(dir, model_id);
|
||||||
if (index != 0) index = properties.size() - index;
|
if (index != 0) index = properties.size() - index;
|
||||||
return properties.get(index).has_colors();
|
return properties.get(index).has_colors();
|
||||||
}
|
}
|
||||||
@ -59,13 +49,7 @@ public class WeightedComputedAppearance implements CamoAppearance {
|
|||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if(this == o) return true;
|
if(this == o) return true;
|
||||||
if(o == null || getClass() != o.getClass()) return false;
|
if(!(o instanceof WeightedComputedAppearance that)) return false;
|
||||||
WeightedComputedAppearance that = (WeightedComputedAppearance) o;
|
|
||||||
return id == that.id;
|
return id == that.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,7 @@ public class GLanguage extends FabricLanguageProvider {
|
|||||||
public void generateTranslations(TranslationBuilder builder) {
|
public void generateTranslations(TranslationBuilder builder) {
|
||||||
builder.add(Registries.ITEM_GROUP.getKey(ReFramed.ITEM_GROUP).get(), "Frames");
|
builder.add(Registries.ITEM_GROUP.getKey(ReFramed.ITEM_GROUP).get(), "Frames");
|
||||||
builder.add("advancements.reframed.description", "Get all the frame types.");
|
builder.add("advancements.reframed.description", "Get all the frame types.");
|
||||||
ReFramed.BLOCKS.forEach(block -> {
|
ReFramed.BLOCKS.forEach(block -> builder.add(block, beautify(Registries.BLOCK.getId(block).getPath()) + " Frame"));
|
||||||
builder.add(block, beautify(Registries.BLOCK.getId(block).getPath()) + " Frame");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String beautify(String name) {
|
private static String beautify(String name) {
|
||||||
|
@ -11,9 +11,7 @@ import net.minecraft.nbt.NbtCompound;
|
|||||||
import net.minecraft.nbt.NbtHelper;
|
import net.minecraft.nbt.NbtHelper;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
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.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
@ -23,8 +21,6 @@ import static fr.adrien1106.reframed.block.ReFramedEntity.BLOCKSTATE_KEY;
|
|||||||
@Mixin(BlockItem.class)
|
@Mixin(BlockItem.class)
|
||||||
public class BlockItemMixin {
|
public class BlockItemMixin {
|
||||||
|
|
||||||
@Shadow @Final @Deprecated private Block block;
|
|
||||||
|
|
||||||
@Inject(
|
@Inject(
|
||||||
method = "writeNbtToBlockEntity",
|
method = "writeNbtToBlockEntity",
|
||||||
at = @At(
|
at = @At(
|
||||||
@ -41,6 +37,7 @@ public class BlockItemMixin {
|
|||||||
|| !Block.isShapeFullCube(block.getBlock().getDefaultState().getCollisionShape(world, pos))
|
|| !Block.isShapeFullCube(block.getBlock().getDefaultState().getCollisionShape(world, pos))
|
||||||
) return;
|
) return;
|
||||||
NbtCompound new_comp = new NbtCompound();
|
NbtCompound new_comp = new NbtCompound();
|
||||||
|
player.getOffHandStack().decrement(1);
|
||||||
new_comp.put(BLOCKSTATE_KEY + 1, NbtHelper.fromBlockState(block.getBlock().getDefaultState()));
|
new_comp.put(BLOCKSTATE_KEY + 1, NbtHelper.fromBlockState(block.getBlock().getDefaultState()));
|
||||||
compound.set(new_comp);
|
compound.set(new_comp);
|
||||||
}
|
}
|
||||||
|
@ -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.AthenaBakedModelMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(0)),
|
||||||
"fr.adrien1106.reframed.mixin.compat.AthenaWrappedGetterMixin", () -> 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.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.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.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))
|
"fr.adrien1106.reframed.mixin.compat.SodiumBlockOcclusionCacheMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(2))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import earth.terrarium.athena.api.client.models.AthenaBlockModel;
|
|||||||
import fr.adrien1106.reframed.client.ReFramedClient;
|
import fr.adrien1106.reframed.client.ReFramedClient;
|
||||||
import fr.adrien1106.reframed.client.model.DynamicBakedModel;
|
import fr.adrien1106.reframed.client.model.DynamicBakedModel;
|
||||||
import fr.adrien1106.reframed.compat.RebakedAthenaModel;
|
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 it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
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
|
level.getBlockEntity(pos) instanceof ThemeableBlockEntity framed_entity
|
||||||
? framed_entity.getTheme(theme_index)
|
? framed_entity.getTheme(theme_index)
|
||||||
: state, pos, direction)
|
: 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());
|
Sprite texture = textures.get(sprite.sprite());
|
||||||
if (texture == null) return quads;
|
if (texture == null) return quads;
|
||||||
emitter.square(direction, sprite.left(), sprite.bottom(), sprite.right(), sprite.top(), sprite.depth());
|
emitter.square(direction, sprite.left(), sprite.bottom(), sprite.right(), sprite.top(), sprite.depth());
|
||||||
|
@ -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.AppearanceAndTintGetter;
|
||||||
import earth.terrarium.athena.api.client.utils.CtmUtils;
|
import earth.terrarium.athena.api.client.utils.CtmUtils;
|
||||||
import earth.terrarium.athena.impl.client.models.ConnectedBlockModel;
|
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.block.BlockState;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
|
@ -2,7 +2,7 @@ package fr.adrien1106.reframed.mixin.compat;
|
|||||||
|
|
||||||
import com.llamalad7.mixinextras.sugar.Local;
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
import earth.terrarium.athena.api.client.fabric.WrappedGetter;
|
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.block.BlockState;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.BlockRenderView;
|
import net.minecraft.world.BlockRenderView;
|
||||||
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
package fr.adrien1106.reframed.mixin.compat;
|
package fr.adrien1106.reframed.mixin.compat;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
import fr.adrien1106.reframed.util.IBlockRenderInfoMixin;
|
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import link.infra.indium.renderer.render.BlockRenderInfo;
|
import link.infra.indium.renderer.render.BlockRenderInfo;
|
||||||
import link.infra.indium.renderer.render.TerrainBlockRenderInfo;
|
import link.infra.indium.renderer.render.TerrainBlockRenderInfo;
|
||||||
import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockOcclusionCache;
|
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)
|
@Mixin(TerrainBlockRenderInfo.class)
|
||||||
public abstract class IndiumTerrainBlockRenderInfoMixin extends BlockRenderInfo implements IBlockRenderInfoMixin {
|
public abstract class IndiumTerrainBlockRenderInfoMixin extends BlockRenderInfo implements IBlockRenderInfoMixin {
|
||||||
|
|
||||||
@Unique private int theme_index = 1;
|
@Unique private int theme_index = 0;
|
||||||
|
|
||||||
@Redirect(
|
@Redirect(
|
||||||
method = "shouldDrawFaceInner",
|
method = "shouldDrawFaceInner",
|
||||||
@ -40,4 +40,9 @@ public abstract class IndiumTerrainBlockRenderInfoMixin extends BlockRenderInfo
|
|||||||
this.theme_index = theme_index;
|
this.theme_index = theme_index;
|
||||||
prepareForBlock(blockState, blockPos, seed, modelAo);
|
prepareForBlock(blockState, blockPos, seed, modelAo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getThemeIndex() {
|
||||||
|
return theme_index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
package fr.adrien1106.reframed.mixin.compat;
|
package fr.adrien1106.reframed.mixin.compat;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.client.model.MultiRetexturableModel;
|
import fr.adrien1106.reframed.client.model.MultiRetexturableModel;
|
||||||
import fr.adrien1106.reframed.util.IBlockRenderInfoMixin;
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
import fr.adrien1106.reframed.util.IMultipartBakedModelMixin;
|
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.AbstractBlockRenderContext;
|
||||||
import link.infra.indium.renderer.render.TerrainRenderContext;
|
import link.infra.indium.renderer.render.TerrainRenderContext;
|
||||||
import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderContext;
|
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 net.minecraft.client.render.model.BakedModel;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
@ -29,13 +31,14 @@ public abstract class IndiumTerrainRenderContextMixin extends AbstractBlockRende
|
|||||||
if (!(ctx.model() instanceof IMultipartBakedModelMixin wrapped)
|
if (!(ctx.model() instanceof IMultipartBakedModelMixin wrapped)
|
||||||
|| !(wrapped.getModel(ctx.state()) instanceof MultiRetexturableModel retexturing_model)) return;
|
|| !(wrapped.getModel(ctx.state()) instanceof MultiRetexturableModel retexturing_model)) return;
|
||||||
|
|
||||||
List<BakedModel> models = retexturing_model.models();
|
List<ForwardingBakedModel> models = retexturing_model.models();
|
||||||
|
BlockHelper.computeInnerCull(ctx.state(), models);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (BakedModel bakedModel : models) {
|
for (BakedModel model : models) {
|
||||||
i++;
|
i++;
|
||||||
aoCalc.clear();
|
aoCalc.clear();
|
||||||
((IBlockRenderInfoMixin) blockInfo).prepareForBlock(ctx.state(), ctx.pos(), ctx.seed(), bakedModel.useAmbientOcclusion(), i);
|
((IBlockRenderInfoMixin) blockInfo).prepareForBlock(ctx.state(), ctx.pos(), ctx.seed(), model.useAmbientOcclusion(), i);
|
||||||
bakedModel.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this);
|
model.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this);
|
||||||
}
|
}
|
||||||
ci.cancel();
|
ci.cancel();
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package fr.adrien1106.reframed.mixin.compat;
|
package fr.adrien1106.reframed.mixin.compat;
|
||||||
|
|
||||||
import com.llamalad7.mixinextras.sugar.Local;
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockOcclusionCache;
|
import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockOcclusionCache;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package fr.adrien1106.reframed.mixin.particles;
|
package fr.adrien1106.reframed.mixin.particles;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.block.ReFramedBlock;
|
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.BlockState;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.particle.BlockDustParticle;
|
import net.minecraft.client.particle.BlockDustParticle;
|
||||||
|
@ -2,7 +2,7 @@ package fr.adrien1106.reframed.mixin.particles;
|
|||||||
|
|
||||||
import com.llamalad7.mixinextras.sugar.Local;
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
import fr.adrien1106.reframed.block.ReFramedBlock;
|
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.BlockState;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
@ -2,7 +2,7 @@ package fr.adrien1106.reframed.mixin.particles;
|
|||||||
|
|
||||||
import com.llamalad7.mixinextras.sugar.Local;
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
import fr.adrien1106.reframed.block.ReFramedBlock;
|
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.BlockState;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.LivingEntity;
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
package fr.adrien1106.reframed.mixin.render;
|
package fr.adrien1106.reframed.mixin.render;
|
||||||
|
|
||||||
import com.llamalad7.mixinextras.sugar.Local;
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
import fr.adrien1106.reframed.util.IBlockRenderInfoMixin;
|
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import net.fabricmc.fabric.impl.client.indigo.renderer.render.BlockRenderInfo;
|
import net.fabricmc.fabric.impl.client.indigo.renderer.render.BlockRenderInfo;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.entity.BlockEntity;
|
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 abstract void prepareForBlock(BlockState blockState, BlockPos blockPos, boolean modelAo);
|
||||||
|
|
||||||
@Shadow public BlockRenderView blockView;
|
@Shadow public BlockRenderView blockView;
|
||||||
@Unique
|
@Unique private int theme_index = 0;
|
||||||
private int theme_index = 1;
|
|
||||||
|
|
||||||
@ModifyArg(method = "prepareForBlock",
|
@ModifyArg(method = "prepareForBlock",
|
||||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/RenderLayers;" +
|
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;
|
this.theme_index = theme_index;
|
||||||
prepareForBlock(state, pos, ao);
|
prepareForBlock(state, pos, ao);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getThemeIndex() {
|
||||||
|
return theme_index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package fr.adrien1106.reframed.mixin.render;
|
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.block.BlockState;
|
||||||
import net.minecraft.client.render.model.BakedModel;
|
import net.minecraft.client.render.model.BakedModel;
|
||||||
import net.minecraft.client.render.model.MultipartBakedModel;
|
import net.minecraft.client.render.model.MultipartBakedModel;
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package fr.adrien1106.reframed.mixin.render;
|
package fr.adrien1106.reframed.mixin.render;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.client.model.MultiRetexturableModel;
|
import fr.adrien1106.reframed.client.model.MultiRetexturableModel;
|
||||||
import fr.adrien1106.reframed.util.IBlockRenderInfoMixin;
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
import fr.adrien1106.reframed.util.IMultipartBakedModelMixin;
|
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.AbstractBlockRenderContext;
|
||||||
import net.fabricmc.fabric.impl.client.indigo.renderer.render.TerrainRenderContext;
|
import net.fabricmc.fabric.impl.client.indigo.renderer.render.TerrainRenderContext;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
@ -28,13 +30,14 @@ public abstract class TerrainRenderContextMixin extends AbstractBlockRenderConte
|
|||||||
if (!(wrapper instanceof IMultipartBakedModelMixin wrapped)
|
if (!(wrapper instanceof IMultipartBakedModelMixin wrapped)
|
||||||
|| !(wrapped.getModel(state) instanceof MultiRetexturableModel retexturing_model)) return;
|
|| !(wrapped.getModel(state) instanceof MultiRetexturableModel retexturing_model)) return;
|
||||||
|
|
||||||
List<BakedModel> models = retexturing_model.models();
|
List<ForwardingBakedModel> models = retexturing_model.models();
|
||||||
|
BlockHelper.computeInnerCull(state, models);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (BakedModel bakedModel : models) {
|
for (BakedModel model : models) {
|
||||||
i++;
|
i++;
|
||||||
aoCalc.clear();
|
aoCalc.clear();
|
||||||
((IBlockRenderInfoMixin) blockInfo).prepareForBlock(state, pos, bakedModel.useAmbientOcclusion(), i);
|
((IBlockRenderInfoMixin) blockInfo).prepareForBlock(state, pos, model.useAmbientOcclusion(), i);
|
||||||
bakedModel.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this);
|
model.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this);
|
||||||
}
|
}
|
||||||
ci.cancel();
|
ci.cancel();
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ package fr.adrien1106.reframed.mixin.sound;
|
|||||||
|
|
||||||
import com.llamalad7.mixinextras.sugar.Local;
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
import fr.adrien1106.reframed.block.ReFramedBlock;
|
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.BlockState;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.item.BlockItem;
|
import net.minecraft.item.BlockItem;
|
||||||
|
@ -2,7 +2,7 @@ package fr.adrien1106.reframed.mixin.sound;
|
|||||||
|
|
||||||
import com.llamalad7.mixinextras.sugar.Local;
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
import fr.adrien1106.reframed.block.ReFramedBlock;
|
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.BlockState;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package fr.adrien1106.reframed.mixin.sound;
|
package fr.adrien1106.reframed.mixin.sound;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.block.ReFramedBlock;
|
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.BlockState;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.entity.LivingEntity;
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
@ -2,7 +2,7 @@ package fr.adrien1106.reframed.mixin.sound;
|
|||||||
|
|
||||||
import com.llamalad7.mixinextras.sugar.Local;
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
import fr.adrien1106.reframed.block.ReFramedBlock;
|
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.BlockState;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.client.render.WorldRenderer;
|
import net.minecraft.client.render.WorldRenderer;
|
||||||
|
@ -5,68 +5,201 @@ import net.minecraft.util.math.Direction;
|
|||||||
import net.minecraft.util.shape.VoxelShape;
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
import net.minecraft.util.shape.VoxelShapes;
|
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 {
|
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) {
|
public static VoxelShape rotateClockwise(VoxelShape shape, Direction.Axis axis) {
|
||||||
VoxelShape[] buffer = new VoxelShape[]{ shape, VoxelShapes.empty() };
|
AtomicReference<VoxelShape> new_shape = new AtomicReference<>(empty());
|
||||||
switch (axis) {
|
shape.forEachBox((minX, minY, minZ, maxX, maxY, maxZ) ->
|
||||||
case Y:
|
new_shape.getAndUpdate(s ->
|
||||||
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));
|
combineAndSimplify(
|
||||||
break;
|
s,
|
||||||
case X:
|
switch (axis) {
|
||||||
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));
|
case Y -> cuboid(1 - maxZ, minY, minX, 1 - minZ, maxY, maxX);
|
||||||
break;
|
case X -> cuboid(minX, 1 - maxZ, minY, maxX, 1 - minZ, maxY);
|
||||||
case Z:
|
case Z -> cuboid(1 - maxY, minX, minZ, 1 - minY, maxX, maxZ);
|
||||||
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;
|
BooleanBiFunction.OR
|
||||||
}
|
)
|
||||||
return buffer[1];
|
)
|
||||||
|
);
|
||||||
|
return new_shape.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static VoxelShape rotateCounterClockwise(VoxelShape shape, Direction.Axis axis) {
|
public static VoxelShape rotateCounterClockwise(VoxelShape shape, Direction.Axis axis) {
|
||||||
VoxelShape[] buffer = new VoxelShape[]{ shape, VoxelShapes.empty() };
|
AtomicReference<VoxelShape> new_shape = new AtomicReference<>(empty());
|
||||||
switch (axis) {
|
shape.forEachBox((minX, minY, minZ, maxX, maxY, maxZ) ->
|
||||||
case Y:
|
new_shape.getAndUpdate(s ->
|
||||||
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));
|
combineAndSimplify(
|
||||||
break;
|
s,
|
||||||
case X:
|
switch (axis) {
|
||||||
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));
|
case Y -> cuboid(minZ, minY, 1 - maxX, maxZ, maxY, 1 - minX);
|
||||||
break;
|
case X -> cuboid(minX, minZ, 1 - maxY, maxX, maxZ, 1 - minY);
|
||||||
case Z:
|
case Z -> cuboid(minY, 1 - maxX, minZ, maxY, 1 - minX, maxZ);
|
||||||
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;
|
BooleanBiFunction.OR
|
||||||
}
|
)
|
||||||
return buffer[1];
|
)
|
||||||
|
);
|
||||||
|
return new_shape.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static VoxelShape mirror(VoxelShape shape, Direction.Axis axis) {
|
public static VoxelShape mirror(VoxelShape shape, Direction.Axis axis) {
|
||||||
VoxelShape[] buffer = new VoxelShape[]{ shape, VoxelShapes.empty() };
|
AtomicReference<VoxelShape> new_shape = new AtomicReference<>(empty());
|
||||||
switch (axis) {
|
shape.forEachBox((minX, minY, minZ, maxX, maxY, maxZ) ->
|
||||||
case Y:
|
new_shape.getAndUpdate(s ->
|
||||||
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));
|
combineAndSimplify(
|
||||||
break;
|
s,
|
||||||
case X:
|
switch (axis) {
|
||||||
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));
|
case Y -> cuboid(minX, 1 - maxY, minZ, maxX, 1 - minY, maxZ);
|
||||||
break;
|
case X -> cuboid(1 - maxX, minY, minZ, 1 - minX, maxY, maxZ);
|
||||||
case Z:
|
case Z -> cuboid(minX, minY, 1 - maxZ, maxX, maxY, 1 - minZ);
|
||||||
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;
|
BooleanBiFunction.OR
|
||||||
}
|
)
|
||||||
return buffer[1];
|
)
|
||||||
|
);
|
||||||
|
return new_shape.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static VoxelShape offset(VoxelShape shape, Direction.Axis axis, float offset) {
|
public static VoxelShape offset(VoxelShape shape, Direction.Axis axis, float offset) {
|
||||||
VoxelShape[] buffer = new VoxelShape[]{ shape, VoxelShapes.empty() };
|
AtomicReference<VoxelShape> new_shape = new AtomicReference<>(empty());
|
||||||
switch (axis) {
|
shape.forEachBox((minX, minY, minZ, maxX, maxY, maxZ) ->
|
||||||
case Y:
|
new_shape.getAndUpdate(s ->
|
||||||
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));
|
combineAndSimplify(
|
||||||
break;
|
s,
|
||||||
case X:
|
switch (axis) {
|
||||||
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));
|
case Y -> cuboid(minX, offset + minY, minZ, maxX, offset + maxY, maxZ);
|
||||||
break;
|
case X -> cuboid(offset + minX, minY, minZ, offset + maxX, maxY, maxZ);
|
||||||
case Z:
|
case Z -> cuboid(minX, minY, offset + minZ, maxX, maxY, offset + maxZ);
|
||||||
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;
|
BooleanBiFunction.OR
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return new_shape.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class VoxelListBuilder {
|
||||||
|
private final List<VoxelShape> 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<VoxelShape, VoxelShape>... 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<VoxelShape, VoxelShape>... 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<VoxelShape, VoxelShape>... modifications) {
|
||||||
|
for(Function<VoxelShape, VoxelShape> 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];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.ReFramedBlock;
|
||||||
import fr.adrien1106.reframed.block.ReFramedEntity;
|
import fr.adrien1106.reframed.block.ReFramedEntity;
|
||||||
import fr.adrien1106.reframed.util.property.Corner;
|
import fr.adrien1106.reframed.block.ReFramedStairBlock;
|
||||||
import fr.adrien1106.reframed.util.property.StairShape;
|
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.Block;
|
||||||
import net.minecraft.block.BlockEntityProvider;
|
import net.minecraft.block.BlockEntityProvider;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
@ -14,42 +24,56 @@ import net.minecraft.sound.SoundCategory;
|
|||||||
import net.minecraft.sound.SoundEvents;
|
import net.minecraft.sound.SoundEvents;
|
||||||
import net.minecraft.util.ActionResult;
|
import net.minecraft.util.ActionResult;
|
||||||
import net.minecraft.util.Hand;
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.Pair;
|
||||||
import net.minecraft.util.function.BooleanBiFunction;
|
import net.minecraft.util.function.BooleanBiFunction;
|
||||||
import net.minecraft.util.hit.BlockHitResult;
|
import net.minecraft.util.hit.BlockHitResult;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.util.math.random.Random;
|
||||||
import net.minecraft.util.shape.VoxelShape;
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
import net.minecraft.util.shape.VoxelShapes;
|
import net.minecraft.util.shape.VoxelShapes;
|
||||||
|
import net.minecraft.world.BlockRenderView;
|
||||||
import net.minecraft.world.BlockView;
|
import net.minecraft.world.BlockView;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static fr.adrien1106.reframed.util.BlockProperties.CORNER;
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.EDGE;
|
||||||
import static fr.adrien1106.reframed.util.BlockProperties.LIGHT;
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.LIGHT;
|
||||||
import static fr.adrien1106.reframed.util.property.StairShape.*;
|
import static fr.adrien1106.reframed.util.blocks.StairShape.*;
|
||||||
import static net.minecraft.util.shape.VoxelShapes.combine;
|
import static net.minecraft.util.shape.VoxelShapes.combine;
|
||||||
|
|
||||||
public class BlockHelper {
|
public class BlockHelper {
|
||||||
|
|
||||||
|
// self culling cache of the models not made thread local so that it is only computed once
|
||||||
|
private static final Cache<CullElement, Integer[]> INNER_CULL_MAP = CacheBuilder.newBuilder().maximumSize(1024).build();
|
||||||
|
private record CullElement(Block block, Object state_key, int model) {}
|
||||||
|
|
||||||
public static Corner getPlacementCorner(ItemPlacementContext ctx) {
|
public static Corner getPlacementCorner(ItemPlacementContext ctx) {
|
||||||
|
Direction side = ctx.getSide().getOpposite();
|
||||||
|
Vec3d pos = getHitPos(ctx.getHitPos(), ctx.getBlockPos());
|
||||||
|
Pair<Direction, Direction> sides = getHitSides(pos, side);
|
||||||
|
|
||||||
|
return Corner.getByDirections(side, sides.getLeft(), sides.getRight());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Pair<Direction, Direction> getHitSides(Vec3d pos, Direction side) {
|
||||||
|
Iterator<Direction.Axis> 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();
|
Direction side = ctx.getSide().getOpposite();
|
||||||
Vec3d pos = getHitPos(ctx.getHitPos(), ctx.getBlockPos());
|
Vec3d pos = getHitPos(ctx.getHitPos(), ctx.getBlockPos());
|
||||||
Direction.Axis axis = getHitAxis(pos, side);
|
Direction.Axis axis = getHitAxis(pos, side);
|
||||||
|
|
||||||
Direction part_direction = Direction.from(
|
Direction part_direction = getHitDirection(axis, pos);
|
||||||
axis,
|
|
||||||
axis.choose(pos.x, pos.y, pos.z) > 0
|
|
||||||
? Direction.AxisDirection.POSITIVE
|
|
||||||
: Direction.AxisDirection.NEGATIVE
|
|
||||||
);
|
|
||||||
|
|
||||||
return Corner.getByDirections(side, part_direction);
|
return Edge.getByDirections(side, part_direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Direction.Axis getHitAxis(Vec3d pos, Direction side) {
|
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))
|
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_1
|
||||||
: axis_2
|
: 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) {
|
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;
|
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) {
|
switch (sol) {
|
||||||
case "right": return INNER_RIGHT;
|
case "right": return INNER_RIGHT;
|
||||||
case "left": return INNER_LEFT;
|
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) {
|
switch (sol) {
|
||||||
case "right": return INNER_RIGHT;
|
case "right": return INNER_RIGHT;
|
||||||
case "left": return INNER_LEFT;
|
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) {
|
switch (sol) {
|
||||||
case "right" -> shape = FIRST_OUTER_RIGHT;
|
case "right" -> shape = FIRST_OUTER_RIGHT;
|
||||||
case "left" -> shape = FIRST_OUTER_LEFT;
|
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) {
|
switch (sol) {
|
||||||
case "right" -> {
|
case "right" -> {
|
||||||
if (shape.equals(STRAIGHT)) shape = SECOND_OUTER_RIGHT;
|
if (shape.equals(STRAIGHT)) shape = SECOND_OUTER_RIGHT;
|
||||||
@ -114,18 +147,23 @@ public class BlockHelper {
|
|||||||
return shape;
|
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(
|
BlockState block_state = world.getBlockState(
|
||||||
pos.offset(reverse ? direction.getOpposite() : direction)
|
pos.offset(reverse ? direction.getOpposite() : direction)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (block_state.isOf(block) && block_state.get(CORNER).hasDirection(reference)) {
|
if (isStair(block_state) && block_state.get(EDGE).hasDirection(reference)) {
|
||||||
if (block_state.get(CORNER).hasDirection(face.getLeftDirection())) return "left";
|
if (block_state.get(EDGE).hasDirection(face.getLeftDirection())) return "left";
|
||||||
else if (block_state.get(CORNER).hasDirection(face.getRightDirection())) return "right";
|
else if (block_state.get(EDGE).hasDirection(face.getRightDirection())) return "right";
|
||||||
}
|
}
|
||||||
return "";
|
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) {
|
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;
|
if(!(world.getBlockEntity(pos) instanceof ReFramedEntity block_entity)) return ActionResult.PASS;
|
||||||
|
|
||||||
@ -141,17 +179,18 @@ public class BlockHelper {
|
|||||||
|
|
||||||
// check for default light emission
|
// check for default light emission
|
||||||
if (placement_state.getLuminance() > 0
|
if (placement_state.getLuminance() > 0
|
||||||
&& themes.stream().noneMatch(theme -> theme.getLuminance() > 0))
|
&& themes.stream().noneMatch(theme -> theme.getLuminance() > 0)
|
||||||
if (block_entity.emitsLight()) Block.dropStack(world, pos, new ItemStack(Items.GLOWSTONE_DUST));
|
&& !block_entity.emitsLight()
|
||||||
else block_entity.toggleLight();
|
)
|
||||||
|
block_entity.toggleLight();
|
||||||
|
|
||||||
world.setBlockState(pos, state.with(LIGHT, block_entity.emitsLight()));
|
world.setBlockState(pos, state.with(LIGHT, block_entity.emitsLight()));
|
||||||
|
|
||||||
// check for default redstone emission
|
// check for default redstone emission
|
||||||
if (placement_state.getWeakRedstonePower(world, pos, Direction.NORTH) > 0
|
if (placement_state.getWeakRedstonePower(world, pos, Direction.NORTH) > 0
|
||||||
&& themes.stream().noneMatch(theme -> theme.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));
|
&& !block_entity.emitsRedstone()
|
||||||
else block_entity.toggleRedstone();
|
) block_entity.toggleRedstone();
|
||||||
|
|
||||||
if(!player.isCreative()) held.decrement(1);
|
if(!player.isCreative()) held.decrement(1);
|
||||||
world.playSound(player, pos, placement_state.getSoundGroup().getPlaceSound(), SoundCategory.BLOCKS, 1f, 1.1f);
|
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) {
|
if(state.contains(LIGHT) && held.getItem() == Items.GLOWSTONE_DUST) {
|
||||||
block_entity.toggleLight();
|
block_entity.toggleLight();
|
||||||
world.setBlockState(pos, state.with(LIGHT, block_entity.emitsLight()));
|
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);
|
world.playSound(player, pos, SoundEvents.BLOCK_GLASS_HIT, SoundCategory.BLOCKS, 1f, 1f);
|
||||||
return ActionResult.SUCCESS;
|
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
|
// 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)) {
|
if(held.getItem() == Items.REDSTONE_TORCH && ext.canAddRedstoneEmission(state, world, pos)) {
|
||||||
block_entity.toggleRedstone();
|
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);
|
world.playSound(player, pos, SoundEvents.BLOCK_LEVER_CLICK, SoundCategory.BLOCKS, 1f, 1f);
|
||||||
return ActionResult.SUCCESS;
|
return ActionResult.SUCCESS;
|
||||||
}
|
}
|
||||||
@ -194,10 +225,6 @@ public class BlockHelper {
|
|||||||
// Frame will lose its collision if applied with popped chorus fruit
|
// Frame will lose its collision if applied with popped chorus fruit
|
||||||
if(held.getItem() == Items.POPPED_CHORUS_FRUIT && ext.canRemoveCollision(state, world, pos)) {
|
if(held.getItem() == Items.POPPED_CHORUS_FRUIT && ext.canRemoveCollision(state, world, pos)) {
|
||||||
block_entity.toggleSolidity();
|
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);
|
world.playSound(player, pos, SoundEvents.ITEM_CHORUS_FRUIT_TELEPORT, SoundCategory.BLOCKS, 1f, 1f);
|
||||||
return ActionResult.SUCCESS;
|
return ActionResult.SUCCESS;
|
||||||
}
|
}
|
||||||
@ -205,7 +232,70 @@ public class BlockHelper {
|
|||||||
return ActionResult.PASS;
|
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<ForwardingBakedModel> 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<List<QuadPosBounds>> 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<QuadPosBounds> 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
|
// 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) {
|
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 self = world.getBlockEntity(pos) instanceof ThemeableBlockEntity e ? e : null;
|
||||||
ThemeableBlockEntity other = world.getBlockEntity(other_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)
|
.reduce((prev, current) -> prev && current).orElse(false)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int luminance(BlockState state) {
|
|
||||||
return state.contains(LIGHT) && state.get(LIGHT) ? 15 : 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -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.BooleanProperty;
|
||||||
import net.minecraft.state.property.EnumProperty;
|
import net.minecraft.state.property.EnumProperty;
|
||||||
|
import net.minecraft.state.property.IntProperty;
|
||||||
|
|
||||||
public class BlockProperties {
|
public class BlockProperties {
|
||||||
public static final BooleanProperty LIGHT = BooleanProperty.of("emits_light");
|
public static final BooleanProperty LIGHT = BooleanProperty.of("emits_light");
|
||||||
|
public static final EnumProperty<Edge> EDGE = EnumProperty.of("edge", Edge.class);
|
||||||
public static final EnumProperty<Corner> CORNER = EnumProperty.of("corner", Corner.class);
|
public static final EnumProperty<Corner> CORNER = EnumProperty.of("corner", Corner.class);
|
||||||
|
public static final IntProperty CORNER_FACE = IntProperty.of("face", 0, 2);
|
||||||
public static final EnumProperty<StairShape> STAIR_SHAPE = EnumProperty.of("shape", StairShape.class);
|
public static final EnumProperty<StairShape> STAIR_SHAPE = EnumProperty.of("shape", StairShape.class);
|
||||||
}
|
}
|
97
src/main/java/fr/adrien1106/reframed/util/blocks/Corner.java
Normal file
97
src/main/java/fr/adrien1106/reframed/util/blocks/Corner.java
Normal file
@ -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());
|
||||||
|
}
|
||||||
|
}
|
@ -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.StringIdentifiable;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
public enum Corner implements StringIdentifiable {
|
public enum Edge implements StringIdentifiable {
|
||||||
NORTH_DOWN("north_down", Direction.NORTH, Direction.DOWN, Direction.EAST, 0),
|
NORTH_DOWN("north_down", Direction.NORTH, Direction.DOWN, Direction.Axis.X, 0),
|
||||||
DOWN_SOUTH("down_south", Direction.DOWN, Direction.SOUTH, Direction.EAST, 1),
|
DOWN_SOUTH("down_south", Direction.DOWN, Direction.SOUTH, Direction.Axis.X, 1),
|
||||||
SOUTH_UP("south_up", Direction.SOUTH, Direction.UP, Direction.EAST, 2),
|
SOUTH_UP("south_up", Direction.SOUTH, Direction.UP, Direction.Axis.X, 2),
|
||||||
UP_NORTH("up_north", Direction.UP, Direction.NORTH, Direction.EAST, 3),
|
UP_NORTH("up_north", Direction.UP, Direction.NORTH, Direction.Axis.X, 3),
|
||||||
WEST_DOWN("west_down", Direction.WEST, Direction.DOWN, Direction.SOUTH, 4),
|
WEST_DOWN("west_down", Direction.WEST, Direction.DOWN, Direction.Axis.Z, 4),
|
||||||
DOWN_EAST("down_east", Direction.DOWN, Direction.EAST, Direction.SOUTH, 5),
|
DOWN_EAST("down_east", Direction.DOWN, Direction.EAST, Direction.Axis.Z, 5),
|
||||||
EAST_UP("east_up", Direction.EAST, Direction.UP, Direction.SOUTH, 6),
|
EAST_UP("east_up", Direction.EAST, Direction.UP, Direction.Axis.Z, 6),
|
||||||
UP_WEST("up_west", Direction.UP, Direction.WEST, Direction.SOUTH, 7),
|
UP_WEST("up_west", Direction.UP, Direction.WEST, Direction.Axis.Z, 7),
|
||||||
WEST_NORTH("west_north", Direction.WEST, Direction.NORTH, Direction.DOWN, 8),
|
WEST_NORTH("west_north", Direction.WEST, Direction.NORTH, Direction.Axis.Y, 8),
|
||||||
NORTH_EAST("north_east", Direction.NORTH, Direction.EAST, Direction.DOWN, 9),
|
NORTH_EAST("north_east", Direction.NORTH, Direction.EAST, Direction.Axis.Y, 9),
|
||||||
EAST_SOUTH("east_south", Direction.EAST, Direction.SOUTH, Direction.DOWN, 10),
|
EAST_SOUTH("east_south", Direction.EAST, Direction.SOUTH, Direction.Axis.Y, 10),
|
||||||
SOUTH_WEST("south_west", Direction.SOUTH, Direction.WEST, Direction.DOWN, 11);
|
SOUTH_WEST("south_west", Direction.SOUTH, Direction.WEST, Direction.Axis.Y, 11);
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final Direction first_direction;
|
private final Direction first_direction;
|
||||||
private final Direction second_direction;
|
private final Direction second_direction;
|
||||||
private final Direction right_direction;
|
private final Direction.Axis axis;
|
||||||
private final Direction left_direction;
|
|
||||||
private final int ID;
|
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.name = name;
|
||||||
this.first_direction = first_direction;
|
this.first_direction = first_direction;
|
||||||
this.second_direction = second_direction;
|
this.second_direction = second_direction;
|
||||||
this.right_direction = right_direction;
|
this.axis = axis;
|
||||||
this.left_direction = right_direction.getOpposite();
|
|
||||||
this.ID = id;
|
this.ID = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,10 +49,18 @@ public enum Corner implements StringIdentifiable {
|
|||||||
return second_direction;
|
return second_direction;
|
||||||
}
|
}
|
||||||
public Direction getRightDirection() {
|
public Direction getRightDirection() {
|
||||||
return right_direction;
|
return switch (axis) {
|
||||||
|
case X -> Direction.WEST;
|
||||||
|
case Y -> Direction.DOWN;
|
||||||
|
case Z -> Direction.SOUTH;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
public Direction getLeftDirection() {
|
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) {
|
public boolean hasDirection(Direction direction) {
|
||||||
@ -66,21 +72,21 @@ public enum Corner implements StringIdentifiable {
|
|||||||
return this.ID;
|
return this.ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Corner getByDirections(Direction direction_1, Direction direction_2) {
|
public static Edge getByDirections(Direction direction_1, Direction direction_2) {
|
||||||
return Arrays.stream(Corner.values())
|
return Arrays.stream(Edge.values())
|
||||||
.filter(value -> value.hasDirection(direction_1) && value.hasDirection(direction_2))
|
.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) {
|
public static Edge fromId(int id) {
|
||||||
return Arrays.stream(Corner.values())
|
return Arrays.stream(Edge.values())
|
||||||
.filter(value -> value.getID() == id)
|
.filter(value -> value.getID() == id)
|
||||||
.findFirst().orElse(Corner.NORTH_DOWN);
|
.findFirst().orElse(Edge.NORTH_DOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Corner fromName(String name) {
|
public static Edge fromName(String name) {
|
||||||
return Arrays.stream(Corner.values())
|
return Arrays.stream(Edge.values())
|
||||||
.filter(value -> value.name().equals(name))
|
.filter(value -> value.name().equals(name))
|
||||||
.findFirst().orElse(Corner.NORTH_DOWN);
|
.findFirst().orElse(Edge.NORTH_DOWN);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package fr.adrien1106.reframed.util;
|
package fr.adrien1106.reframed.util.blocks;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
@ -1,4 +1,4 @@
|
|||||||
package fr.adrien1106.reframed.util.property;
|
package fr.adrien1106.reframed.util.blocks;
|
||||||
|
|
||||||
import net.minecraft.util.StringIdentifiable;
|
import net.minecraft.util.StringIdentifiable;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package fr.adrien1106.reframed.util;
|
package fr.adrien1106.reframed.util.blocks;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package fr.adrien1106.reframed.util;
|
package fr.adrien1106.reframed.util.mixin;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.util.math.BlockPos;
|
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, boolean ao, int theme_index);
|
||||||
|
|
||||||
void prepareForBlock(BlockState state, BlockPos pos, long seed, boolean ao, int theme_index);
|
void prepareForBlock(BlockState state, BlockPos pos, long seed, boolean ao, int theme_index);
|
||||||
|
|
||||||
|
int getThemeIndex();
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package fr.adrien1106.reframed.util;
|
package fr.adrien1106.reframed.util.mixin;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.client.render.model.BakedModel;
|
import net.minecraft.client.render.model.BakedModel;
|
@ -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]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -30,7 +30,7 @@
|
|||||||
"fabricloader": "^${loader_version}",
|
"fabricloader": "^${loader_version}",
|
||||||
"fabric-api": "*"
|
"fabric-api": "*"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggests": {
|
||||||
"athena": "^${athena_version}",
|
"athena": "^${athena_version}",
|
||||||
"sodium": "^${sodium_version}",
|
"sodium": "^${sodium_version}",
|
||||||
"indium": "^${indium_version}"
|
"indium": "^${indium_version}"
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
"compat.AthenaBakedModelMixin",
|
"compat.AthenaBakedModelMixin",
|
||||||
"compat.AthenaConnectedBlockModelMixin",
|
"compat.AthenaConnectedBlockModelMixin",
|
||||||
"compat.AthenaWrappedGetterMixin",
|
"compat.AthenaWrappedGetterMixin",
|
||||||
|
"compat.IndiumAbstractBlockRenderContextMixin",
|
||||||
"compat.IndiumTerrainBlockRenderInfoMixin",
|
"compat.IndiumTerrainBlockRenderInfoMixin",
|
||||||
"compat.IndiumTerrainRenderContextMixin",
|
"compat.IndiumTerrainRenderContextMixin",
|
||||||
"compat.SodiumBlockOcclusionCacheMixin",
|
"compat.SodiumBlockOcclusionCacheMixin",
|
||||||
@ -21,6 +22,7 @@
|
|||||||
"particles.AccessorParticle",
|
"particles.AccessorParticle",
|
||||||
"particles.AccessorSpriteBillboardParticle",
|
"particles.AccessorSpriteBillboardParticle",
|
||||||
"particles.MixinBlockDustParticle",
|
"particles.MixinBlockDustParticle",
|
||||||
|
"render.AbstractBlockRenderContextMixin",
|
||||||
"render.BlockRenderInfoMixin",
|
"render.BlockRenderInfoMixin",
|
||||||
"render.MultipartBakedModelMixin",
|
"render.MultipartBakedModelMixin",
|
||||||
"render.TerrainRenderContextMixin",
|
"render.TerrainRenderContextMixin",
|
||||||
|
Loading…
Reference in New Issue
Block a user