Filterable Funnels

- Belt funnels can now be assigned filters for better item routing
- Fixed items facing the wrong way if moving on a slope in negative directions
- Items can now be picked up from belts by right clicking
This commit is contained in:
simibubi 2019-11-18 16:14:26 +01:00
parent 0bded65338
commit e742149c8d
8 changed files with 154 additions and 11 deletions

View file

@ -44,6 +44,7 @@ import com.simibubi.create.modules.logistics.block.LinkedTileEntityRenderer;
import com.simibubi.create.modules.logistics.block.RedstoneBridgeTileEntity; import com.simibubi.create.modules.logistics.block.RedstoneBridgeTileEntity;
import com.simibubi.create.modules.logistics.block.StockswitchTileEntity; import com.simibubi.create.modules.logistics.block.StockswitchTileEntity;
import com.simibubi.create.modules.logistics.block.belts.BeltFunnelTileEntity; import com.simibubi.create.modules.logistics.block.belts.BeltFunnelTileEntity;
import com.simibubi.create.modules.logistics.block.belts.BeltFunnelTileEntityRenderer;
import com.simibubi.create.modules.logistics.block.belts.EntityDetectorTileEntity; import com.simibubi.create.modules.logistics.block.belts.EntityDetectorTileEntity;
import com.simibubi.create.modules.logistics.block.belts.EntityDetectorTileEntityRenderer; import com.simibubi.create.modules.logistics.block.belts.EntityDetectorTileEntityRenderer;
import com.simibubi.create.modules.logistics.block.belts.ExtractorTileEntity; import com.simibubi.create.modules.logistics.block.belts.ExtractorTileEntity;
@ -180,6 +181,7 @@ public enum AllTileEntities {
bind(RedstoneBridgeTileEntity.class, new LinkedTileEntityRenderer()); bind(RedstoneBridgeTileEntity.class, new LinkedTileEntityRenderer());
bind(LinkedExtractorTileEntity.class, new LinkedExtractorTileEntityRenderer()); bind(LinkedExtractorTileEntity.class, new LinkedExtractorTileEntityRenderer());
bind(ExtractorTileEntity.class, new ExtractorTileEntityRenderer()); bind(ExtractorTileEntity.class, new ExtractorTileEntityRenderer());
bind(BeltFunnelTileEntity.class, new BeltFunnelTileEntityRenderer());
bind(EntityDetectorTileEntity.class, new EntityDetectorTileEntityRenderer()); bind(EntityDetectorTileEntity.class, new EntityDetectorTileEntityRenderer());
bind(MechanicalPressTileEntity.class, new MechanicalPressTileEntityRenderer()); bind(MechanicalPressTileEntity.class, new MechanicalPressTileEntityRenderer());
bind(FlexpeaterTileEntity.class, new FlexpeaterTileEntityRenderer()); bind(FlexpeaterTileEntity.class, new FlexpeaterTileEntityRenderer());

View file

@ -1,5 +1,6 @@
package com.simibubi.create.modules.contraptions.relays.belt; package com.simibubi.create.modules.contraptions.relays.belt;
import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -114,6 +115,8 @@ public class BeltBlock extends HorizontalKineticBlock implements IWithoutBlockIt
BeltTileEntity belt = null; BeltTileEntity belt = null;
belt = (BeltTileEntity) worldIn.getTileEntity(pos); belt = (BeltTileEntity) worldIn.getTileEntity(pos);
if (state.get(SLOPE) == Slope.VERTICAL)
return;
if (entityIn instanceof PlayerEntity && entityIn.isSneaking()) if (entityIn instanceof PlayerEntity && entityIn.isSneaking())
return; return;
if (belt == null || belt.getSpeed() == 0) if (belt == null || belt.getSpeed() == 0)
@ -162,6 +165,7 @@ public class BeltBlock extends HorizontalKineticBlock implements IWithoutBlockIt
boolean isShaft = heldItem.getItem() == AllBlocks.SHAFT.get().asItem(); boolean isShaft = heldItem.getItem() == AllBlocks.SHAFT.get().asItem();
boolean isCasing = heldItem.getItem() == AllBlocks.LOGISTICAL_CASING.get().asItem(); boolean isCasing = heldItem.getItem() == AllBlocks.LOGISTICAL_CASING.get().asItem();
boolean isDye = Tags.Items.DYES.contains(heldItem.getItem()); boolean isDye = Tags.Items.DYES.contains(heldItem.getItem());
boolean isHand = heldItem.isEmpty() && handIn == Hand.MAIN_HAND;
if (isDye) { if (isDye) {
if (worldIn.isRemote) if (worldIn.isRemote)
@ -182,6 +186,25 @@ public class BeltBlock extends HorizontalKineticBlock implements IWithoutBlockIt
return false; return false;
BeltTileEntity belt = (BeltTileEntity) te; BeltTileEntity belt = (BeltTileEntity) te;
if (isHand) {
TileEntity controllerTe = worldIn.getTileEntity(belt.getController());
if (controllerTe == null || !(controllerTe instanceof BeltTileEntity))
return false;
if (worldIn.isRemote)
return true;
BeltTileEntity controllerBelt = (BeltTileEntity) controllerTe;
for (Iterator<TransportedItemStack> iterator = controllerBelt.getInventory().items.iterator(); iterator
.hasNext();) {
TransportedItemStack transportedItemStack = iterator.next();
if (Math.abs(belt.index + .5 - transportedItemStack.beltPosition) < .75f) {
player.inventory.placeItemBackInInventory(worldIn, transportedItemStack.stack);
iterator.remove();
controllerBelt.markDirty();
controllerBelt.sendData();
}
}
}
if (isShaft) { if (isShaft) {
if (state.get(PART) != Part.MIDDLE) if (state.get(PART) != Part.MIDDLE)
return false; return false;
@ -255,7 +278,7 @@ public class BeltBlock extends HorizontalKineticBlock implements IWithoutBlockIt
public PathNodeType getAiPathNodeType(BlockState state, IBlockReader world, BlockPos pos, MobEntity entity) { public PathNodeType getAiPathNodeType(BlockState state, IBlockReader world, BlockPos pos, MobEntity entity) {
return PathNodeType.DANGER_OTHER; return PathNodeType.DANGER_OTHER;
} }
@Override @Override
public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) { public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
return VoxelShapes.or(BeltShapes.getShape(state), BeltShapes.getCasingShape(state)); return VoxelShapes.or(BeltShapes.getShape(state), BeltShapes.getCasingShape(state));

View file

@ -121,8 +121,8 @@ public class BeltInventory {
// See if any new belt processing catches the item // See if any new belt processing catches the item
int upcomingSegment = (int) (current.beltPosition + (beltMovementPositive ? .5f : -.5f)); int upcomingSegment = (int) (current.beltPosition + (beltMovementPositive ? .5f : -.5f));
for (int segment = upcomingSegment; beltMovementPositive for (int segment = upcomingSegment; beltMovementPositive
? segment <= current.beltPosition + limitedMovement ? segment + .5f <= current.beltPosition + limitedMovement
: segment >= current.beltPosition + limitedMovement; segment += beltMovementPositive ? 1 : -1) { : segment + .5f >= current.beltPosition + limitedMovement; segment += beltMovementPositive ? 1 : -1) {
BeltTileEntity beltSegment = getBeltSegment(segmentBefore); BeltTileEntity beltSegment = getBeltSegment(segmentBefore);
if (beltSegment == null) if (beltSegment == null)
break; break;

View file

@ -263,7 +263,7 @@ public class BeltTileEntity extends KineticTileEntity {
return new Vec3i(movement.getX(), movingUp ? 1 : -1, movement.getZ()); return new Vec3i(movement.getX(), movingUp ? 1 : -1, movement.getZ());
} }
protected Direction getMovementFacing() { public Direction getMovementFacing() {
return Direction.getFacingFromAxisDirection(getBeltFacing().getAxis(), return Direction.getFacingFromAxisDirection(getBeltFacing().getAxis(),
getBeltMovementSpeed() < 0 ? POSITIVE : NEGATIVE); getBeltMovementSpeed() < 0 ? POSITIVE : NEGATIVE);
} }

View file

@ -64,7 +64,8 @@ public class BeltTileEntityRenderer extends TileEntityRenderer<BeltTileEntity> {
boolean onSlope = slope != Slope.HORIZONTAL boolean onSlope = slope != Slope.HORIZONTAL
&& MathHelper.clamp(offset, .5f, te.beltLength - .5f) == offset; && MathHelper.clamp(offset, .5f, te.beltLength - .5f) == offset;
float slopeAngle = onSlope float slopeAngle = onSlope
? slope == Slope.DOWNWARD ^ te.getDirectionAwareBeltMovementSpeed() > 0 ? -45 : 45 ? slope == Slope.DOWNWARD ^ te.getDirectionAwareBeltMovementSpeed() > 0
^ te.getBeltMovementSpeed() < 0 ? -45 : 45
: 0; : 0;
GlStateManager.translated(offsetVec.x, offsetVec.y, offsetVec.z); GlStateManager.translated(offsetVec.x, offsetVec.y, offsetVec.z);
@ -150,5 +151,5 @@ public class BeltTileEntityRenderer extends TileEntityRenderer<BeltTileEntity> {
buffer.putBulkData(((BeltModelAnimator) KineticTileEntityRenderer.cachedBuffers buffer.putBulkData(((BeltModelAnimator) KineticTileEntityRenderer.cachedBuffers
.get(te.getBlockState().with(BeltBlock.CASING, false))).getTransformed(te, x, y, z, te.color)); .get(te.getBlockState().with(BeltBlock.CASING, false))).getTransformed(te, x, y, z, te.color));
} }
} }

View file

@ -1,27 +1,35 @@
package com.simibubi.create.modules.logistics.block.belts; package com.simibubi.create.modules.logistics.block.belts;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.block.IWithTileEntity; import com.simibubi.create.foundation.block.IWithTileEntity;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.BeltAttachmentState; import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.BeltAttachmentState;
import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.IBeltAttachment; import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.IBeltAttachment;
import com.simibubi.create.modules.contraptions.relays.belt.BeltInventory.TransportedItemStack;
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock; import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock;
import com.simibubi.create.modules.contraptions.relays.belt.BeltInventory.TransportedItemStack;
import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity; import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.modules.logistics.block.IBlockWithFilter;
import com.simibubi.create.modules.logistics.block.IInventoryManipulator; import com.simibubi.create.modules.logistics.block.IInventoryManipulator;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.block.HorizontalBlock; import net.minecraft.block.HorizontalBlock;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.state.StateContainer.Builder; import net.minecraft.state.StateContainer.Builder;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.shapes.ISelectionContext; import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes; import net.minecraft.util.math.shapes.VoxelShapes;
@ -30,7 +38,8 @@ import net.minecraft.world.IWorld;
import net.minecraft.world.IWorldReader; import net.minecraft.world.IWorldReader;
import net.minecraft.world.World; import net.minecraft.world.World;
public class BeltFunnelBlock extends HorizontalBlock implements IBeltAttachment, IWithTileEntity<BeltFunnelTileEntity> { public class BeltFunnelBlock extends HorizontalBlock
implements IBeltAttachment, IWithTileEntity<BeltFunnelTileEntity>, IBlockWithFilter {
public static final VoxelShape SHAPE_NORTH = makeCuboidShape(3, -4, -1, 13, 8, 5), public static final VoxelShape SHAPE_NORTH = makeCuboidShape(3, -4, -1, 13, 8, 5),
SHAPE_SOUTH = makeCuboidShape(3, -4, 11, 13, 8, 17), SHAPE_WEST = makeCuboidShape(-1, -4, 3, 5, 8, 13), SHAPE_SOUTH = makeCuboidShape(3, -4, 11, 13, 8, 17), SHAPE_WEST = makeCuboidShape(-1, -4, 3, 5, 8, 13),
@ -38,6 +47,7 @@ public class BeltFunnelBlock extends HorizontalBlock implements IBeltAttachment,
public BeltFunnelBlock() { public BeltFunnelBlock() {
super(Properties.from(Blocks.ANDESITE)); super(Properties.from(Blocks.ANDESITE));
cacheItemPositions();
} }
@Override @Override
@ -154,6 +164,12 @@ public class BeltFunnelBlock extends HorizontalBlock implements IBeltAttachment,
@Override @Override
public boolean processItem(BeltTileEntity te, TransportedItemStack transported, BeltAttachmentState state) { public boolean processItem(BeltTileEntity te, TransportedItemStack transported, BeltAttachmentState state) {
Direction movementFacing = te.getMovementFacing();
if (movementFacing.getAxis() == Axis.Z)
movementFacing = movementFacing.getOpposite();
if (movementFacing != te.getWorld().getBlockState(state.attachmentPos)
.get(HORIZONTAL_FACING))
return false;
return process(te, transported, state); return process(te, transported, state);
} }
@ -167,4 +183,54 @@ public class BeltFunnelBlock extends HorizontalBlock implements IBeltAttachment,
return true; return true;
} }
@Override
public boolean onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn,
BlockRayTraceResult hit) {
return handleActivatedFilterSlots(state, worldIn, pos, player, handIn, hit);
}
private static final List<Vec3d> itemPositions = new ArrayList<>(Direction.values().length);
private void cacheItemPositions() {
itemPositions.clear();
Vec3d position = Vec3d.ZERO;
Vec3d shift = VecHelper.getCenterOf(BlockPos.ZERO);
float zFightOffset = 1 / 128f;
for (int i = 0; i < 4; i++) {
Direction facing = Direction.byHorizontalIndex(i);
position = new Vec3d(8f / 16f + zFightOffset, 9f / 16f, 2.25f / 16f);
float angle = facing.getHorizontalAngle();
if (facing.getAxis() == Axis.X)
angle = -angle;
position = VecHelper.rotate(position.subtract(shift), angle, Axis.Y).add(shift);
itemPositions.add(position);
}
}
@Override
public boolean showsCount() {
return true;
}
@Override
public float getItemHitboxScale() {
return 1.76f / 16f;
}
@Override
public Vec3d getFilterPosition(BlockState state) {
Direction facing = state.get(HORIZONTAL_FACING).getOpposite();
return itemPositions.get(facing.getHorizontalIndex());
}
@Override
public Direction getFilterFacing(BlockState state) {
return state.get(HORIZONTAL_FACING).getOpposite();
}
} }

View file

@ -4,6 +4,7 @@ import com.simibubi.create.AllTileEntities;
import com.simibubi.create.foundation.block.SyncedTileEntity; import com.simibubi.create.foundation.block.SyncedTileEntity;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.relays.belt.BeltInventory.ItemHandlerSegment; import com.simibubi.create.modules.contraptions.relays.belt.BeltInventory.ItemHandlerSegment;
import com.simibubi.create.modules.logistics.block.IHaveFilter;
import com.simibubi.create.modules.logistics.block.IInventoryManipulator; import com.simibubi.create.modules.logistics.block.IInventoryManipulator;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@ -21,27 +22,32 @@ import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.ItemHandlerHelper;
public class BeltFunnelTileEntity extends SyncedTileEntity implements ITickableTileEntity, IInventoryManipulator { public class BeltFunnelTileEntity extends SyncedTileEntity
implements ITickableTileEntity, IInventoryManipulator, IHaveFilter {
private LazyOptional<IItemHandler> inventory; private LazyOptional<IItemHandler> inventory;
protected boolean waitingForInventorySpace; protected boolean waitingForInventorySpace;
private boolean initialize; private boolean initialize;
private ItemStack filter;
private ItemStack justEaten; private ItemStack justEaten;
public BeltFunnelTileEntity() { public BeltFunnelTileEntity() {
super(AllTileEntities.BELT_FUNNEL.type); super(AllTileEntities.BELT_FUNNEL.type);
inventory = LazyOptional.empty(); inventory = LazyOptional.empty();
filter = ItemStack.EMPTY;
} }
@Override @Override
public void read(CompoundNBT compound) { public void read(CompoundNBT compound) {
filter = ItemStack.read(compound.getCompound("Filter"));
waitingForInventorySpace = compound.getBoolean("Waiting"); waitingForInventorySpace = compound.getBoolean("Waiting");
super.read(compound); super.read(compound);
} }
@Override @Override
public CompoundNBT write(CompoundNBT compound) { public CompoundNBT write(CompoundNBT compound) {
compound.put("Filter", filter.serializeNBT());
compound.putBoolean("Waiting", waitingForInventorySpace); compound.putBoolean("Waiting", waitingForInventorySpace);
return super.write(compound); return super.write(compound);
} }
@ -109,16 +115,26 @@ public class BeltFunnelTileEntity extends SyncedTileEntity implements ITickableT
return stack; return stack;
if (waitingForInventorySpace && !(inventory.orElse(null) instanceof ItemHandlerSegment)) if (waitingForInventorySpace && !(inventory.orElse(null) instanceof ItemHandlerSegment))
return stack; return stack;
if (!filter.isEmpty() && !ItemStack.areItemsEqual(filter, stack))
return stack;
IItemHandler inv = inventory.orElse(null); IItemHandler inv = inventory.orElse(null);
ItemStack remainder = ItemHandlerHelper.insertItemStacked(inv, stack.copy(), false); ItemStack inserted = stack.copy();
int amountToExtract = Math.min(filter.isEmpty() ? 64 : filter.getCount(), stack.getCount());
inserted.setCount(amountToExtract);
ItemStack remainder = ItemHandlerHelper.insertItemStacked(inv, inserted, false);
if (remainder.isEmpty()) { if (remainder.isEmpty()) {
if (!world.isRemote) if (!world.isRemote)
world.playSound(null, pos, SoundEvents.ENTITY_GENERIC_EAT, SoundCategory.BLOCKS, .125f, 1f); world.playSound(null, pos, SoundEvents.ENTITY_GENERIC_EAT, SoundCategory.BLOCKS, .125f, 1f);
justEaten = stack; justEaten = stack.copy();
remainder = stack.copy();
remainder.setCount(stack.getCount() - amountToExtract);
} else { } else {
waitingForInventorySpace = true; waitingForInventorySpace = true;
remainder.grow(stack.getCount() - amountToExtract);
} }
sendData(); sendData();
@ -134,4 +150,17 @@ public class BeltFunnelTileEntity extends SyncedTileEntity implements ITickableT
1 / 6f, zSpeed); 1 / 6f, zSpeed);
} }
@Override
public void setFilter(ItemStack stack) {
filter = stack.copy();
markDirty();
sendData();
neighborChanged();
}
@Override
public ItemStack getFilter() {
return filter.copy();
}
} }

View file

@ -0,0 +1,22 @@
package com.simibubi.create.modules.logistics.block.belts;
import com.simibubi.create.modules.logistics.block.FilteredTileEntityRenderer;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
public class BeltFunnelTileEntityRenderer extends TileEntityRenderer<BeltFunnelTileEntity> {
FilteredTileEntityRenderer filterRenderer;
public BeltFunnelTileEntityRenderer() {
filterRenderer = new FilteredTileEntityRenderer();
}
@Override
public void render(BeltFunnelTileEntity tileEntityIn, double x, double y, double z, float partialTicks,
int destroyStage) {
super.render(tileEntityIn, x, y, z, partialTicks, destroyStage);
filterRenderer.render(tileEntityIn, x, y, z, partialTicks, destroyStage);
}
}