Filtered Funneling

- Added filtering behaviour and in-world slots to new funnel blocks
- Filtering behaviour now supports slots active on multiple sides
- Funnels no longer wipe their TE when changing state
- Fixed VoxelShape for extended belt funnels
This commit is contained in:
simibubi 2020-06-26 12:35:24 +02:00
parent a2c19b21d9
commit 69dd19cd58
10 changed files with 253 additions and 18 deletions

View file

@ -75,9 +75,9 @@ public class AllShapes {
.forDirectional(UP),
BELT_FUNNEL_RETRACTED = shape(3, -5, 14, 13, 13, 19).add(0, -5, 8, 16, 16, 14)
.forHorizontal(NORTH),
BELT_FUNNEL_DEFAULT = shape(3, -5, 12, 13, 13, 17).add(0, -5, 6, 16, 16, 12)
.forHorizontal(NORTH),
BELT_FUNNEL_EXTENDED = shape(3, -5, 6, 13, 13, 17).add(0, -5, 0, 16, 16, 6)
BELT_FUNNEL_EXTENDED = shape(3, -4, 6, 13, 13, 17).add(2, -4, 10, 14, 14, 14)
.add(1, -4, 6, 15, 15, 10)
.add(0, -5, 0, 16, 16, 6)
.forHorizontal(NORTH),
PUMP = shape(2, 0, 2, 14, 5, 14).add(4, 0, 4, 12, 16, 12)
.add(3, 12, 3, 13, 16, 13)

View file

@ -84,6 +84,7 @@ import com.simibubi.create.content.logistics.block.mechanicalArm.ArmRenderer;
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmTileEntity;
import com.simibubi.create.content.logistics.block.packager.PackagerRenderer;
import com.simibubi.create.content.logistics.block.packager.PackagerTileEntity;
import com.simibubi.create.content.logistics.block.realityFunnel.RealityFunnelTileEntity;
import com.simibubi.create.content.logistics.block.redstone.AnalogLeverRenderer;
import com.simibubi.create.content.logistics.block.redstone.AnalogLeverTileEntity;
import com.simibubi.create.content.logistics.block.redstone.NixieTubeRenderer;
@ -217,11 +218,12 @@ public class AllTileEntities {
register("adjustable_crate", AdjustableCrateTileEntity::new, AllBlocks.ADJUSTABLE_CRATE);
public static final TileEntityEntry<CreativeCrateTileEntity> CREATIVE_CRATE =
register("creative_crate", CreativeCrateTileEntity::new, AllBlocks.CREATIVE_CRATE);
public static final TileEntityEntry<RealityFunnelTileEntity> REALITY_FUNNEL = register("reality_funnel",
RealityFunnelTileEntity::new, AllBlocks.REALITY_FUNNEL, AllBlocks.BELT_FUNNEL, AllBlocks.CHUTE_FUNNEL);
public static final TileEntityEntry<PackagerTileEntity> PACKAGER =
register("packager", PackagerTileEntity::new, AllBlocks.PACKAGER);
public static final TileEntityEntry<ExtractorTileEntity> EXTRACTOR =
register("extractor", ExtractorTileEntity::new, AllBlocks.EXTRACTOR, AllBlocks.VERTICAL_EXTRACTOR);
public static final TileEntityEntry<LinkedExtractorTileEntity> LINKED_EXTRACTOR = register("linked_extractor",
@ -270,7 +272,7 @@ public class AllTileEntities {
bind(HAND_CRANK, HandCrankRenderer::new);
bind(CUCKOO_CLOCK, CuckooClockRenderer::new);
bind(ANALOG_LEVER, AnalogLeverRenderer::new);
bind(MECHANICAL_PUMP, PumpRenderer::new);
bind(FLUID_TANK, FluidTankRenderer::new);
@ -302,6 +304,7 @@ public class AllTileEntities {
bind(TRANSPOSER, SmartTileEntityRenderer::new);
bind(LINKED_TRANSPOSER, SmartTileEntityRenderer::new);
bind(FUNNEL, SmartTileEntityRenderer::new);
bind(REALITY_FUNNEL, SmartTileEntityRenderer::new);
bind(BELT_TUNNEL, BeltTunnelRenderer::new);
bind(MECHANICAL_ARM, ArmRenderer::new);
bind(BELT_OBSERVER, BeltObserverRenderer::new);

View file

@ -26,7 +26,7 @@ public class DirectionalExtenderScrollOptionSlot extends CenteredSideValueBoxTra
@Override
protected void rotate(BlockState state, MatrixStack ms) {
if (!direction.getAxis().isHorizontal())
if (!getSide().getAxis().isHorizontal())
MatrixStacker.of(ms).rotateY(AngleHelper.horizontalAngle(state.get(BlockStateProperties.FACING)) - 90);
super.rotate(state, ms);
}

View file

@ -0,0 +1,96 @@
package com.simibubi.create.content.logistics.block.realityFunnel;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.logistics.block.realityFunnel.BeltFunnelBlock.Shape;
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.DirectionHelper;
import com.simibubi.create.foundation.utility.MatrixStacker;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.BlockState;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.math.Vec3d;
public class FunnelFilterSlotPositioning extends ValueBoxTransform.Sided {
@Override
protected Vec3d getLocalOffset(BlockState state) {
if (AllBlocks.BELT_FUNNEL.has(state))
if (state.get(BeltFunnelBlock.SHAPE) == Shape.RETRACTED)
return VecHelper.rotateCentered(VecHelper.voxelSpace(8, 13, 7.5f),
AngleHelper.horizontalAngle(getSide()), Axis.Y);
Vec3d localOffset =
getSide() == Direction.UP ? VecHelper.voxelSpace(8, 14.5f, 8) : VecHelper.voxelSpace(8, 1.5f, 8);
if (getSide().getAxis()
.isHorizontal()) {
Vec3d southLocation = VecHelper.voxelSpace(8, 8, 14.5f);
localOffset = VecHelper.rotateCentered(southLocation, AngleHelper.horizontalAngle(getSide()), Axis.Y);
}
if (AllBlocks.CHUTE_FUNNEL.has(state)) {
Direction facing = state.get(ChuteFunnelBlock.HORIZONTAL_FACING);
localOffset = localOffset.subtract(new Vec3d(facing.getDirectionVec()).scale(2 / 16f));
}
return localOffset;
}
@Override
protected void rotate(BlockState state, MatrixStack ms) {
Direction facing = RealityFunnelBlock.getFunnelFacing(state);
if (!facing.getAxis()
.isVertical()
&& !(AllBlocks.BELT_FUNNEL.has(state) && state.get(BeltFunnelBlock.SHAPE) == Shape.RETRACTED)) {
Direction verticalDirection = DirectionHelper.rotateAround(getSide(), facing.rotateY()
.getAxis());
if (facing.getAxis() == Axis.Z)
verticalDirection = verticalDirection.getOpposite();
boolean reverse = state.getBlock() instanceof HorizontalInteractionFunnelBlock
&& !state.get(HorizontalInteractionFunnelBlock.PUSHING);
float yRot = -AngleHelper.horizontalAngle(verticalDirection) + 180;
float xRot = -90;
boolean alongX = facing.getAxis() == Axis.X;
float zRotLast = alongX ^ facing.getAxisDirection() == AxisDirection.POSITIVE ? 180 : 0;
if (reverse)
zRotLast += 180;
MatrixStacker.of(ms)
.rotateZ(alongX ? xRot : 0)
.rotateX(alongX ? 0 : xRot)
.rotateY(yRot)
.rotateZ(zRotLast);
return;
}
super.rotate(state, ms);
}
@Override
protected boolean isSideActive(BlockState state, Direction direction) {
Direction facing = RealityFunnelBlock.getFunnelFacing(state);
if (facing == null)
return false;
if (AllBlocks.BELT_FUNNEL.has(state))
return state.get(BeltFunnelBlock.SHAPE) == Shape.RETRACTED ? direction == facing
: direction != Direction.DOWN && direction.getAxis() != facing.getAxis();
return direction.getAxis() != facing.getAxis();
}
@Override
protected Vec3d getSouthLocation() {
return Vec3d.ZERO;
}
}

View file

@ -1,6 +1,7 @@
package com.simibubi.create.content.logistics.block.realityFunnel;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
import net.minecraft.block.Block;
@ -13,6 +14,7 @@ import net.minecraft.item.ItemUseContext;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer.Builder;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
@ -33,6 +35,16 @@ public abstract class HorizontalInteractionFunnelBlock extends HorizontalBlock i
.with(POWERED, false));
}
@Override
public boolean hasTileEntity(BlockState state) {
return true;
}
@Override
public TileEntity createTileEntity(BlockState state, IBlockReader world) {
return AllTileEntities.REALITY_FUNNEL.create();
}
@Override
protected void fillStateContainer(Builder<Block, BlockState> p_206840_1_) {
super.fillStateContainer(p_206840_1_.add(HORIZONTAL_FACING, POWERED, PUSHING));
@ -44,6 +56,16 @@ public abstract class HorizontalInteractionFunnelBlock extends HorizontalBlock i
.isBlockPowered(ctx.getPos()));
}
@Override
public void onReplaced(BlockState p_196243_1_, World p_196243_2_, BlockPos p_196243_3_, BlockState p_196243_4_,
boolean p_196243_5_) {
if (p_196243_1_.hasTileEntity()
&& (p_196243_1_.getBlock() != p_196243_4_.getBlock() && !RealityFunnelBlock.isFunnel(p_196243_4_)
|| !p_196243_4_.hasTileEntity())) {
p_196243_2_.removeTileEntity(p_196243_3_);
}
}
@Override
public ItemStack getPickBlock(BlockState state, RayTraceResult target, IBlockReader world, BlockPos pos,
PlayerEntity player) {

View file

@ -1,7 +1,10 @@
package com.simibubi.create.content.logistics.block.realityFunnel;
import javax.annotation.Nullable;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllShapes;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.logistics.block.chute.ChuteBlock;
import com.simibubi.create.foundation.block.ProperDirectionalBlock;
@ -11,6 +14,7 @@ import net.minecraft.item.BlockItemUseContext;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer.Builder;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.ISelectionContext;
@ -44,6 +48,16 @@ public class RealityFunnelBlock extends ProperDirectionalBlock {
.isBlockPowered(context.getPos()));
}
@Override
public boolean hasTileEntity(BlockState state) {
return true;
}
@Override
public TileEntity createTileEntity(BlockState state, IBlockReader world) {
return AllTileEntities.REALITY_FUNNEL.create();
}
@Override
protected void fillStateContainer(Builder<Block, BlockState> builder) {
super.fillStateContainer(builder.add(POWERED));
@ -105,4 +119,29 @@ public class RealityFunnelBlock extends ProperDirectionalBlock {
return !(block instanceof RealityFunnelBlock) && !(block instanceof HorizontalInteractionFunnelBlock);
}
@Nullable
public static Direction getFunnelFacing(BlockState state) {
if (state.has(FACING))
return state.get(FACING);
if (state.has(BlockStateProperties.HORIZONTAL_FACING))
return state.get(BlockStateProperties.HORIZONTAL_FACING);
return null;
}
@Override
public void onReplaced(BlockState p_196243_1_, World p_196243_2_, BlockPos p_196243_3_, BlockState p_196243_4_,
boolean p_196243_5_) {
if (p_196243_1_.hasTileEntity()
&& (p_196243_1_.getBlock() != p_196243_4_.getBlock() && !isFunnel(p_196243_4_)
|| !p_196243_4_.hasTileEntity())) {
p_196243_2_.removeTileEntity(p_196243_3_);
}
}
@Nullable
public static boolean isFunnel(BlockState state) {
return state.getBlock() instanceof RealityFunnelBlock
|| state.getBlock() instanceof HorizontalInteractionFunnelBlock;
}
}

View file

@ -0,0 +1,36 @@
package com.simibubi.create.content.logistics.block.realityFunnel;
import java.util.List;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InsertingBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.inventory.InventoryManagementBehaviour.Attachments;
import net.minecraft.tileentity.TileEntityType;
public class RealityFunnelTileEntity extends SmartTileEntity {
private FilteringBehaviour filtering;
private InsertingBehaviour inserting;
public RealityFunnelTileEntity(TileEntityType<?> tileEntityTypeIn) {
super(tileEntityTypeIn);
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
filtering = new FilteringBehaviour(this, new FunnelFilterSlotPositioning());
behaviours.add(filtering);
inserting =
new InsertingBehaviour(this, Attachments.toward(() -> RealityFunnelBlock.getFunnelFacing(getBlockState())));
behaviours.add(inserting);
}
@Override
public double getMaxRenderDistanceSquared() {
return 64;
}
}

View file

@ -98,8 +98,8 @@ public abstract class ValueBoxTransform {
@Override
protected Vec3d getLocalOffset(BlockState state) {
Vec3d location = getSouthLocation();
location = VecHelper.rotateCentered(location, AngleHelper.horizontalAngle(direction), Axis.Y);
location = VecHelper.rotateCentered(location, AngleHelper.verticalAngle(direction), Axis.Z);
location = VecHelper.rotateCentered(location, AngleHelper.horizontalAngle(getSide()), Axis.Y);
location = VecHelper.rotateCentered(location, AngleHelper.verticalAngle(getSide()), Axis.Z);
return location;
}
@ -107,8 +107,8 @@ public abstract class ValueBoxTransform {
@Override
protected void rotate(BlockState state, MatrixStack ms) {
float yRot = AngleHelper.horizontalAngle(direction) + 180;
float xRot = direction == Direction.UP ? 90 : direction == Direction.DOWN ? 270 : 0;
float yRot = AngleHelper.horizontalAngle(getSide()) + 180;
float xRot = getSide() == Direction.UP ? 90 : getSide() == Direction.DOWN ? 270 : 0;
MatrixStacker.of(ms)
.rotateY(yRot)
.rotateX(xRot);
@ -116,18 +116,22 @@ public abstract class ValueBoxTransform {
@Override
public boolean shouldRender(BlockState state) {
return super.shouldRender(state) && isSideActive(state, direction);
return super.shouldRender(state) && isSideActive(state, getSide());
}
@Override
public boolean testHit(BlockState state, Vec3d localHit) {
return isSideActive(state, direction) && super.testHit(state, localHit);
return isSideActive(state, getSide()) && super.testHit(state, localHit);
}
protected boolean isSideActive(BlockState state, Direction direction) {
return true;
}
public Direction getSide() {
return direction;
}
}
}

View file

@ -3,6 +3,8 @@ package com.simibubi.create.foundation.tileEntity.behaviour.filtering;
import com.simibubi.create.AllKeys;
import com.simibubi.create.content.logistics.item.filter.FilterItem;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform;
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform.Sided;
import com.simibubi.create.foundation.utility.RaycastHelper;
import net.minecraft.client.Minecraft;
@ -47,15 +49,20 @@ public class FilteringHandler {
BlockRayTraceResult ray = RaycastHelper.rayTraceRange(world, player, 10);
if (ray == null)
return;
if (behaviour.slotPositioning instanceof ValueBoxTransform.Sided)
((Sided) behaviour.slotPositioning).fromSide(ray.getFace());
if (behaviour.testHit(ray.getHitVec())) {
if (event.getSide() != LogicalSide.CLIENT) {
ItemStack heldItem = player.getHeldItem(hand).copy();
ItemStack heldItem = player.getHeldItem(hand)
.copy();
if (!player.isCreative()) {
if (behaviour.getFilter().getItem() instanceof FilterItem)
if (behaviour.getFilter()
.getItem() instanceof FilterItem)
player.inventory.placeItemBackInInventory(world, behaviour.getFilter());
if (heldItem.getItem() instanceof FilterItem)
player.getHeldItem(hand).shrink(1);
player.getHeldItem(hand)
.shrink(1);
}
if (heldItem.getItem() instanceof FilterItem)
heldItem.setCount(1);
@ -87,6 +94,8 @@ public class FilteringHandler {
return false;
if (!filtering.isCountVisible())
return false;
if (filtering.slotPositioning instanceof ValueBoxTransform.Sided)
((Sided) filtering.slotPositioning).fromSide(result.getFace());
if (!filtering.testHit(objectMouseOver.getHitVec()))
return false;
ItemStack filterItem = filtering.getFilter();

View file

@ -9,6 +9,9 @@ import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBox;
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBox.ItemValueBox;
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxRenderer;
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform;
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform.Sided;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.block.BlockState;
@ -16,6 +19,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
@ -42,6 +46,8 @@ public class FilteringRenderer {
return;
if (mc.player.isSneaking())
return;
if (behaviour.slotPositioning instanceof ValueBoxTransform.Sided)
((Sided) behaviour.slotPositioning).fromSide(result.getFace());
if (!behaviour.slotPositioning.shouldRender(state))
return;
@ -83,8 +89,28 @@ public class FilteringRenderer {
.isEmpty())
return;
ValueBoxTransform slotPositioning = behaviour.slotPositioning;
BlockState blockState = tileEntityIn.getBlockState();
if (slotPositioning instanceof ValueBoxTransform.Sided) {
ValueBoxTransform.Sided sided = (ValueBoxTransform.Sided) slotPositioning;
Direction side = sided.getSide();
for (Direction d : Iterate.directions) {
sided.fromSide(d);
if (!slotPositioning.shouldRender(blockState))
continue;
ms.push();
slotPositioning.transform(blockState, ms);
ValueBoxRenderer.renderItemIntoValueBox(behaviour.getFilter(), ms, buffer, light, overlay);
ms.pop();
}
sided.fromSide(side);
return;
}
ms.push();
behaviour.slotPositioning.transform(tileEntityIn.getBlockState(), ms);
slotPositioning.transform(blockState, ms);
ValueBoxRenderer.renderItemIntoValueBox(behaviour.getFilter(), ms, buffer, light, overlay);
ms.pop();
}