added new blocks and further axiom support #17
@ -21,11 +21,8 @@ or based on preferences add the person(s) to the project
|
|||||||
|
|
||||||
### What Shapes are planed to be added
|
### What Shapes are planed to be added
|
||||||
Currently, the list of shapes to be added is pretty simple as the mod is still under development:
|
Currently, the list of shapes to be added is pretty simple as the mod is still under development:
|
||||||
- Fence
|
|
||||||
- Button
|
|
||||||
- Pressure Plate
|
- Pressure Plate
|
||||||
- Carpet (maybe redundant with Layer)
|
- Carpet (maybe redundant with Layer)
|
||||||
- Post
|
|
||||||
- Half Slab (maybe redundant with Layer)
|
- Half Slab (maybe redundant with Layer)
|
||||||
- Slabs Stair (a stair with one end being of a second theme, might be done in multiple blocks)
|
- Slabs Stair (a stair with one end being of a second theme, might be done in multiple blocks)
|
||||||
|
|
||||||
|
@ -84,6 +84,9 @@ repositories {
|
|||||||
includeGroup "maven.modrinth"
|
includeGroup "maven.modrinth"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
maven {
|
||||||
|
url = "https://jitpack.io"
|
||||||
|
}
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|
||||||
// Add repositories to retrieve artifacts from in here.
|
// Add repositories to retrieve artifacts from in here.
|
||||||
@ -120,6 +123,7 @@ dependencies {
|
|||||||
|
|
||||||
// Axiom for blueprint support
|
// Axiom for blueprint support
|
||||||
modCompileOnly "maven.modrinth:N6n5dqoA:nvx3oDkz"
|
modCompileOnly "maven.modrinth:N6n5dqoA:nvx3oDkz"
|
||||||
|
modCompileOnly "com.github.moulberry:AxiomClientAPI:1.0.5.3"
|
||||||
|
|
||||||
// Fabric API.
|
// Fabric API.
|
||||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||||
|
@ -37,7 +37,18 @@ 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, SMALL_CUBE, SMALL_CUBES_STEP, STAIR, HALF_STAIR, STAIRS_CUBE, HALF_STAIRS_SLAB, HALF_STAIRS_STAIR, SLAB, SLABS_CUBE, STEP, STEPS_SLAB, LAYER, PILLAR, PILLARS_WALL, WALL, PANE, TRAPDOOR, DOOR;
|
public static Block
|
||||||
|
CUBE,
|
||||||
|
SMALL_CUBE, SMALL_CUBES_STEP,
|
||||||
|
STAIR, STAIRS_CUBE,
|
||||||
|
HALF_STAIR, HALF_STAIRS_SLAB, HALF_STAIRS_STAIR,
|
||||||
|
SLAB, SLABS_CUBE,
|
||||||
|
STEP, STEPS_SLAB,
|
||||||
|
LAYER,
|
||||||
|
PILLAR, PILLARS_WALL, WALL,
|
||||||
|
PANE, TRAPDOOR, DOOR,
|
||||||
|
BUTTON,
|
||||||
|
POST, POST_FENCE, FENCE;
|
||||||
|
|
||||||
public static final ArrayList<Item> ITEMS = new ArrayList<>();
|
public static final ArrayList<Item> ITEMS = new ArrayList<>();
|
||||||
public static Item HAMMER, SCREWDRIVER, BLUEPRINT, BLUEPRINT_WRITTEN;
|
public static Item HAMMER, SCREWDRIVER, BLUEPRINT, BLUEPRINT_WRITTEN;
|
||||||
@ -70,6 +81,10 @@ public class ReFramed implements ModInitializer {
|
|||||||
PANE = registerBlock("pane" , new ReFramedPaneBlock(cp(Blocks.OAK_FENCE)));
|
PANE = registerBlock("pane" , new ReFramedPaneBlock(cp(Blocks.OAK_FENCE)));
|
||||||
TRAPDOOR = registerBlock("trapdoor" , new ReFramedTrapdoorBlock(cp(Blocks.OAK_TRAPDOOR)));
|
TRAPDOOR = registerBlock("trapdoor" , new ReFramedTrapdoorBlock(cp(Blocks.OAK_TRAPDOOR)));
|
||||||
DOOR = registerBlock("door" , new ReFramedDoorBlock(cp(Blocks.OAK_DOOR)));
|
DOOR = registerBlock("door" , new ReFramedDoorBlock(cp(Blocks.OAK_DOOR)));
|
||||||
|
BUTTON = registerBlock("button" , new ReFramedButtonBlock(cp(Blocks.OAK_BUTTON)));
|
||||||
|
POST = registerBlock("post" , new ReFramedPostBlock(cp(Blocks.OAK_FENCE)));
|
||||||
|
FENCE = registerBlock("fence" , new ReFramedFenceBlock(cp(Blocks.OAK_FENCE)));
|
||||||
|
POST_FENCE = registerBlock("post_fence" , new ReFramedPostFenceBlock(cp(Blocks.OAK_FENCE)));
|
||||||
|
|
||||||
HAMMER = registerItem("hammer" , new ReFramedHammerItem(new Item.Settings().maxCount(1)));
|
HAMMER = registerItem("hammer" , new ReFramedHammerItem(new Item.Settings().maxCount(1)));
|
||||||
SCREWDRIVER = registerItem("screwdriver" , new ReFramedScrewdriverItem(new Item.Settings().maxCount(1)));
|
SCREWDRIVER = registerItem("screwdriver" , new ReFramedScrewdriverItem(new Item.Settings().maxCount(1)));
|
||||||
|
@ -0,0 +1,104 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.state.property.BooleanProperty;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.WorldAccess;
|
||||||
|
import org.apache.commons.lang3.function.TriFunction;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
import static net.minecraft.state.property.Properties.SOUTH;
|
||||||
|
|
||||||
|
public abstract class ConnectingReFramedBlock extends WaterloggableReFramedBlock {
|
||||||
|
|
||||||
|
public ConnectingReFramedBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState()
|
||||||
|
.with(EAST, false)
|
||||||
|
.with(NORTH, false)
|
||||||
|
.with(WEST, false)
|
||||||
|
.with(SOUTH, false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
super.appendProperties(builder.add(EAST, NORTH, SOUTH, WEST));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getStateForNeighborUpdate(BlockState state, Direction dir, BlockState other_state, WorldAccess world, BlockPos pos, BlockPos moved) {
|
||||||
|
BlockState new_state = super.getStateForNeighborUpdate(state, dir, other_state, world, pos, moved);
|
||||||
|
if (dir == Direction.DOWN) return new_state;
|
||||||
|
|
||||||
|
return placementState(new_state, world, pos, this::connectsTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
BlockState state = super.getPlacementState(ctx);
|
||||||
|
World world = ctx.getWorld();
|
||||||
|
BlockPos pos = ctx.getBlockPos();
|
||||||
|
|
||||||
|
return placementState(state, world, pos, this::connectsTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
|
||||||
|
super.onStateReplaced(state, world, pos, new_state, moved);
|
||||||
|
|
||||||
|
if(!state.isOf(new_state.getBlock())) world.removeBlockEntity(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
return Direction.Type.HORIZONTAL.stream().reduce(state, (s, dir) ->
|
||||||
|
s.with(getConnectionProperty(rotation.rotate(dir)), state.get(getConnectionProperty(dir)))
|
||||||
|
, (prev, next) -> next);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
return Direction.Type.HORIZONTAL.stream().reduce(state, (s, dir) ->
|
||||||
|
s.with(getConnectionProperty(mirror.apply(dir)), state.get(getConnectionProperty(dir)))
|
||||||
|
, (prev, next) -> next);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract boolean connectsTo(BlockState state, boolean fs, Direction dir);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context);
|
||||||
|
|
||||||
|
public static BooleanProperty getConnectionProperty(Direction dir) {
|
||||||
|
return switch (dir) {
|
||||||
|
case NORTH -> NORTH;
|
||||||
|
case EAST -> EAST;
|
||||||
|
case SOUTH -> SOUTH;
|
||||||
|
case WEST -> WEST;
|
||||||
|
default -> null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockState placementState(BlockState state, BlockView world, BlockPos pos, TriFunction<BlockState, Boolean, Direction, Boolean> connectsTo) {
|
||||||
|
for (Direction dir: Direction.Type.HORIZONTAL) {
|
||||||
|
BlockState neighbor = world.getBlockState(pos.offset(dir));
|
||||||
|
state = state.with(getConnectionProperty(dir), connectsTo.apply(
|
||||||
|
neighbor,
|
||||||
|
neighbor.isSideSolidFullSquare(world, pos.offset(dir), dir.getOpposite()),
|
||||||
|
dir
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
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 net.minecraft.state.property.Properties.AXIS;
|
||||||
|
|
||||||
|
public abstract class PillarReFramedBlock extends WaterloggableReFramedBlock {
|
||||||
|
public PillarReFramedBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState().with(AXIS, Direction.Axis.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder< Block, BlockState > builder) {
|
||||||
|
super.appendProperties(builder.add(AXIS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
return super.getPlacementState(ctx).with(AXIS, ctx.getSide().getAxis());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
return state.with(AXIS, rotation.rotate(Direction.get(Direction.AxisDirection.POSITIVE, state.get(AXIS))).getAxis());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
return state.with(AXIS, mirror.apply(Direction.get(Direction.AxisDirection.POSITIVE, state.get(AXIS))).getAxis());
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,6 @@ import net.minecraft.entity.player.PlayerEntity;
|
|||||||
import net.minecraft.item.BlockItem;
|
import net.minecraft.item.BlockItem;
|
||||||
import net.minecraft.item.ItemPlacementContext;
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.item.Items;
|
|
||||||
import net.minecraft.nbt.NbtCompound;
|
import net.minecraft.nbt.NbtCompound;
|
||||||
import net.minecraft.nbt.NbtHelper;
|
import net.minecraft.nbt.NbtHelper;
|
||||||
import net.minecraft.registry.Registries;
|
import net.minecraft.registry.Registries;
|
||||||
@ -73,8 +72,8 @@ public class ReFramedBlock extends Block implements BlockEntityProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
|
||||||
if(!(newState.getBlock() instanceof ReFramedBlock) &&
|
if(!(new_state.getBlock() instanceof ReFramedBlock) &&
|
||||||
world.getBlockEntity(pos) instanceof ReFramedEntity frame_entity &&
|
world.getBlockEntity(pos) instanceof ReFramedEntity frame_entity &&
|
||||||
world.getGameRules().getBoolean(GameRules.DO_TILE_DROPS)
|
world.getGameRules().getBoolean(GameRules.DO_TILE_DROPS)
|
||||||
) {
|
) {
|
||||||
@ -85,19 +84,9 @@ public class ReFramedBlock extends Block implements BlockEntityProvider {
|
|||||||
if(theme.getBlock() != Blocks.AIR) drops.add(new ItemStack(theme.getBlock()));
|
if(theme.getBlock() != Blocks.AIR) drops.add(new ItemStack(theme.getBlock()));
|
||||||
});
|
});
|
||||||
|
|
||||||
if(frame_entity.emitsRedstone()
|
|
||||||
&& themes.stream().noneMatch(theme -> theme.getWeakRedstonePower(world, pos, Direction.NORTH) != 0))
|
|
||||||
drops.add(new ItemStack(Items.REDSTONE_TORCH));
|
|
||||||
if(frame_entity.emitsLight()
|
|
||||||
&& themes.stream().noneMatch(theme -> theme.getLuminance() != 0))
|
|
||||||
drops.add(new ItemStack(Items.GLOWSTONE_DUST));
|
|
||||||
if(!frame_entity.isSolid()
|
|
||||||
&& themes.stream().anyMatch(AbstractBlockState::isSolid))
|
|
||||||
drops.add(new ItemStack(Items.POPPED_CHORUS_FRUIT));
|
|
||||||
|
|
||||||
ItemScatterer.spawn(world, pos, drops);
|
ItemScatterer.spawn(world, pos, drops);
|
||||||
}
|
}
|
||||||
super.onStateReplaced(state, world, pos, newState, moved);
|
super.onStateReplaced(state, world, pos, new_state, moved);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPlaced(World world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack, BlockState old_state, BlockEntity old_entity) {
|
public void onPlaced(World world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack, BlockState old_state, BlockEntity old_entity) {
|
||||||
|
@ -0,0 +1,238 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.util.VoxelHelper;
|
||||||
|
import net.minecraft.block.*;
|
||||||
|
import net.minecraft.block.enums.BlockFace;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.entity.projectile.PersistentProjectileEntity;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.server.world.ServerWorld;
|
||||||
|
import net.minecraft.sound.SoundCategory;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.hit.BlockHitResult;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.math.random.Random;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.WorldAccess;
|
||||||
|
import net.minecraft.world.WorldView;
|
||||||
|
import net.minecraft.world.event.GameEvent;
|
||||||
|
import net.minecraft.world.explosion.Explosion;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
|
||||||
|
public class ReFramedButtonBlock extends WaterloggableReFramedBlock {
|
||||||
|
|
||||||
|
public static final VoxelShape[] BUTTON_VOXELS;
|
||||||
|
|
||||||
|
public ReFramedButtonBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState()
|
||||||
|
.with(HORIZONTAL_FACING, Direction.NORTH)
|
||||||
|
.with(BLOCK_FACE, BlockFace.WALL)
|
||||||
|
.with(POWERED, false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
super.appendProperties(builder.add(HORIZONTAL_FACING, BLOCK_FACE, POWERED));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPlaceAt(BlockState state, WorldView world, BlockPos pos) {
|
||||||
|
return canPlaceAt(world, pos, getDirection(state).getOpposite());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean canPlaceAt(WorldView world, BlockPos pos, Direction direction) {
|
||||||
|
BlockPos other_pos = pos.offset(direction);
|
||||||
|
return world.getBlockState(other_pos).isSideSolidFullSquare(world, other_pos, direction.getOpposite());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
BlockState state = super.getPlacementState(ctx);
|
||||||
|
Direction side = ctx.getSide();
|
||||||
|
return state
|
||||||
|
.with(HORIZONTAL_FACING, side.getAxis() == Direction.Axis.Y
|
||||||
|
? ctx.getHorizontalPlayerFacing()
|
||||||
|
: side
|
||||||
|
)
|
||||||
|
.with(BLOCK_FACE, side.getAxis() != Direction.Axis.Y
|
||||||
|
? BlockFace.WALL
|
||||||
|
: side == Direction.UP ? BlockFace.FLOOR : BlockFace.CEILING
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState other_state, WorldAccess world, BlockPos pos, BlockPos other_pos) {
|
||||||
|
return getDirection(state).getOpposite() == direction && !state.canPlaceAt(world, pos)
|
||||||
|
? Blocks.AIR.getDefaultState()
|
||||||
|
: super.getStateForNeighborUpdate(state, direction, other_state, world, pos, other_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
|
||||||
|
ActionResult result = super.onUse(state, world, pos, player, hand, hit);
|
||||||
|
if (result.isAccepted()) return result;
|
||||||
|
|
||||||
|
if (state.get(POWERED)) return ActionResult.CONSUME;
|
||||||
|
powerOn(state, world, pos);
|
||||||
|
playClickSound(player, world, pos, true);
|
||||||
|
world.emitGameEvent(player, GameEvent.BLOCK_ACTIVATE, pos);
|
||||||
|
|
||||||
|
return ActionResult.success(world.isClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onExploded(BlockState state, World world, BlockPos pos, Explosion explosion, BiConsumer<ItemStack, BlockPos> stackMerger) {
|
||||||
|
if (explosion.getDestructionType() == Explosion.DestructionType.TRIGGER_BLOCK && !world.isClient() && !(Boolean)state.get(POWERED)) {
|
||||||
|
powerOn(state, world, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onExploded(state, world, pos, explosion, stackMerger);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void powerOn(BlockState state, World world, BlockPos pos) {
|
||||||
|
world.setBlockState(pos, state.with(POWERED, true), 3);
|
||||||
|
updateNeighbors(state, world, pos);
|
||||||
|
world.scheduleBlockTick(pos, this, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void playClickSound(@Nullable PlayerEntity player, WorldAccess world, BlockPos pos, boolean powered) {
|
||||||
|
world.playSound(
|
||||||
|
powered ? player : null,
|
||||||
|
pos,
|
||||||
|
powered ? BlockSetType.OAK.buttonClickOn() : BlockSetType.OAK.buttonClickOff(),
|
||||||
|
SoundCategory.BLOCKS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
return BUTTON_VOXELS[
|
||||||
|
(state.get(POWERED) ? 12 : 0) +
|
||||||
|
(4 * state.get(BLOCK_FACE).ordinal()) +
|
||||||
|
state.get(HORIZONTAL_FACING).ordinal() - 2
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
return state.with(HORIZONTAL_FACING, rotation.rotate(state.get(HORIZONTAL_FACING)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
return state.with(HORIZONTAL_FACING, mirror.apply(state.get(HORIZONTAL_FACING)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
|
||||||
|
super.onStateReplaced(state, world, pos, new_state, false);
|
||||||
|
|
||||||
|
if(!state.isOf(new_state.getBlock())) {
|
||||||
|
if (!moved && state.get(POWERED)) updateNeighbors(state, world, pos);
|
||||||
|
world.removeBlockEntity(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWeakRedstonePower(BlockState state, BlockView view, BlockPos pos, Direction dir) {
|
||||||
|
return state.get(POWERED) ? 15 : super.getWeakRedstonePower(state, view, pos, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStrongRedstonePower(BlockState state, BlockView view, BlockPos pos, Direction dir) {
|
||||||
|
return dir == getDirection(state) ? state.getWeakRedstonePower(view, pos, dir) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean emitsRedstonePower(BlockState state) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random random) {
|
||||||
|
if (state.get(POWERED)) tryPowerWithProjectiles(state, world, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity) {
|
||||||
|
if (!world.isClient && !state.get(POWERED)) tryPowerWithProjectiles(state, world, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void tryPowerWithProjectiles(BlockState state, World world, BlockPos pos) {
|
||||||
|
PersistentProjectileEntity projectile = world.getNonSpectatingEntities(
|
||||||
|
PersistentProjectileEntity.class,
|
||||||
|
state.getOutlineShape(world, pos).getBoundingBox().offset(pos)
|
||||||
|
).stream().findFirst().orElse(null);
|
||||||
|
boolean has_projectile = projectile != null;
|
||||||
|
if (has_projectile != state.get(POWERED)) {
|
||||||
|
world.setBlockState(pos, state.with(POWERED, has_projectile), 3);
|
||||||
|
this.updateNeighbors(state, world, pos);
|
||||||
|
this.playClickSound(null, world, pos, has_projectile);
|
||||||
|
world.emitGameEvent(projectile, has_projectile ? GameEvent.BLOCK_ACTIVATE : GameEvent.BLOCK_DEACTIVATE, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_projectile) {
|
||||||
|
world.scheduleBlockTick(pos, this, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateNeighbors(BlockState state, World world, BlockPos pos) {
|
||||||
|
world.updateNeighborsAlways(pos, this);
|
||||||
|
world.updateNeighborsAlways(pos.offset(getDirection(state).getOpposite()), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Direction getDirection(BlockState state) {
|
||||||
|
return switch (state.get(BLOCK_FACE)) {
|
||||||
|
case CEILING -> Direction.DOWN;
|
||||||
|
case FLOOR -> Direction.UP;
|
||||||
|
default -> state.get(HORIZONTAL_FACING);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static {
|
||||||
|
VoxelShape SHAPE = createCuboidShape(5, 0, 6, 11, 2, 10);
|
||||||
|
VoxelShape POWERED_SHAPE = createCuboidShape(5, 0, 6, 11, 1, 10);
|
||||||
|
BUTTON_VOXELS = VoxelHelper.VoxelListBuilder.create(SHAPE, 24)
|
||||||
|
.add()
|
||||||
|
.add(0, VoxelHelper::rotateY)
|
||||||
|
.add()
|
||||||
|
.add(VoxelHelper::rotateZ, VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::mirrorZ)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::mirrorX)
|
||||||
|
.add(0, VoxelHelper::mirrorY)
|
||||||
|
.add()
|
||||||
|
.add(2, VoxelHelper::mirrorY)
|
||||||
|
.add()
|
||||||
|
.add(POWERED_SHAPE)
|
||||||
|
.add()
|
||||||
|
.add(12, VoxelHelper::rotateY)
|
||||||
|
.add()
|
||||||
|
.add(VoxelHelper::rotateZ, VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::mirrorZ)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::mirrorX)
|
||||||
|
.add(12, VoxelHelper::mirrorY)
|
||||||
|
.add()
|
||||||
|
.add(13, VoxelHelper::mirrorY)
|
||||||
|
.add()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
@ -113,7 +113,7 @@ public class ReFramedDoorBlock extends WaterloggableReFramedBlock {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockState onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) {
|
public BlockState onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) {
|
||||||
if (!world.isClient() && (player.isCreative() || !player.canHarvest(state))) {
|
if (!world.isClient() && (player.isCreative() || player.canHarvest(state))) {
|
||||||
DoubleBlockHalf half = state.get(DOUBLE_BLOCK_HALF);
|
DoubleBlockHalf half = state.get(DOUBLE_BLOCK_HALF);
|
||||||
BlockPos other_pos = half == DoubleBlockHalf.LOWER ? pos.up() : pos.down();
|
BlockPos other_pos = half == DoubleBlockHalf.LOWER ? pos.up() : pos.down();
|
||||||
BlockState other_state = world.getBlockState(other_pos);
|
BlockState other_state = world.getBlockState(other_pos);
|
||||||
@ -127,10 +127,10 @@ public class ReFramedDoorBlock extends WaterloggableReFramedBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
|
||||||
super.onStateReplaced(state, world, pos, newState, moved);
|
super.onStateReplaced(state, world, pos, new_state, moved);
|
||||||
|
|
||||||
if(!state.isOf(newState.getBlock())) world.removeBlockEntity(pos);
|
if(!state.isOf(new_state.getBlock())) world.removeBlockEntity(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,105 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.util.VoxelHelper;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.FenceGateBlock;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.entity.ai.pathing.NavigationType;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.item.Items;
|
||||||
|
import net.minecraft.item.LeadItem;
|
||||||
|
import net.minecraft.registry.tag.BlockTags;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.function.BooleanBiFunction;
|
||||||
|
import net.minecraft.util.hit.BlockHitResult;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.util.shape.VoxelShapes;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
public class ReFramedFenceBlock extends ConnectingReFramedBlock {
|
||||||
|
|
||||||
|
public static final VoxelShape[] FENCE_VOXELS;
|
||||||
|
|
||||||
|
public ReFramedFenceBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean connectsTo(BlockState state, boolean fs, Direction dir) {
|
||||||
|
return fs || state.isIn(BlockTags.FENCES)
|
||||||
|
|| (state.getBlock() instanceof FenceGateBlock && FenceGateBlock.canWallConnect(state, dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
VoxelShape shape = FENCE_VOXELS[0];
|
||||||
|
for (Direction dir: Direction.Type.HORIZONTAL) {
|
||||||
|
if (state.get(getConnectionProperty(dir)))
|
||||||
|
shape = VoxelShapes.union(shape, FENCE_VOXELS[dir.ordinal() - 1]);
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) {
|
||||||
|
VoxelShape shape = FENCE_VOXELS[5];
|
||||||
|
for (Direction dir: Direction.Type.HORIZONTAL) {
|
||||||
|
if (state.get(getConnectionProperty(dir)))
|
||||||
|
shape = VoxelShapes.union(shape, FENCE_VOXELS[dir.ordinal() + 4]);
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCameraCollisionShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
return getOutlineShape(state, world, pos, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCullingShape(BlockState state, BlockView view, BlockPos pos) {
|
||||||
|
return getOutlineShape(state, view, pos, ShapeContext.absent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
|
||||||
|
ActionResult result = super.onUse(state, world, pos, player, hand, hit);
|
||||||
|
if (result.isAccepted()) return result;
|
||||||
|
if (world.isClient) {
|
||||||
|
ItemStack itemStack = player.getStackInHand(hand);
|
||||||
|
return itemStack.isOf(Items.LEAD) ? ActionResult.SUCCESS : ActionResult.PASS;
|
||||||
|
} else {
|
||||||
|
return LeadItem.attachHeldMobsToBlock(player, world, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
VoxelShape POST = createCuboidShape(6, 0, 6, 10, 16, 10);
|
||||||
|
VoxelShape POST_COLLISION = createCuboidShape(6, 0, 6, 10, 24, 10);
|
||||||
|
VoxelShape SIDE = VoxelShapes.combineAndSimplify(
|
||||||
|
createCuboidShape(7, 12, 0, 9, 15, 6),
|
||||||
|
createCuboidShape(7, 6, 0, 9, 9, 6),
|
||||||
|
BooleanBiFunction.OR
|
||||||
|
);
|
||||||
|
VoxelShape SIDE_COLLISION = createCuboidShape(7, 0, 0, 9, 24, 6);
|
||||||
|
FENCE_VOXELS = VoxelHelper.VoxelListBuilder.create(POST, 5)
|
||||||
|
.add(SIDE)
|
||||||
|
.add(VoxelHelper::mirrorZ)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::mirrorX)
|
||||||
|
.add(POST_COLLISION)
|
||||||
|
.add(SIDE_COLLISION)
|
||||||
|
.add(VoxelHelper::mirrorZ)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::mirrorX)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,8 @@ import net.minecraft.block.BlockState;
|
|||||||
import net.minecraft.block.ShapeContext;
|
import net.minecraft.block.ShapeContext;
|
||||||
import net.minecraft.item.BlockItem;
|
import net.minecraft.item.BlockItem;
|
||||||
import net.minecraft.item.ItemPlacementContext;
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.loot.context.LootContextParameterSet;
|
||||||
import net.minecraft.state.StateManager;
|
import net.minecraft.state.StateManager;
|
||||||
import net.minecraft.util.BlockMirror;
|
import net.minecraft.util.BlockMirror;
|
||||||
import net.minecraft.util.BlockRotation;
|
import net.minecraft.util.BlockRotation;
|
||||||
@ -14,6 +16,8 @@ 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 java.util.List;
|
||||||
|
|
||||||
import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder;
|
import static fr.adrien1106.reframed.util.VoxelHelper.VoxelListBuilder;
|
||||||
import static net.minecraft.state.property.Properties.FACING;
|
import static net.minecraft.state.property.Properties.FACING;
|
||||||
import static net.minecraft.state.property.Properties.LAYERS;
|
import static net.minecraft.state.property.Properties.LAYERS;
|
||||||
@ -27,6 +31,16 @@ public class ReFramedLayerBlock extends ReFramedSlabBlock {
|
|||||||
setDefaultState(getDefaultState().with(LAYERS, 1));
|
setDefaultState(getDefaultState().with(LAYERS, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getDroppedStacks(BlockState state, LootContextParameterSet.Builder builder) {
|
||||||
|
List<ItemStack> drops = super.getDroppedStacks(state, builder);
|
||||||
|
drops.forEach((stack) -> {
|
||||||
|
if (stack.getItem() instanceof BlockItem bi && bi.getBlock() instanceof ReFramedLayerBlock)
|
||||||
|
stack.setCount(state.get(LAYERS));
|
||||||
|
});
|
||||||
|
return drops;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
super.appendProperties(builder.add(LAYERS));
|
super.appendProperties(builder.add(LAYERS));
|
||||||
|
@ -1,122 +1,39 @@
|
|||||||
package fr.adrien1106.reframed.block;
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.util.VoxelHelper;
|
import fr.adrien1106.reframed.util.VoxelHelper;
|
||||||
import net.minecraft.block.Block;
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.PaneBlock;
|
import net.minecraft.block.PaneBlock;
|
||||||
import net.minecraft.block.ShapeContext;
|
import net.minecraft.block.ShapeContext;
|
||||||
import net.minecraft.item.ItemPlacementContext;
|
|
||||||
import net.minecraft.registry.tag.BlockTags;
|
import net.minecraft.registry.tag.BlockTags;
|
||||||
import net.minecraft.state.StateManager;
|
|
||||||
import net.minecraft.state.property.BooleanProperty;
|
|
||||||
import net.minecraft.util.BlockMirror;
|
|
||||||
import net.minecraft.util.BlockRotation;
|
|
||||||
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.shape.VoxelShape;
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
import net.minecraft.util.shape.VoxelShapes;
|
import net.minecraft.util.shape.VoxelShapes;
|
||||||
import net.minecraft.world.BlockView;
|
import net.minecraft.world.BlockView;
|
||||||
import net.minecraft.world.World;
|
|
||||||
import net.minecraft.world.WorldAccess;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import static net.minecraft.state.property.Properties.*;
|
public class ReFramedPaneBlock extends ConnectingReFramedBlock {
|
||||||
|
|
||||||
public class ReFramedPaneBlock extends WaterloggableReFramedBlock {
|
|
||||||
|
|
||||||
public static final VoxelShape[] PANE_VOXELS;
|
public static final VoxelShape[] PANE_VOXELS;
|
||||||
|
|
||||||
public ReFramedPaneBlock(Settings settings) {
|
public ReFramedPaneBlock(Settings settings) {
|
||||||
super(settings);
|
super(settings);
|
||||||
setDefaultState(getDefaultState()
|
|
||||||
.with(EAST, false)
|
|
||||||
.with(NORTH, false)
|
|
||||||
.with(WEST, false)
|
|
||||||
.with(SOUTH, false)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
|
||||||
super.appendProperties(builder.add(EAST, NORTH, SOUTH, WEST));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BlockState getStateForNeighborUpdate(BlockState state, Direction dir, BlockState other_state, WorldAccess world, BlockPos pos, BlockPos moved) {
|
|
||||||
BlockState new_state = super.getStateForNeighborUpdate(state, dir, other_state, world, pos, moved);
|
|
||||||
if (dir == Direction.DOWN) return new_state;
|
|
||||||
|
|
||||||
for (Direction side: Direction.Type.HORIZONTAL) {
|
|
||||||
BlockState neighbor = world.getBlockState(pos.offset(side));
|
|
||||||
new_state = new_state.with(getPaneProperty(side), connectsTo(
|
|
||||||
neighbor,
|
|
||||||
neighbor.isSideSolidFullSquare(world, pos.offset(side), side.getOpposite())
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return new_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
|
||||||
BlockState state = super.getPlacementState(ctx);
|
|
||||||
World world = ctx.getWorld();
|
|
||||||
BlockPos pos = ctx.getBlockPos();
|
|
||||||
|
|
||||||
for (Direction dir: Direction.Type.HORIZONTAL) {
|
|
||||||
BlockState neighbor = world.getBlockState(pos.offset(dir));
|
|
||||||
state = state.with(getPaneProperty(dir), connectsTo(
|
|
||||||
neighbor,
|
|
||||||
neighbor.isSideSolidFullSquare(world, pos.offset(dir), dir.getOpposite())
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
@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
|
@Override
|
||||||
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
VoxelShape shape = PANE_VOXELS[0];
|
VoxelShape shape = PANE_VOXELS[0];
|
||||||
for (Direction dir: Direction.Type.HORIZONTAL) {
|
for (Direction dir: Direction.Type.HORIZONTAL) {
|
||||||
if (state.get(getPaneProperty(dir)))
|
if (state.get(getConnectionProperty(dir)))
|
||||||
shape = VoxelShapes.union(shape, PANE_VOXELS[dir.ordinal() - 1]);
|
shape = VoxelShapes.union(shape, PANE_VOXELS[dir.ordinal() - 1]);
|
||||||
}
|
}
|
||||||
return shape;
|
return shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
protected boolean connectsTo(BlockState state, boolean fs, Direction dir) {
|
||||||
return Direction.Type.HORIZONTAL.stream().reduce(state, (s, dir) ->
|
|
||||||
s.with(getPaneProperty(rotation.rotate(dir)), state.get(getPaneProperty(dir)))
|
|
||||||
, (prev, next) -> next);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
|
||||||
return Direction.Type.HORIZONTAL.stream().reduce(state, (s, dir) ->
|
|
||||||
s.with(getPaneProperty(mirror.apply(dir)), state.get(getPaneProperty(dir)))
|
|
||||||
, (prev, next) -> next);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean connectsTo(BlockState state, boolean fs) {
|
|
||||||
return !cannotConnect(state) && fs || state.getBlock() instanceof PaneBlock || state.isIn(BlockTags.WALLS);
|
return !cannotConnect(state) && fs || state.getBlock() instanceof PaneBlock || state.isIn(BlockTags.WALLS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BooleanProperty getPaneProperty(Direction dir) {
|
|
||||||
return switch (dir) {
|
|
||||||
case NORTH -> NORTH;
|
|
||||||
case EAST -> EAST;
|
|
||||||
case SOUTH -> SOUTH;
|
|
||||||
case WEST -> WEST;
|
|
||||||
default -> null;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
VoxelShape POST = createCuboidShape(7, 0, 7, 9, 16, 9);
|
VoxelShape POST = createCuboidShape(7, 0, 7, 9, 16, 9);
|
||||||
VoxelShape SIDE = createCuboidShape(7, 0, 0, 9, 16, 7);
|
VoxelShape SIDE = createCuboidShape(7, 0, 0, 9, 16, 7);
|
||||||
|
@ -1,38 +1,21 @@
|
|||||||
package fr.adrien1106.reframed.block;
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.util.VoxelHelper;
|
import fr.adrien1106.reframed.util.VoxelHelper;
|
||||||
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.item.ItemPlacementContext;
|
|
||||||
import net.minecraft.state.StateManager;
|
|
||||||
import net.minecraft.util.BlockMirror;
|
|
||||||
import net.minecraft.util.BlockRotation;
|
|
||||||
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.shape.VoxelShape;
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
import net.minecraft.world.BlockView;
|
import net.minecraft.world.BlockView;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import static net.minecraft.state.property.Properties.AXIS;
|
import static net.minecraft.state.property.Properties.AXIS;
|
||||||
|
|
||||||
public class ReFramedPillarBlock extends WaterloggableReFramedBlock {
|
public class ReFramedPillarBlock extends PillarReFramedBlock {
|
||||||
|
|
||||||
public static final VoxelShape[] PILLAR_VOXELS;
|
public static final VoxelShape[] PILLAR_VOXELS;
|
||||||
|
|
||||||
public ReFramedPillarBlock(Settings settings) {
|
public ReFramedPillarBlock(Settings settings) {
|
||||||
super(settings);
|
super(settings);
|
||||||
setDefaultState(getDefaultState().with(AXIS, Direction.Axis.Y));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
|
||||||
super.appendProperties(builder.add(AXIS));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
|
||||||
return super.getPlacementState(ctx).with(AXIS, ctx.getSide().getAxis());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -44,16 +27,6 @@ public class ReFramedPillarBlock extends WaterloggableReFramedBlock {
|
|||||||
return PILLAR_VOXELS[axis.ordinal()];
|
return PILLAR_VOXELS[axis.ordinal()];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
|
||||||
return state.with(AXIS, rotation.rotate(Direction.get(Direction.AxisDirection.POSITIVE, state.get(AXIS))).getAxis());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
|
||||||
return state.with(AXIS, mirror.apply(Direction.get(Direction.AxisDirection.POSITIVE, state.get(AXIS))).getAxis());
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
final VoxelShape PILLAR = createCuboidShape(0, 4, 4, 16, 12, 12);
|
final VoxelShape PILLAR = createCuboidShape(0, 4, 4, 16, 12, 12);
|
||||||
PILLAR_VOXELS = VoxelHelper.VoxelListBuilder.create(PILLAR, 3)
|
PILLAR_VOXELS = VoxelHelper.VoxelListBuilder.create(PILLAR, 3)
|
||||||
|
@ -72,10 +72,10 @@ public class ReFramedPillarsWallBlock extends WaterloggableReFramedDoubleBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
|
||||||
super.onStateReplaced(state, world, pos, newState, moved);
|
super.onStateReplaced(state, world, pos, new_state, moved);
|
||||||
|
|
||||||
if(!state.isOf(newState.getBlock())) world.removeBlockEntity(pos);
|
if(!state.isOf(new_state.getBlock())) world.removeBlockEntity(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.util.VoxelHelper;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
|
||||||
|
import static net.minecraft.state.property.Properties.AXIS;
|
||||||
|
|
||||||
|
public class ReFramedPostBlock extends PillarReFramedBlock {
|
||||||
|
|
||||||
|
public static final VoxelShape[] POST_VOXELS;
|
||||||
|
|
||||||
|
public ReFramedPostBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
return getPillarShape(state.get(AXIS));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VoxelShape getPillarShape(Direction.Axis axis) {
|
||||||
|
return POST_VOXELS[axis.ordinal()];
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
final VoxelShape POST = createCuboidShape(0, 6, 6, 16, 10, 10);
|
||||||
|
POST_VOXELS = VoxelHelper.VoxelListBuilder.create(POST, 3)
|
||||||
|
.add(VoxelHelper::rotateZ)
|
||||||
|
.add(VoxelHelper::rotateX)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,152 @@
|
|||||||
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.FenceGateBlock;
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.entity.ai.pathing.NavigationType;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.item.ItemPlacementContext;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.item.Items;
|
||||||
|
import net.minecraft.item.LeadItem;
|
||||||
|
import net.minecraft.registry.tag.BlockTags;
|
||||||
|
import net.minecraft.state.StateManager;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.BlockMirror;
|
||||||
|
import net.minecraft.util.BlockRotation;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.hit.BlockHitResult;
|
||||||
|
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 static fr.adrien1106.reframed.block.ConnectingReFramedBlock.getConnectionProperty;
|
||||||
|
import static fr.adrien1106.reframed.block.ConnectingReFramedBlock.placementState;
|
||||||
|
import static fr.adrien1106.reframed.block.ReFramedFenceBlock.FENCE_VOXELS;
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
import static net.minecraft.state.property.Properties.WEST;
|
||||||
|
|
||||||
|
public class ReFramedPostFenceBlock extends WaterloggableReFramedDoubleBlock {
|
||||||
|
|
||||||
|
public ReFramedPostFenceBlock(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
setDefaultState(getDefaultState()
|
||||||
|
.with(EAST, false)
|
||||||
|
.with(NORTH, false)
|
||||||
|
.with(WEST, false)
|
||||||
|
.with(SOUTH, false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
super.appendProperties(builder.add(EAST, NORTH, SOUTH, WEST));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
|
||||||
|
super.onStateReplaced(state, world, pos, new_state, moved);
|
||||||
|
|
||||||
|
if(!state.isOf(new_state.getBlock())) world.removeBlockEntity(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getStateForNeighborUpdate(BlockState state, Direction dir, BlockState other_state, WorldAccess world, BlockPos pos, BlockPos moved) {
|
||||||
|
BlockState new_state = super.getStateForNeighborUpdate(state, dir, other_state, world, pos, moved);
|
||||||
|
if (dir == Direction.DOWN) return new_state;
|
||||||
|
|
||||||
|
return placementState(new_state, world, pos, this::connectsTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
|
BlockState state = super.getPlacementState(ctx);
|
||||||
|
World world = ctx.getWorld();
|
||||||
|
BlockPos pos = ctx.getBlockPos();
|
||||||
|
|
||||||
|
return placementState(state, world, pos, this::connectsTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState rotate(BlockState state, BlockRotation rotation) {
|
||||||
|
return Direction.Type.HORIZONTAL.stream().reduce(state, (s, dir) ->
|
||||||
|
s.with(getConnectionProperty(rotation.rotate(dir)), state.get(getConnectionProperty(dir)))
|
||||||
|
, (prev, next) -> next);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState mirror(BlockState state, BlockMirror mirror) {
|
||||||
|
return Direction.Type.HORIZONTAL.stream().reduce(state, (s, dir) ->
|
||||||
|
s.with(getConnectionProperty(mirror.apply(dir)), state.get(getConnectionProperty(dir)))
|
||||||
|
, (prev, next) -> next);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean connectsTo(BlockState state, boolean fs, Direction dir) {
|
||||||
|
return fs || state.isIn(BlockTags.FENCES)
|
||||||
|
|| (state.getBlock() instanceof FenceGateBlock && FenceGateBlock.canWallConnect(state, dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getShape(BlockState state, int i) {
|
||||||
|
if (i == 1) return FENCE_VOXELS[0];
|
||||||
|
VoxelShape shape = VoxelShapes.empty();
|
||||||
|
for (Direction dir: Direction.Type.HORIZONTAL) {
|
||||||
|
if (state.get(getConnectionProperty(dir)))
|
||||||
|
shape = VoxelShapes.union(shape, FENCE_VOXELS[dir.ordinal() - 1]);
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
VoxelShape shape = FENCE_VOXELS[0];
|
||||||
|
for (Direction dir: Direction.Type.HORIZONTAL) {
|
||||||
|
if (state.get(getConnectionProperty(dir)))
|
||||||
|
shape = VoxelShapes.union(shape, FENCE_VOXELS[dir.ordinal() - 1]);
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) {
|
||||||
|
VoxelShape shape = FENCE_VOXELS[5];
|
||||||
|
for (Direction dir: Direction.Type.HORIZONTAL) {
|
||||||
|
if (state.get(getConnectionProperty(dir)))
|
||||||
|
shape = VoxelShapes.union(shape, FENCE_VOXELS[dir.ordinal() + 4]);
|
||||||
|
}
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCameraCollisionShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
|
return getOutlineShape(state, world, pos, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCullingShape(BlockState state, BlockView view, BlockPos pos) {
|
||||||
|
return getOutlineShape(state, view, pos, ShapeContext.absent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
|
||||||
|
ActionResult result = super.onUse(state, world, pos, player, hand, hit);
|
||||||
|
if (result.isAccepted()) return result;
|
||||||
|
if (world.isClient) {
|
||||||
|
ItemStack itemStack = player.getStackInHand(hand);
|
||||||
|
return itemStack.isOf(Items.LEAD) ? ActionResult.SUCCESS : ActionResult.PASS;
|
||||||
|
} else {
|
||||||
|
return LeadItem.attachHeldMobsToBlock(player, world, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -87,10 +87,10 @@ public class ReFramedStairBlock extends WaterloggableReFramedBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
|
||||||
super.onStateReplaced(state, world, pos, newState, moved);
|
super.onStateReplaced(state, world, pos, new_state, moved);
|
||||||
|
|
||||||
if(!state.isOf(newState.getBlock())) world.removeBlockEntity(pos);
|
if(!state.isOf(new_state.getBlock())) world.removeBlockEntity(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -77,10 +77,10 @@ public class ReFramedStairsCubeBlock extends ReFramedDoubleBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
|
||||||
super.onStateReplaced(state, world, pos, newState, moved);
|
super.onStateReplaced(state, world, pos, new_state, moved);
|
||||||
|
|
||||||
if(!state.isOf(newState.getBlock())) world.removeBlockEntity(pos);
|
if(!state.isOf(new_state.getBlock())) world.removeBlockEntity(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -84,10 +84,10 @@ public class ReFramedTrapdoorBlock extends WaterloggableReFramedBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
|
||||||
super.onStateReplaced(state, world, pos, newState, moved);
|
super.onStateReplaced(state, world, pos, new_state, moved);
|
||||||
|
|
||||||
if(!state.isOf(newState.getBlock())) world.removeBlockEntity(pos);
|
if(!state.isOf(new_state.getBlock())) world.removeBlockEntity(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -130,6 +130,20 @@ public class ReFramedClient implements ClientModInitializer {
|
|||||||
HELPER.addReFramedModel("trapdoor_top" , HELPER.auto(new Identifier("block/oak_trapdoor_top")));
|
HELPER.addReFramedModel("trapdoor_top" , HELPER.auto(new Identifier("block/oak_trapdoor_top")));
|
||||||
// DOOR
|
// DOOR
|
||||||
HELPER.addReFramedModel("door_inventory" , HELPER.auto(ReFramed.id("block/door")));
|
HELPER.addReFramedModel("door_inventory" , HELPER.auto(ReFramed.id("block/door")));
|
||||||
|
// BUTTON
|
||||||
|
HELPER.addReFramedModel("button_inventory" , HELPER.auto(new Identifier("block/button_inventory")));
|
||||||
|
HELPER.addReFramedModel("button" , HELPER.auto(new Identifier("block/button")));
|
||||||
|
HELPER.addReFramedModel("button_pressed" , HELPER.auto(new Identifier("block/button_pressed")));
|
||||||
|
// POST
|
||||||
|
HELPER.addReFramedModel("post" , HELPER.auto(ReFramed.id("block/post")));
|
||||||
|
// FENCE
|
||||||
|
HELPER.addReFramedModel("fence_inventory" , HELPER.auto(ReFramed.id("block/fence/inventory")));
|
||||||
|
HELPER.addReFramedModel("fence_core" , HELPER.auto(ReFramed.id("block/fence/core")));
|
||||||
|
HELPER.addReFramedModel("fence_side_off" , HELPER.auto(ReFramed.id("block/fence/side_off")));
|
||||||
|
HELPER.addReFramedModel("fence_side_on" , HELPER.auto(ReFramed.id("block/fence/side_on")));
|
||||||
|
// POST FENCE
|
||||||
|
HELPER.addReFramedModel("post_fence_inventory" , HELPER.autoDouble(ReFramed.id("block/post"), ReFramed.id("block/fence/full/inventory")));
|
||||||
|
HELPER.addReFramedModel("post_fence_side" , HELPER.autoDouble(ReFramed.id("block/fence/full/side_core"), ReFramed.id("block/fence/full/side_bars")));
|
||||||
|
|
||||||
|
|
||||||
//item model assignments (in lieu of models/item/___.json)
|
//item model assignments (in lieu of models/item/___.json)
|
||||||
@ -152,6 +166,10 @@ public class ReFramedClient implements ClientModInitializer {
|
|||||||
HELPER.assignItemModel("pane_inventory" , ReFramed.PANE);
|
HELPER.assignItemModel("pane_inventory" , ReFramed.PANE);
|
||||||
HELPER.assignItemModel("trapdoor_bottom" , ReFramed.TRAPDOOR);
|
HELPER.assignItemModel("trapdoor_bottom" , ReFramed.TRAPDOOR);
|
||||||
HELPER.assignItemModel("door_inventory" , ReFramed.DOOR);
|
HELPER.assignItemModel("door_inventory" , ReFramed.DOOR);
|
||||||
|
HELPER.assignItemModel("button_inventory" , ReFramed.BUTTON);
|
||||||
|
HELPER.assignItemModel("post" , ReFramed.POST);
|
||||||
|
HELPER.assignItemModel("fence_inventory" , ReFramed.FENCE);
|
||||||
|
HELPER.assignItemModel("post_fence_inventory" , ReFramed.POST_FENCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void privateInit() {
|
private void privateInit() {
|
||||||
|
@ -5,12 +5,15 @@ 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.BakedQuad;
|
||||||
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;
|
||||||
|
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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
@ -35,7 +38,17 @@ public class DoubleRetexturingBakedModel extends ForwardingBakedModel implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void emitBlockQuads(BlockRenderView world, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {}
|
public List<BakedQuad> getQuads(BlockState blockState, Direction face, Random rand) {
|
||||||
|
List<BakedQuad> quads = new ArrayList<>(model_1.getQuads(blockState, face, rand));
|
||||||
|
quads.addAll(model_2.getQuads(blockState, face, rand));
|
||||||
|
return quads;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void emitBlockQuads(BlockRenderView world, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
|
||||||
|
model_1.emitBlockQuads(world, state, pos, randomSupplier, context);
|
||||||
|
model_2.emitBlockQuads(world, state, pos, randomSupplier, context);
|
||||||
|
}
|
||||||
|
|
||||||
@Override // models are emitted here because no checks are done on items
|
@Override // models are emitted here because no checks are done on items
|
||||||
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
|
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
|
||||||
|
@ -12,11 +12,13 @@ import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
|||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.*;
|
import net.fabricmc.fabric.api.renderer.v1.mesh.*;
|
||||||
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.model.ModelHelper;
|
||||||
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.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.render.model.BakedModel;
|
import net.minecraft.client.render.model.BakedModel;
|
||||||
|
import net.minecraft.client.render.model.BakedQuad;
|
||||||
import net.minecraft.client.render.model.ModelBakeSettings;
|
import net.minecraft.client.render.model.ModelBakeSettings;
|
||||||
import net.minecraft.client.texture.Sprite;
|
import net.minecraft.client.texture.Sprite;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
@ -25,6 +27,7 @@ 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.atomic.AtomicInteger;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
@ -70,6 +73,39 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
|||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<BakedQuad>[] quads = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BakedQuad> getQuads(BlockState state, Direction face, Random rand) {
|
||||||
|
if (quads == null) {
|
||||||
|
quads = ModelHelper.toQuadLists(
|
||||||
|
getRetexturedMesh(
|
||||||
|
new MeshCacheKey(
|
||||||
|
hashCode(),
|
||||||
|
appearance_manager.getDefaultAppearance(theme_index),
|
||||||
|
0
|
||||||
|
),
|
||||||
|
state
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return quads[ModelHelper.toFaceIndex(face)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCamo(BlockRenderView world, BlockState state, BlockPos pos) {
|
||||||
|
if (state == null || state.isAir()) {
|
||||||
|
quads = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CamoAppearance camo = appearance_manager.getCamoAppearance(world, state, pos, theme_index, false);
|
||||||
|
MeshCacheKey key = new MeshCacheKey(
|
||||||
|
hashCode(),
|
||||||
|
camo,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
quads = ModelHelper.toQuadLists(camo.hashCode() == -1 ? transformMesh(key, state) : getRetexturedMesh(key, state));
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract Mesh convertModel(BlockState state);
|
protected abstract Mesh convertModel(BlockState state);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -89,6 +125,7 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
|||||||
@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) {
|
||||||
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()) {
|
||||||
getRetexturedMesh(
|
getRetexturedMesh(
|
||||||
@ -176,7 +213,7 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
|||||||
emitter.copyFrom(quad);
|
emitter.copyFrom(quad);
|
||||||
i = key.appearance.transformQuad(emitter, i, quad_index.get(), key.model_id, uv_lock);
|
i = key.appearance.transformQuad(emitter, i, quad_index.get(), key.model_id, 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
|
// 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();
|
if (quad.cullFace() == null) quad_index.getAndIncrement();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@ 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.RenderMaterial;
|
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.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.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.util.function.BooleanBiFunction;
|
import net.minecraft.util.function.BooleanBiFunction;
|
||||||
@ -52,8 +51,6 @@ public class RenderHelper {
|
|||||||
Random random = Random.create();
|
Random random = Random.create();
|
||||||
|
|
||||||
List<List<QuadPosBounds>> model_bounds = models.stream()
|
List<List<QuadPosBounds>> model_bounds = models.stream()
|
||||||
.map(ForwardingBakedModel::getWrappedModel)
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.map(wrapped -> wrapped.getQuads(state, null, random))
|
.map(wrapped -> wrapped.getQuads(state, null, random))
|
||||||
.map(quads -> quads.stream().map(quad -> {
|
.map(quads -> quads.stream().map(quad -> {
|
||||||
quad_emitter.fromVanilla(quad, material, null);
|
quad_emitter.fromVanilla(quad, material, null);
|
||||||
@ -98,12 +95,17 @@ public class RenderHelper {
|
|||||||
|
|
||||||
// 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
|
||||||
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 other = world.getBlockEntity(other_pos) instanceof ThemeableBlockEntity e ? e : null;
|
|
||||||
BlockState other_state = world.getBlockState(other_pos);
|
BlockState other_state = world.getBlockState(other_pos);
|
||||||
|
ThemeableBlockEntity self = world.getBlockEntity(pos) instanceof ThemeableBlockEntity e
|
||||||
|
&& self_state.getBlock() instanceof ReFramedBlock
|
||||||
|
? e : null;
|
||||||
|
ThemeableBlockEntity other = world.getBlockEntity(other_pos) instanceof ThemeableBlockEntity e
|
||||||
|
&& other_state.getBlock() instanceof ReFramedBlock
|
||||||
|
? e : null;
|
||||||
|
|
||||||
// normal behaviour
|
// normal behaviour
|
||||||
if (self == null && other == null) return Block.shouldDrawSide(self_state, world, pos, side, other_pos);
|
if (theme_index == 0 || (self == null && other == null))
|
||||||
|
return Block.shouldDrawSide(self_state, world, pos, side, other_pos);
|
||||||
|
|
||||||
// self is a normal Block
|
// self is a normal Block
|
||||||
if (self == null && other_state.getBlock() instanceof ReFramedBlock other_block) {
|
if (self == null && other_state.getBlock() instanceof ReFramedBlock other_block) {
|
||||||
|
@ -19,6 +19,8 @@ public class GBlockTag extends BlockTagProvider {
|
|||||||
providers.put(ReFramedPillarsWallBlock.class, new PillarsWall());
|
providers.put(ReFramedPillarsWallBlock.class, new PillarsWall());
|
||||||
providers.put(ReFramedWallBlock.class, new Wall());
|
providers.put(ReFramedWallBlock.class, new Wall());
|
||||||
providers.put(ReFramedPaneBlock.class, new Pane());
|
providers.put(ReFramedPaneBlock.class, new Pane());
|
||||||
|
providers.put(ReFramedFenceBlock.class, new Fence());
|
||||||
|
providers.put(ReFramedPostFenceBlock.class, new PostFence());
|
||||||
}
|
}
|
||||||
|
|
||||||
public GBlockTag(FabricDataOutput output, CompletableFuture<WrapperLookup> registries) {
|
public GBlockTag(FabricDataOutput output, CompletableFuture<WrapperLookup> registries) {
|
||||||
|
@ -37,6 +37,10 @@ public class GBlockstate extends FabricModelProvider {
|
|||||||
providers.put(ReFramedPaneBlock.class, new Pane());
|
providers.put(ReFramedPaneBlock.class, new Pane());
|
||||||
providers.put(ReFramedTrapdoorBlock.class, new Trapdoor());
|
providers.put(ReFramedTrapdoorBlock.class, new Trapdoor());
|
||||||
providers.put(ReFramedDoorBlock.class, new Door());
|
providers.put(ReFramedDoorBlock.class, new Door());
|
||||||
|
providers.put(ReFramedButtonBlock.class, new Button());
|
||||||
|
providers.put(ReFramedPostBlock.class, new Post());
|
||||||
|
providers.put(ReFramedFenceBlock.class, new Fence());
|
||||||
|
providers.put(ReFramedPostFenceBlock.class, new PostFence());
|
||||||
}
|
}
|
||||||
|
|
||||||
public GBlockstate(FabricDataOutput output) {
|
public GBlockstate(FabricDataOutput output) {
|
||||||
|
@ -39,6 +39,10 @@ public class GRecipe extends FabricRecipeProvider {
|
|||||||
providers.put(ReFramedPaneBlock.class, new Pane());
|
providers.put(ReFramedPaneBlock.class, new Pane());
|
||||||
providers.put(ReFramedTrapdoorBlock.class, new Trapdoor());
|
providers.put(ReFramedTrapdoorBlock.class, new Trapdoor());
|
||||||
providers.put(ReFramedDoorBlock.class, new Door());
|
providers.put(ReFramedDoorBlock.class, new Door());
|
||||||
|
providers.put(ReFramedButtonBlock.class, new Button());
|
||||||
|
providers.put(ReFramedPostBlock.class, new Post());
|
||||||
|
providers.put(ReFramedFenceBlock.class, new Fence());
|
||||||
|
providers.put(ReFramedPostFenceBlock.class, new PostFence());
|
||||||
providers.put(ReFramedBlueprintItem.class, new Blueprint());
|
providers.put(ReFramedBlueprintItem.class, new Blueprint());
|
||||||
providers.put(ReFramedHammerItem.class, new Hammer());
|
providers.put(ReFramedHammerItem.class, new Hammer());
|
||||||
providers.put(ReFramedScrewdriverItem.class, new Screwdriver());
|
providers.put(ReFramedScrewdriverItem.class, new Screwdriver());
|
||||||
|
@ -0,0 +1,95 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.enums.BlockFace;
|
||||||
|
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.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
|
||||||
|
public class Button implements RecipeSetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 8);
|
||||||
|
ShapelessRecipeJsonBuilder.create(RecipeCategory.BUILDING_BLOCKS, convertible, 1)
|
||||||
|
.input(ReFramed.CUBE, 1)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier button = ReFramed.id("button_special");
|
||||||
|
Identifier button_pressed = ReFramed.id("button_pressed_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
// FLOOR OFF
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.NORTH, BLOCK_FACE, BlockFace.FLOOR),
|
||||||
|
GBlockstate.variant(button, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.EAST, BLOCK_FACE, BlockFace.FLOOR),
|
||||||
|
GBlockstate.variant(button, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.SOUTH, BLOCK_FACE, BlockFace.FLOOR),
|
||||||
|
GBlockstate.variant(button, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.WEST, BLOCK_FACE, BlockFace.FLOOR),
|
||||||
|
GBlockstate.variant(button, true, R0, R270))
|
||||||
|
// CEILING OFF
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.SOUTH, BLOCK_FACE, BlockFace.CEILING),
|
||||||
|
GBlockstate.variant(button, true, R180, R0))
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.WEST, BLOCK_FACE, BlockFace.CEILING),
|
||||||
|
GBlockstate.variant(button, true, R180, R90))
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.NORTH, BLOCK_FACE, BlockFace.CEILING),
|
||||||
|
GBlockstate.variant(button, true, R180, R180))
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.EAST, BLOCK_FACE, BlockFace.CEILING),
|
||||||
|
GBlockstate.variant(button, true, R180, R270))
|
||||||
|
// WALL OFF
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.NORTH, BLOCK_FACE, BlockFace.WALL),
|
||||||
|
GBlockstate.variant(button, true, R90, R0))
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.EAST, BLOCK_FACE, BlockFace.WALL),
|
||||||
|
GBlockstate.variant(button, true, R90, R90))
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.SOUTH, BLOCK_FACE, BlockFace.WALL),
|
||||||
|
GBlockstate.variant(button, true, R90, R180))
|
||||||
|
.with(GBlockstate.when(POWERED, false, HORIZONTAL_FACING, Direction.WEST, BLOCK_FACE, BlockFace.WALL),
|
||||||
|
GBlockstate.variant(button, true, R90, R270))
|
||||||
|
// FLOOR ON
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.NORTH, BLOCK_FACE, BlockFace.FLOOR),
|
||||||
|
GBlockstate.variant(button_pressed, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.EAST, BLOCK_FACE, BlockFace.FLOOR),
|
||||||
|
GBlockstate.variant(button_pressed, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.SOUTH, BLOCK_FACE, BlockFace.FLOOR),
|
||||||
|
GBlockstate.variant(button_pressed, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.WEST, BLOCK_FACE, BlockFace.FLOOR),
|
||||||
|
GBlockstate.variant(button_pressed, true, R0, R270))
|
||||||
|
// CEILING ON
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.SOUTH, BLOCK_FACE, BlockFace.CEILING),
|
||||||
|
GBlockstate.variant(button_pressed, true, R180, R0))
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.WEST, BLOCK_FACE, BlockFace.CEILING),
|
||||||
|
GBlockstate.variant(button_pressed, true, R180, R90))
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.NORTH, BLOCK_FACE, BlockFace.CEILING),
|
||||||
|
GBlockstate.variant(button_pressed, true, R180, R180))
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.EAST, BLOCK_FACE, BlockFace.CEILING),
|
||||||
|
GBlockstate.variant(button_pressed, true, R180, R270))
|
||||||
|
// WALL ON
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.NORTH, BLOCK_FACE, BlockFace.WALL),
|
||||||
|
GBlockstate.variant(button_pressed, true, R90, R0))
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.EAST, BLOCK_FACE, BlockFace.WALL),
|
||||||
|
GBlockstate.variant(button_pressed, true, R90, R90))
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.SOUTH, BLOCK_FACE, BlockFace.WALL),
|
||||||
|
GBlockstate.variant(button_pressed, true, R90, R180))
|
||||||
|
.with(GBlockstate.when(POWERED, true, HORIZONTAL_FACING, Direction.WEST, BLOCK_FACE, BlockFace.WALL),
|
||||||
|
GBlockstate.variant(button_pressed, true, R90, R270));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import fr.adrien1106.reframed.generator.TagGetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.Blocks;
|
||||||
|
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.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.registry.tag.BlockTags;
|
||||||
|
import net.minecraft.registry.tag.TagKey;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
|
||||||
|
public class Fence implements RecipeSetter, TagGetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 4);
|
||||||
|
ShapedRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 4)
|
||||||
|
.pattern("I-I")
|
||||||
|
.pattern("I-I")
|
||||||
|
.input('I', ReFramed.CUBE)
|
||||||
|
.input('-', Blocks.BAMBOO)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<TagKey<Block>> getTags() {
|
||||||
|
return List.of(BlockTags.FENCES, BlockTags.WOODEN_FENCES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier side_on = ReFramed.id("fence_side_on_special");
|
||||||
|
Identifier side_off = ReFramed.id("fence_side_off_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
.with(GBlockstate.variant(ReFramed.id("fence_core_special"), true, R0, R0))
|
||||||
|
// SIDE ON
|
||||||
|
.with(GBlockstate.when(NORTH, true),
|
||||||
|
GBlockstate.variant(side_on, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EAST, true),
|
||||||
|
GBlockstate.variant(side_on, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(SOUTH, true),
|
||||||
|
GBlockstate.variant(side_on, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(WEST, true),
|
||||||
|
GBlockstate.variant(side_on, true, R0, R270))
|
||||||
|
// SIDE OFF
|
||||||
|
.with(GBlockstate.when(NORTH, false),
|
||||||
|
GBlockstate.variant(side_off, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EAST, false),
|
||||||
|
GBlockstate.variant(side_off, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(SOUTH, false),
|
||||||
|
GBlockstate.variant(side_off, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(WEST, false),
|
||||||
|
GBlockstate.variant(side_off, true, R0, R270));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
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.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.R0;
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.R90;
|
||||||
|
import static net.minecraft.state.property.Properties.AXIS;
|
||||||
|
|
||||||
|
public class Post implements RecipeSetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.CUBE, 6);
|
||||||
|
ShapedRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 12)
|
||||||
|
.pattern("I")
|
||||||
|
.pattern("I")
|
||||||
|
.pattern("I")
|
||||||
|
.input('I', ReFramed.CUBE)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier model_id = ReFramed.id("post_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
.with(GBlockstate.when(AXIS, Direction.Axis.X),
|
||||||
|
GBlockstate.variant(model_id, true, R90, R90))
|
||||||
|
.with(GBlockstate.when(AXIS, Direction.Axis.Y),
|
||||||
|
GBlockstate.variant(model_id, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(AXIS, Direction.Axis.Z),
|
||||||
|
GBlockstate.variant(model_id, true, R90, R0));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
package fr.adrien1106.reframed.generator.block;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
|
import fr.adrien1106.reframed.generator.TagGetter;
|
||||||
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
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.ItemConvertible;
|
||||||
|
import net.minecraft.recipe.book.RecipeCategory;
|
||||||
|
import net.minecraft.registry.tag.BlockTags;
|
||||||
|
import net.minecraft.registry.tag.TagKey;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
import static net.minecraft.state.property.Properties.*;
|
||||||
|
|
||||||
|
public class PostFence implements RecipeSetter, TagGetter, BlockStateProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecipe(RecipeExporter exporter, ItemConvertible convertible) {
|
||||||
|
RecipeProvider.offerStonecuttingRecipe(exporter, RecipeCategory.BUILDING_BLOCKS, convertible, ReFramed.FENCE, 1);
|
||||||
|
ShapelessRecipeJsonBuilder
|
||||||
|
.create(RecipeCategory.BUILDING_BLOCKS, convertible, 2)
|
||||||
|
.input(ReFramed.FENCE, 2)
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(ReFramed.CUBE), FabricRecipeProvider.conditionsFromItem(ReFramed.CUBE))
|
||||||
|
.criterion(FabricRecipeProvider.hasItem(convertible), FabricRecipeProvider.conditionsFromItem(convertible))
|
||||||
|
.offerTo(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<TagKey<Block>> getTags() {
|
||||||
|
return List.of(BlockTags.FENCES, BlockTags.WOODEN_FENCES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockStateSupplier getMultipart(Block block) {
|
||||||
|
Identifier side_on = ReFramed.id("post_fence_side_special");
|
||||||
|
Identifier side_off = ReFramed.id("fence_side_off_special");
|
||||||
|
return MultipartBlockStateSupplier.create(block)
|
||||||
|
.with(GBlockstate.variant(ReFramed.id("fence_core_special"), true, R0, R0))
|
||||||
|
// SIDE ON
|
||||||
|
.with(GBlockstate.when(NORTH, true),
|
||||||
|
GBlockstate.variant(side_on, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EAST, true),
|
||||||
|
GBlockstate.variant(side_on, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(SOUTH, true),
|
||||||
|
GBlockstate.variant(side_on, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(WEST, true),
|
||||||
|
GBlockstate.variant(side_on, true, R0, R270))
|
||||||
|
// SIDE OFF
|
||||||
|
.with(GBlockstate.when(NORTH, false),
|
||||||
|
GBlockstate.variant(side_off, true, R0, R0))
|
||||||
|
.with(GBlockstate.when(EAST, false),
|
||||||
|
GBlockstate.variant(side_off, true, R0, R90))
|
||||||
|
.with(GBlockstate.when(SOUTH, false),
|
||||||
|
GBlockstate.variant(side_off, true, R0, R180))
|
||||||
|
.with(GBlockstate.when(WEST, false),
|
||||||
|
GBlockstate.variant(side_off, true, R0, R270));
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ package fr.adrien1106.reframed.mixin;
|
|||||||
|
|
||||||
import com.llamalad7.mixinextras.sugar.Local;
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
|
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
|
||||||
|
import fr.adrien1106.reframed.block.ReFramedBlock;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockEntityProvider;
|
import net.minecraft.block.BlockEntityProvider;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
@ -9,6 +10,7 @@ import net.minecraft.item.BlockItem;
|
|||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.nbt.NbtCompound;
|
import net.minecraft.nbt.NbtCompound;
|
||||||
import net.minecraft.nbt.NbtHelper;
|
import net.minecraft.nbt.NbtHelper;
|
||||||
|
import net.minecraft.state.property.Properties;
|
||||||
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.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
@ -32,8 +34,12 @@ public class BlockItemMixin {
|
|||||||
private static void placeBlockWithOffHandCamo(World world, PlayerEntity player, BlockPos pos, ItemStack stack, CallbackInfoReturnable<Boolean> cir, @Local LocalRef<NbtCompound> compound) {
|
private static void placeBlockWithOffHandCamo(World world, PlayerEntity player, BlockPos pos, ItemStack stack, CallbackInfoReturnable<Boolean> cir, @Local LocalRef<NbtCompound> compound) {
|
||||||
if (compound.get() != null
|
if (compound.get() != null
|
||||||
|| player.getOffHandStack().isEmpty()
|
|| player.getOffHandStack().isEmpty()
|
||||||
|
|| player.getMainHandStack().isEmpty()
|
||||||
|
|| !(player.getMainHandStack().getItem() instanceof BlockItem frame)
|
||||||
|
|| !(frame.getBlock() instanceof ReFramedBlock)
|
||||||
|| !(player.getOffHandStack().getItem() instanceof BlockItem block)
|
|| !(player.getOffHandStack().getItem() instanceof BlockItem block)
|
||||||
|| block.getBlock() instanceof BlockEntityProvider
|
|| block.getBlock() instanceof BlockEntityProvider
|
||||||
|
|| (world.getBlockState(pos).contains(Properties.LAYERS) && world.getBlockState(pos).get(Properties.LAYERS) > 1)
|
||||||
|| !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();
|
||||||
|
@ -26,14 +26,24 @@ public class CompatMixinPlugin implements IMixinConfigPlugin {
|
|||||||
CONDITIONS.put("fr.adrien1106.reframed.mixin.render.BlockRenderInfoMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)));
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.render.BlockRenderInfoMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)));
|
||||||
CONDITIONS.put("fr.adrien1106.reframed.mixin.render.AbstractBlockRenderContextMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)));
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.render.AbstractBlockRenderContextMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)));
|
||||||
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.IndiumTerrainRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)));
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.IndiumTerrainRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)));
|
||||||
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.IndiumTerrainBlockRenderInfoMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)));
|
|
||||||
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.IndiumAbstractBlockRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)));
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.IndiumAbstractBlockRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)));
|
||||||
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.IndiumBlockRenderInfoMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)));
|
||||||
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.IndiumNonTerrainBlockRenderContextMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(1)));
|
||||||
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.render.BlockRenderContextMixin", () -> !LOADER.isModLoaded(COMPAT_MOD.get(1)));
|
||||||
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.SodiumBlockOcclusionCacheMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(2)));
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.SodiumBlockOcclusionCacheMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(2)));
|
||||||
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityConnectionPredicateMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4)));
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityConnectionPredicateMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4)));
|
||||||
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityCTMBakedModelMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4)));
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityCTMBakedModelMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4)));
|
||||||
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityCTMQuadTransformMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4)));
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityCTMQuadTransformMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4)));
|
||||||
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityModelWrappingHandlerMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4)));
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.ContinuityModelWrappingHandlerMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(4)));
|
||||||
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomChunkedBlockRegionMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5)));
|
||||||
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomClientBlockEntitySerializerMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5)));
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomClientBlockEntitySerializerMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5)));
|
||||||
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomClipboardMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5)));
|
||||||
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomCloneBuilderToolMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5)));
|
||||||
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomPlacementMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5)));
|
||||||
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomMappedBlockAndTintGetterMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5)));
|
||||||
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomMoveBuilderToolMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5)));
|
||||||
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomScale3xMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5)));
|
||||||
|
CONDITIONS.put("fr.adrien1106.reframed.mixin.compat.AxiomRotSpriteMixin", () -> LOADER.isModLoaded(COMPAT_MOD.get(5)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,161 @@
|
|||||||
|
package fr.adrien1106.reframed.mixin.compat;
|
||||||
|
|
||||||
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
|
import com.moulberry.axiom.render.regions.ChunkedBlockRegion;
|
||||||
|
import com.moulberry.axiom.utils.IntMatrix;
|
||||||
|
import com.moulberry.axiom.world_modification.CompressedBlockEntity;
|
||||||
|
import fr.adrien1106.reframed.client.model.MultiRetexturableModel;
|
||||||
|
import fr.adrien1106.reframed.client.model.RetexturingBakedModel;
|
||||||
|
import fr.adrien1106.reframed.util.mixin.IAxiomChunkedBlockRegionMixin;
|
||||||
|
import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin;
|
||||||
|
import fr.adrien1106.reframed.util.mixin.ThemedBlockEntity;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.client.render.BufferBuilder;
|
||||||
|
import net.minecraft.client.render.Camera;
|
||||||
|
import net.minecraft.client.render.OverlayTexture;
|
||||||
|
import net.minecraft.client.render.block.BlockRenderManager;
|
||||||
|
import net.minecraft.client.render.model.BakedModel;
|
||||||
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
import net.minecraft.nbt.NbtCompound;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.util.math.random.Random;
|
||||||
|
import net.minecraft.world.BlockRenderView;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.block.ReFramedEntity.BLOCKSTATE_KEY;
|
||||||
|
|
||||||
|
@Mixin(ChunkedBlockRegion.class) // TODO: Look here for better rotation/flip support
|
||||||
|
public abstract class AxiomChunkedBlockRegionMixin implements IAxiomChunkedBlockRegionMixin {
|
||||||
|
|
||||||
|
@Shadow public abstract BlockState getBlockState(BlockPos pos);
|
||||||
|
|
||||||
|
@Shadow public abstract @Nullable BlockEntity getBlockEntity(BlockPos pos);
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private IntMatrix transform;
|
||||||
|
@Unique
|
||||||
|
private IntMatrix inverse_transform;
|
||||||
|
@Unique
|
||||||
|
private Long2ObjectMap<CompressedBlockEntity> block_entities;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static boolean isFrameModel(BakedModel model) {
|
||||||
|
return model instanceof RetexturingBakedModel || model instanceof MultiRetexturableModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static List<BakedModel> getModels(BakedModel model, BlockState state) {
|
||||||
|
if (isFrameModel(model))
|
||||||
|
return List.of(model);
|
||||||
|
else if (model instanceof IMultipartBakedModelMixin mpm)
|
||||||
|
return mpm.getModels(state).stream().filter(AxiomChunkedBlockRegionMixin::isFrameModel).toList();
|
||||||
|
else
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "renderBlock",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE_ASSIGN",
|
||||||
|
target = "Lnet/minecraft/client/render/block/BlockRenderManager;getModel(Lnet/minecraft/block/BlockState;)Lnet/minecraft/client/render/model/BakedModel;",
|
||||||
|
shift = At.Shift.AFTER
|
||||||
|
),
|
||||||
|
cancellable = true)
|
||||||
|
private static void onRenderBlock(BufferBuilder blockBuilder, BlockRenderManager renderer, BlockPos.Mutable pos, Random rand, MatrixStack matrices, BlockRenderView world, Matrix4f currentPoseMatrix, Matrix4f basePoseMatrix, int x, int y, int z, BlockState state, boolean useAmbientOcclusion, CallbackInfo ci, @Local BakedModel model) {
|
||||||
|
List<BakedModel> models;
|
||||||
|
if ((models = getModels(model, state)).isEmpty() // not a retexturable model
|
||||||
|
|| !(world.getBlockEntity(pos) instanceof ThemedBlockEntity block_entity) // not a themed block entity
|
||||||
|
) return;
|
||||||
|
|
||||||
|
models.stream().flatMap(m -> m instanceof MultiRetexturableModel mm
|
||||||
|
? mm.models().stream()
|
||||||
|
: Stream.of((RetexturingBakedModel)m)
|
||||||
|
).forEach(m -> {
|
||||||
|
m.setCamo(world, block_entity.getTheme(m.getThemeIndex()), pos);
|
||||||
|
if (useAmbientOcclusion && state.getLuminance() == 0 && m.useAmbientOcclusion()) renderer.getModelRenderer()
|
||||||
|
.renderSmooth(world, m, state, pos, matrices, blockBuilder, true, rand, state.getRenderingSeed(pos), OverlayTexture.DEFAULT_UV);
|
||||||
|
else renderer.getModelRenderer()
|
||||||
|
.renderFlat(world, m, state, pos, matrices, blockBuilder, true, rand, state.getRenderingSeed(pos), OverlayTexture.DEFAULT_UV);
|
||||||
|
});
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "getBlockEntity",
|
||||||
|
at = @At("HEAD"),
|
||||||
|
remap = false,
|
||||||
|
cancellable = true
|
||||||
|
)
|
||||||
|
private void onGetBlockEntity(BlockPos pos, CallbackInfoReturnable<BlockEntity> cir) {
|
||||||
|
if (inverse_transform == null) return;
|
||||||
|
long key = BlockPos.asLong(
|
||||||
|
inverse_transform.transformX(pos.getX(), pos.getY(), pos.getZ()),
|
||||||
|
inverse_transform.transformY(pos.getX(), pos.getY(), pos.getZ()),
|
||||||
|
inverse_transform.transformZ(pos.getX(), pos.getY(), pos.getZ())
|
||||||
|
);
|
||||||
|
NbtCompound compound;
|
||||||
|
if (!block_entities.containsKey(key)
|
||||||
|
|| !(compound = block_entities.get(key).decompress()).contains(BLOCKSTATE_KEY + 1)
|
||||||
|
) return;
|
||||||
|
cir.setReturnValue(new ThemedBlockEntity(compound, pos, getBlockState(pos)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "uploadDirty",
|
||||||
|
at = @At("HEAD")
|
||||||
|
)
|
||||||
|
private void onUploadDirty(Camera camera, Vec3d translation, boolean canResort, boolean canUseAmbientOcclusion, CallbackInfo ci) {
|
||||||
|
if (transform == null) inverse_transform = new IntMatrix();
|
||||||
|
else inverse_transform = transform.copy();
|
||||||
|
inverse_transform.invert();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "flip",
|
||||||
|
at = @At("RETURN")
|
||||||
|
)
|
||||||
|
private void onFlip(Direction.Axis axis, CallbackInfoReturnable<ChunkedBlockRegion> cir) {
|
||||||
|
((IAxiomChunkedBlockRegionMixin) cir.getReturnValue()).setTransform(transform, block_entities);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "rotate",
|
||||||
|
at = @At("RETURN")
|
||||||
|
)
|
||||||
|
private void onRotate(Direction.Axis axis, int count, CallbackInfoReturnable<ChunkedBlockRegion> cir) {
|
||||||
|
((IAxiomChunkedBlockRegionMixin) cir.getReturnValue()).setTransform(transform, block_entities);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTransform(IntMatrix transform, Long2ObjectMap<CompressedBlockEntity> block_entities) {
|
||||||
|
this.transform = transform;
|
||||||
|
this.block_entities = block_entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntMatrix getTransform() {
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long2ObjectMap<CompressedBlockEntity> getBlockEntities() {
|
||||||
|
return block_entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package fr.adrien1106.reframed.mixin.compat;
|
||||||
|
|
||||||
|
import com.moulberry.axiom.clipboard.Clipboard;
|
||||||
|
import com.moulberry.axiom.clipboard.ClipboardObject;
|
||||||
|
import com.moulberry.axiom.utils.IntMatrix;
|
||||||
|
import fr.adrien1106.reframed.util.mixin.IAxiomChunkedBlockRegionMixin;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(Clipboard.class)
|
||||||
|
public class AxiomClipboardMixin {
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "setClipboard(Lcom/moulberry/axiom/clipboard/ClipboardObject;)I",
|
||||||
|
at = @At(
|
||||||
|
value = "TAIL"
|
||||||
|
),
|
||||||
|
remap = false
|
||||||
|
)
|
||||||
|
private void onInit(ClipboardObject object, CallbackInfoReturnable<Integer> cir) {
|
||||||
|
((IAxiomChunkedBlockRegionMixin) object.blockRegion()).setTransform(new IntMatrix(), object.blockEntities());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package fr.adrien1106.reframed.mixin.compat;
|
||||||
|
|
||||||
|
import com.moulberry.axiom.buildertools.CloneBuilderTool;
|
||||||
|
import com.moulberry.axiom.clipboard.SelectionBuffer;
|
||||||
|
import com.moulberry.axiom.render.regions.ChunkedBlockRegion;
|
||||||
|
import com.moulberry.axiom.utils.IntMatrix;
|
||||||
|
import com.moulberry.axiom.world_modification.CompressedBlockEntity;
|
||||||
|
import fr.adrien1106.reframed.util.mixin.IAxiomChunkedBlockRegionMixin;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(CloneBuilderTool.class)
|
||||||
|
public class AxiomCloneBuilderToolMixin {
|
||||||
|
|
||||||
|
@Shadow(remap = false) private ChunkedBlockRegion blockRegion;
|
||||||
|
|
||||||
|
@Shadow(remap = false) @Final private IntMatrix transformMatrix;
|
||||||
|
|
||||||
|
@Shadow(remap = false) private Long2ObjectMap<CompressedBlockEntity> blockEntities;
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "lambda$initiateClone$0",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE_ASSIGN",
|
||||||
|
target = "Lcom/moulberry/axiom/clipboard/SelectionBuffer$CopyResult;blockEntities()Lit/unimi/dsi/fastutil/longs/Long2ObjectMap;",
|
||||||
|
shift = At.Shift.AFTER
|
||||||
|
),
|
||||||
|
remap = false
|
||||||
|
)
|
||||||
|
private void onInitiateClone(int copyId, int offsetX, int offsetY, int offsetZ, SelectionBuffer.CopyResult copyResult, CallbackInfo ci) {
|
||||||
|
((IAxiomChunkedBlockRegionMixin) blockRegion).setTransform(transformMatrix, blockEntities);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package fr.adrien1106.reframed.mixin.compat;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.block.ReFramedEntity;
|
||||||
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(targets = "com.moulberry.axiom.render.ChunkRenderOverrider$MappedBlockAndTintGetter")
|
||||||
|
public class AxiomMappedBlockAndTintGetterMixin {
|
||||||
|
|
||||||
|
@Shadow @Final private World level;
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "getBlockEntity",
|
||||||
|
at = @At(
|
||||||
|
value = "RETURN"
|
||||||
|
),
|
||||||
|
remap = false,
|
||||||
|
cancellable = true
|
||||||
|
)
|
||||||
|
private void onGetBlockEntity(BlockPos pos, CallbackInfoReturnable<BlockEntity> cir) {
|
||||||
|
if (!(level.getBlockEntity(pos) instanceof ReFramedEntity frame_entity)) return;
|
||||||
|
cir.setReturnValue(frame_entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package fr.adrien1106.reframed.mixin.compat;
|
||||||
|
|
||||||
|
import com.moulberry.axiom.buildertools.MoveBuilderTool;
|
||||||
|
import com.moulberry.axiom.clipboard.SelectionBuffer;
|
||||||
|
import com.moulberry.axiom.render.regions.ChunkedBlockRegion;
|
||||||
|
import com.moulberry.axiom.utils.IntMatrix;
|
||||||
|
import com.moulberry.axiom.world_modification.CompressedBlockEntity;
|
||||||
|
import fr.adrien1106.reframed.util.mixin.IAxiomChunkedBlockRegionMixin;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(MoveBuilderTool.class)
|
||||||
|
public class AxiomMoveBuilderToolMixin {
|
||||||
|
|
||||||
|
@Shadow(remap = false) private ChunkedBlockRegion blockRegion;
|
||||||
|
|
||||||
|
@Shadow(remap = false) @Final private IntMatrix transformMatrix;
|
||||||
|
|
||||||
|
@Shadow(remap = false) private Long2ObjectMap<CompressedBlockEntity> blockEntities;
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "lambda$initiateMovement$1",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE_ASSIGN",
|
||||||
|
target = "Lcom/moulberry/axiom/clipboard/SelectionBuffer$CopyResult;blockEntities()Lit/unimi/dsi/fastutil/longs/Long2ObjectMap;",
|
||||||
|
shift = At.Shift.AFTER
|
||||||
|
),
|
||||||
|
remap = false
|
||||||
|
)
|
||||||
|
private void onInitiateClone(int copyId, int offsetX, int offsetY, int offsetZ, SelectionBuffer.CopyResult copyResult, CallbackInfo ci) {
|
||||||
|
((IAxiomChunkedBlockRegionMixin) blockRegion).setTransform(transformMatrix, blockEntities);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package fr.adrien1106.reframed.mixin.compat;
|
||||||
|
|
||||||
|
import com.moulberry.axiom.clipboard.Placement;
|
||||||
|
import com.moulberry.axiom.render.regions.ChunkedBlockRegion;
|
||||||
|
import com.moulberry.axiom.utils.IntMatrix;
|
||||||
|
import com.moulberry.axiom.world_modification.CompressedBlockEntity;
|
||||||
|
import fr.adrien1106.reframed.util.mixin.IAxiomChunkedBlockRegionMixin;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(Placement.class)
|
||||||
|
public class AxiomPlacementMixin {
|
||||||
|
|
||||||
|
@Shadow(remap = false) private Long2ObjectMap<CompressedBlockEntity> blockEntities;
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "replacePlacement(Lcom/moulberry/axiom/render/regions/ChunkedBlockRegion;Ljava/lang/String;)V",
|
||||||
|
at = @At("HEAD"),
|
||||||
|
remap = false
|
||||||
|
)
|
||||||
|
private void onReplacePlacement(ChunkedBlockRegion region, String description, CallbackInfo ci) {
|
||||||
|
((IAxiomChunkedBlockRegionMixin) region).setTransform(new IntMatrix(), blockEntities);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "startPlacement(Lnet/minecraft/util/math/BlockPos;Lcom/moulberry/axiom/render/regions/ChunkedBlockRegion;Lit/unimi/dsi/fastutil/longs/Long2ObjectMap;Ljava/lang/String;)I",
|
||||||
|
at = @At("HEAD"),
|
||||||
|
remap = false
|
||||||
|
)
|
||||||
|
private void onStartPlacement(BlockPos target, ChunkedBlockRegion region, Long2ObjectMap<CompressedBlockEntity> entities, String description, CallbackInfoReturnable<Integer> cir) {
|
||||||
|
((IAxiomChunkedBlockRegionMixin) region).setTransform(new IntMatrix(), entities);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package fr.adrien1106.reframed.mixin.compat;
|
||||||
|
|
||||||
|
import com.moulberry.axiom.render.regions.ChunkedBlockRegion;
|
||||||
|
import com.moulberry.axiom.scaling.RotSprite;
|
||||||
|
import fr.adrien1106.reframed.util.mixin.IAxiomChunkedBlockRegionMixin;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(RotSprite.class)
|
||||||
|
public class AxiomRotSpriteMixin {
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "rotateCachedWithOutput",
|
||||||
|
at = @At(
|
||||||
|
value = "HEAD"
|
||||||
|
),
|
||||||
|
remap = false
|
||||||
|
)
|
||||||
|
private static void onRotateCachedWithOutput(ChunkedBlockRegion in, Matrix4f matrix4f, ChunkedBlockRegion out, int x, int y, int z, CallbackInfoReturnable<ChunkedBlockRegion> cir) {
|
||||||
|
IAxiomChunkedBlockRegionMixin iin = (IAxiomChunkedBlockRegionMixin) in;
|
||||||
|
((IAxiomChunkedBlockRegionMixin) out).setTransform(iin.getTransform(), iin.getBlockEntities());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package fr.adrien1106.reframed.mixin.compat;
|
||||||
|
|
||||||
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
|
import com.moulberry.axiom.render.regions.ChunkedBlockRegion;
|
||||||
|
import com.moulberry.axiom.scaling.Scale3x;
|
||||||
|
import fr.adrien1106.reframed.util.mixin.IAxiomChunkedBlockRegionMixin;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(Scale3x.class)
|
||||||
|
public class AxiomScale3xMixin {
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "scale3x",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE_ASSIGN",
|
||||||
|
target = "Lcom/moulberry/axiom/render/regions/ChunkedBlockRegion;<init>()V",
|
||||||
|
shift = At.Shift.AFTER
|
||||||
|
),
|
||||||
|
remap = false
|
||||||
|
)
|
||||||
|
private static void onInit(ChunkedBlockRegion in, boolean postProcessing, CallbackInfoReturnable<ChunkedBlockRegion> cir, @Local(ordinal = 1) ChunkedBlockRegion out) {
|
||||||
|
IAxiomChunkedBlockRegionMixin iin = (IAxiomChunkedBlockRegionMixin) in;
|
||||||
|
((IAxiomChunkedBlockRegionMixin) out).setTransform(iin.getTransform(), iin.getBlockEntities());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
package fr.adrien1106.reframed.mixin.compat;
|
||||||
|
|
||||||
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
|
import fr.adrien1106.reframed.client.util.RenderHelper;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
|
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
|
||||||
|
import link.infra.indium.renderer.render.BlockRenderInfo;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.world.BlockRenderView;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(BlockRenderInfo.class)
|
||||||
|
public abstract class IndiumBlockRenderInfoMixin implements IBlockRenderInfoMixin {
|
||||||
|
|
||||||
|
@Shadow public abstract void prepareForBlock(BlockState blockState, BlockPos blockPos, long seed, boolean modelAo);
|
||||||
|
|
||||||
|
@Shadow public BlockPos blockPos;
|
||||||
|
@Shadow public BlockRenderView blockView;
|
||||||
|
@Shadow public BlockState blockState;
|
||||||
|
@Shadow(remap = false) private int cullResultFlags;
|
||||||
|
|
||||||
|
@Unique private int theme_index = 0;
|
||||||
|
@Unique private int model_hash = 0;
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "shouldDrawFace",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Llink/infra/indium/renderer/render/BlockRenderInfo;shouldDrawFaceInner(Lnet/minecraft/util/math/Direction;)Z"
|
||||||
|
),
|
||||||
|
cancellable = true
|
||||||
|
)
|
||||||
|
private void shouldDrawInnerFace(Direction face, CallbackInfoReturnable<Boolean> cir, @Local int mask) {
|
||||||
|
BlockPos other_pos = blockPos.offset(face);
|
||||||
|
if (!(blockView.getBlockEntity(blockPos) instanceof ThemeableBlockEntity
|
||||||
|
|| blockView.getBlockEntity(other_pos) instanceof ThemeableBlockEntity)
|
||||||
|
) return;
|
||||||
|
boolean result = RenderHelper.shouldDrawSide(blockState, blockView, blockPos, face, other_pos, theme_index);
|
||||||
|
if (result) cullResultFlags |= mask;
|
||||||
|
cir.setReturnValue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void prepareForBlock(BlockState blockState, BlockPos blockPos, long seed, boolean modelAo, int theme_index, int model_hash) {
|
||||||
|
this.theme_index = theme_index;
|
||||||
|
this.model_hash = model_hash;
|
||||||
|
prepareForBlock(blockState, blockPos, seed, modelAo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getThemeIndex() {
|
||||||
|
return theme_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getModelHash() {
|
||||||
|
return model_hash;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
package fr.adrien1106.reframed.mixin.compat;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.client.model.MultiRetexturableModel;
|
||||||
|
import fr.adrien1106.reframed.client.model.RetexturingBakedModel;
|
||||||
|
import fr.adrien1106.reframed.client.util.RenderHelper;
|
||||||
|
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
|
||||||
|
import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin;
|
||||||
|
import link.infra.indium.renderer.aocalc.AoCalculator;
|
||||||
|
import link.infra.indium.renderer.render.AbstractBlockRenderContext;
|
||||||
|
import link.infra.indium.renderer.render.BlockRenderInfo;
|
||||||
|
import link.infra.indium.renderer.render.NonTerrainBlockRenderContext;
|
||||||
|
import link.infra.indium.renderer.render.SingleBlockLightDataCache;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.client.render.VertexConsumer;
|
||||||
|
import net.minecraft.client.render.model.BakedModel;
|
||||||
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.random.Random;
|
||||||
|
import net.minecraft.world.BlockRenderView;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Mixin(NonTerrainBlockRenderContext.class)
|
||||||
|
public abstract class IndiumNonTerrainBlockRenderContextMixin extends AbstractBlockRenderContext {
|
||||||
|
|
||||||
|
@Shadow(remap = false) @Final private SingleBlockLightDataCache lightCache;
|
||||||
|
|
||||||
|
@Shadow private VertexConsumer vertexConsumer;
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "render",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Llink/infra/indium/renderer/render/BlockRenderInfo;prepareForWorld(Lnet/minecraft/world/BlockRenderView;Z)V",
|
||||||
|
shift = At.Shift.AFTER
|
||||||
|
),
|
||||||
|
remap = false,
|
||||||
|
cancellable = true
|
||||||
|
)
|
||||||
|
private void renderMultipleModels(BlockRenderView blockView, BakedModel wrapper, BlockState state, BlockPos pos, MatrixStack matrixStack, VertexConsumer buffer, boolean cull, Random random, long seed, int overlay, CallbackInfo ci) {
|
||||||
|
if (!(wrapper instanceof IMultipartBakedModelMixin wrapped)) return;
|
||||||
|
List<BakedModel> models = wrapped.getModels(state);
|
||||||
|
if (models.stream().noneMatch(bakedModel ->
|
||||||
|
bakedModel instanceof MultiRetexturableModel
|
||||||
|
|| bakedModel instanceof RetexturingBakedModel
|
||||||
|
)) return;
|
||||||
|
|
||||||
|
models.forEach(model -> {
|
||||||
|
if (model instanceof MultiRetexturableModel multi_model) {
|
||||||
|
RenderHelper.computeInnerCull(state, multi_model.models(), model.hashCode());
|
||||||
|
multi_model.models().forEach(rexteruable_model ->
|
||||||
|
renderModel(state, pos, seed, rexteruable_model, aoCalc, blockInfo, this, model.hashCode())
|
||||||
|
);
|
||||||
|
} else if (model instanceof RetexturingBakedModel rexteruable_model)
|
||||||
|
renderModel(state, pos, seed, rexteruable_model, aoCalc, blockInfo, this, model.hashCode());
|
||||||
|
else model.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this);
|
||||||
|
});
|
||||||
|
|
||||||
|
blockInfo.release();
|
||||||
|
lightCache.release();
|
||||||
|
vertexConsumer = null;
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static void renderModel(BlockState state, BlockPos pos, long seed, RetexturingBakedModel model, AoCalculator aoCalc, BlockRenderInfo block_info, RenderContext context, int model_hash) {
|
||||||
|
aoCalc.clear();
|
||||||
|
((IBlockRenderInfoMixin) block_info).prepareForBlock(
|
||||||
|
state, pos, seed,
|
||||||
|
model.useAmbientOcclusion(block_info.blockView, pos),
|
||||||
|
model.getThemeIndex(), model_hash
|
||||||
|
);
|
||||||
|
model.emitBlockQuads(block_info.blockView, block_info.blockState, block_info.blockPos, block_info.randomSupplier, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,55 +0,0 @@
|
|||||||
package fr.adrien1106.reframed.mixin.compat;
|
|
||||||
|
|
||||||
import fr.adrien1106.reframed.client.util.RenderHelper;
|
|
||||||
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
|
|
||||||
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
|
||||||
import link.infra.indium.renderer.render.BlockRenderInfo;
|
|
||||||
import link.infra.indium.renderer.render.TerrainBlockRenderInfo;
|
|
||||||
import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockOcclusionCache;
|
|
||||||
import net.minecraft.block.BlockState;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.util.math.Direction;
|
|
||||||
import net.minecraft.world.BlockView;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
|
|
||||||
@Mixin(TerrainBlockRenderInfo.class)
|
|
||||||
public abstract class IndiumTerrainBlockRenderInfoMixin extends BlockRenderInfo implements IBlockRenderInfoMixin {
|
|
||||||
|
|
||||||
@Unique private int theme_index = 0;
|
|
||||||
@Unique private int model_hash = 0;
|
|
||||||
|
|
||||||
@Redirect(
|
|
||||||
method = "shouldDrawFaceInner",
|
|
||||||
at = @At(
|
|
||||||
value = "INVOKE",
|
|
||||||
target = "Lme/jellysquid/mods/sodium/client/render/chunk/compile/pipeline/BlockOcclusionCache;shouldDrawSide(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/BlockView;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/Direction;)Z"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
private boolean shouldDrawCamoSide(BlockOcclusionCache instance, BlockState state, BlockView view, BlockPos pos, Direction face) {
|
|
||||||
BlockPos other_pos = pos.offset(face);
|
|
||||||
if (!(view.getBlockEntity(pos) instanceof ThemeableBlockEntity
|
|
||||||
|| view.getBlockEntity(other_pos) instanceof ThemeableBlockEntity))
|
|
||||||
return instance.shouldDrawSide(state, view, pos, face);
|
|
||||||
return RenderHelper.shouldDrawSide(state, view, pos, face, other_pos, theme_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void prepareForBlock(BlockState blockState, BlockPos blockPos, long seed, boolean modelAo, int theme_index, int model_hash) {
|
|
||||||
this.theme_index = theme_index;
|
|
||||||
this.model_hash = model_hash;
|
|
||||||
prepareForBlock(blockState, blockPos, seed, modelAo);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getThemeIndex() {
|
|
||||||
return theme_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getModelHash() {
|
|
||||||
return model_hash;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,40 @@
|
|||||||
|
package fr.adrien1106.reframed.mixin.render;
|
||||||
|
|
||||||
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
|
import fr.adrien1106.reframed.client.model.RetexturingBakedModel;
|
||||||
|
import fr.adrien1106.reframed.client.util.RenderHelper;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.client.render.block.BlockModelRenderer;
|
||||||
|
import net.minecraft.client.render.model.BakedModel;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.world.BlockView;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
@Mixin(BlockModelRenderer.class)
|
||||||
|
public class BlockModelRendererMixin {
|
||||||
|
|
||||||
|
@Redirect(
|
||||||
|
method = "renderSmooth",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/block/Block;shouldDrawSide(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/BlockView;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/Direction;Lnet/minecraft/util/math/BlockPos;)Z"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private boolean shouldDrawFrameSideS(BlockState state, BlockView world, BlockPos pos, Direction side, BlockPos other_pos, @Local(argsOnly = true) BakedModel model) {
|
||||||
|
return RenderHelper.shouldDrawSide(state, world, pos, side, other_pos, model instanceof RetexturingBakedModel rm ? rm.getThemeIndex() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(
|
||||||
|
method = "renderFlat",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/block/Block;shouldDrawSide(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/BlockView;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/Direction;Lnet/minecraft/util/math/BlockPos;)Z"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private boolean shouldDrawFrameSideF(BlockState state, BlockView world, BlockPos pos, Direction side, BlockPos other_pos, @Local(argsOnly = true) BakedModel model) {
|
||||||
|
return RenderHelper.shouldDrawSide(state, world, pos, side, other_pos, model instanceof RetexturingBakedModel rm ? rm.getThemeIndex() : 0);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
package fr.adrien1106.reframed.mixin.render;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.client.model.MultiRetexturableModel;
|
||||||
|
import fr.adrien1106.reframed.client.model.RetexturingBakedModel;
|
||||||
|
import fr.adrien1106.reframed.client.util.RenderHelper;
|
||||||
|
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
|
||||||
|
import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||||
|
import net.fabricmc.fabric.impl.client.indigo.renderer.aocalc.AoCalculator;
|
||||||
|
import net.fabricmc.fabric.impl.client.indigo.renderer.render.AbstractBlockRenderContext;
|
||||||
|
import net.fabricmc.fabric.impl.client.indigo.renderer.render.BlockRenderContext;
|
||||||
|
import net.fabricmc.fabric.impl.client.indigo.renderer.render.BlockRenderInfo;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.client.render.VertexConsumer;
|
||||||
|
import net.minecraft.client.render.model.BakedModel;
|
||||||
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.random.Random;
|
||||||
|
import net.minecraft.world.BlockRenderView;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Mixin(BlockRenderContext.class)
|
||||||
|
public abstract class BlockRenderContextMixin extends AbstractBlockRenderContext {
|
||||||
|
|
||||||
|
@Shadow private VertexConsumer vertexConsumer;
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "render",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lnet/fabricmc/fabric/impl/client/indigo/renderer/render/BlockRenderInfo;prepareForWorld(Lnet/minecraft/world/BlockRenderView;Z)V",
|
||||||
|
shift = At.Shift.AFTER
|
||||||
|
),
|
||||||
|
cancellable = true
|
||||||
|
)
|
||||||
|
private void renderMultipleModels(BlockRenderView blockView, BakedModel wrapper, BlockState state, BlockPos pos, MatrixStack matrixStack, VertexConsumer buffer, boolean cull, Random random, long seed, int overlay, CallbackInfo ci) {
|
||||||
|
if (!(wrapper instanceof IMultipartBakedModelMixin wrapped)) return;
|
||||||
|
List<BakedModel> models = wrapped.getModels(state);
|
||||||
|
if (models.stream().noneMatch(bakedModel ->
|
||||||
|
bakedModel instanceof MultiRetexturableModel
|
||||||
|
|| bakedModel instanceof RetexturingBakedModel
|
||||||
|
)) return;
|
||||||
|
|
||||||
|
models.forEach(model -> {
|
||||||
|
if (model instanceof MultiRetexturableModel multi_model) {
|
||||||
|
RenderHelper.computeInnerCull(state, multi_model.models(), model.hashCode());
|
||||||
|
multi_model.models().forEach(rexteruable_model ->
|
||||||
|
renderModel(state, pos, rexteruable_model, aoCalc, blockInfo, this, model.hashCode())
|
||||||
|
);
|
||||||
|
} else if (model instanceof RetexturingBakedModel rexteruable_model)
|
||||||
|
renderModel(state, pos, rexteruable_model, aoCalc, blockInfo, this, model.hashCode());
|
||||||
|
else model.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this);
|
||||||
|
});
|
||||||
|
|
||||||
|
blockInfo.release();
|
||||||
|
vertexConsumer = null;
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static void renderModel(BlockState state, BlockPos pos, RetexturingBakedModel model, AoCalculator aoCalc, BlockRenderInfo block_info, RenderContext context, int model_hash) {
|
||||||
|
aoCalc.clear();
|
||||||
|
((IBlockRenderInfoMixin) block_info).prepareForBlock(
|
||||||
|
state, pos,
|
||||||
|
model.useAmbientOcclusion(block_info.blockView, pos),
|
||||||
|
model.getThemeIndex(), model_hash
|
||||||
|
);
|
||||||
|
model.emitBlockQuads(block_info.blockView, block_info.blockState, block_info.blockPos, block_info.randomSupplier, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -188,7 +188,6 @@ public class BlockHelper {
|
|||||||
if(!(world.getBlockEntity(pos) instanceof ReFramedEntity block_entity)) return ActionResult.PASS;
|
if(!(world.getBlockEntity(pos) instanceof ReFramedEntity block_entity)) return ActionResult.PASS;
|
||||||
|
|
||||||
ItemStack held = player.getStackInHand(hand);
|
ItemStack held = player.getStackInHand(hand);
|
||||||
ReframedInteractible ext = state.getBlock() instanceof ReframedInteractible e ? e : ReframedInteractible.Default.INSTANCE;
|
|
||||||
|
|
||||||
// frame will emit light if applied with glowstone
|
// frame will emit light if applied with glowstone
|
||||||
if(state.contains(LIGHT) && held.getItem() == Items.GLOWSTONE_DUST) {
|
if(state.contains(LIGHT) && held.getItem() == Items.GLOWSTONE_DUST) {
|
||||||
@ -199,14 +198,14 @@ 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) {
|
||||||
block_entity.toggleRedstone();
|
block_entity.toggleRedstone();
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) {
|
||||||
block_entity.toggleSolidity();
|
block_entity.toggleSolidity();
|
||||||
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;
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
package fr.adrien1106.reframed.util.blocks;
|
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.util.math.Direction;
|
|
||||||
import net.minecraft.world.BlockView;
|
|
||||||
|
|
||||||
public interface ReframedInteractible {
|
|
||||||
default boolean canAddRedstoneEmission(BlockState state, BlockView view, BlockPos pos) {
|
|
||||||
return state.getWeakRedstonePower(view, pos, Direction.UP) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
default boolean canRemoveCollision(BlockState state, BlockView view, BlockPos pos) {
|
|
||||||
return !state.getCollisionShape(view, pos).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
class Default implements ReframedInteractible {
|
|
||||||
public static final Default INSTANCE = new Default();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,14 @@
|
|||||||
|
package fr.adrien1106.reframed.util.mixin;
|
||||||
|
|
||||||
|
import com.moulberry.axiom.utils.IntMatrix;
|
||||||
|
import com.moulberry.axiom.world_modification.CompressedBlockEntity;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
|
|
||||||
|
public interface IAxiomChunkedBlockRegionMixin {
|
||||||
|
|
||||||
|
void setTransform(IntMatrix transform, Long2ObjectMap<CompressedBlockEntity> block_entities);
|
||||||
|
|
||||||
|
IntMatrix getTransform();
|
||||||
|
|
||||||
|
Long2ObjectMap<CompressedBlockEntity> getBlockEntities();
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package fr.adrien1106.reframed.util.mixin;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.nbt.NbtCompound;
|
||||||
|
import net.minecraft.nbt.NbtHelper;
|
||||||
|
import net.minecraft.registry.Registries;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static fr.adrien1106.reframed.block.ReFramedEntity.BLOCKSTATE_KEY;
|
||||||
|
|
||||||
|
public class ThemedBlockEntity extends BlockEntity implements ThemeableBlockEntity {
|
||||||
|
private final List<BlockState> themes;
|
||||||
|
|
||||||
|
public ThemedBlockEntity(NbtCompound compound, BlockPos pos, BlockState state) {
|
||||||
|
super(null, pos, state);
|
||||||
|
themes = new ArrayList<>();
|
||||||
|
for (int i = 1; compound.contains(BLOCKSTATE_KEY + i ); i++) {
|
||||||
|
themes.add(NbtHelper.toBlockState(
|
||||||
|
Registries.BLOCK.getReadOnlyWrapper(),
|
||||||
|
compound.getCompound(BLOCKSTATE_KEY + i)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getTheme(int i) {
|
||||||
|
return themes.get(Math.max(0, i-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTheme(BlockState state, int i) {
|
||||||
|
themes.set(Math.max(0, i-1), state);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BlockState> getThemes() {
|
||||||
|
return themes;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"credit": "Made with Blockbench",
|
||||||
|
"parent": "block/block",
|
||||||
|
"textures": {
|
||||||
|
"particle": "#side"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"from": [7, 0, 7],
|
||||||
|
"to": [9, 16, 9],
|
||||||
|
"faces": {
|
||||||
|
"up": {"uv": [7, 7, 9, 9], "texture": "#top", "cullface": "up"},
|
||||||
|
"down": {"uv": [7, 7, 9, 9], "texture": "#bottom", "cullface": "down"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
{
|
||||||
|
"credit": "Made with Blockbench",
|
||||||
|
"parent": "block/block",
|
||||||
|
"textures": {
|
||||||
|
"particle": "#side"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"from": [7, 12, 0],
|
||||||
|
"to": [9, 15, 6],
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [7, 1, 9, 4], "texture": "#side", "cullface": "north"},
|
||||||
|
"east": {"uv": [10, 1, 16, 4], "texture": "#side"},
|
||||||
|
"south": {"uv": [7, 1, 9, 4], "texture": "#side"},
|
||||||
|
"west": {"uv": [0, 1, 6, 4], "texture": "#side"},
|
||||||
|
"up": {"uv": [7, 0, 9, 6], "texture": "#top"},
|
||||||
|
"down": {"uv": [7, 10, 9, 16], "texture": "#bottom"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [7, 6, 10],
|
||||||
|
"to": [9, 9, 16],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [0, -5, 0]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [7, 7, 9, 10], "texture": "#side", "cullface": "south"},
|
||||||
|
"east": {"uv": [10, 7, 16, 10], "texture": "#side"},
|
||||||
|
"south": {"uv": [7, 7, 9, 10], "texture": "#side", "cullface": "south"},
|
||||||
|
"west": {"uv": [0, 7, 6, 10], "texture": "#side"},
|
||||||
|
"up": {"uv": [7, 0, 9, 6], "texture": "#top"},
|
||||||
|
"down": {"uv": [7, 10, 9, 16], "texture": "#bottom"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [7, 12, 10],
|
||||||
|
"to": [9, 15, 16],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [0, 0, 10]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [7, 1, 9, 4], "texture": "#side"},
|
||||||
|
"east": {"uv": [10, 1, 16, 4], "texture": "#side"},
|
||||||
|
"south": {"uv": [7, 1, 9, 4], "texture": "#side", "cullface": "south"},
|
||||||
|
"west": {"uv": [0, 1, 6, 4], "texture": "#side"},
|
||||||
|
"up": {"uv": [7, 0, 9, 6], "texture": "#top"},
|
||||||
|
"down": {"uv": [7, 10, 9, 16], "texture": "#bottom"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [7, 6, 0],
|
||||||
|
"to": [9, 9, 6],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [0, -5, -10]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [7, 7, 9, 10], "texture": "#side", "cullface": "north"},
|
||||||
|
"east": {"uv": [10, 7, 16, 10], "texture": "#side"},
|
||||||
|
"south": {"uv": [7, 7, 9, 10], "texture": "#side"},
|
||||||
|
"west": {"uv": [0, 7, 6, 10], "texture": "#side"},
|
||||||
|
"up": {"uv": [7, 0, 9, 6], "texture": "#top"},
|
||||||
|
"down": {"uv": [7, 10, 9, 16], "texture": "#bottom"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"credit": "Made with Blockbench",
|
||||||
|
"parent": "block/block",
|
||||||
|
"textures": {
|
||||||
|
"particle": "#side"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"from": [7, 12, 0],
|
||||||
|
"to": [9, 15, 6],
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [7, 1, 9, 4], "texture": "#side", "cullface": "north"},
|
||||||
|
"east": {"uv": [10, 1, 16, 4], "texture": "#side"},
|
||||||
|
"south": {"uv": [7, 1, 9, 4], "texture": "#side"},
|
||||||
|
"west": {"uv": [0, 1, 6, 4], "texture": "#side"},
|
||||||
|
"up": {"uv": [7, 0, 9, 6], "texture": "#top"},
|
||||||
|
"down": {"uv": [7, 10, 9, 16], "texture": "#bottom"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [7, 6, 0],
|
||||||
|
"to": [9, 9, 6],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [0, -5, -10]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [7, 7, 9, 10], "texture": "#side", "cullface": "north"},
|
||||||
|
"east": {"uv": [10, 7, 16, 10], "texture": "#side"},
|
||||||
|
"south": {"uv": [7, 7, 9, 10], "texture": "#side"},
|
||||||
|
"west": {"uv": [0, 7, 6, 10], "texture": "#side"},
|
||||||
|
"up": {"uv": [7, 0, 9, 6], "texture": "#top"},
|
||||||
|
"down": {"uv": [7, 10, 9, 16], "texture": "#bottom"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
"credit": "Made with Blockbench",
|
||||||
|
"parent": "block/block",
|
||||||
|
"textures": {
|
||||||
|
"particle": "#side"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"from": [6, 0, 6],
|
||||||
|
"to": [7, 16, 7],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [-1, 0, -1]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [9, 0, 10, 16], "texture": "#side"},
|
||||||
|
"west": {"uv": [6, 0, 7, 16], "texture": "#side"},
|
||||||
|
"up": {"uv": [6, 6, 7, 7], "texture": "#top", "cullface": "up"},
|
||||||
|
"down": {"uv": [6, 9, 7, 10], "texture": "#bottom", "cullface": "down"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [7, 0, 6],
|
||||||
|
"to": [9, 6, 7],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [0, 0, -1]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [7, 10, 9, 16], "texture": "#side"},
|
||||||
|
"down": {"uv": [7, 9, 9, 10], "texture": "#bottom", "cullface": "down"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [7, 9, 6],
|
||||||
|
"to": [9, 12, 7],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [0, 6, -1]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [7, 4, 9, 7], "texture": "#side"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [7, 12, 6],
|
||||||
|
"to": [9, 15, 7],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [0, 9, -1]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [7, 1, 9, 4], "texture": "#side"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [7, 6, 6],
|
||||||
|
"to": [9, 9, 7],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [0, 3, -1]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [7, 7, 9, 10], "texture": "#side"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [7, 15, 6],
|
||||||
|
"to": [9, 16, 7],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [0, 10, -1]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [7, 0, 9, 1], "texture": "#side"},
|
||||||
|
"up": {"uv": [7, 6, 9, 7], "texture": "#top", "cullface": "up"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"credit": "Made with Blockbench",
|
||||||
|
"parent": "block/block",
|
||||||
|
"textures": {
|
||||||
|
"particle": "#side"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"from": [7, 12, 10],
|
||||||
|
"to": [9, 15, 16],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [0, 1, 0]},
|
||||||
|
"faces": {
|
||||||
|
"east": {"uv": [0, 1, 6, 4], "texture": "#side"},
|
||||||
|
"south": {"uv": [7, 1, 9, 4], "texture": "#side", "cullface": "south"},
|
||||||
|
"west": {"uv": [10, 1, 16, 4], "texture": "#side"},
|
||||||
|
"up": {"uv": [7, 10, 9, 16], "texture": "#top"},
|
||||||
|
"down": {"uv": [7, 0, 9, 6], "texture": "#bottom"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [7, 6, 10],
|
||||||
|
"to": [9, 9, 16],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [0, -5, 0]},
|
||||||
|
"faces": {
|
||||||
|
"east": {"uv": [0, 7, 6, 10], "texture": "#side"},
|
||||||
|
"south": {"uv": [7, 2, 9, 5], "texture": "#side", "cullface": "south"},
|
||||||
|
"west": {"uv": [10, 7, 16, 10], "texture": "#side"},
|
||||||
|
"up": {"uv": [7, 10, 9, 16], "texture": "#top"},
|
||||||
|
"down": {"uv": [7, 0, 9, 6], "texture": "#bottom"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [7, 12, 0],
|
||||||
|
"to": [9, 15, 6],
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [7, 1, 9, 4], "texture": "#side", "cullface": "north"},
|
||||||
|
"east": {"uv": [10, 1, 16, 4], "texture": "#side"},
|
||||||
|
"west": {"uv": [0, 1, 6, 4], "texture": "#side"},
|
||||||
|
"up": {"uv": [7, 0, 9, 6], "texture": "#top"},
|
||||||
|
"down": {"uv": [7, 10, 9, 16], "texture": "#bottom"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [7, 6, 0],
|
||||||
|
"to": [9, 9, 6],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [0, -5, -10]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [7, 7, 9, 10], "texture": "#side", "cullface": "north"},
|
||||||
|
"east": {"uv": [10, 7, 16, 10], "texture": "#side"},
|
||||||
|
"west": {"uv": [0, 7, 6, 10], "texture": "#side"},
|
||||||
|
"up": {"uv": [7, 0, 9, 6], "texture": "#top"},
|
||||||
|
"down": {"uv": [7, 10, 9, 16], "texture": "#bottom"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [6, 0, 6],
|
||||||
|
"to": [10, 16, 10],
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [6, 0, 10, 16], "texture": "#side"},
|
||||||
|
"east": {"uv": [6, 0, 10, 16], "texture": "#side"},
|
||||||
|
"south": {"uv": [6, 0, 10, 16], "texture": "#side", "cullface": "south"},
|
||||||
|
"west": {"uv": [6, 0, 10, 16], "texture": "#side"},
|
||||||
|
"up": {"uv": [6, 6, 10, 10], "texture": "#top"},
|
||||||
|
"down": {"uv": [6, 6, 10, 10], "texture": "#bottom"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"credit": "Made with Blockbench",
|
||||||
|
"parent": "block/block",
|
||||||
|
"textures": {
|
||||||
|
"particle": "#side"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"from": [6, 0, 6],
|
||||||
|
"to": [9, 16, 7],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [-1, 0, -1]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [7, 0, 10, 16], "texture": "#side"},
|
||||||
|
"west": {"uv": [6, 0, 7, 16], "texture": "#side"},
|
||||||
|
"up": {"uv": [6, 6, 9, 7], "texture": "#top", "cullface": "up"},
|
||||||
|
"down": {"uv": [6, 9, 9, 10], "texture": "#bottom", "cullface": "down"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
{
|
||||||
|
"credit": "Made with Blockbench",
|
||||||
|
"parent": "block/block",
|
||||||
|
"textures": {
|
||||||
|
"particle": "#side"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"from": [7, 12, 0],
|
||||||
|
"to": [9, 15, 6],
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [7, 1, 9, 4], "texture": "#side", "cullface": "north"},
|
||||||
|
"east": {"uv": [10, 1, 16, 4], "texture": "#side"},
|
||||||
|
"west": {"uv": [0, 1, 6, 4], "texture": "#side"},
|
||||||
|
"up": {"uv": [7, 0, 9, 6], "texture": "#top"},
|
||||||
|
"down": {"uv": [7, 10, 9, 16], "texture": "#bottom"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [7, 6, 0],
|
||||||
|
"to": [9, 9, 6],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [0, -5, -10]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [7, 7, 9, 10], "texture": "#side", "cullface": "north"},
|
||||||
|
"east": {"uv": [10, 7, 16, 10], "texture": "#side"},
|
||||||
|
"west": {"uv": [0, 7, 6, 10], "texture": "#side"},
|
||||||
|
"up": {"uv": [7, 0, 9, 6], "texture": "#top"},
|
||||||
|
"down": {"uv": [7, 10, 9, 16], "texture": "#bottom"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [6, 0, 6],
|
||||||
|
"to": [7, 16, 7],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [-1, 0, -1]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [9, 0, 10, 16], "texture": "#side"},
|
||||||
|
"west": {"uv": [6, 0, 7, 16], "texture": "#side"},
|
||||||
|
"up": {"uv": [6, 6, 7, 7], "texture": "#top", "cullface": "up"},
|
||||||
|
"down": {"uv": [6, 9, 7, 10], "texture": "#bottom", "cullface": "down"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [7, 0, 6],
|
||||||
|
"to": [9, 6, 7],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [0, 0, -1]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [7, 10, 9, 16], "texture": "#side"},
|
||||||
|
"down": {"uv": [7, 9, 9, 10], "texture": "#bottom", "cullface": "down"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [7, 9, 6],
|
||||||
|
"to": [9, 12, 7],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [0, 6, -1]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [7, 4, 9, 7], "texture": "#side"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [7, 15, 6],
|
||||||
|
"to": [9, 16, 7],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [0, 10, -1]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [7, 0, 9, 1], "texture": "#side"},
|
||||||
|
"up": {"uv": [7, 6, 9, 7], "texture": "#top", "cullface": "up"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
21
src/main/resources/assets/reframed/models/block/post.json
Normal file
21
src/main/resources/assets/reframed/models/block/post.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"credit": "Made with Blockbench",
|
||||||
|
"parent": "block/block",
|
||||||
|
"textures": {
|
||||||
|
"particle": "#side"
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"from": [6, 0, 6],
|
||||||
|
"to": [10, 16, 10],
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [6, 0, 10, 16], "texture": "#side"},
|
||||||
|
"east": {"uv": [4, 0, 10, 16], "texture": "#side"},
|
||||||
|
"south": {"uv": [6, 0, 10, 16], "texture": "#side"},
|
||||||
|
"west": {"uv": [6, 0, 10, 16], "texture": "#side"},
|
||||||
|
"up": {"uv": [6, 6, 10, 10], "texture": "#top", "cullface": "up"},
|
||||||
|
"down": {"uv": [6, 6, 10, 10], "texture": "#bottom", "cullface": "down"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -15,13 +15,22 @@
|
|||||||
"compat.AthenaBakedModelMixin",
|
"compat.AthenaBakedModelMixin",
|
||||||
"compat.AthenaConnectedBlockModelMixin",
|
"compat.AthenaConnectedBlockModelMixin",
|
||||||
"compat.AthenaWrappedGetterMixin",
|
"compat.AthenaWrappedGetterMixin",
|
||||||
|
"compat.AxiomChunkedBlockRegionMixin",
|
||||||
"compat.AxiomClientBlockEntitySerializerMixin",
|
"compat.AxiomClientBlockEntitySerializerMixin",
|
||||||
|
"compat.AxiomClipboardMixin",
|
||||||
|
"compat.AxiomCloneBuilderToolMixin",
|
||||||
|
"compat.AxiomMappedBlockAndTintGetterMixin",
|
||||||
|
"compat.AxiomMoveBuilderToolMixin",
|
||||||
|
"compat.AxiomPlacementMixin",
|
||||||
|
"compat.AxiomRotSpriteMixin",
|
||||||
|
"compat.AxiomScale3xMixin",
|
||||||
"compat.ContinuityConnectionPredicateMixin",
|
"compat.ContinuityConnectionPredicateMixin",
|
||||||
"compat.ContinuityCTMBakedModelMixin",
|
"compat.ContinuityCTMBakedModelMixin",
|
||||||
"compat.ContinuityCTMQuadTransformMixin",
|
"compat.ContinuityCTMQuadTransformMixin",
|
||||||
"compat.ContinuityModelWrappingHandlerMixin",
|
"compat.ContinuityModelWrappingHandlerMixin",
|
||||||
"compat.IndiumAbstractBlockRenderContextMixin",
|
"compat.IndiumAbstractBlockRenderContextMixin",
|
||||||
"compat.IndiumTerrainBlockRenderInfoMixin",
|
"compat.IndiumBlockRenderInfoMixin",
|
||||||
|
"compat.IndiumNonTerrainBlockRenderContextMixin",
|
||||||
"compat.IndiumTerrainRenderContextMixin",
|
"compat.IndiumTerrainRenderContextMixin",
|
||||||
"compat.SodiumBlockOcclusionCacheMixin",
|
"compat.SodiumBlockOcclusionCacheMixin",
|
||||||
"model.WeightedBakedModelAccessor",
|
"model.WeightedBakedModelAccessor",
|
||||||
@ -29,6 +38,8 @@
|
|||||||
"particles.AccessorSpriteBillboardParticle",
|
"particles.AccessorSpriteBillboardParticle",
|
||||||
"particles.MixinBlockDustParticle",
|
"particles.MixinBlockDustParticle",
|
||||||
"render.AbstractBlockRenderContextMixin",
|
"render.AbstractBlockRenderContextMixin",
|
||||||
|
"render.BlockModelRendererMixin",
|
||||||
|
"render.BlockRenderContextMixin",
|
||||||
"render.BlockRenderInfoMixin",
|
"render.BlockRenderInfoMixin",
|
||||||
"render.MultipartBakedModelMixin",
|
"render.MultipartBakedModelMixin",
|
||||||
"render.TerrainRenderContextMixin",
|
"render.TerrainRenderContextMixin",
|
||||||
|
Loading…
Reference in New Issue
Block a user